opencastle 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +12 -3
  2. package/dist/cli/convoy/engine.d.ts.map +1 -1
  3. package/dist/cli/convoy/engine.js +0 -9
  4. package/dist/cli/convoy/engine.js.map +1 -1
  5. package/dist/cli/convoy/engine.test.js +1 -0
  6. package/dist/cli/convoy/engine.test.js.map +1 -1
  7. package/dist/cli/convoy/export.d.ts +1 -3
  8. package/dist/cli/convoy/export.d.ts.map +1 -1
  9. package/dist/cli/convoy/export.js +9 -88
  10. package/dist/cli/convoy/export.js.map +1 -1
  11. package/dist/cli/convoy/export.test.js +7 -186
  12. package/dist/cli/convoy/export.test.js.map +1 -1
  13. package/dist/cli/convoy/pipeline.d.ts.map +1 -1
  14. package/dist/cli/convoy/pipeline.js +0 -21
  15. package/dist/cli/convoy/pipeline.js.map +1 -1
  16. package/dist/cli/convoy/pipeline.test.js +0 -21
  17. package/dist/cli/convoy/pipeline.test.js.map +1 -1
  18. package/dist/cli/dashboard.d.ts.map +1 -1
  19. package/dist/cli/dashboard.js +32 -8
  20. package/dist/cli/dashboard.js.map +1 -1
  21. package/dist/cli/destroy.d.ts.map +1 -1
  22. package/dist/cli/destroy.js +13 -0
  23. package/dist/cli/destroy.js.map +1 -1
  24. package/dist/cli/dispute.d.ts +3 -0
  25. package/dist/cli/dispute.d.ts.map +1 -0
  26. package/dist/cli/dispute.js +25 -0
  27. package/dist/cli/dispute.js.map +1 -0
  28. package/dist/cli/doctor.d.ts +1 -1
  29. package/dist/cli/doctor.d.ts.map +1 -1
  30. package/dist/cli/doctor.js +14 -1
  31. package/dist/cli/doctor.js.map +1 -1
  32. package/dist/cli/eject.d.ts.map +1 -1
  33. package/dist/cli/eject.js +14 -0
  34. package/dist/cli/eject.js.map +1 -1
  35. package/dist/cli/init.d.ts.map +1 -1
  36. package/dist/cli/init.js +14 -0
  37. package/dist/cli/init.js.map +1 -1
  38. package/dist/cli/log.d.ts +0 -11
  39. package/dist/cli/log.d.ts.map +1 -1
  40. package/dist/cli/log.js +2 -114
  41. package/dist/cli/log.js.map +1 -1
  42. package/dist/cli/pipeline.js +21 -5
  43. package/dist/cli/pipeline.js.map +1 -1
  44. package/dist/cli/run.js +2 -2
  45. package/dist/cli/run.js.map +1 -1
  46. package/dist/cli/update.d.ts.map +1 -1
  47. package/dist/cli/update.js +16 -0
  48. package/dist/cli/update.js.map +1 -1
  49. package/dist/cli/watch.d.ts.map +1 -1
  50. package/dist/cli/watch.js +1 -3
  51. package/dist/cli/watch.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/cli/convoy/engine.test.ts +1 -0
  54. package/src/cli/convoy/engine.ts +0 -3
  55. package/src/cli/convoy/export.test.ts +7 -224
  56. package/src/cli/convoy/export.ts +10 -106
  57. package/src/cli/convoy/pipeline.test.ts +0 -25
  58. package/src/cli/convoy/pipeline.ts +0 -19
  59. package/src/cli/dashboard.ts +33 -8
  60. package/src/cli/destroy.ts +15 -0
  61. package/src/cli/dispute.ts +28 -0
  62. package/src/cli/doctor.ts +16 -1
  63. package/src/cli/eject.ts +16 -0
  64. package/src/cli/init.ts +16 -0
  65. package/src/cli/log.ts +2 -120
  66. package/src/cli/pipeline.ts +24 -5
  67. package/src/cli/run.ts +2 -2
  68. package/src/cli/update.ts +18 -0
  69. package/src/cli/watch.ts +1 -3
  70. package/src/dashboard/dist/_astro/index.Je1YjU_y.css +1 -0
  71. package/src/dashboard/dist/index.html +141 -1391
  72. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  73. package/src/dashboard/scripts/etl.test.ts +4 -62
  74. package/src/dashboard/scripts/etl.ts +13 -33
  75. package/src/dashboard/src/pages/index.astro +204 -1630
  76. package/src/dashboard/src/styles/dashboard.css +473 -7
  77. package/src/orchestrator/prompts/brainstorm.prompt.md +1 -0
  78. package/src/orchestrator/prompts/generate-convoy.prompt.md +7 -0
  79. package/src/orchestrator/prompts/generate-prd.prompt.md +6 -0
  80. package/dist/cli/convoy/log-merge.test.d.ts +0 -2
  81. package/dist/cli/convoy/log-merge.test.d.ts.map +0 -1
  82. package/dist/cli/convoy/log-merge.test.js +0 -147
  83. package/dist/cli/convoy/log-merge.test.js.map +0 -1
  84. package/src/cli/convoy/log-merge.test.ts +0 -179
  85. package/src/dashboard/dist/_astro/index.6L3_HsPT.css +0 -1
