opencastle 0.31.7 → 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/README.md +4 -0
- 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 +280 -6
- 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/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/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/package.json +2 -1
- 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 +301 -7
- 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/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/skills.ts +121 -0
- package/src/cli/types.ts +4 -1
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/orchestrator/prompts/assess-complexity.prompt.md +13 -0
- package/src/orchestrator/prompts/generate-convoy.prompt.md +19 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { c } from './prompt.js';
|
|
2
|
+
const HELP = `
|
|
3
|
+
opencastle skills [subcommand]
|
|
4
|
+
|
|
5
|
+
Skill refinement and failure tracking.
|
|
6
|
+
|
|
7
|
+
Subcommands:
|
|
8
|
+
refine Scan for failure patterns and generate refinement proposals
|
|
9
|
+
failures Show failure stats per skill
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
--dry-run Preview what proposals would be generated without saving
|
|
13
|
+
--help, -h Show this help
|
|
14
|
+
`;
|
|
15
|
+
function parseSkillsArgs(args) {
|
|
16
|
+
const opts = { subcommand: null, help: false, dryRun: false };
|
|
17
|
+
for (const arg of args) {
|
|
18
|
+
if (arg === '--help' || arg === '-h') {
|
|
19
|
+
opts.help = true;
|
|
20
|
+
}
|
|
21
|
+
else if (arg === '--dry-run' || arg === '--dryRun') {
|
|
22
|
+
opts.dryRun = true;
|
|
23
|
+
}
|
|
24
|
+
else if (!arg.startsWith('--')) {
|
|
25
|
+
opts.subcommand ??= arg;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return opts;
|
|
29
|
+
}
|
|
30
|
+
export default async function skills({ args }) {
|
|
31
|
+
const opts = parseSkillsArgs(args);
|
|
32
|
+
if (opts.help || !opts.subcommand) {
|
|
33
|
+
console.log(HELP);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const { getFailureStats, getSkillFailures, detectFailurePatterns, generateRefinementProposal, saveProposal, } = await import('./convoy/skill-refinement.js');
|
|
37
|
+
switch (opts.subcommand) {
|
|
38
|
+
case 'refine': {
|
|
39
|
+
const stats = getFailureStats();
|
|
40
|
+
const uniqueSkills = stats.map(s => s.skill_name);
|
|
41
|
+
if (uniqueSkills.length === 0) {
|
|
42
|
+
console.log(' No skill failures recorded yet.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const generated = [];
|
|
46
|
+
for (const skillName of uniqueSkills) {
|
|
47
|
+
const failures = getSkillFailures(skillName);
|
|
48
|
+
const { threshold_met } = detectFailurePatterns(failures);
|
|
49
|
+
if (!threshold_met)
|
|
50
|
+
continue;
|
|
51
|
+
const proposal = generateRefinementProposal(skillName, failures);
|
|
52
|
+
const proposalPath = opts.dryRun
|
|
53
|
+
? `.opencastle/proposals/${skillName}-refinement.md`
|
|
54
|
+
: saveProposal(proposal, undefined, failures);
|
|
55
|
+
generated.push({ skill: skillName, path: proposalPath });
|
|
56
|
+
}
|
|
57
|
+
if (generated.length === 0) {
|
|
58
|
+
console.log(' No skills currently meet the refinement threshold.');
|
|
59
|
+
}
|
|
60
|
+
else if (opts.dryRun) {
|
|
61
|
+
console.log(` [dry-run] Would generate ${generated.length} refinement proposal${generated.length === 1 ? '' : 's'}:`);
|
|
62
|
+
for (const g of generated) {
|
|
63
|
+
console.log(` ${c.dim('◆')} ${g.skill}: ${g.path}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.log(` ${c.green('✔')} ${generated.length} skill${generated.length === 1 ? '' : 's'} have refinement proposals. Review in .opencastle/proposals/`);
|
|
68
|
+
for (const g of generated) {
|
|
69
|
+
console.log(` ${c.dim('◆')} ${g.skill}: ${g.path}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case 'failures': {
|
|
75
|
+
const stats = getFailureStats();
|
|
76
|
+
if (stats.length === 0) {
|
|
77
|
+
console.log(' No skill failures recorded yet.');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const colW = [30, 10, 30, 26];
|
|
81
|
+
const header = [
|
|
82
|
+
'Skill'.padEnd(colW[0]),
|
|
83
|
+
'Failures'.padEnd(colW[1]),
|
|
84
|
+
'Agents'.padEnd(colW[2]),
|
|
85
|
+
'Latest',
|
|
86
|
+
].join(' ');
|
|
87
|
+
console.log(`\n ${c.bold(header)}`);
|
|
88
|
+
console.log(' ' + '-'.repeat(header.length));
|
|
89
|
+
for (const s of stats) {
|
|
90
|
+
const row = [
|
|
91
|
+
s.skill_name.slice(0, colW[0] - 1).padEnd(colW[0]),
|
|
92
|
+
String(s.count).padEnd(colW[1]),
|
|
93
|
+
s.agents.join(', ').slice(0, colW[2] - 1).padEnd(colW[2]),
|
|
94
|
+
s.latest.slice(0, 10),
|
|
95
|
+
].join(' ');
|
|
96
|
+
console.log(` ${row}`);
|
|
97
|
+
}
|
|
98
|
+
console.log('');
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
console.error(` ${c.red('✗')} Unknown subcommand: ${opts.subcommand}`);
|
|
103
|
+
console.log(HELP);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/cli/skills.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/types.d.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
|
export type IdeChoice = 'vscode' | 'cursor' | 'claude-code' | 'opencode';
|
|
4
4
|
export type TechTool = 'sanity' | 'contentful' | 'strapi' | 'supabase' | 'convex' | 'vercel' | 'nx' | 'chrome-devtools' | 'nextjs' | 'astro' | 'netlify' | 'turborepo' | 'prisma' | 'cypress' | 'playwright' | 'vitest' | 'figma' | 'resend';
|
|
5
5
|
export type TeamTool = 'linear' | 'jira' | 'slack' | 'teams';
|
|
@@ -130,6 +130,7 @@ export interface TaskDefaults {
|
|
|
130
130
|
escalate_to?: string;
|
|
131
131
|
circuit_breaker?: CircuitBreakerConfig;
|
|
132
132
|
review?: 'auto' | 'fast' | 'panel' | 'none';
|
|
133
|
+
review_stages?: boolean;
|
|
133
134
|
reviewer_model?: string;
|
|
134
135
|
review_budget?: number;
|
|
135
136
|
on_review_budget_exceeded?: 'skip' | 'downgrade' | 'stop';
|
|
@@ -153,6 +154,8 @@ export interface TaskDefaults {
|
|
|
153
154
|
mcp_server_approval_timeout?: number;
|
|
154
155
|
/** Browser test gate configuration for default built-in gates. */
|
|
155
156
|
browser_test?: BrowserTestConfig;
|
|
157
|
+
/** Auto-context compaction configuration (Phase 44). */
|
|
158
|
+
compaction?: CompactionConfig;
|
|
156
159
|
}
|
|
157
160
|
/** Validated task spec from YAML. */
|
|
158
161
|
export interface TaskSpec {
|
package/dist/cli/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencastle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Multi-agent orchestration framework for AI coding assistants",
|
|
6
6
|
"bin": {
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"website:dev": "astro dev --root website",
|
|
47
47
|
"website:build": "astro build --root website",
|
|
48
48
|
"website:preview": "astro preview --root website",
|
|
49
|
+
"build:plugins": "tsx scripts/build-plugins.ts",
|
|
49
50
|
"prepublishOnly": "npm run build"
|
|
50
51
|
},
|
|
51
52
|
"engines": {
|
package/src/cli/agents.ts
CHANGED
|
@@ -17,6 +17,7 @@ const HELP = `
|
|
|
17
17
|
Options:
|
|
18
18
|
--older-than <days> Days threshold for compact subcommand
|
|
19
19
|
--yes, -y Skip confirmation prompt
|
|
20
|
+
--dry-run Preview what would be deleted without deleting
|
|
20
21
|
--help, -h Show this help
|
|
21
22
|
`
|
|
22
23
|
|
|
@@ -25,6 +26,7 @@ interface AgentsOptions {
|
|
|
25
26
|
agentName: string | null
|
|
26
27
|
olderThan: number | null
|
|
27
28
|
yes: boolean
|
|
29
|
+
dryRun: boolean
|
|
28
30
|
help: boolean
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -34,6 +36,7 @@ function parseAgentsArgs(args: string[]): AgentsOptions {
|
|
|
34
36
|
agentName: null,
|
|
35
37
|
olderThan: null,
|
|
36
38
|
yes: false,
|
|
39
|
+
dryRun: false,
|
|
37
40
|
help: false,
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -56,6 +59,10 @@ function parseAgentsArgs(args: string[]): AgentsOptions {
|
|
|
56
59
|
case '-y':
|
|
57
60
|
opts.yes = true
|
|
58
61
|
break
|
|
62
|
+
case '--dry-run':
|
|
63
|
+
case '--dryRun':
|
|
64
|
+
opts.dryRun = true
|
|
65
|
+
break
|
|
59
66
|
default:
|
|
60
67
|
if (arg.startsWith('--')) {
|
|
61
68
|
console.error(` \u2717 Unknown option: ${arg}`)
|
|
@@ -141,12 +148,16 @@ export default async function agents({ args }: CliContext): Promise<void> {
|
|
|
141
148
|
console.error(' \u2717 purge requires an agent name: opencastle agents purge <agent>')
|
|
142
149
|
process.exit(1)
|
|
143
150
|
}
|
|
151
|
+
const existing = store.getAgentIdentities(opts.agentName, 1000)
|
|
152
|
+
if (existing.length === 0) {
|
|
153
|
+
console.log(` No identities found for agent "${opts.agentName}".`)
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
if (opts.dryRun) {
|
|
157
|
+
console.log(` [dry-run] Would purge ${existing.length} identities for agent "${opts.agentName}"`)
|
|
158
|
+
return
|
|
159
|
+
}
|
|
144
160
|
if (!opts.yes) {
|
|
145
|
-
const existing = store.getAgentIdentities(opts.agentName, 1000)
|
|
146
|
-
if (existing.length === 0) {
|
|
147
|
-
console.log(` No identities found for agent "${opts.agentName}".`)
|
|
148
|
-
return
|
|
149
|
-
}
|
|
150
161
|
console.log(`\n This will delete ${existing.length} identities for agent "${opts.agentName}".`)
|
|
151
162
|
console.log(` Use --yes or -y to confirm.`)
|
|
152
163
|
return
|
|
@@ -161,6 +172,10 @@ export default async function agents({ args }: CliContext): Promise<void> {
|
|
|
161
172
|
console.error(' \u2717 compact requires --older-than <days>')
|
|
162
173
|
process.exit(1)
|
|
163
174
|
}
|
|
175
|
+
if (opts.dryRun) {
|
|
176
|
+
console.log(` [dry-run] Would delete identities older than ${opts.olderThan} days`)
|
|
177
|
+
return
|
|
178
|
+
}
|
|
164
179
|
const deleted = store.deleteAgentIdentitiesOlderThan(opts.olderThan)
|
|
165
180
|
console.log(` \u2713 Deleted ${deleted} identities older than ${opts.olderThan} days.`)
|
|
166
181
|
break
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { pruneArtifacts } from './convoy/artifacts.js'
|
|
2
|
+
import type { CliContext } from './types.js'
|
|
3
|
+
|
|
4
|
+
const HELP = `
|
|
5
|
+
opencastle artifacts <subcommand> [options]
|
|
6
|
+
|
|
7
|
+
Manage filesystem artifact storage.
|
|
8
|
+
|
|
9
|
+
Subcommands:
|
|
10
|
+
prune Prune old convoy artifact directories
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--keep <N> Number of recent artifacts to keep (default: 10)
|
|
14
|
+
--dry-run Preview what would be pruned without deleting
|
|
15
|
+
--help, -h Show this help
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
export default function artifactsCli({ args }: CliContext): void {
|
|
19
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
20
|
+
console.log(HELP)
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const dryRun = args.includes('--dry-run') || args.includes('--dryRun')
|
|
25
|
+
const subcommand = args.find(a => !a.startsWith('--'))
|
|
26
|
+
|
|
27
|
+
if (subcommand === 'prune') {
|
|
28
|
+
const keepIdx = args.indexOf('--keep')
|
|
29
|
+
const keepCount = keepIdx >= 0 && args[keepIdx + 1] ? parseInt(args[keepIdx + 1], 10) : 10
|
|
30
|
+
|
|
31
|
+
if (dryRun) {
|
|
32
|
+
console.log(` [dry-run] Would prune convoy artifacts, keeping ${keepCount} most recent`)
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const result = pruneArtifacts(keepCount)
|
|
37
|
+
console.log(`Pruned ${result.removed} convoy artifact directories, freed ${(result.freed_bytes / 1024).toFixed(1)} KB`)
|
|
38
|
+
} else {
|
|
39
|
+
console.log(HELP)
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/cli/baselines.ts
CHANGED
|
@@ -16,6 +16,7 @@ const HELP = `
|
|
|
16
16
|
--slug <name> Baseline name (used as filename)
|
|
17
17
|
--from <file> Source PNG file path
|
|
18
18
|
--dir <path> Baselines directory (default: .opencastle/baselines)
|
|
19
|
+
--dry-run Preview what would be updated without writing
|
|
19
20
|
--help, -h Show this help
|
|
20
21
|
`
|
|
21
22
|
|
|
@@ -24,6 +25,7 @@ interface BaselinesOptions {
|
|
|
24
25
|
slug: string | null
|
|
25
26
|
from: string | null
|
|
26
27
|
dir: string
|
|
28
|
+
dryRun: boolean
|
|
27
29
|
help: boolean
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -33,6 +35,7 @@ function parseBaselinesArgs(args: string[]): BaselinesOptions {
|
|
|
33
35
|
slug: null,
|
|
34
36
|
from: null,
|
|
35
37
|
dir: '.opencastle/baselines',
|
|
38
|
+
dryRun: false,
|
|
36
39
|
help: false,
|
|
37
40
|
}
|
|
38
41
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -63,6 +66,10 @@ function parseBaselinesArgs(args: string[]): BaselinesOptions {
|
|
|
63
66
|
}
|
|
64
67
|
opts.dir = args[++i]
|
|
65
68
|
break
|
|
69
|
+
case '--dry-run':
|
|
70
|
+
case '--dryRun':
|
|
71
|
+
opts.dryRun = true
|
|
72
|
+
break
|
|
66
73
|
default:
|
|
67
74
|
if (arg.startsWith('--')) {
|
|
68
75
|
console.error(` \u2717 Unknown option: ${arg}`)
|
|
@@ -109,6 +116,11 @@ export default async function baselines({ args }: CliContext): Promise<void> {
|
|
|
109
116
|
console.error(' \u2717 Source file contains potential secrets \u2014 baseline not updated')
|
|
110
117
|
process.exit(1)
|
|
111
118
|
}
|
|
119
|
+
if (opts.dryRun) {
|
|
120
|
+
const dest = join(opts.dir, `${opts.slug}.png`)
|
|
121
|
+
console.log(` [dry-run] Would update baseline: ${dest}`)
|
|
122
|
+
break
|
|
123
|
+
}
|
|
112
124
|
mkdirSync(opts.dir, { recursive: true })
|
|
113
125
|
const dest = join(opts.dir, `${opts.slug}.png`)
|
|
114
126
|
writeFileSync(dest, data)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { mkdtempSync, rmSync, existsSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { tmpdir } from 'node:os'
|
|
5
|
+
import {
|
|
6
|
+
getArtifactDir,
|
|
7
|
+
writeArtifact,
|
|
8
|
+
listArtifacts,
|
|
9
|
+
readArtifact,
|
|
10
|
+
extractArtifactRefs,
|
|
11
|
+
pruneArtifacts,
|
|
12
|
+
} from './artifacts.js'
|
|
13
|
+
|
|
14
|
+
describe('artifacts', () => {
|
|
15
|
+
let tmpDir: string
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'artifacts-test-'))
|
|
19
|
+
vi.spyOn(process, 'cwd').mockReturnValue(tmpDir)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
vi.restoreAllMocks()
|
|
24
|
+
rmSync(tmpDir, { recursive: true, force: true })
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('writeArtifact', () => {
|
|
28
|
+
it('creates file in correct directory structure', () => {
|
|
29
|
+
const artifact = writeArtifact('convoy-1', 'task-1', 'report.md', '# Report\nContent here', 'report')
|
|
30
|
+
expect(artifact.path).toContain('convoy-1')
|
|
31
|
+
expect(artifact.path).toContain('task-1')
|
|
32
|
+
expect(artifact.path).toContain('report.md')
|
|
33
|
+
expect(existsSync(artifact.path)).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('creates .meta.json sidecar', () => {
|
|
37
|
+
const artifact = writeArtifact('convoy-1', 'task-1', 'report.md', '# Report\nContent here', 'report')
|
|
38
|
+
const metaPath = artifact.path + '.meta.json'
|
|
39
|
+
expect(existsSync(metaPath)).toBe(true)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('returns Artifact with correct metadata', () => {
|
|
43
|
+
const content = '# Report\nLine 2'
|
|
44
|
+
const artifact = writeArtifact('convoy-1', 'task-1', 'report.md', content, 'report')
|
|
45
|
+
expect(artifact.task_id).toBe('task-1')
|
|
46
|
+
expect(artifact.convoy_id).toBe('convoy-1')
|
|
47
|
+
expect(artifact.filename).toBe('report.md')
|
|
48
|
+
expect(artifact.type).toBe('report')
|
|
49
|
+
expect(artifact.size_bytes).toBe(Buffer.byteLength(content, 'utf8'))
|
|
50
|
+
expect(artifact.summary).toBe('# Report')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('summary is truncated to 120 chars when first line is long', () => {
|
|
54
|
+
const longFirstLine = 'A'.repeat(200)
|
|
55
|
+
const content = longFirstLine + '\nSecond line'
|
|
56
|
+
const artifact = writeArtifact('convoy-1', 'task-1', 'long.md', content, 'report')
|
|
57
|
+
expect(artifact.summary.length).toBe(120)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('listArtifacts', () => {
|
|
62
|
+
it('returns refs for all files in task dir excluding .meta.json', () => {
|
|
63
|
+
writeArtifact('convoy-1', 'task-1', 'report.md', '# Report', 'report')
|
|
64
|
+
writeArtifact('convoy-1', 'task-1', 'migration.sql', 'ALTER TABLE users', 'code')
|
|
65
|
+
const refs = listArtifacts('convoy-1', 'task-1')
|
|
66
|
+
expect(refs).toHaveLength(2)
|
|
67
|
+
const filenames = refs.map(r => r.filename)
|
|
68
|
+
expect(filenames).toContain('report.md')
|
|
69
|
+
expect(filenames).toContain('migration.sql')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('returns empty array when dir does not exist', () => {
|
|
73
|
+
const refs = listArtifacts('nonexistent-convoy', 'nonexistent-task')
|
|
74
|
+
expect(refs).toHaveLength(0)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('populates summary from .meta.json sidecar', () => {
|
|
78
|
+
writeArtifact('convoy-1', 'task-1', 'diff.patch', 'diff --git a/file.ts\nchanges here', 'diff')
|
|
79
|
+
const refs = listArtifacts('convoy-1', 'task-1')
|
|
80
|
+
expect(refs[0].summary).toBe('diff --git a/file.ts')
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('readArtifact', () => {
|
|
85
|
+
it('returns file content', () => {
|
|
86
|
+
const content = '# Report\nDetailed content here'
|
|
87
|
+
const artifact = writeArtifact('convoy-1', 'task-1', 'report.md', content, 'report')
|
|
88
|
+
const ref = { task_id: 'task-1', filename: 'report.md', summary: '# Report', path: artifact.path }
|
|
89
|
+
expect(readArtifact(ref)).toBe(content)
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
describe('extractArtifactRefs', () => {
|
|
94
|
+
it('parses [ARTIFACT: filename] summary pattern correctly', () => {
|
|
95
|
+
writeArtifact('convoy-1', 'task-1', 'report.md', '# Report', 'report')
|
|
96
|
+
const output = 'I completed the work.\n[ARTIFACT: report.md] Full analysis report\nSee the artifact for details.'
|
|
97
|
+
const refs = extractArtifactRefs('task-1', 'convoy-1', output)
|
|
98
|
+
expect(refs).toHaveLength(1)
|
|
99
|
+
expect(refs[0].filename).toBe('report.md')
|
|
100
|
+
expect(refs[0].summary).toBe('Full analysis report')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('parses multiple artifacts in one output', () => {
|
|
104
|
+
writeArtifact('convoy-1', 'task-1', 'report.md', '# Report', 'report')
|
|
105
|
+
writeArtifact('convoy-1', 'task-1', 'migration.sql', 'ALTER TABLE', 'code')
|
|
106
|
+
const output = '[ARTIFACT: report.md] Analysis report\n[ARTIFACT: migration.sql] Database migration script'
|
|
107
|
+
const refs = extractArtifactRefs('task-1', 'convoy-1', output)
|
|
108
|
+
expect(refs).toHaveLength(2)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('logs warning to stderr for referenced but missing artifacts', () => {
|
|
112
|
+
const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true)
|
|
113
|
+
const output = '[ARTIFACT: missing.md] A report that does not exist on disk'
|
|
114
|
+
const refs = extractArtifactRefs('task-1', 'convoy-1', output)
|
|
115
|
+
expect(refs).toHaveLength(0)
|
|
116
|
+
expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('[artifacts] Warning'))
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('returns empty array when no artifact patterns found', () => {
|
|
120
|
+
const refs = extractArtifactRefs('task-1', 'convoy-1', 'No artifacts here, just a normal response.')
|
|
121
|
+
expect(refs).toHaveLength(0)
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
describe('pruneArtifacts', () => {
|
|
126
|
+
it('removes convoy dirs beyond keepCount', () => {
|
|
127
|
+
writeArtifact('convoy-a', 'task-1', 'file.md', 'content', 'report')
|
|
128
|
+
writeArtifact('convoy-b', 'task-1', 'file.md', 'content', 'report')
|
|
129
|
+
writeArtifact('convoy-c', 'task-1', 'file.md', 'content', 'report')
|
|
130
|
+
const result = pruneArtifacts(1)
|
|
131
|
+
expect(result.removed).toBe(2)
|
|
132
|
+
expect(result.freed_bytes).toBeGreaterThan(0)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('returns zero removed when within keepCount', () => {
|
|
136
|
+
writeArtifact('convoy-1', 'task-1', 'file.md', 'content', 'report')
|
|
137
|
+
writeArtifact('convoy-2', 'task-1', 'file.md', 'content', 'report')
|
|
138
|
+
const result = pruneArtifacts(5)
|
|
139
|
+
expect(result.removed).toBe(0)
|
|
140
|
+
expect(result.freed_bytes).toBe(0)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('returns zero when no artifacts directory exists', () => {
|
|
144
|
+
const result = pruneArtifacts(10)
|
|
145
|
+
expect(result.removed).toBe(0)
|
|
146
|
+
expect(result.freed_bytes).toBe(0)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('returns correct freed bytes count', () => {
|
|
150
|
+
const content = 'A'.repeat(1000)
|
|
151
|
+
writeArtifact('convoy-old1', 'task-1', 'large.md', content, 'report')
|
|
152
|
+
writeArtifact('convoy-old2', 'task-1', 'large.md', content, 'report')
|
|
153
|
+
writeArtifact('convoy-new', 'task-1', 'large.md', content, 'report')
|
|
154
|
+
const result = pruneArtifacts(1)
|
|
155
|
+
expect(result.removed).toBe(2)
|
|
156
|
+
expect(result.freed_bytes).toBeGreaterThan(0)
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
describe('round-trip', () => {
|
|
161
|
+
it('write → list → read produces identical content', () => {
|
|
162
|
+
const content = '# Report\nLine 2\nLine 3'
|
|
163
|
+
writeArtifact('convoy-1', 'task-1', 'report.md', content, 'report')
|
|
164
|
+
const refs = listArtifacts('convoy-1', 'task-1')
|
|
165
|
+
expect(refs).toHaveLength(1)
|
|
166
|
+
const retrieved = readArtifact(refs[0])
|
|
167
|
+
expect(retrieved).toBe(content)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
describe('path sanitization', () => {
|
|
172
|
+
it('rejects filenames with ..', () => {
|
|
173
|
+
expect(() => writeArtifact('convoy-1', 'task-1', '../evil.ts', 'content', 'code')).toThrow()
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('rejects filenames with /', () => {
|
|
177
|
+
expect(() => writeArtifact('convoy-1', 'task-1', 'sub/evil.ts', 'content', 'code')).toThrow()
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('rejects convoy IDs with path traversal', () => {
|
|
181
|
+
expect(() => writeArtifact('../evil', 'task-1', 'file.md', 'content', 'report')).toThrow()
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('rejects task IDs with backslash', () => {
|
|
185
|
+
expect(() => writeArtifact('convoy-1', 'task\\evil', 'file.md', 'content', 'report')).toThrow()
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
describe('getArtifactDir', () => {
|
|
190
|
+
it('returns path ending with trailing slash', () => {
|
|
191
|
+
const dir = getArtifactDir('convoy-1', 'task-1')
|
|
192
|
+
expect(dir.endsWith('/')).toBe(true)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('includes convoy-id and task-id in path', () => {
|
|
196
|
+
const dir = getArtifactDir('convoy-abc', 'task-xyz')
|
|
197
|
+
expect(dir).toContain('convoy-abc')
|
|
198
|
+
expect(dir).toContain('task-xyz')
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
})
|