opencastle 0.26.1 → 0.27.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.
- package/README.md +7 -1
- package/bin/cli.mjs +10 -0
- package/dist/cli/agents.d.ts +3 -0
- package/dist/cli/agents.d.ts.map +1 -0
- package/dist/cli/agents.js +161 -0
- package/dist/cli/agents.js.map +1 -0
- package/dist/cli/baselines.d.ts +3 -0
- package/dist/cli/baselines.d.ts.map +1 -0
- package/dist/cli/baselines.js +128 -0
- package/dist/cli/baselines.js.map +1 -0
- package/dist/cli/convoy/engine.d.ts +68 -2
- package/dist/cli/convoy/engine.d.ts.map +1 -1
- package/dist/cli/convoy/engine.js +2102 -26
- package/dist/cli/convoy/engine.js.map +1 -1
- package/dist/cli/convoy/engine.test.js +1572 -70
- package/dist/cli/convoy/engine.test.js.map +1 -1
- package/dist/cli/convoy/events.d.ts +4 -1
- package/dist/cli/convoy/events.d.ts.map +1 -1
- package/dist/cli/convoy/events.js +74 -13
- package/dist/cli/convoy/events.js.map +1 -1
- package/dist/cli/convoy/events.test.js +154 -27
- package/dist/cli/convoy/events.test.js.map +1 -1
- package/dist/cli/convoy/expertise.d.ts +16 -0
- package/dist/cli/convoy/expertise.d.ts.map +1 -0
- package/dist/cli/convoy/expertise.js +121 -0
- package/dist/cli/convoy/expertise.js.map +1 -0
- package/dist/cli/convoy/expertise.test.d.ts +2 -0
- package/dist/cli/convoy/expertise.test.d.ts.map +1 -0
- package/dist/cli/convoy/expertise.test.js +96 -0
- package/dist/cli/convoy/expertise.test.js.map +1 -0
- package/dist/cli/convoy/export.test.js +1 -0
- package/dist/cli/convoy/export.test.js.map +1 -1
- package/dist/cli/convoy/formula.d.ts +19 -0
- package/dist/cli/convoy/formula.d.ts.map +1 -0
- package/dist/cli/convoy/formula.js +142 -0
- package/dist/cli/convoy/formula.js.map +1 -0
- package/dist/cli/convoy/formula.test.d.ts +2 -0
- package/dist/cli/convoy/formula.test.d.ts.map +1 -0
- package/dist/cli/convoy/formula.test.js +342 -0
- package/dist/cli/convoy/formula.test.js.map +1 -0
- package/dist/cli/convoy/gates.d.ts +128 -0
- package/dist/cli/convoy/gates.d.ts.map +1 -0
- package/dist/cli/convoy/gates.js +606 -0
- package/dist/cli/convoy/gates.js.map +1 -0
- package/dist/cli/convoy/gates.test.d.ts +2 -0
- package/dist/cli/convoy/gates.test.d.ts.map +1 -0
- package/dist/cli/convoy/gates.test.js +976 -0
- package/dist/cli/convoy/gates.test.js.map +1 -0
- package/dist/cli/convoy/health.d.ts +11 -0
- package/dist/cli/convoy/health.d.ts.map +1 -1
- package/dist/cli/convoy/health.js +54 -0
- package/dist/cli/convoy/health.js.map +1 -1
- package/dist/cli/convoy/health.test.js +56 -1
- package/dist/cli/convoy/health.test.js.map +1 -1
- package/dist/cli/convoy/issues.d.ts +8 -0
- package/dist/cli/convoy/issues.d.ts.map +1 -0
- package/dist/cli/convoy/issues.js +98 -0
- package/dist/cli/convoy/issues.js.map +1 -0
- package/dist/cli/convoy/issues.test.d.ts +2 -0
- package/dist/cli/convoy/issues.test.d.ts.map +1 -0
- package/dist/cli/convoy/issues.test.js +107 -0
- package/dist/cli/convoy/issues.test.js.map +1 -0
- package/dist/cli/convoy/knowledge.d.ts +5 -0
- package/dist/cli/convoy/knowledge.d.ts.map +1 -0
- package/dist/cli/convoy/knowledge.js +116 -0
- package/dist/cli/convoy/knowledge.js.map +1 -0
- package/dist/cli/convoy/knowledge.test.d.ts +2 -0
- package/dist/cli/convoy/knowledge.test.d.ts.map +1 -0
- package/dist/cli/convoy/knowledge.test.js +87 -0
- package/dist/cli/convoy/knowledge.test.js.map +1 -0
- package/dist/cli/convoy/lessons.d.ts +17 -0
- package/dist/cli/convoy/lessons.d.ts.map +1 -0
- package/dist/cli/convoy/lessons.js +149 -0
- package/dist/cli/convoy/lessons.js.map +1 -0
- package/dist/cli/convoy/lessons.test.d.ts +2 -0
- package/dist/cli/convoy/lessons.test.d.ts.map +1 -0
- package/dist/cli/convoy/lessons.test.js +135 -0
- package/dist/cli/convoy/lessons.test.js.map +1 -0
- package/dist/cli/convoy/lock.d.ts +13 -0
- package/dist/cli/convoy/lock.d.ts.map +1 -0
- package/dist/cli/convoy/lock.js +88 -0
- package/dist/cli/convoy/lock.js.map +1 -0
- package/dist/cli/convoy/lock.test.d.ts +2 -0
- package/dist/cli/convoy/lock.test.d.ts.map +1 -0
- package/dist/cli/convoy/lock.test.js +136 -0
- package/dist/cli/convoy/lock.test.js.map +1 -0
- package/dist/cli/convoy/merge.d.ts +4 -0
- package/dist/cli/convoy/merge.d.ts.map +1 -1
- package/dist/cli/convoy/merge.js +18 -1
- package/dist/cli/convoy/merge.js.map +1 -1
- package/dist/cli/convoy/merge.test.js +6 -7
- package/dist/cli/convoy/merge.test.js.map +1 -1
- package/dist/cli/convoy/partition.d.ts +51 -0
- package/dist/cli/convoy/partition.d.ts.map +1 -0
- package/dist/cli/convoy/partition.js +186 -0
- package/dist/cli/convoy/partition.js.map +1 -0
- package/dist/cli/convoy/partition.test.d.ts +2 -0
- package/dist/cli/convoy/partition.test.d.ts.map +1 -0
- package/dist/cli/convoy/partition.test.js +315 -0
- package/dist/cli/convoy/partition.test.js.map +1 -0
- package/dist/cli/convoy/pipeline.test.js +6 -0
- package/dist/cli/convoy/pipeline.test.js.map +1 -1
- package/dist/cli/convoy/store.d.ts +47 -5
- package/dist/cli/convoy/store.d.ts.map +1 -1
- package/dist/cli/convoy/store.js +525 -19
- package/dist/cli/convoy/store.js.map +1 -1
- package/dist/cli/convoy/store.test.js +1345 -12
- package/dist/cli/convoy/store.test.js.map +1 -1
- package/dist/cli/convoy/types.d.ts +156 -2
- package/dist/cli/convoy/types.d.ts.map +1 -1
- package/dist/cli/destroy.d.ts +3 -0
- package/dist/cli/destroy.d.ts.map +1 -0
- package/dist/cli/destroy.js +69 -0
- package/dist/cli/destroy.js.map +1 -0
- package/dist/cli/destroy.test.d.ts +2 -0
- package/dist/cli/destroy.test.d.ts.map +1 -0
- package/dist/cli/destroy.test.js +116 -0
- package/dist/cli/destroy.test.js.map +1 -0
- package/dist/cli/gitignore.d.ts +9 -0
- package/dist/cli/gitignore.d.ts.map +1 -1
- package/dist/cli/gitignore.js +29 -0
- package/dist/cli/gitignore.js.map +1 -1
- package/dist/cli/plan.d.ts +3 -0
- package/dist/cli/plan.d.ts.map +1 -0
- package/dist/cli/plan.js +288 -0
- package/dist/cli/plan.js.map +1 -0
- package/dist/cli/run/adapters/claude.d.ts +2 -0
- package/dist/cli/run/adapters/claude.d.ts.map +1 -1
- package/dist/cli/run/adapters/claude.js +89 -49
- package/dist/cli/run/adapters/claude.js.map +1 -1
- package/dist/cli/run/adapters/claude.test.d.ts +2 -0
- package/dist/cli/run/adapters/claude.test.d.ts.map +1 -0
- package/dist/cli/run/adapters/claude.test.js +205 -0
- package/dist/cli/run/adapters/claude.test.js.map +1 -0
- package/dist/cli/run/adapters/copilot.d.ts +1 -0
- package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
- package/dist/cli/run/adapters/copilot.js +84 -46
- package/dist/cli/run/adapters/copilot.js.map +1 -1
- package/dist/cli/run/adapters/copilot.test.d.ts +2 -0
- package/dist/cli/run/adapters/copilot.test.d.ts.map +1 -0
- package/dist/cli/run/adapters/copilot.test.js +195 -0
- package/dist/cli/run/adapters/copilot.test.js.map +1 -0
- package/dist/cli/run/adapters/cursor.d.ts +1 -0
- package/dist/cli/run/adapters/cursor.d.ts.map +1 -1
- package/dist/cli/run/adapters/cursor.js +83 -47
- package/dist/cli/run/adapters/cursor.js.map +1 -1
- package/dist/cli/run/adapters/cursor.test.d.ts +2 -0
- package/dist/cli/run/adapters/cursor.test.d.ts.map +1 -0
- package/dist/cli/run/adapters/cursor.test.js +129 -0
- package/dist/cli/run/adapters/cursor.test.js.map +1 -0
- package/dist/cli/run/adapters/opencode.d.ts +1 -0
- package/dist/cli/run/adapters/opencode.d.ts.map +1 -1
- package/dist/cli/run/adapters/opencode.js +81 -47
- package/dist/cli/run/adapters/opencode.js.map +1 -1
- package/dist/cli/run/adapters/opencode.test.d.ts +2 -0
- package/dist/cli/run/adapters/opencode.test.d.ts.map +1 -0
- package/dist/cli/run/adapters/opencode.test.js +119 -0
- package/dist/cli/run/adapters/opencode.test.js.map +1 -0
- package/dist/cli/run/executor.js +1 -1
- package/dist/cli/run/executor.js.map +1 -1
- package/dist/cli/run/schema.d.ts.map +1 -1
- package/dist/cli/run/schema.js +245 -4
- package/dist/cli/run/schema.js.map +1 -1
- package/dist/cli/run/schema.test.js +669 -0
- package/dist/cli/run/schema.test.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +362 -22
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/types.d.ts +85 -2
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/types.js.map +1 -1
- package/dist/cli/watch.d.ts +15 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +279 -0
- package/dist/cli/watch.js.map +1 -0
- package/package.json +1 -1
- package/src/cli/agents.ts +177 -0
- package/src/cli/baselines.ts +143 -0
- package/src/cli/convoy/engine.test.ts +1839 -70
- package/src/cli/convoy/engine.ts +2417 -38
- package/src/cli/convoy/events.test.ts +179 -38
- package/src/cli/convoy/events.ts +88 -16
- package/src/cli/convoy/expertise.test.ts +128 -0
- package/src/cli/convoy/expertise.ts +163 -0
- package/src/cli/convoy/export.test.ts +1 -0
- package/src/cli/convoy/formula.test.ts +405 -0
- package/src/cli/convoy/formula.ts +174 -0
- package/src/cli/convoy/gates.test.ts +1169 -0
- package/src/cli/convoy/gates.ts +774 -0
- package/src/cli/convoy/health.test.ts +64 -2
- package/src/cli/convoy/health.ts +80 -2
- package/src/cli/convoy/issues.test.ts +143 -0
- package/src/cli/convoy/issues.ts +136 -0
- package/src/cli/convoy/knowledge.test.ts +101 -0
- package/src/cli/convoy/knowledge.ts +132 -0
- package/src/cli/convoy/lessons.test.ts +188 -0
- package/src/cli/convoy/lessons.ts +164 -0
- package/src/cli/convoy/lock.test.ts +181 -0
- package/src/cli/convoy/lock.ts +103 -0
- package/src/cli/convoy/merge.test.ts +6 -7
- package/src/cli/convoy/merge.ts +19 -1
- package/src/cli/convoy/partition.test.ts +423 -0
- package/src/cli/convoy/partition.ts +232 -0
- package/src/cli/convoy/pipeline.test.ts +6 -0
- package/src/cli/convoy/store.test.ts +1512 -14
- package/src/cli/convoy/store.ts +676 -30
- package/src/cli/convoy/types.ts +170 -1
- package/src/cli/destroy.test.ts +141 -0
- package/src/cli/destroy.ts +88 -0
- package/src/cli/gitignore.ts +36 -0
- package/src/cli/plan.ts +316 -0
- package/src/cli/run/adapters/claude.test.ts +234 -0
- package/src/cli/run/adapters/claude.ts +45 -5
- package/src/cli/run/adapters/copilot.test.ts +224 -0
- package/src/cli/run/adapters/copilot.ts +34 -4
- package/src/cli/run/adapters/cursor.test.ts +144 -0
- package/src/cli/run/adapters/cursor.ts +33 -2
- package/src/cli/run/adapters/opencode.test.ts +135 -0
- package/src/cli/run/adapters/opencode.ts +30 -2
- package/src/cli/run/executor.ts +1 -1
- package/src/cli/run/schema.test.ts +758 -0
- package/src/cli/run/schema.ts +300 -25
- package/src/cli/run.ts +341 -21
- package/src/cli/types.ts +86 -1
- package/src/cli/watch.ts +298 -0
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { parse as yamlParse, stringify as yamlStringify } from 'yaml'
|
|
3
|
+
import { parseTaskSpecText } from '../run/schema.js'
|
|
4
|
+
import type { TaskSpec, ValidationResult } from '../types.js'
|
|
5
|
+
|
|
6
|
+
export interface FormulaTemplate {
|
|
7
|
+
name: string
|
|
8
|
+
description?: string
|
|
9
|
+
variables: Record<string, {
|
|
10
|
+
description?: string
|
|
11
|
+
required: boolean
|
|
12
|
+
default?: string
|
|
13
|
+
}>
|
|
14
|
+
spec: unknown
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class FormulaValidationError extends Error {
|
|
18
|
+
readonly missingVariables: string[]
|
|
19
|
+
constructor(missingVariables: string[]) {
|
|
20
|
+
super(`Missing required formula variables: ${missingVariables.join(', ')}`)
|
|
21
|
+
this.name = 'FormulaValidationError'
|
|
22
|
+
this.missingVariables = missingVariables
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Matches {{varname}} and {{varname | filter}} with optional whitespace
|
|
27
|
+
const PLACEHOLDER_RE = /\{\{(\s*\w+\s*(?:\|\s*\w+\s*)?)\}\}/g
|
|
28
|
+
|
|
29
|
+
function toKebab(value: string): string {
|
|
30
|
+
return value
|
|
31
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
32
|
+
.replace(/[\s_]+/g, '-')
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function toSnake(value: string): string {
|
|
37
|
+
return value
|
|
38
|
+
.replace(/([a-z])([A-Z])/g, '$1_$2')
|
|
39
|
+
.replace(/[\s-]+/g, '_')
|
|
40
|
+
.toLowerCase()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function toUpper(value: string): string {
|
|
44
|
+
return value
|
|
45
|
+
.replace(/[\s-]+/g, '_')
|
|
46
|
+
.toUpperCase()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function parseFormula(templatePath: string): FormulaTemplate {
|
|
50
|
+
let raw: string
|
|
51
|
+
try {
|
|
52
|
+
raw = readFileSync(templatePath, 'utf8')
|
|
53
|
+
} catch (err: unknown) {
|
|
54
|
+
throw new Error(`Cannot read formula file: ${(err as Error).message}`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let parsed: unknown
|
|
58
|
+
try {
|
|
59
|
+
parsed = yamlParse(raw)
|
|
60
|
+
} catch (err: unknown) {
|
|
61
|
+
throw new Error(`Formula YAML parse error: ${(err as Error).message}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
65
|
+
throw new Error('Formula file must be a YAML mapping')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const obj = parsed as Record<string, unknown>
|
|
69
|
+
|
|
70
|
+
if (!obj.name || typeof obj.name !== 'string') {
|
|
71
|
+
throw new Error('Formula template must have a "name" field')
|
|
72
|
+
}
|
|
73
|
+
if (obj.spec === undefined || obj.spec === null) {
|
|
74
|
+
throw new Error('Formula template must have a "spec" field')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const variables: FormulaTemplate['variables'] = {}
|
|
78
|
+
if (obj.variables && typeof obj.variables === 'object' && !Array.isArray(obj.variables)) {
|
|
79
|
+
for (const [key, val] of Object.entries(obj.variables as Record<string, unknown>)) {
|
|
80
|
+
if (!val || typeof val !== 'object' || Array.isArray(val)) continue
|
|
81
|
+
const v = val as Record<string, unknown>
|
|
82
|
+
variables[key] = {
|
|
83
|
+
description: typeof v.description === 'string' ? v.description : undefined,
|
|
84
|
+
required: v.required === true,
|
|
85
|
+
default: typeof v.default === 'string' ? v.default : undefined,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
name: obj.name,
|
|
92
|
+
description: typeof obj.description === 'string' ? obj.description : undefined,
|
|
93
|
+
variables,
|
|
94
|
+
spec: obj.spec,
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function substituteVariables(
|
|
99
|
+
template: FormulaTemplate,
|
|
100
|
+
vars: Record<string, string>,
|
|
101
|
+
): TaskSpec {
|
|
102
|
+
const specYaml = yamlStringify(template.spec)
|
|
103
|
+
const missing: string[] = []
|
|
104
|
+
|
|
105
|
+
const result = specYaml.replace(PLACEHOLDER_RE, (match, inner: string) => {
|
|
106
|
+
const parts = inner.split('|').map((p: string) => p.trim())
|
|
107
|
+
const varName = parts[0]
|
|
108
|
+
const filter = parts[1] ?? null
|
|
109
|
+
|
|
110
|
+
let value: string
|
|
111
|
+
if (varName in vars) {
|
|
112
|
+
value = vars[varName]
|
|
113
|
+
} else if (varName in template.variables) {
|
|
114
|
+
const def = template.variables[varName]
|
|
115
|
+
if (def.required) {
|
|
116
|
+
missing.push(varName)
|
|
117
|
+
return match // keep placeholder; collect all missing vars
|
|
118
|
+
}
|
|
119
|
+
value = def.default ?? ''
|
|
120
|
+
} else {
|
|
121
|
+
value = ''
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (filter === 'kebab') return toKebab(value)
|
|
125
|
+
if (filter === 'snake') return toSnake(value)
|
|
126
|
+
if (filter === 'upper') return toUpper(value)
|
|
127
|
+
return value
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
if (missing.length > 0) {
|
|
131
|
+
throw new FormulaValidationError(missing)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return parseTaskSpecText(result)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function validateTemplate(template: FormulaTemplate): ValidationResult {
|
|
138
|
+
const errors: string[] = []
|
|
139
|
+
const VALID_IDENTIFIER = /^[a-zA-Z0-9_]+$/
|
|
140
|
+
|
|
141
|
+
if (!template.name || typeof template.name !== 'string') {
|
|
142
|
+
errors.push('"name" field is required')
|
|
143
|
+
}
|
|
144
|
+
if (template.spec === undefined || template.spec === null) {
|
|
145
|
+
errors.push('"spec" field is required')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (const key of Object.keys(template.variables)) {
|
|
149
|
+
if (!VALID_IDENTIFIER.test(key)) {
|
|
150
|
+
errors.push(
|
|
151
|
+
`Variable name "${key}" is not a valid identifier (alphanumeric + underscore only)`,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Warn on undeclared {{variable}} placeholders in spec
|
|
157
|
+
if (template.spec !== undefined && template.spec !== null) {
|
|
158
|
+
try {
|
|
159
|
+
const specYaml = yamlStringify(template.spec)
|
|
160
|
+
for (const match of specYaml.matchAll(PLACEHOLDER_RE)) {
|
|
161
|
+
const varName = match[1].split('|')[0].trim()
|
|
162
|
+
if (!(varName in template.variables)) {
|
|
163
|
+
process.stderr.write(
|
|
164
|
+
`Warning: template contains undeclared placeholder "{{${varName}}}"\n`,
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
// If stringify fails, skip placeholder checking
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return { valid: errors.length === 0, errors }
|
|
174
|
+
}
|