opencastle 0.21.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/convoy/engine.d.ts +4 -0
- package/dist/cli/convoy/engine.d.ts.map +1 -1
- package/dist/cli/convoy/engine.js +23 -1
- package/dist/cli/convoy/engine.js.map +1 -1
- package/dist/cli/convoy/engine.test.js +148 -0
- package/dist/cli/convoy/engine.test.js.map +1 -1
- package/dist/cli/convoy/export.d.ts +1 -0
- package/dist/cli/convoy/export.d.ts.map +1 -1
- package/dist/cli/convoy/export.js +39 -0
- package/dist/cli/convoy/export.js.map +1 -1
- package/dist/cli/convoy/export.test.js +31 -0
- package/dist/cli/convoy/export.test.js.map +1 -1
- package/dist/cli/convoy/pipeline.d.ts +35 -0
- package/dist/cli/convoy/pipeline.d.ts.map +1 -0
- package/dist/cli/convoy/pipeline.js +353 -0
- package/dist/cli/convoy/pipeline.js.map +1 -0
- package/dist/cli/convoy/pipeline.test.d.ts +2 -0
- package/dist/cli/convoy/pipeline.test.d.ts.map +1 -0
- package/dist/cli/convoy/pipeline.test.js +778 -0
- package/dist/cli/convoy/pipeline.test.js.map +1 -0
- package/dist/cli/convoy/store.d.ts +18 -4
- package/dist/cli/convoy/store.d.ts.map +1 -1
- package/dist/cli/convoy/store.js +119 -14
- package/dist/cli/convoy/store.js.map +1 -1
- package/dist/cli/convoy/store.test.js +413 -4
- package/dist/cli/convoy/store.test.js.map +1 -1
- package/dist/cli/convoy/types.d.ts +21 -0
- package/dist/cli/convoy/types.d.ts.map +1 -1
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +1 -0
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/run/adapters/claude-code.d.ts.map +1 -1
- package/dist/cli/run/adapters/claude-code.js +13 -0
- package/dist/cli/run/adapters/claude-code.js.map +1 -1
- package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
- package/dist/cli/run/adapters/copilot.js +8 -0
- package/dist/cli/run/adapters/copilot.js.map +1 -1
- package/dist/cli/run/adapters/cursor.d.ts.map +1 -1
- package/dist/cli/run/adapters/cursor.js +13 -0
- package/dist/cli/run/adapters/cursor.js.map +1 -1
- package/dist/cli/run/adapters/opencode.d.ts.map +1 -1
- package/dist/cli/run/adapters/opencode.js +13 -0
- package/dist/cli/run/adapters/opencode.js.map +1 -1
- package/dist/cli/run/schema.d.ts +5 -1
- package/dist/cli/run/schema.d.ts.map +1 -1
- package/dist/cli/run/schema.js +41 -8
- package/dist/cli/run/schema.js.map +1 -1
- package/dist/cli/run/schema.test.js +194 -5
- package/dist/cli/run/schema.test.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +167 -2
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/types.d.ts +11 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/convoy/engine.test.ts +177 -0
- package/src/cli/convoy/engine.ts +24 -1
- package/src/cli/convoy/export.test.ts +37 -0
- package/src/cli/convoy/export.ts +46 -0
- package/src/cli/convoy/pipeline.test.ts +939 -0
- package/src/cli/convoy/pipeline.ts +430 -0
- package/src/cli/convoy/store.test.ts +452 -4
- package/src/cli/convoy/store.ts +152 -23
- package/src/cli/convoy/types.ts +23 -0
- package/src/cli/dashboard.ts +1 -0
- package/src/cli/run/adapters/claude-code.ts +13 -1
- package/src/cli/run/adapters/copilot.ts +8 -0
- package/src/cli/run/adapters/cursor.ts +13 -1
- package/src/cli/run/adapters/opencode.ts +13 -1
- package/src/cli/run/schema.test.ts +244 -5
- package/src/cli/run/schema.ts +49 -8
- package/src/cli/run.ts +163 -2
- package/src/cli/types.ts +12 -1
- package/src/dashboard/dist/_astro/{index.DyyaCW8L.css → index.Cq68OHaZ.css} +1 -1
- package/src/dashboard/dist/index.html +225 -3
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/src/pages/index.astro +241 -2
- package/src/dashboard/src/styles/dashboard.css +116 -0
- package/src/orchestrator/customizations/KNOWN-ISSUES.md +1 -1
package/src/cli/convoy/store.ts
CHANGED
|
@@ -7,23 +7,25 @@ import type {
|
|
|
7
7
|
WorkerRecord,
|
|
8
8
|
WorkerStatus,
|
|
9
9
|
EventRecord,
|
|
10
|
+
PipelineRecord,
|
|
11
|
+
PipelineStatus,
|
|
10
12
|
} from './types.js'
|
|
11
13
|
|
|
12
|
-
const SCHEMA_VERSION =
|
|
14
|
+
const SCHEMA_VERSION = 4
|
|
13
15
|
|
|
14
16
|
export interface ConvoyStore {
|
|
15
|
-
insertConvoy(record: Omit<ConvoyRecord, 'started_at' | 'finished_at'>): void
|
|
17
|
+
insertConvoy(record: Omit<ConvoyRecord, 'started_at' | 'finished_at' | 'total_tokens' | 'total_cost_usd' | 'pipeline_id'> & { pipeline_id?: string | null }): void
|
|
16
18
|
getConvoy(id: string): ConvoyRecord | undefined
|
|
17
19
|
getLatestConvoy(): ConvoyRecord | undefined
|
|
18
20
|
updateConvoyStatus(
|
|
19
21
|
id: string,
|
|
20
22
|
status: ConvoyStatus,
|
|
21
|
-
extra?: { started_at?: string; finished_at?: string },
|
|
23
|
+
extra?: { started_at?: string; finished_at?: string; total_tokens?: number | null; total_cost_usd?: string | null },
|
|
22
24
|
): void
|
|
23
25
|
insertTask(
|
|
24
26
|
record: Omit<
|
|
25
27
|
TaskRecord,
|
|
26
|
-
'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at'
|
|
28
|
+
'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at' | 'prompt_tokens' | 'completion_tokens' | 'total_tokens' | 'cost_usd'
|
|
27
29
|
>,
|
|
28
30
|
): void
|
|
29
31
|
getTask(id: string, convoyId: string): TaskRecord | undefined
|
|
@@ -33,7 +35,7 @@ export interface ConvoyStore {
|
|
|
33
35
|
convoyId: string,
|
|
34
36
|
status: ConvoyTaskStatus,
|
|
35
37
|
extra?: Partial<
|
|
36
|
-
Pick<TaskRecord, 'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at' | 'retries'>
|
|
38
|
+
Pick<TaskRecord, 'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at' | 'retries' | 'prompt_tokens' | 'completion_tokens' | 'total_tokens' | 'cost_usd'>
|
|
37
39
|
>,
|
|
38
40
|
): void
|
|
39
41
|
getReadyTasks(convoyId: string): TaskRecord[]
|
|
@@ -46,6 +48,15 @@ export interface ConvoyStore {
|
|
|
46
48
|
): void
|
|
47
49
|
insertEvent(record: Omit<EventRecord, 'id'>): void
|
|
48
50
|
getEvents(convoyId: string): EventRecord[]
|
|
51
|
+
insertPipeline(record: Omit<PipelineRecord, 'started_at' | 'finished_at' | 'total_tokens' | 'total_cost_usd'>): void
|
|
52
|
+
getPipeline(id: string): PipelineRecord | undefined
|
|
53
|
+
getLatestPipeline(): PipelineRecord | undefined
|
|
54
|
+
updatePipelineStatus(
|
|
55
|
+
id: string,
|
|
56
|
+
status: PipelineStatus,
|
|
57
|
+
extra?: { started_at?: string; finished_at?: string; total_tokens?: number | null; total_cost_usd?: string | null },
|
|
58
|
+
): void
|
|
59
|
+
getConvoysByPipeline(pipelineId: string): ConvoyRecord[]
|
|
49
60
|
withTransaction<T>(fn: () => T): T
|
|
50
61
|
close(): void
|
|
51
62
|
}
|
|
@@ -61,8 +72,8 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
61
72
|
}
|
|
62
73
|
|
|
63
74
|
private initSchema(): void {
|
|
64
|
-
|
|
65
|
-
if (
|
|
75
|
+
let version = (this.db.prepare('PRAGMA user_version').get() as { user_version: number }).user_version
|
|
76
|
+
if (version === 0) {
|
|
66
77
|
this.db.exec(`
|
|
67
78
|
CREATE TABLE IF NOT EXISTS convoy (
|
|
68
79
|
id TEXT PRIMARY KEY,
|
|
@@ -72,8 +83,25 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
72
83
|
branch TEXT,
|
|
73
84
|
created_at TEXT NOT NULL,
|
|
74
85
|
started_at TEXT,
|
|
75
|
-
finished_at
|
|
76
|
-
spec_yaml
|
|
86
|
+
finished_at TEXT,
|
|
87
|
+
spec_yaml TEXT NOT NULL,
|
|
88
|
+
total_tokens INTEGER,
|
|
89
|
+
total_cost_usd TEXT,
|
|
90
|
+
pipeline_id TEXT
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE TABLE IF NOT EXISTS pipeline (
|
|
94
|
+
id TEXT PRIMARY KEY,
|
|
95
|
+
name TEXT NOT NULL,
|
|
96
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
97
|
+
branch TEXT,
|
|
98
|
+
spec_yaml TEXT NOT NULL,
|
|
99
|
+
convoy_specs TEXT NOT NULL,
|
|
100
|
+
created_at TEXT NOT NULL,
|
|
101
|
+
started_at TEXT,
|
|
102
|
+
finished_at TEXT,
|
|
103
|
+
total_tokens INTEGER,
|
|
104
|
+
total_cost_usd TEXT
|
|
77
105
|
);
|
|
78
106
|
|
|
79
107
|
CREATE TABLE IF NOT EXISTS task (
|
|
@@ -92,10 +120,14 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
92
120
|
exit_code INTEGER,
|
|
93
121
|
started_at TEXT,
|
|
94
122
|
finished_at TEXT,
|
|
95
|
-
retries
|
|
96
|
-
max_retries
|
|
97
|
-
files
|
|
98
|
-
depends_on
|
|
123
|
+
retries INTEGER NOT NULL DEFAULT 0,
|
|
124
|
+
max_retries INTEGER NOT NULL DEFAULT 1,
|
|
125
|
+
files TEXT,
|
|
126
|
+
depends_on TEXT,
|
|
127
|
+
prompt_tokens INTEGER,
|
|
128
|
+
completion_tokens INTEGER,
|
|
129
|
+
total_tokens INTEGER,
|
|
130
|
+
cost_usd TEXT
|
|
99
131
|
);
|
|
100
132
|
|
|
101
133
|
CREATE TABLE IF NOT EXISTS worker (
|
|
@@ -122,20 +154,52 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
122
154
|
);
|
|
123
155
|
`)
|
|
124
156
|
this.db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`)
|
|
157
|
+
version = SCHEMA_VERSION
|
|
125
158
|
}
|
|
126
|
-
if (
|
|
159
|
+
if (version === 1) {
|
|
127
160
|
this.db.exec('ALTER TABLE task ADD COLUMN adapter TEXT')
|
|
128
161
|
this.db.exec('PRAGMA user_version = 2')
|
|
162
|
+
version = 2
|
|
163
|
+
}
|
|
164
|
+
if (version === 2) {
|
|
165
|
+
this.db.exec('ALTER TABLE task ADD COLUMN prompt_tokens INTEGER')
|
|
166
|
+
this.db.exec('ALTER TABLE task ADD COLUMN completion_tokens INTEGER')
|
|
167
|
+
this.db.exec('ALTER TABLE task ADD COLUMN total_tokens INTEGER')
|
|
168
|
+
this.db.exec('ALTER TABLE task ADD COLUMN cost_usd TEXT')
|
|
169
|
+
this.db.exec('ALTER TABLE convoy ADD COLUMN total_tokens INTEGER')
|
|
170
|
+
this.db.exec('ALTER TABLE convoy ADD COLUMN total_cost_usd TEXT')
|
|
171
|
+
this.db.exec('PRAGMA user_version = 3')
|
|
172
|
+
version = 3
|
|
173
|
+
}
|
|
174
|
+
if (version === 3) {
|
|
175
|
+
this.db.exec(`
|
|
176
|
+
CREATE TABLE IF NOT EXISTS pipeline (
|
|
177
|
+
id TEXT PRIMARY KEY,
|
|
178
|
+
name TEXT NOT NULL,
|
|
179
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
180
|
+
branch TEXT,
|
|
181
|
+
spec_yaml TEXT NOT NULL,
|
|
182
|
+
convoy_specs TEXT NOT NULL,
|
|
183
|
+
created_at TEXT NOT NULL,
|
|
184
|
+
started_at TEXT,
|
|
185
|
+
finished_at TEXT,
|
|
186
|
+
total_tokens INTEGER,
|
|
187
|
+
total_cost_usd TEXT
|
|
188
|
+
)
|
|
189
|
+
`)
|
|
190
|
+
this.db.exec('ALTER TABLE convoy ADD COLUMN pipeline_id TEXT')
|
|
191
|
+
this.db.exec('PRAGMA user_version = 4')
|
|
192
|
+
version = 4
|
|
129
193
|
}
|
|
130
194
|
}
|
|
131
195
|
|
|
132
|
-
insertConvoy(record: Omit<ConvoyRecord, 'started_at' | 'finished_at'>): void {
|
|
196
|
+
insertConvoy(record: Omit<ConvoyRecord, 'started_at' | 'finished_at' | 'total_tokens' | 'total_cost_usd' | 'pipeline_id'> & { pipeline_id?: string | null }): void {
|
|
133
197
|
this.db
|
|
134
198
|
.prepare(
|
|
135
|
-
`INSERT INTO convoy (id, name, spec_hash, status, branch, created_at, started_at, finished_at, spec_yaml)
|
|
136
|
-
VALUES (:id, :name, :spec_hash, :status, :branch, :created_at, NULL, NULL, :spec_yaml)`,
|
|
199
|
+
`INSERT INTO convoy (id, name, spec_hash, status, branch, created_at, started_at, finished_at, spec_yaml, pipeline_id)
|
|
200
|
+
VALUES (:id, :name, :spec_hash, :status, :branch, :created_at, NULL, NULL, :spec_yaml, :pipeline_id)`,
|
|
137
201
|
)
|
|
138
|
-
.run(record)
|
|
202
|
+
.run({ ...record, pipeline_id: record.pipeline_id ?? null })
|
|
139
203
|
}
|
|
140
204
|
|
|
141
205
|
getConvoy(id: string): ConvoyRecord | undefined {
|
|
@@ -153,10 +217,10 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
153
217
|
updateConvoyStatus(
|
|
154
218
|
id: string,
|
|
155
219
|
status: ConvoyStatus,
|
|
156
|
-
extra?: { started_at?: string; finished_at?: string },
|
|
220
|
+
extra?: { started_at?: string; finished_at?: string; total_tokens?: number | null; total_cost_usd?: string | null },
|
|
157
221
|
): void {
|
|
158
222
|
const sets = ['status = :status']
|
|
159
|
-
const params: Record<string, string | null> = { id, status }
|
|
223
|
+
const params: Record<string, string | number | null> = { id, status }
|
|
160
224
|
|
|
161
225
|
if (extra?.started_at !== undefined) {
|
|
162
226
|
sets.push('started_at = :started_at')
|
|
@@ -166,6 +230,14 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
166
230
|
sets.push('finished_at = :finished_at')
|
|
167
231
|
params.finished_at = extra.finished_at
|
|
168
232
|
}
|
|
233
|
+
if (extra?.total_tokens !== undefined) {
|
|
234
|
+
sets.push('total_tokens = :total_tokens')
|
|
235
|
+
params.total_tokens = extra.total_tokens
|
|
236
|
+
}
|
|
237
|
+
if (extra?.total_cost_usd !== undefined) {
|
|
238
|
+
sets.push('total_cost_usd = :total_cost_usd')
|
|
239
|
+
params.total_cost_usd = extra.total_cost_usd
|
|
240
|
+
}
|
|
169
241
|
|
|
170
242
|
this.db.prepare(`UPDATE convoy SET ${sets.join(', ')} WHERE id = :id`).run(params)
|
|
171
243
|
}
|
|
@@ -173,7 +245,7 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
173
245
|
insertTask(
|
|
174
246
|
record: Omit<
|
|
175
247
|
TaskRecord,
|
|
176
|
-
'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at'
|
|
248
|
+
'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at' | 'prompt_tokens' | 'completion_tokens' | 'total_tokens' | 'cost_usd'
|
|
177
249
|
>,
|
|
178
250
|
): void {
|
|
179
251
|
this.db
|
|
@@ -207,12 +279,12 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
207
279
|
convoyId: string,
|
|
208
280
|
status: ConvoyTaskStatus,
|
|
209
281
|
extra?: Partial<
|
|
210
|
-
Pick<TaskRecord, 'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at' | 'retries'>
|
|
282
|
+
Pick<TaskRecord, 'worker_id' | 'worktree' | 'output' | 'exit_code' | 'started_at' | 'finished_at' | 'retries' | 'prompt_tokens' | 'completion_tokens' | 'total_tokens' | 'cost_usd'>
|
|
211
283
|
>,
|
|
212
284
|
): void {
|
|
213
285
|
const sets = ['status = :status']
|
|
214
286
|
const params: Record<string, string | number | null> = { id, convoy_id: convoyId, status }
|
|
215
|
-
const extraFields = ['worker_id', 'worktree', 'output', 'exit_code', 'started_at', 'finished_at', 'retries'] as const
|
|
287
|
+
const extraFields = ['worker_id', 'worktree', 'output', 'exit_code', 'started_at', 'finished_at', 'retries', 'prompt_tokens', 'completion_tokens', 'total_tokens', 'cost_usd'] as const
|
|
216
288
|
|
|
217
289
|
if (extra) {
|
|
218
290
|
for (const field of extraFields) {
|
|
@@ -298,6 +370,63 @@ class ConvoyStoreImpl implements ConvoyStore {
|
|
|
298
370
|
.all({ convoy_id: convoyId }) as unknown as EventRecord[]
|
|
299
371
|
}
|
|
300
372
|
|
|
373
|
+
insertPipeline(record: Omit<PipelineRecord, 'started_at' | 'finished_at' | 'total_tokens' | 'total_cost_usd'>): void {
|
|
374
|
+
this.db
|
|
375
|
+
.prepare(
|
|
376
|
+
`INSERT INTO pipeline (id, name, status, branch, spec_yaml, convoy_specs, created_at,
|
|
377
|
+
started_at, finished_at, total_tokens, total_cost_usd)
|
|
378
|
+
VALUES (:id, :name, :status, :branch, :spec_yaml, :convoy_specs, :created_at,
|
|
379
|
+
NULL, NULL, NULL, NULL)`,
|
|
380
|
+
)
|
|
381
|
+
.run(record)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
getPipeline(id: string): PipelineRecord | undefined {
|
|
385
|
+
return this.db
|
|
386
|
+
.prepare('SELECT * FROM pipeline WHERE id = :id')
|
|
387
|
+
.get({ id }) as PipelineRecord | undefined
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
getLatestPipeline(): PipelineRecord | undefined {
|
|
391
|
+
return this.db
|
|
392
|
+
.prepare('SELECT * FROM pipeline ORDER BY created_at DESC LIMIT 1')
|
|
393
|
+
.get() as PipelineRecord | undefined
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
updatePipelineStatus(
|
|
397
|
+
id: string,
|
|
398
|
+
status: PipelineStatus,
|
|
399
|
+
extra?: { started_at?: string; finished_at?: string; total_tokens?: number | null; total_cost_usd?: string | null },
|
|
400
|
+
): void {
|
|
401
|
+
const sets = ['status = :status']
|
|
402
|
+
const params: Record<string, string | number | null> = { id, status }
|
|
403
|
+
|
|
404
|
+
if (extra?.started_at !== undefined) {
|
|
405
|
+
sets.push('started_at = :started_at')
|
|
406
|
+
params.started_at = extra.started_at
|
|
407
|
+
}
|
|
408
|
+
if (extra?.finished_at !== undefined) {
|
|
409
|
+
sets.push('finished_at = :finished_at')
|
|
410
|
+
params.finished_at = extra.finished_at
|
|
411
|
+
}
|
|
412
|
+
if (extra?.total_tokens !== undefined) {
|
|
413
|
+
sets.push('total_tokens = :total_tokens')
|
|
414
|
+
params.total_tokens = extra.total_tokens
|
|
415
|
+
}
|
|
416
|
+
if (extra?.total_cost_usd !== undefined) {
|
|
417
|
+
sets.push('total_cost_usd = :total_cost_usd')
|
|
418
|
+
params.total_cost_usd = extra.total_cost_usd
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
this.db.prepare(`UPDATE pipeline SET ${sets.join(', ')} WHERE id = :id`).run(params)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
getConvoysByPipeline(pipelineId: string): ConvoyRecord[] {
|
|
425
|
+
return this.db
|
|
426
|
+
.prepare('SELECT * FROM convoy WHERE pipeline_id = :pipeline_id ORDER BY created_at')
|
|
427
|
+
.all({ pipeline_id: pipelineId }) as unknown as ConvoyRecord[]
|
|
428
|
+
}
|
|
429
|
+
|
|
301
430
|
withTransaction<T>(fn: () => T): T {
|
|
302
431
|
this.db.exec('BEGIN')
|
|
303
432
|
try {
|
package/src/cli/convoy/types.ts
CHANGED
|
@@ -11,6 +11,8 @@ export type ConvoyTaskStatus =
|
|
|
11
11
|
|
|
12
12
|
export type WorkerStatus = 'spawned' | 'running' | 'done' | 'failed' | 'killed'
|
|
13
13
|
|
|
14
|
+
export type PipelineStatus = 'pending' | 'running' | 'done' | 'failed'
|
|
15
|
+
|
|
14
16
|
export interface ConvoyRecord {
|
|
15
17
|
id: string
|
|
16
18
|
name: string
|
|
@@ -21,6 +23,9 @@ export interface ConvoyRecord {
|
|
|
21
23
|
started_at: string | null
|
|
22
24
|
finished_at: string | null
|
|
23
25
|
spec_yaml: string
|
|
26
|
+
total_tokens: number | null
|
|
27
|
+
total_cost_usd: string | null
|
|
28
|
+
pipeline_id: string | null
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export interface TaskRecord {
|
|
@@ -43,6 +48,10 @@ export interface TaskRecord {
|
|
|
43
48
|
max_retries: number
|
|
44
49
|
files: string | null
|
|
45
50
|
depends_on: string | null
|
|
51
|
+
prompt_tokens: number | null
|
|
52
|
+
completion_tokens: number | null
|
|
53
|
+
total_tokens: number | null
|
|
54
|
+
cost_usd: string | null
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
export interface WorkerRecord {
|
|
@@ -67,3 +76,17 @@ export interface EventRecord {
|
|
|
67
76
|
data: string | null
|
|
68
77
|
created_at: string
|
|
69
78
|
}
|
|
79
|
+
|
|
80
|
+
export interface PipelineRecord {
|
|
81
|
+
id: string
|
|
82
|
+
name: string
|
|
83
|
+
status: PipelineStatus
|
|
84
|
+
branch: string | null
|
|
85
|
+
spec_yaml: string
|
|
86
|
+
convoy_specs: string
|
|
87
|
+
created_at: string
|
|
88
|
+
started_at: string | null
|
|
89
|
+
finished_at: string | null
|
|
90
|
+
total_tokens: number | null
|
|
91
|
+
total_cost_usd: string | null
|
|
92
|
+
}
|
package/src/cli/dashboard.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
|
-
import type { Task, ExecuteOptions, ExecuteResult } from '../../types.js'
|
|
2
|
+
import type { Task, ExecuteOptions, ExecuteResult, TokenUsage } from '../../types.js'
|
|
3
3
|
|
|
4
4
|
/** Adapter name */
|
|
5
5
|
export const name = 'claude-code'
|
|
@@ -60,10 +60,22 @@ export async function execute(task: Task, options: ExecuteOptions = {}): Promise
|
|
|
60
60
|
|
|
61
61
|
proc.on('close', (code) => {
|
|
62
62
|
const output = [stdout, stderr].filter(Boolean).join('\n')
|
|
63
|
+
let usage: TokenUsage | undefined
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(stdout) as Record<string, unknown>
|
|
66
|
+
const u = parsed?.usage as Record<string, number> | undefined
|
|
67
|
+
if (u) {
|
|
68
|
+
const promptTokens = (u.input_tokens ?? u.prompt_tokens) as number | undefined
|
|
69
|
+
const completionTokens = (u.output_tokens ?? u.completion_tokens) as number | undefined
|
|
70
|
+
const total = ((promptTokens ?? 0) + (completionTokens ?? 0)) || undefined
|
|
71
|
+
usage = { prompt_tokens: promptTokens, completion_tokens: completionTokens, total_tokens: total }
|
|
72
|
+
}
|
|
73
|
+
} catch { /* not JSON or no usage — graceful degradation */ }
|
|
63
74
|
resolve({
|
|
64
75
|
success: code === 0,
|
|
65
76
|
output: output.slice(0, 10000), // Cap output size
|
|
66
77
|
exitCode: code ?? -1,
|
|
78
|
+
usage,
|
|
67
79
|
})
|
|
68
80
|
})
|
|
69
81
|
|
|
@@ -100,11 +100,19 @@ export async function execute(task: Task, options: ExecuteOptions = {}): Promise
|
|
|
100
100
|
const timeoutMs = parseTimeout(task.timeout)
|
|
101
101
|
const response = await session.sendAndWait({ prompt }, timeoutMs)
|
|
102
102
|
const output = response?.data?.content ?? ''
|
|
103
|
+
const rawUsage = (response?.data as Record<string, unknown> | undefined)?.usage ?? (response as Record<string, unknown> | undefined)?.usage
|
|
104
|
+
const u = rawUsage as Record<string, number> | undefined
|
|
105
|
+
const usageResult = u ? {
|
|
106
|
+
prompt_tokens: u.prompt_tokens ?? u.promptTokens,
|
|
107
|
+
completion_tokens: u.completion_tokens ?? u.completionTokens,
|
|
108
|
+
total_tokens: u.total_tokens ?? u.totalTokens,
|
|
109
|
+
} : undefined
|
|
103
110
|
|
|
104
111
|
return {
|
|
105
112
|
success: true,
|
|
106
113
|
output: output.slice(0, 10_000),
|
|
107
114
|
exitCode: 0,
|
|
115
|
+
usage: usageResult,
|
|
108
116
|
}
|
|
109
117
|
} catch (err: unknown) {
|
|
110
118
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
|
-
import type { Task, ExecuteOptions, ExecuteResult } from '../../types.js'
|
|
2
|
+
import type { Task, ExecuteOptions, ExecuteResult, TokenUsage } from '../../types.js'
|
|
3
3
|
|
|
4
4
|
/** Adapter name */
|
|
5
5
|
export const name = 'cursor'
|
|
@@ -59,10 +59,22 @@ export async function execute(task: Task, options: ExecuteOptions = {}): Promise
|
|
|
59
59
|
|
|
60
60
|
proc.on('close', (code) => {
|
|
61
61
|
const output = [stdout, stderr].filter(Boolean).join('\n')
|
|
62
|
+
let usage: TokenUsage | undefined
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(stdout) as Record<string, unknown>
|
|
65
|
+
const u = parsed?.usage as Record<string, number> | undefined
|
|
66
|
+
if (u) {
|
|
67
|
+
const promptTokens = (u.input_tokens ?? u.prompt_tokens) as number | undefined
|
|
68
|
+
const completionTokens = (u.output_tokens ?? u.completion_tokens) as number | undefined
|
|
69
|
+
const total = ((promptTokens ?? 0) + (completionTokens ?? 0)) || undefined
|
|
70
|
+
usage = { prompt_tokens: promptTokens, completion_tokens: completionTokens, total_tokens: total }
|
|
71
|
+
}
|
|
72
|
+
} catch { /* not JSON or no usage — graceful degradation */ }
|
|
62
73
|
resolve({
|
|
63
74
|
success: code === 0,
|
|
64
75
|
output: output.slice(0, 10000), // Cap output size
|
|
65
76
|
exitCode: code ?? -1,
|
|
77
|
+
usage,
|
|
66
78
|
})
|
|
67
79
|
})
|
|
68
80
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
|
-
import type { Task, ExecuteOptions, ExecuteResult } from '../../types.js'
|
|
2
|
+
import type { Task, ExecuteOptions, ExecuteResult, TokenUsage } from '../../types.js'
|
|
3
3
|
|
|
4
4
|
/** Adapter name */
|
|
5
5
|
export const name = 'opencode'
|
|
@@ -53,10 +53,22 @@ export async function execute(task: Task, options: ExecuteOptions = {}): Promise
|
|
|
53
53
|
|
|
54
54
|
proc.on('close', (code) => {
|
|
55
55
|
const output = [stdout, stderr].filter(Boolean).join('\n')
|
|
56
|
+
let usage: TokenUsage | undefined
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(stdout) as Record<string, unknown>
|
|
59
|
+
const u = parsed?.usage as Record<string, number> | undefined
|
|
60
|
+
if (u) {
|
|
61
|
+
const promptTokens = (u.input_tokens ?? u.prompt_tokens) as number | undefined
|
|
62
|
+
const completionTokens = (u.output_tokens ?? u.completion_tokens) as number | undefined
|
|
63
|
+
const total = ((promptTokens ?? 0) + (completionTokens ?? 0)) || undefined
|
|
64
|
+
usage = { prompt_tokens: promptTokens, completion_tokens: completionTokens, total_tokens: total }
|
|
65
|
+
}
|
|
66
|
+
} catch { /* not JSON or no usage — graceful degradation */ }
|
|
56
67
|
resolve({
|
|
57
68
|
success: code === 0,
|
|
58
69
|
output: output.slice(0, 10000), // Cap output size
|
|
59
70
|
exitCode: code ?? -1,
|
|
71
|
+
usage,
|
|
60
72
|
})
|
|
61
73
|
})
|
|
62
74
|
|