opencastle 0.31.6 → 0.32.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/LICENSE +93 -21
- package/README.md +9 -3
- package/bin/cli.mjs +15 -0
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +19 -5
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/artifacts-cli.d.ts +3 -0
- package/dist/cli/artifacts-cli.d.ts.map +1 -0
- package/dist/cli/artifacts-cli.js +36 -0
- package/dist/cli/artifacts-cli.js.map +1 -0
- package/dist/cli/baselines.d.ts.map +1 -1
- package/dist/cli/baselines.js +11 -0
- package/dist/cli/baselines.js.map +1 -1
- package/dist/cli/convoy/artifacts.d.ts +25 -0
- package/dist/cli/convoy/artifacts.d.ts.map +1 -0
- package/dist/cli/convoy/artifacts.js +129 -0
- package/dist/cli/convoy/artifacts.js.map +1 -0
- package/dist/cli/convoy/artifacts.test.d.ts +2 -0
- package/dist/cli/convoy/artifacts.test.d.ts.map +1 -0
- package/dist/cli/convoy/artifacts.test.js +169 -0
- package/dist/cli/convoy/artifacts.test.js.map +1 -0
- package/dist/cli/convoy/compaction.d.ts +23 -0
- package/dist/cli/convoy/compaction.d.ts.map +1 -0
- package/dist/cli/convoy/compaction.js +117 -0
- package/dist/cli/convoy/compaction.js.map +1 -0
- package/dist/cli/convoy/compaction.test.d.ts +2 -0
- package/dist/cli/convoy/compaction.test.d.ts.map +1 -0
- package/dist/cli/convoy/compaction.test.js +205 -0
- package/dist/cli/convoy/compaction.test.js.map +1 -0
- package/dist/cli/convoy/contracts.d.ts +22 -0
- package/dist/cli/convoy/contracts.d.ts.map +1 -0
- package/dist/cli/convoy/contracts.js +254 -0
- package/dist/cli/convoy/contracts.js.map +1 -0
- package/dist/cli/convoy/contracts.test.d.ts +2 -0
- package/dist/cli/convoy/contracts.test.d.ts.map +1 -0
- package/dist/cli/convoy/contracts.test.js +239 -0
- package/dist/cli/convoy/contracts.test.js.map +1 -0
- package/dist/cli/convoy/dag-analysis.d.ts +40 -0
- package/dist/cli/convoy/dag-analysis.d.ts.map +1 -0
- package/dist/cli/convoy/dag-analysis.js +282 -0
- package/dist/cli/convoy/dag-analysis.js.map +1 -0
- package/dist/cli/convoy/dag-analysis.test.d.ts +2 -0
- package/dist/cli/convoy/dag-analysis.test.d.ts.map +1 -0
- package/dist/cli/convoy/dag-analysis.test.js +289 -0
- package/dist/cli/convoy/dag-analysis.test.js.map +1 -0
- package/dist/cli/convoy/effort-scaling.d.ts +20 -0
- package/dist/cli/convoy/effort-scaling.d.ts.map +1 -0
- package/dist/cli/convoy/effort-scaling.js +82 -0
- package/dist/cli/convoy/effort-scaling.js.map +1 -0
- package/dist/cli/convoy/effort-scaling.test.d.ts +2 -0
- package/dist/cli/convoy/effort-scaling.test.d.ts.map +1 -0
- package/dist/cli/convoy/effort-scaling.test.js +120 -0
- package/dist/cli/convoy/effort-scaling.test.js.map +1 -0
- package/dist/cli/convoy/engine.d.ts.map +1 -1
- package/dist/cli/convoy/engine.js +298 -11
- package/dist/cli/convoy/engine.js.map +1 -1
- package/dist/cli/convoy/engine.test.js +155 -18
- package/dist/cli/convoy/engine.test.js.map +1 -1
- package/dist/cli/convoy/event-schemas.d.ts.map +1 -1
- package/dist/cli/convoy/event-schemas.js +55 -0
- package/dist/cli/convoy/event-schemas.js.map +1 -1
- package/dist/cli/convoy/isolation.d.ts +27 -0
- package/dist/cli/convoy/isolation.d.ts.map +1 -0
- package/dist/cli/convoy/isolation.js +120 -0
- package/dist/cli/convoy/isolation.js.map +1 -0
- package/dist/cli/convoy/isolation.test.d.ts +2 -0
- package/dist/cli/convoy/isolation.test.d.ts.map +1 -0
- package/dist/cli/convoy/isolation.test.js +105 -0
- package/dist/cli/convoy/isolation.test.js.map +1 -0
- package/dist/cli/convoy/review-stages.d.ts +9 -0
- package/dist/cli/convoy/review-stages.d.ts.map +1 -0
- package/dist/cli/convoy/review-stages.js +134 -0
- package/dist/cli/convoy/review-stages.js.map +1 -0
- package/dist/cli/convoy/review-stages.test.d.ts +2 -0
- package/dist/cli/convoy/review-stages.test.d.ts.map +1 -0
- package/dist/cli/convoy/review-stages.test.js +197 -0
- package/dist/cli/convoy/review-stages.test.js.map +1 -0
- package/dist/cli/convoy/skill-refinement.d.ts +39 -0
- package/dist/cli/convoy/skill-refinement.d.ts.map +1 -0
- package/dist/cli/convoy/skill-refinement.js +239 -0
- package/dist/cli/convoy/skill-refinement.js.map +1 -0
- package/dist/cli/convoy/skill-refinement.test.d.ts +2 -0
- package/dist/cli/convoy/skill-refinement.test.d.ts.map +1 -0
- package/dist/cli/convoy/skill-refinement.test.js +230 -0
- package/dist/cli/convoy/skill-refinement.test.js.map +1 -0
- package/dist/cli/convoy/spec-builder.d.ts +1 -0
- package/dist/cli/convoy/spec-builder.d.ts.map +1 -1
- package/dist/cli/convoy/spec-builder.js +11 -0
- package/dist/cli/convoy/spec-builder.js.map +1 -1
- package/dist/cli/convoy/spec-builder.test.js +54 -0
- package/dist/cli/convoy/spec-builder.test.js.map +1 -1
- package/dist/cli/convoy/store.d.ts +3 -2
- package/dist/cli/convoy/store.d.ts.map +1 -1
- package/dist/cli/convoy/store.js +20 -2
- package/dist/cli/convoy/store.js.map +1 -1
- package/dist/cli/convoy/store.test.js +15 -15
- package/dist/cli/convoy/store.test.js.map +1 -1
- package/dist/cli/convoy/tdd-gate.d.ts +15 -0
- package/dist/cli/convoy/tdd-gate.d.ts.map +1 -0
- package/dist/cli/convoy/tdd-gate.js +119 -0
- package/dist/cli/convoy/tdd-gate.js.map +1 -0
- package/dist/cli/convoy/tdd-gate.test.d.ts +2 -0
- package/dist/cli/convoy/tdd-gate.test.d.ts.map +1 -0
- package/dist/cli/convoy/tdd-gate.test.js +227 -0
- package/dist/cli/convoy/tdd-gate.test.js.map +1 -0
- package/dist/cli/convoy/types.d.ts +91 -0
- package/dist/cli/convoy/types.d.ts.map +1 -1
- package/dist/cli/convoy/types.js +8 -0
- package/dist/cli/convoy/types.js.map +1 -1
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +54 -0
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/insights.d.ts +3 -0
- package/dist/cli/insights.d.ts.map +1 -0
- package/dist/cli/insights.js +94 -0
- package/dist/cli/insights.js.map +1 -0
- package/dist/cli/lesson.d.ts.map +1 -1
- package/dist/cli/lesson.js +7 -0
- package/dist/cli/lesson.js.map +1 -1
- package/dist/cli/log.d.ts.map +1 -1
- package/dist/cli/log.js +7 -0
- package/dist/cli/log.js.map +1 -1
- package/dist/cli/package-config.d.ts +12 -0
- package/dist/cli/package-config.d.ts.map +1 -0
- package/dist/cli/package-config.js +37 -0
- package/dist/cli/package-config.js.map +1 -0
- package/dist/cli/package.d.ts +23 -0
- package/dist/cli/package.d.ts.map +1 -0
- package/dist/cli/package.js +285 -0
- package/dist/cli/package.js.map +1 -0
- package/dist/cli/package.test.d.ts +2 -0
- package/dist/cli/package.test.d.ts.map +1 -0
- package/dist/cli/package.test.js +236 -0
- package/dist/cli/package.test.js.map +1 -0
- package/dist/cli/pipeline.d.ts +6 -0
- package/dist/cli/pipeline.d.ts.map +1 -1
- package/dist/cli/pipeline.js +15 -2
- package/dist/cli/pipeline.js.map +1 -1
- package/dist/cli/run/schema.d.ts.map +1 -1
- package/dist/cli/run/schema.js +32 -0
- package/dist/cli/run/schema.js.map +1 -1
- package/dist/cli/run/schema.test.js +51 -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 +10 -1
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -0
- package/dist/cli/skills.d.ts.map +1 -0
- package/dist/cli/skills.js +107 -0
- package/dist/cli/skills.js.map +1 -0
- package/dist/cli/types.d.ts +4 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/update.js +2 -2
- package/package.json +3 -2
- package/src/cli/agents.ts +20 -5
- package/src/cli/artifacts-cli.ts +41 -0
- package/src/cli/baselines.ts +12 -0
- package/src/cli/convoy/artifacts.test.ts +201 -0
- package/src/cli/convoy/artifacts.ts +186 -0
- package/src/cli/convoy/compaction.test.ts +245 -0
- package/src/cli/convoy/compaction.ts +164 -0
- package/src/cli/convoy/contracts.test.ts +279 -0
- package/src/cli/convoy/contracts.ts +280 -0
- package/src/cli/convoy/dag-analysis.test.ts +349 -0
- package/src/cli/convoy/dag-analysis.ts +371 -0
- package/src/cli/convoy/effort-scaling.test.ts +140 -0
- package/src/cli/convoy/effort-scaling.ts +90 -0
- package/src/cli/convoy/engine.test.ts +175 -18
- package/src/cli/convoy/engine.ts +315 -12
- package/src/cli/convoy/event-schemas.ts +55 -0
- package/src/cli/convoy/isolation.test.ts +137 -0
- package/src/cli/convoy/isolation.ts +165 -0
- package/src/cli/convoy/review-stages.test.ts +235 -0
- package/src/cli/convoy/review-stages.ts +166 -0
- package/src/cli/convoy/skill-refinement.test.ts +277 -0
- package/src/cli/convoy/skill-refinement.ts +306 -0
- package/src/cli/convoy/spec-builder.test.ts +61 -0
- package/src/cli/convoy/spec-builder.ts +9 -0
- package/src/cli/convoy/store.test.ts +15 -15
- package/src/cli/convoy/store.ts +26 -4
- package/src/cli/convoy/tdd-gate.test.ts +281 -0
- package/src/cli/convoy/tdd-gate.ts +154 -0
- package/src/cli/convoy/types.ts +51 -0
- package/src/cli/dashboard.ts +55 -0
- package/src/cli/insights.ts +99 -0
- package/src/cli/lesson.ts +8 -0
- package/src/cli/log.ts +8 -0
- package/src/cli/package-config.ts +48 -0
- package/src/cli/package.test.ts +276 -0
- package/src/cli/package.ts +329 -0
- package/src/cli/pipeline.ts +21 -2
- package/src/cli/run/schema.test.ts +58 -0
- package/src/cli/run/schema.ts +33 -0
- package/src/cli/run.ts +14 -1
- package/src/cli/skills.ts +121 -0
- package/src/cli/types.ts +4 -1
- package/src/cli/update.ts +2 -2
- package/src/dashboard/dist/_astro/{index.Je1YjU_y.css → index.BRDFmNzR.css} +1 -1
- package/src/dashboard/dist/index.html +163 -2
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/src/pages/index.astro +162 -1
- package/src/dashboard/src/styles/dashboard.css +85 -0
- package/src/orchestrator/agents/developer.agent.md +8 -0
- package/src/orchestrator/agents/ui-ux-expert.agent.md +7 -0
- package/src/orchestrator/prompts/assess-complexity.prompt.md +13 -0
- package/src/orchestrator/prompts/brainstorm.prompt.md +18 -0
- package/src/orchestrator/prompts/generate-convoy.prompt.md +61 -0
- package/src/orchestrator/skills/decomposition/SKILL.md +35 -0
- package/src/orchestrator/skills/frontend-design/SKILL.md +27 -1
- package/src/orchestrator/skills/project-consistency/SKILL.md +350 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { readFileSync, existsSync, mkdirSync, readdirSync, cpSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { resolve, join } from 'node:path'
|
|
3
|
+
import { c } from './prompt.js'
|
|
4
|
+
import type { CliContext } from './types.js'
|
|
5
|
+
import { PLATFORM_CONFIGS, getSkillsForPlatform } from './package-config.js'
|
|
6
|
+
|
|
7
|
+
const HELP = `
|
|
8
|
+
opencastle package [options]
|
|
9
|
+
|
|
10
|
+
Package OpenCastle orchestrator as a plugin for IDE marketplaces.
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--platform, -p <name> Target platform (claude-code, cursor, opencode, gemini)
|
|
14
|
+
--all Generate packages for all platforms
|
|
15
|
+
--output, -o <dir> Output directory (default: dist/plugins)
|
|
16
|
+
--dry-run Preview what would be built without writing files
|
|
17
|
+
--help, -h Show this help
|
|
18
|
+
`
|
|
19
|
+
|
|
20
|
+
export interface PackageArgs {
|
|
21
|
+
platform: string | null
|
|
22
|
+
all: boolean
|
|
23
|
+
output: string
|
|
24
|
+
dryRun: boolean
|
|
25
|
+
help: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function parseArgs(args: string[]): PackageArgs {
|
|
29
|
+
const opts: PackageArgs = { platform: null, all: false, output: 'dist/plugins', dryRun: false, help: false }
|
|
30
|
+
for (let i = 0; i < args.length; i++) {
|
|
31
|
+
const arg = args[i]
|
|
32
|
+
if (arg === '--help' || arg === '-h') {
|
|
33
|
+
opts.help = true
|
|
34
|
+
} else if (arg === '--all') {
|
|
35
|
+
opts.all = true
|
|
36
|
+
} else if (arg === '--dry-run' || arg === '--dryRun') {
|
|
37
|
+
opts.dryRun = true
|
|
38
|
+
} else if ((arg === '--platform' || arg === '-p') && args[i + 1]) {
|
|
39
|
+
opts.platform = args[++i]
|
|
40
|
+
} else if ((arg === '--output' || arg === '-o') && args[i + 1]) {
|
|
41
|
+
opts.output = args[++i]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return opts
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function readVersion(pkgRoot: string): string {
|
|
48
|
+
const pkgPath = resolve(pkgRoot, 'package.json')
|
|
49
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { version: string }
|
|
50
|
+
return pkg.version
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function listSkillDirs(pkgRoot: string): string[] {
|
|
54
|
+
const skillsPath = resolve(pkgRoot, 'src/orchestrator/skills')
|
|
55
|
+
if (!existsSync(skillsPath)) return []
|
|
56
|
+
return readdirSync(skillsPath, { withFileTypes: true })
|
|
57
|
+
.filter(d => d.isDirectory())
|
|
58
|
+
.map(d => d.name)
|
|
59
|
+
.sort()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function generateManifest(
|
|
63
|
+
platform: string,
|
|
64
|
+
version: string,
|
|
65
|
+
skills: string[],
|
|
66
|
+
agents: string[],
|
|
67
|
+
): object {
|
|
68
|
+
const base = {
|
|
69
|
+
name: 'opencastle',
|
|
70
|
+
version,
|
|
71
|
+
description: 'OpenCastle multi-agent orchestration framework',
|
|
72
|
+
skills,
|
|
73
|
+
agents,
|
|
74
|
+
}
|
|
75
|
+
if (platform === 'claude-code') {
|
|
76
|
+
return { ...base, hooks: ['SessionStart'] }
|
|
77
|
+
}
|
|
78
|
+
if (platform === 'gemini') {
|
|
79
|
+
return { ...base, type: 'extension' }
|
|
80
|
+
}
|
|
81
|
+
return base
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function generateEntryPoint(platform: string, version: string, skills: string[]): string {
|
|
85
|
+
const skillList = skills.map(s => '- ' + s).join('\n')
|
|
86
|
+
switch (platform) {
|
|
87
|
+
case 'claude-code':
|
|
88
|
+
return [
|
|
89
|
+
'# OpenCastle v' + version,
|
|
90
|
+
'',
|
|
91
|
+
'Multi-agent orchestration framework for Claude Code.',
|
|
92
|
+
'',
|
|
93
|
+
'## Available Skills',
|
|
94
|
+
'',
|
|
95
|
+
skillList,
|
|
96
|
+
'',
|
|
97
|
+
'## Usage',
|
|
98
|
+
'',
|
|
99
|
+
'Skills are available in the `skills/` directory. Reference them in your agent instructions.',
|
|
100
|
+
'',
|
|
101
|
+
].join('\n')
|
|
102
|
+
case 'cursor':
|
|
103
|
+
return [
|
|
104
|
+
'# OpenCastle v' + version + ' -- Cursor Rules',
|
|
105
|
+
'',
|
|
106
|
+
'Multi-agent orchestration framework for Cursor.',
|
|
107
|
+
'',
|
|
108
|
+
'## Skills',
|
|
109
|
+
'',
|
|
110
|
+
skillList,
|
|
111
|
+
'',
|
|
112
|
+
'## Instructions',
|
|
113
|
+
'',
|
|
114
|
+
'Reference skill files using the `skills/` directory in your workspace.',
|
|
115
|
+
'',
|
|
116
|
+
].join('\n')
|
|
117
|
+
case 'opencode':
|
|
118
|
+
return [
|
|
119
|
+
'# OpenCastle v' + version,
|
|
120
|
+
'',
|
|
121
|
+
'Multi-agent orchestration framework for OpenCode.',
|
|
122
|
+
'',
|
|
123
|
+
'## Setup',
|
|
124
|
+
'',
|
|
125
|
+
'Copy this package to your project and reference skill files as needed.',
|
|
126
|
+
'',
|
|
127
|
+
'## Available Skills',
|
|
128
|
+
'',
|
|
129
|
+
skillList,
|
|
130
|
+
'',
|
|
131
|
+
].join('\n')
|
|
132
|
+
case 'gemini':
|
|
133
|
+
return [
|
|
134
|
+
'# OpenCastle v' + version,
|
|
135
|
+
'',
|
|
136
|
+
'Multi-agent orchestration framework for Gemini CLI.',
|
|
137
|
+
'',
|
|
138
|
+
'## Tool Mapping',
|
|
139
|
+
'',
|
|
140
|
+
'Each skill maps to a specialized tool capability.',
|
|
141
|
+
'',
|
|
142
|
+
'## Available Skills',
|
|
143
|
+
'',
|
|
144
|
+
skillList,
|
|
145
|
+
'',
|
|
146
|
+
].join('\n')
|
|
147
|
+
default:
|
|
148
|
+
return '# OpenCastle v' + version + '\n'
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function generateReadme(platform: string, version: string): string {
|
|
153
|
+
const config = PLATFORM_CONFIGS[platform]
|
|
154
|
+
const displayName = config?.displayName ?? platform
|
|
155
|
+
return [
|
|
156
|
+
'# OpenCastle Plugin for ' + displayName,
|
|
157
|
+
'',
|
|
158
|
+
'Version: ' + version,
|
|
159
|
+
'',
|
|
160
|
+
'## Installation',
|
|
161
|
+
'',
|
|
162
|
+
'Copy the contents of this directory to your ' + displayName + ' workspace or plugin directory.',
|
|
163
|
+
'',
|
|
164
|
+
'## Usage',
|
|
165
|
+
'',
|
|
166
|
+
'Reference the `' + (config?.entryPoint ?? 'README.md') + '` file in your ' + displayName + ' configuration.',
|
|
167
|
+
'',
|
|
168
|
+
'## Skills',
|
|
169
|
+
'',
|
|
170
|
+
'See the `skills/` directory for available skills.',
|
|
171
|
+
'',
|
|
172
|
+
'## Agents',
|
|
173
|
+
'',
|
|
174
|
+
'See the `agents/` directory for available agent definitions.',
|
|
175
|
+
'',
|
|
176
|
+
'## More Info',
|
|
177
|
+
'',
|
|
178
|
+
'Visit https://www.opencastle.dev/ for documentation.',
|
|
179
|
+
'',
|
|
180
|
+
].join('\n')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface BuildResult {
|
|
184
|
+
platform: string
|
|
185
|
+
outputDir: string
|
|
186
|
+
skillCount: number
|
|
187
|
+
agentCount: number
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function buildPluginPackage(
|
|
191
|
+
pkgRoot: string,
|
|
192
|
+
platform: string,
|
|
193
|
+
outputBase: string,
|
|
194
|
+
): BuildResult {
|
|
195
|
+
const config = PLATFORM_CONFIGS[platform]
|
|
196
|
+
if (!config) {
|
|
197
|
+
throw new Error('Unknown platform: ' + platform + '. Valid: ' + Object.keys(PLATFORM_CONFIGS).join(', '))
|
|
198
|
+
}
|
|
199
|
+
const outputDir = resolve(outputBase, config.outputDir)
|
|
200
|
+
mkdirSync(outputDir, { recursive: true })
|
|
201
|
+
|
|
202
|
+
const version = readVersion(pkgRoot)
|
|
203
|
+
const allSkills = listSkillDirs(pkgRoot)
|
|
204
|
+
const filteredSkills = getSkillsForPlatform(platform, allSkills)
|
|
205
|
+
|
|
206
|
+
if (config.includedDirs.includes('skills')) {
|
|
207
|
+
const skillsOut = join(outputDir, 'skills')
|
|
208
|
+
mkdirSync(skillsOut, { recursive: true })
|
|
209
|
+
const skillsSrc = resolve(pkgRoot, 'src/orchestrator/skills')
|
|
210
|
+
for (const skill of filteredSkills) {
|
|
211
|
+
const src = join(skillsSrc, skill)
|
|
212
|
+
if (existsSync(src)) {
|
|
213
|
+
cpSync(src, join(skillsOut, skill), { recursive: true })
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const agentsSrc = resolve(pkgRoot, 'src/orchestrator/agents')
|
|
219
|
+
const agentFiles = existsSync(agentsSrc)
|
|
220
|
+
? readdirSync(agentsSrc).filter(f => f.endsWith('.agent.md'))
|
|
221
|
+
: []
|
|
222
|
+
if (config.includedDirs.includes('agents')) {
|
|
223
|
+
const agentsOut = join(outputDir, 'agents')
|
|
224
|
+
mkdirSync(agentsOut, { recursive: true })
|
|
225
|
+
for (const f of agentFiles) {
|
|
226
|
+
cpSync(join(agentsSrc, f), join(agentsOut, f))
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (config.includedDirs.includes('instructions')) {
|
|
231
|
+
const instrSrc = resolve(pkgRoot, 'src/orchestrator/instructions')
|
|
232
|
+
if (existsSync(instrSrc)) {
|
|
233
|
+
const instrOut = join(outputDir, 'instructions')
|
|
234
|
+
mkdirSync(instrOut, { recursive: true })
|
|
235
|
+
const files = readdirSync(instrSrc).filter(f => f.endsWith('.instructions.md'))
|
|
236
|
+
for (const f of files) {
|
|
237
|
+
cpSync(join(instrSrc, f), join(instrOut, f))
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (config.includedDirs.includes('prompts')) {
|
|
243
|
+
const promptsSrc = resolve(pkgRoot, 'src/orchestrator/prompts')
|
|
244
|
+
if (existsSync(promptsSrc)) {
|
|
245
|
+
const promptsOut = join(outputDir, 'prompts')
|
|
246
|
+
mkdirSync(promptsOut, { recursive: true })
|
|
247
|
+
const files = readdirSync(promptsSrc).filter(f => f.endsWith('.prompt.md'))
|
|
248
|
+
for (const f of files) {
|
|
249
|
+
cpSync(join(promptsSrc, f), join(promptsOut, f))
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (config.includedDirs.includes('agent-workflows')) {
|
|
255
|
+
const wfSrc = resolve(pkgRoot, 'src/orchestrator/agent-workflows')
|
|
256
|
+
if (existsSync(wfSrc)) {
|
|
257
|
+
const wfOut = join(outputDir, 'agent-workflows')
|
|
258
|
+
mkdirSync(wfOut, { recursive: true })
|
|
259
|
+
const files = readdirSync(wfSrc).filter(f => f.endsWith('.md'))
|
|
260
|
+
for (const f of files) {
|
|
261
|
+
cpSync(join(wfSrc, f), join(wfOut, f))
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const agentNames = agentFiles.map(f => f.replace('.agent.md', ''))
|
|
267
|
+
const manifest = generateManifest(platform, version, filteredSkills, agentNames)
|
|
268
|
+
writeFileSync(join(outputDir, config.manifestFile), JSON.stringify(manifest, null, 2) + '\n', 'utf8')
|
|
269
|
+
|
|
270
|
+
const entryContent = generateEntryPoint(platform, version, filteredSkills)
|
|
271
|
+
writeFileSync(join(outputDir, config.entryPoint), entryContent, 'utf8')
|
|
272
|
+
|
|
273
|
+
const readmeContent = generateReadme(platform, version)
|
|
274
|
+
writeFileSync(join(outputDir, 'README.md'), readmeContent, 'utf8')
|
|
275
|
+
|
|
276
|
+
return { platform, outputDir, skillCount: filteredSkills.length, agentCount: agentFiles.length }
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export default async function packageCmd({ args, pkgRoot }: CliContext): Promise<void> {
|
|
280
|
+
const opts = parseArgs(args)
|
|
281
|
+
if (opts.help) {
|
|
282
|
+
console.log(HELP)
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const platforms = opts.all
|
|
287
|
+
? Object.keys(PLATFORM_CONFIGS)
|
|
288
|
+
: opts.platform
|
|
289
|
+
? [opts.platform]
|
|
290
|
+
: null
|
|
291
|
+
if (!platforms) {
|
|
292
|
+
console.error(' ' + c.red('✗') + ' Specify --platform <name> or --all')
|
|
293
|
+
console.log(HELP)
|
|
294
|
+
process.exit(1)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (opts.dryRun) {
|
|
298
|
+
console.log(` [dry-run] Would build packages for: ${platforms.join(', ')}`)
|
|
299
|
+
console.log(` [dry-run] Output directory: ${resolve(process.cwd(), opts.output)}`)
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const outputBase = resolve(process.cwd(), opts.output)
|
|
304
|
+
const results: BuildResult[] = []
|
|
305
|
+
const errors: string[] = []
|
|
306
|
+
|
|
307
|
+
for (const platform of platforms) {
|
|
308
|
+
try {
|
|
309
|
+
console.log(' ' + c.dim('→') + ' Building ' + platform + '...')
|
|
310
|
+
const result = buildPluginPackage(pkgRoot, platform, outputBase)
|
|
311
|
+
results.push(result)
|
|
312
|
+
console.log(
|
|
313
|
+
' ' + c.green('✓') + ' ' + platform + ': ' +
|
|
314
|
+
result.skillCount + ' skills, ' + result.agentCount + ' agents → ' + result.outputDir
|
|
315
|
+
)
|
|
316
|
+
} catch (err) {
|
|
317
|
+
const msg = (err as Error).message
|
|
318
|
+
errors.push(platform + ': ' + msg)
|
|
319
|
+
console.error(' ' + c.red('✗') + ' ' + platform + ': ' + msg)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
console.log()
|
|
324
|
+
if (errors.length > 0) {
|
|
325
|
+
console.error(' ' + c.red('✗') + ' ' + errors.length + ' platform(s) failed')
|
|
326
|
+
process.exit(1)
|
|
327
|
+
}
|
|
328
|
+
console.log(' ' + c.green('✔') + ' ' + results.length + ' package(s) built in ' + outputBase)
|
|
329
|
+
}
|
package/src/cli/pipeline.ts
CHANGED
|
@@ -18,6 +18,17 @@ export interface ConvoyGroup {
|
|
|
18
18
|
depends_on: string[]
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
function appendTaskComplexity(base: string, taskComplexity: ComplexityAssessment['task_complexity']): string {
|
|
22
|
+
if (!taskComplexity?.length) return base
|
|
23
|
+
let result = base + '\n\n## Pre-Computed Task Complexity\n\n'
|
|
24
|
+
result += '| Workstream | Phase | Complexity | Rationale |\n'
|
|
25
|
+
result += '|-----------|-------|-----------|----------|\n'
|
|
26
|
+
for (const tc of taskComplexity) {
|
|
27
|
+
result += `| ${tc.workstream} | ${tc.phase} | ${tc.complexity} | ${tc.rationale} |\n`
|
|
28
|
+
}
|
|
29
|
+
return result
|
|
30
|
+
}
|
|
31
|
+
|
|
21
32
|
export interface ComplexityAssessment {
|
|
22
33
|
original_prompt: string
|
|
23
34
|
total_tasks: number
|
|
@@ -28,6 +39,12 @@ export interface ComplexityAssessment {
|
|
|
28
39
|
recommended_strategy: 'single' | 'chain'
|
|
29
40
|
chain_rationale?: string
|
|
30
41
|
convoy_groups: ConvoyGroup[]
|
|
42
|
+
task_complexity?: Array<{
|
|
43
|
+
workstream: string
|
|
44
|
+
phase: number
|
|
45
|
+
complexity: 1 | 2 | 3 | 5 | 8 | 13
|
|
46
|
+
rationale: string
|
|
47
|
+
}>
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
export function parseComplexityAssessment(jsonText: string): ComplexityAssessment | null {
|
|
@@ -572,12 +589,13 @@ export default async function pipeline({ args, pkgRoot }: CliContext): Promise<v
|
|
|
572
589
|
].filter(Boolean).join('\n')
|
|
573
590
|
|
|
574
591
|
const prdContent = await readFile(prdPath, 'utf8')
|
|
592
|
+
const contextForSpec = appendTaskComplexity(prdContent, complexity?.task_complexity)
|
|
575
593
|
const groupSpecPath = resolve(convoyDir, `${group.name}.convoy.yml`)
|
|
576
594
|
|
|
577
595
|
const { specPath: resolvedGroupSpecPath } = await generateAndValidateSpec({
|
|
578
596
|
sharedOpts,
|
|
579
597
|
goalText: chainGoal,
|
|
580
|
-
contextText:
|
|
598
|
+
contextText: contextForSpec,
|
|
581
599
|
specPath: groupSpecPath,
|
|
582
600
|
skipValidation: opts.skipValidation,
|
|
583
601
|
groupName: group.name,
|
|
@@ -643,12 +661,13 @@ export default async function pipeline({ args, pkgRoot }: CliContext): Promise<v
|
|
|
643
661
|
|
|
644
662
|
// ── Generate convoy spec ──────────────────────────────────────────────────
|
|
645
663
|
const singlePrdContent = await readFile(prdPath, 'utf8')
|
|
664
|
+
const singleContextForSpec = appendTaskComplexity(singlePrdContent, complexity?.task_complexity)
|
|
646
665
|
const singleGoal = complexity?.original_prompt ?? opts.text ?? ''
|
|
647
666
|
|
|
648
667
|
const specResult = await generateAndValidateSpec({
|
|
649
668
|
sharedOpts,
|
|
650
669
|
goalText: singleGoal,
|
|
651
|
-
contextText:
|
|
670
|
+
contextText: singleContextForSpec,
|
|
652
671
|
specPath: opts.outputSpec ? resolve(process.cwd(), opts.outputSpec) : undefined,
|
|
653
672
|
skipValidation: opts.skipValidation,
|
|
654
673
|
enrichment: complexity ? deriveSpecEnrichment(complexity) : undefined,
|
|
@@ -1830,6 +1830,64 @@ describe('validateSpec — built_in_gates config', () => {
|
|
|
1830
1830
|
expect(result.valid).toBe(false)
|
|
1831
1831
|
expect(result.errors).toContainEqual(expect.stringContaining('gate_timeout'))
|
|
1832
1832
|
})
|
|
1833
|
+
|
|
1834
|
+
it('accepts tdd_check as boolean', () => {
|
|
1835
|
+
const result = validateSpec({
|
|
1836
|
+
...validSpec,
|
|
1837
|
+
defaults: { built_in_gates: { tdd_check: true } },
|
|
1838
|
+
})
|
|
1839
|
+
expect(result.valid).toBe(true)
|
|
1840
|
+
})
|
|
1841
|
+
|
|
1842
|
+
it('accepts tdd_check as object', () => {
|
|
1843
|
+
const result = validateSpec({
|
|
1844
|
+
...validSpec,
|
|
1845
|
+
defaults: { built_in_gates: { tdd_check: { enabled: true, mode: 'block' } } },
|
|
1846
|
+
})
|
|
1847
|
+
expect(result.valid).toBe(true)
|
|
1848
|
+
})
|
|
1849
|
+
|
|
1850
|
+
it('rejects tdd_check with invalid value', () => {
|
|
1851
|
+
const result = validateSpec({
|
|
1852
|
+
...validSpec,
|
|
1853
|
+
defaults: { built_in_gates: { tdd_check: 'yes' } },
|
|
1854
|
+
})
|
|
1855
|
+
expect(result.valid).toBe(false)
|
|
1856
|
+
expect(result.errors).toContainEqual(expect.stringContaining('tdd_check'))
|
|
1857
|
+
})
|
|
1858
|
+
})
|
|
1859
|
+
|
|
1860
|
+
describe('validateSpec — review_stages', () => {
|
|
1861
|
+
const validSpec = {
|
|
1862
|
+
name: 'test-run',
|
|
1863
|
+
version: 1,
|
|
1864
|
+
tasks: [{ id: 'task-1', prompt: 'Do something' }],
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
it('accepts review_stages as true', () => {
|
|
1868
|
+
const result = validateSpec({
|
|
1869
|
+
...validSpec,
|
|
1870
|
+
defaults: { review_stages: true },
|
|
1871
|
+
})
|
|
1872
|
+
expect(result.valid).toBe(true)
|
|
1873
|
+
})
|
|
1874
|
+
|
|
1875
|
+
it('accepts review_stages as false', () => {
|
|
1876
|
+
const result = validateSpec({
|
|
1877
|
+
...validSpec,
|
|
1878
|
+
defaults: { review_stages: false },
|
|
1879
|
+
})
|
|
1880
|
+
expect(result.valid).toBe(true)
|
|
1881
|
+
})
|
|
1882
|
+
|
|
1883
|
+
it('rejects review_stages with non-boolean value', () => {
|
|
1884
|
+
const result = validateSpec({
|
|
1885
|
+
...validSpec,
|
|
1886
|
+
defaults: { review_stages: 'yes' },
|
|
1887
|
+
})
|
|
1888
|
+
expect(result.valid).toBe(false)
|
|
1889
|
+
expect(result.errors).toContainEqual(expect.stringContaining('review_stages'))
|
|
1890
|
+
})
|
|
1833
1891
|
})
|
|
1834
1892
|
|
|
1835
1893
|
describe('validateSpec — browser_test config', () => {
|
package/src/cli/run/schema.ts
CHANGED
|
@@ -268,6 +268,10 @@ export function validateSpec(spec: unknown): ValidationResult {
|
|
|
268
268
|
} else {
|
|
269
269
|
const bg = d.built_in_gates as Record<string, unknown>
|
|
270
270
|
const boolOrAutoFields = ['secret_scan', 'blast_radius', 'dependency_audit', 'regression_test', 'browser_test'] as const
|
|
271
|
+
// tdd_check can be boolean or object (TDDGateConfig)
|
|
272
|
+
if (bg.tdd_check !== undefined && typeof bg.tdd_check !== 'boolean' && (typeof bg.tdd_check !== 'object' || Array.isArray(bg.tdd_check) || bg.tdd_check === null)) {
|
|
273
|
+
errors.push('`defaults.built_in_gates.tdd_check` must be a boolean or an object')
|
|
274
|
+
}
|
|
271
275
|
for (const field of boolOrAutoFields) {
|
|
272
276
|
if (bg[field] !== undefined && typeof bg[field] !== 'boolean' && bg[field] !== 'auto') {
|
|
273
277
|
errors.push(`\`defaults.built_in_gates.${field}\` must be a boolean or "auto"`)
|
|
@@ -287,6 +291,35 @@ export function validateSpec(spec: unknown): ValidationResult {
|
|
|
287
291
|
validateBrowserTestConfig(d.browser_test, 'defaults.browser_test', errors)
|
|
288
292
|
}
|
|
289
293
|
|
|
294
|
+
// compaction config validation (Phase 44)
|
|
295
|
+
if (d.compaction !== undefined) {
|
|
296
|
+
if (!d.compaction || typeof d.compaction !== 'object' || Array.isArray(d.compaction)) {
|
|
297
|
+
errors.push('`defaults.compaction` must be an object')
|
|
298
|
+
} else {
|
|
299
|
+
const comp = d.compaction as Record<string, unknown>
|
|
300
|
+
if (comp.enabled !== undefined && typeof comp.enabled !== 'boolean') {
|
|
301
|
+
errors.push('`defaults.compaction.enabled` must be a boolean')
|
|
302
|
+
}
|
|
303
|
+
if (comp.token_threshold_pct !== undefined) {
|
|
304
|
+
const pct = Number(comp.token_threshold_pct)
|
|
305
|
+
if (!Number.isFinite(pct) || pct < 1 || pct > 100) {
|
|
306
|
+
errors.push('`defaults.compaction.token_threshold_pct` must be a number between 1 and 100')
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (comp.summary_max_tokens !== undefined) {
|
|
310
|
+
const smt = Number(comp.summary_max_tokens)
|
|
311
|
+
if (!Number.isInteger(smt) || smt < 1) {
|
|
312
|
+
errors.push('`defaults.compaction.summary_max_tokens` must be a positive integer')
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// review_stages validation (Phase 40 — two-stage review toggle)
|
|
319
|
+
if (d.review_stages !== undefined && typeof d.review_stages !== 'boolean') {
|
|
320
|
+
errors.push('`defaults.review_stages` must be a boolean')
|
|
321
|
+
}
|
|
322
|
+
|
|
290
323
|
// review validation
|
|
291
324
|
const VALID_REVIEW = ['auto', 'fast', 'panel', 'none']
|
|
292
325
|
if (d.review !== undefined && !VALID_REVIEW.includes(d.review as string)) {
|
package/src/cli/run.ts
CHANGED
|
@@ -532,7 +532,9 @@ export default async function run({ args, pkgRoot }: CliContext): Promise<void>
|
|
|
532
532
|
const { createConvoyStore } = await import('./convoy/store.js')
|
|
533
533
|
const store = createConvoyStore(dbPath)
|
|
534
534
|
const latestPipeline = store.getLatestPipeline()
|
|
535
|
-
|
|
535
|
+
|
|
536
|
+
// ── Pipeline resume (pending / running / failed) ────────────
|
|
537
|
+
if (latestPipeline && latestPipeline.status !== 'done') {
|
|
536
538
|
store.close()
|
|
537
539
|
const resumePipelineSpec = parseTaskSpecText(latestPipeline.spec_yaml)
|
|
538
540
|
if (opts.concurrency !== null) resumePipelineSpec.concurrency = opts.concurrency
|
|
@@ -572,6 +574,17 @@ export default async function run({ args, pkgRoot }: CliContext): Promise<void>
|
|
|
572
574
|
process.exit(resumePipelineResult.status !== 'done' ? 1 : 0)
|
|
573
575
|
}
|
|
574
576
|
|
|
577
|
+
// ── Pipeline done — don't fall through to convoy check ──────
|
|
578
|
+
if (latestPipeline && latestPipeline.status === 'done') {
|
|
579
|
+
store.close()
|
|
580
|
+
console.error(
|
|
581
|
+
` ✗ Last pipeline "${latestPipeline.name}" already finished with status: done`
|
|
582
|
+
)
|
|
583
|
+
console.error(` Only interrupted (running/pending/failed) pipelines can be resumed.`)
|
|
584
|
+
process.exit(1)
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// ── Standalone convoy resume ────────────────────────────────
|
|
575
588
|
const convoy = store.getLatestConvoy()
|
|
576
589
|
store.close()
|
|
577
590
|
if (!convoy) {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { CliContext } from './types.js'
|
|
2
|
+
import { c } from './prompt.js'
|
|
3
|
+
|
|
4
|
+
const HELP = `
|
|
5
|
+
opencastle skills [subcommand]
|
|
6
|
+
|
|
7
|
+
Skill refinement and failure tracking.
|
|
8
|
+
|
|
9
|
+
Subcommands:
|
|
10
|
+
refine Scan for failure patterns and generate refinement proposals
|
|
11
|
+
failures Show failure stats per skill
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--dry-run Preview what proposals would be generated without saving
|
|
15
|
+
--help, -h Show this help
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
function parseSkillsArgs(args: string[]): { subcommand: string | null; help: boolean; dryRun: boolean } {
|
|
19
|
+
const opts = { subcommand: null as string | null, help: false, dryRun: false }
|
|
20
|
+
for (const arg of args) {
|
|
21
|
+
if (arg === '--help' || arg === '-h') {
|
|
22
|
+
opts.help = true
|
|
23
|
+
} else if (arg === '--dry-run' || arg === '--dryRun') {
|
|
24
|
+
opts.dryRun = true
|
|
25
|
+
} else if (!arg.startsWith('--')) {
|
|
26
|
+
opts.subcommand ??= arg
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return opts
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default async function skills({ args }: CliContext): Promise<void> {
|
|
33
|
+
const opts = parseSkillsArgs(args)
|
|
34
|
+
|
|
35
|
+
if (opts.help || !opts.subcommand) {
|
|
36
|
+
console.log(HELP)
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
getFailureStats,
|
|
42
|
+
getSkillFailures,
|
|
43
|
+
detectFailurePatterns,
|
|
44
|
+
generateRefinementProposal,
|
|
45
|
+
saveProposal,
|
|
46
|
+
} = await import('./convoy/skill-refinement.js')
|
|
47
|
+
|
|
48
|
+
switch (opts.subcommand) {
|
|
49
|
+
case 'refine': {
|
|
50
|
+
const stats = getFailureStats()
|
|
51
|
+
const uniqueSkills = stats.map(s => s.skill_name)
|
|
52
|
+
|
|
53
|
+
if (uniqueSkills.length === 0) {
|
|
54
|
+
console.log(' No skill failures recorded yet.')
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const generated: Array<{ skill: string; path: string }> = []
|
|
59
|
+
for (const skillName of uniqueSkills) {
|
|
60
|
+
const failures = getSkillFailures(skillName)
|
|
61
|
+
const { threshold_met } = detectFailurePatterns(failures)
|
|
62
|
+
if (!threshold_met) continue
|
|
63
|
+
const proposal = generateRefinementProposal(skillName, failures)
|
|
64
|
+
const proposalPath = opts.dryRun
|
|
65
|
+
? `.opencastle/proposals/${skillName}-refinement.md`
|
|
66
|
+
: saveProposal(proposal, undefined, failures)
|
|
67
|
+
generated.push({ skill: skillName, path: proposalPath })
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (generated.length === 0) {
|
|
71
|
+
console.log(' No skills currently meet the refinement threshold.')
|
|
72
|
+
} else if (opts.dryRun) {
|
|
73
|
+
console.log(` [dry-run] Would generate ${generated.length} refinement proposal${generated.length === 1 ? '' : 's'}:`)
|
|
74
|
+
for (const g of generated) {
|
|
75
|
+
console.log(` ${c.dim('◆')} ${g.skill}: ${g.path}`)
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
console.log(` ${c.green('✔')} ${generated.length} skill${generated.length === 1 ? '' : 's'} have refinement proposals. Review in .opencastle/proposals/`)
|
|
79
|
+
for (const g of generated) {
|
|
80
|
+
console.log(` ${c.dim('◆')} ${g.skill}: ${g.path}`)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
break
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
case 'failures': {
|
|
87
|
+
const stats = getFailureStats()
|
|
88
|
+
if (stats.length === 0) {
|
|
89
|
+
console.log(' No skill failures recorded yet.')
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const colW = [30, 10, 30, 26]
|
|
94
|
+
const header = [
|
|
95
|
+
'Skill'.padEnd(colW[0]),
|
|
96
|
+
'Failures'.padEnd(colW[1]),
|
|
97
|
+
'Agents'.padEnd(colW[2]),
|
|
98
|
+
'Latest',
|
|
99
|
+
].join(' ')
|
|
100
|
+
console.log(`\n ${c.bold(header)}`)
|
|
101
|
+
console.log(' ' + '-'.repeat(header.length))
|
|
102
|
+
|
|
103
|
+
for (const s of stats) {
|
|
104
|
+
const row = [
|
|
105
|
+
s.skill_name.slice(0, colW[0] - 1).padEnd(colW[0]),
|
|
106
|
+
String(s.count).padEnd(colW[1]),
|
|
107
|
+
s.agents.join(', ').slice(0, colW[2] - 1).padEnd(colW[2]),
|
|
108
|
+
s.latest.slice(0, 10),
|
|
109
|
+
].join(' ')
|
|
110
|
+
console.log(` ${row}`)
|
|
111
|
+
}
|
|
112
|
+
console.log('')
|
|
113
|
+
break
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
default:
|
|
117
|
+
console.error(` ${c.red('✗')} Unknown subcommand: ${opts.subcommand}`)
|
|
118
|
+
console.log(HELP)
|
|
119
|
+
process.exit(1)
|
|
120
|
+
}
|
|
121
|
+
}
|
package/src/cli/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChildProcess } from 'node:child_process';
|
|
2
|
-
import type { BuiltInGatesConfig, BrowserTestConfig, GuardConfig, CircuitBreakerConfig, TaskStep, Hook, TaskOutput, TaskInput, WatchConfig, MCPServerConfig } from './convoy/types.js';
|
|
2
|
+
import type { BuiltInGatesConfig, BrowserTestConfig, GuardConfig, CircuitBreakerConfig, CompactionConfig, TaskStep, Hook, TaskOutput, TaskInput, WatchConfig, MCPServerConfig } from './convoy/types.js';
|
|
3
3
|
|
|
4
4
|
// ── Stack selection types ──────────────────────────────────────
|
|
5
5
|
|
|
@@ -165,6 +165,7 @@ export interface TaskDefaults {
|
|
|
165
165
|
escalate_to?: string;
|
|
166
166
|
circuit_breaker?: CircuitBreakerConfig;
|
|
167
167
|
review?: 'auto' | 'fast' | 'panel' | 'none';
|
|
168
|
+
review_stages?: boolean;
|
|
168
169
|
reviewer_model?: string;
|
|
169
170
|
review_budget?: number;
|
|
170
171
|
on_review_budget_exceeded?: 'skip' | 'downgrade' | 'stop';
|
|
@@ -188,6 +189,8 @@ export interface TaskDefaults {
|
|
|
188
189
|
mcp_server_approval_timeout?: number;
|
|
189
190
|
/** Browser test gate configuration for default built-in gates. */
|
|
190
191
|
browser_test?: BrowserTestConfig;
|
|
192
|
+
/** Auto-context compaction configuration (Phase 44). */
|
|
193
|
+
compaction?: CompactionConfig;
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
/** Validated task spec from YAML. */
|
package/src/cli/update.ts
CHANGED
|
@@ -19,8 +19,8 @@ const UPDATE_HELP = `
|
|
|
19
19
|
|
|
20
20
|
Options:
|
|
21
21
|
--dry-run Preview what would be changed without writing files
|
|
22
|
-
--force
|
|
23
|
-
--reconfigure Re-run IDE
|
|
22
|
+
--force Force update even if versions match
|
|
23
|
+
--reconfigure Re-run IDE and stack selection
|
|
24
24
|
--help, -h Show this help
|
|
25
25
|
`
|
|
26
26
|
|