@@ -1,25 +1,25 @@
1
1
  {
2
- "hash": "3120eea2",
2
+ "hash": "0aac54bb",
3
3
  "configHash": "30f8ea04",
4
- "lockfileHash": "29db8675",
5
- "browserHash": "392b96fc",
4
+ "lockfileHash": "407e8b0e",
5
+ "browserHash": "3a6bf93e",
6
6
  "optimized": {
7
7
  "astro > cssesc": {
8
8
  "src": "../../../../../node_modules/cssesc/cssesc.js",
9
9
  "file": "astro___cssesc.js",
10
- "fileHash": "c3358443",
10
+ "fileHash": "2a163e0c",
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": "f6721631",
16
+ "fileHash": "34f9775b",
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": "337d00e2",
22
+ "fileHash": "29370f9f",
23
23
  "needsInterop": true
24
24
  }
25
25
  },
@@ -1,4 +1,4 @@
1
- import { mkdtempSync, rmSync, realpathSync, readFileSync, existsSync, mkdirSync } from 'node:fs'
1
+ import { mkdtempSync, rmSync, realpathSync, readFileSync, existsSync } from 'node:fs'
2
2
  import { tmpdir } from 'node:os'
3
3
  import { join } from 'node:path'
4
4
  import { describe, it, expect, beforeEach, afterEach } from 'vitest'
@@ -47,14 +47,13 @@ describe('runEtl — no database', () => {
47
47
  it('returns zero counts when db is missing', async () => {
48
48
  const dbPath = join(tmpDir, 'nonexistent.db')
49
49
  const result = await runEtl({ dbPath, outputDir })
50
- expect(result).toEqual({ convoyCount: 0, taskCount: 0 })
50
+ expect(result).toEqual({ convoyCount: 0 })
51
51
  })
52
52
 
53
- it('creates the output directory structure even when db is missing', async () => {
53
+ it('creates the output directory when db is missing', async () => {
54
54
  const dbPath = join(tmpDir, 'nonexistent.db')
55
55
  await runEtl({ dbPath, outputDir })
56
56
  expect(existsSync(outputDir)).toBe(true)
57
- expect(existsSync(join(outputDir, 'convoys'))).toBe(true)
58
57
  })
59
58
  })
60
59
 
@@ -120,10 +119,9 @@ describe('runEtl — with seeded database', () => {
120
119
  }
121
120
  })
122
121
 
123
- it('returns correct convoy and task counts', async () => {
122
+ it('returns correct convoy count', async () => {
124
123
  const result = await runEtl({ dbPath, outputDir })
125
124
  expect(result.convoyCount).toBe(2)
126
- expect(result.taskCount).toBe(2)
127
125
  })
128
126
 
129
127
  it('overall-stats.json has correct convoy counts', async () => {
@@ -151,60 +149,4 @@ describe('runEtl — with seeded database', () => {
151
149
  expect(item).toHaveProperty('total_cost_usd')
152
150
  }
153
151
  })
154
-
155
- it('creates per-convoy detail JSON files', async () => {
156
- await runEtl({ dbPath, outputDir })
157
- const detailPath = join(outputDir, 'convoys', 'convoy-abc.json')
158
- expect(existsSync(detailPath)).toBe(true)
159
- const detail = JSON.parse(readFileSync(detailPath, 'utf8'))
160
- expect(detail.convoy.id).toBe('convoy-abc')
161
- expect(detail.convoy.name).toBe('Test Convoy')
162
- expect(detail.convoy.status).toBe('done')
163
- expect(detail.convoy).toHaveProperty('branch')
164
- expect(detail.convoy).toHaveProperty('total_tokens')
165
- expect(detail.convoy).toHaveProperty('total_cost_usd')
166
- expect(detail).toHaveProperty('taskSummary')
167
- expect(detail.taskSummary).toHaveProperty('total')
168
- expect(Array.isArray(detail.tasks)).toBe(true)
169
- })
170
-
171
- it('detail file has correct task fields', async () => {
172
- await runEtl({ dbPath, outputDir })
173
- const detail = JSON.parse(
174
- readFileSync(join(outputDir, 'convoys', 'convoy-abc.json'), 'utf8'),
175
- )
176
- expect(detail.tasks).toHaveLength(2)
177
- for (const task of detail.tasks) {
178
- expect(task).toHaveProperty('id')
179
- expect(task).toHaveProperty('phase')
180
- expect(task).toHaveProperty('agent')
181
- expect(task).toHaveProperty('model')
182
- expect(task).toHaveProperty('status')
183
- expect(task).toHaveProperty('retries')
184
- expect(task).toHaveProperty('started_at')
185
- expect(task).toHaveProperty('finished_at')
186
- expect(task).toHaveProperty('total_tokens')
187
- expect(task).toHaveProperty('cost_usd')
188
- expect(task).toHaveProperty('review_level')
189
- expect(task).toHaveProperty('review_verdict')
190
- expect(task).toHaveProperty('drift_score')
191
- }
192
- })
193
-
194
- it('creates detail file for each convoy', async () => {
195
- await runEtl({ dbPath, outputDir })
196
- expect(existsSync(join(outputDir, 'convoys', 'convoy-abc.json'))).toBe(true)
197
- expect(existsSync(join(outputDir, 'convoys', 'convoy-def.json'))).toBe(true)
198
- })
199
-
200
- it('detail file includes artifacts and events fields', async () => {
201
- await runEtl({ dbPath, outputDir })
202
- const detail = JSON.parse(
203
- readFileSync(join(outputDir, 'convoys', 'convoy-abc.json'), 'utf8'),
204
- )
205
- expect(Array.isArray(detail.artifacts)).toBe(true)
206
- expect(typeof detail.artifact_count).toBe('number')
207
- expect(typeof detail.has_more_events).toBe('boolean')
208
- expect(Array.isArray(detail.events)).toBe(true)
209
- })
210
152
  })
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, writeFileSync, copyFileSync } from 'node:fs'
1
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
2
2
  import { resolve, dirname } from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
 
@@ -8,12 +8,10 @@ const __dirname = dirname(__filename)
8
8
  export interface EtlOptions {
9
9
  dbPath: string
10
10
  outputDir: string
11
- eventsPath?: string
12
11
  }
13
12
 
14
13
  export interface EtlResult {
15
14
  convoyCount: number
16
- taskCount: number
17
15
  }
18
16
 
19
17
  const EMPTY_OVERALL_STATS = {
@@ -29,7 +27,6 @@ export async function runEtl(options: EtlOptions): Promise<EtlResult> {
29
27
  const { dbPath, outputDir } = options
30
28
 
31
29
  mkdirSync(outputDir, { recursive: true })
32
- mkdirSync(resolve(outputDir, 'convoys'), { recursive: true })
33
30
 
34
31
  if (!existsSync(dbPath)) {
35
32
  console.warn(` \u26a0 No convoy database found at ${dbPath}. Writing empty JSON files.`)
@@ -39,7 +36,7 @@ export async function runEtl(options: EtlOptions): Promise<EtlResult> {
39
36
  'utf8',
40
37
  )
41
38
  writeFileSync(resolve(outputDir, 'convoy-list.json'), JSON.stringify([], null, 2), 'utf8')
42
- return { convoyCount: 0, taskCount: 0 }
39
+ return { convoyCount: 0 }
43
40
  }
44
41
 
45
42
  const { createConvoyStore } = await import('../../cli/convoy/store.js')
@@ -66,6 +63,7 @@ export async function runEtl(options: EtlOptions): Promise<EtlResult> {
66
63
  name: c.name,
67
64
  status: c.status,
68
65
  created_at: c.created_at,
66
+ started_at: c.started_at,
69
67
  finished_at: c.finished_at,
70
68
  total_tokens: c.total_tokens,
71
69
  total_cost_usd: c.total_cost_usd,
@@ -76,53 +74,35 @@ export async function runEtl(options: EtlOptions): Promise<EtlResult> {
76
74
  'utf8',
77
75
  )
78
76
 
79
- let totalTasks = 0
80
- for (const convoy of allConvoys) {
81
- const detail = store.getConvoyDetails(convoy.id)
77
+ mkdirSync(resolve(outputDir, 'convoys'), { recursive: true })
78
+ let detailCount = 0
79
+ for (const c of allConvoys) {
80
+ const detail = store.getConvoyDetails(c.id)
82
81
  if (detail) {
83
- totalTasks += detail.tasks.length
84
82
  writeFileSync(
85
- resolve(outputDir, 'convoys', `${convoy.id}.json`),
83
+ resolve(outputDir, 'convoys', c.id + '.json'),
86
84
  JSON.stringify(detail, null, 2),
87
85
  'utf8',
88
86
  )
87
+ detailCount++
89
88
  }
90
89
  }
91
90
 
92
- console.log(`ETL complete: ${allConvoys.length} convoys exported, ${totalTasks} tasks.`)
91
+ console.log(`ETL complete: ${allConvoys.length} convoys summarized, ${detailCount} detail files generated.`)
93
92
 
94
- // Copy observability event logs for the live dashboard charts
95
- const eventsSource = options.eventsPath
96
- ? resolve(process.cwd(), options.eventsPath)
97
- : resolve(process.cwd(), '.opencastle', 'logs', 'events.ndjson')
98
- if (existsSync(eventsSource)) {
99
- copyFileSync(eventsSource, resolve(outputDir, 'events.ndjson'))
100
- } else {
101
- writeFileSync(resolve(outputDir, 'events.ndjson'), '', 'utf8')
102
- }
103
-
104
- // Copy pipelines log (optional, write empty if absent)
105
- const pipelinesSource = resolve(process.cwd(), '.opencastle', 'logs', 'pipelines.ndjson')
106
- if (existsSync(pipelinesSource)) {
107
- copyFileSync(pipelinesSource, resolve(outputDir, 'pipelines.ndjson'))
108
- } else {
109
- writeFileSync(resolve(outputDir, 'pipelines.ndjson'), '', 'utf8')
110
- }
111
-
112
- return { convoyCount: allConvoys.length, taskCount: totalTasks }
93
+ return { convoyCount: allConvoys.length }
113
94
  } finally {
114
95
  store.close()
115
96
  }
116
97
  }
117
98
 
118
- function parseArgs(): { db?: string; out?: string; events?: string } {
99
+ function parseArgs(): { db?: string; out?: string } {
119
100
  const args = process.argv.slice(2)
120
101
  const result: Record<string, string> = {}
121
102
  for (let i = 0; i < args.length; i++) {
122
103
  const a = args[i]
123
104
  if (a === '--db' && args[i+1]) { result.db = args[++i] }
124
105
  else if (a === '--out' && args[i+1]) { result.out = args[++i] }
125
- else if (a === '--events' && args[i+1]) { result.events = args[++i] }
126
106
  }
127
107
  return result
128
108
  }
@@ -135,7 +115,7 @@ if (isMain) {
135
115
  const parsed = parseArgs()
136
116
  const dbPath = parsed.db != null ? resolve(process.cwd(), parsed.db) : resolve(process.cwd(), '.opencastle', 'convoy.db')
137
117
  const outputDir = parsed.out != null ? resolve(process.cwd(), parsed.out) : resolve(__dirname, '..', 'public', 'data')
138
- runEtl({ dbPath, outputDir, eventsPath: parsed.events }).catch((err: unknown) => {
118
+ runEtl({ dbPath, outputDir }).catch((err: unknown) => {
139
119
  console.error('ETL failed:', (err as Error).message)
140
120
  process.exit(1)
141
121
  })