clavix 4.7.0 ā 4.8.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/dist/cli/commands/execute.js +29 -9
- package/dist/cli/commands/verify.d.ts +28 -0
- package/dist/cli/commands/verify.js +347 -0
- package/dist/core/adapters/amp-adapter.d.ts +3 -0
- package/dist/core/adapters/amp-adapter.js +1 -0
- package/dist/core/adapters/cline-adapter.d.ts +3 -0
- package/dist/core/adapters/cline-adapter.js +1 -0
- package/dist/core/adapters/codebuddy-adapter.d.ts +3 -0
- package/dist/core/adapters/codebuddy-adapter.js +1 -0
- package/dist/core/adapters/codex-adapter.d.ts +3 -0
- package/dist/core/adapters/codex-adapter.js +1 -0
- package/dist/core/adapters/cursor-adapter.d.ts +3 -0
- package/dist/core/adapters/cursor-adapter.js +1 -0
- package/dist/core/adapters/droid-adapter.d.ts +3 -0
- package/dist/core/adapters/droid-adapter.js +1 -0
- package/dist/core/adapters/instructions-generator.js +9 -2
- package/dist/core/adapters/kilocode-adapter.d.ts +3 -0
- package/dist/core/adapters/kilocode-adapter.js +1 -0
- package/dist/core/adapters/opencode-adapter.d.ts +3 -0
- package/dist/core/adapters/opencode-adapter.js +1 -0
- package/dist/core/adapters/roocode-adapter.d.ts +3 -0
- package/dist/core/adapters/roocode-adapter.js +1 -0
- package/dist/core/adapters/windsurf-adapter.d.ts +3 -0
- package/dist/core/adapters/windsurf-adapter.js +1 -0
- package/dist/core/basic-checklist-generator.d.ts +35 -0
- package/dist/core/basic-checklist-generator.js +344 -0
- package/dist/core/checklist-parser.d.ts +48 -0
- package/dist/core/checklist-parser.js +238 -0
- package/dist/core/command-transformer.d.ts +55 -0
- package/dist/core/command-transformer.js +65 -0
- package/dist/core/prompt-manager.d.ts +7 -0
- package/dist/core/prompt-manager.js +47 -22
- package/dist/core/verification-hooks.d.ts +67 -0
- package/dist/core/verification-hooks.js +309 -0
- package/dist/core/verification-manager.d.ts +106 -0
- package/dist/core/verification-manager.js +422 -0
- package/dist/templates/slash-commands/_canonical/execute.md +72 -1
- package/dist/templates/slash-commands/_canonical/verify.md +292 -0
- package/dist/templates/slash-commands/_components/agent-protocols/verification-methods.md +184 -0
- package/dist/types/agent.d.ts +4 -0
- package/dist/types/verification.d.ts +204 -0
- package/dist/types/verification.js +8 -0
- package/dist/utils/template-loader.d.ts +1 -1
- package/dist/utils/template-loader.js +5 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { Command, Flags } from '@oclif/core';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
4
|
import { PromptManager } from '../../core/prompt-manager.js';
|
|
5
|
+
import { ChecklistParser } from '../../core/checklist-parser.js';
|
|
5
6
|
export default class Execute extends Command {
|
|
6
7
|
static description = 'Execute a saved prompt from fast/deep optimization';
|
|
7
8
|
static examples = [
|
|
@@ -45,7 +46,7 @@ export default class Execute extends Command {
|
|
|
45
46
|
let selectedPrompt = null;
|
|
46
47
|
// Execute specific prompt by ID
|
|
47
48
|
if (flags.id) {
|
|
48
|
-
selectedPrompt = allPrompts.find(p => p.id === flags.id) || null;
|
|
49
|
+
selectedPrompt = allPrompts.find((p) => p.id === flags.id) || null;
|
|
49
50
|
if (!selectedPrompt) {
|
|
50
51
|
console.log(chalk.red(`\nā Prompt not found: ${flags.id}\n`));
|
|
51
52
|
console.log(chalk.cyan('Run clavix prompts list to see available prompts'));
|
|
@@ -58,10 +59,10 @@ export default class Execute extends Command {
|
|
|
58
59
|
let filtered = allPrompts;
|
|
59
60
|
// Apply source filter
|
|
60
61
|
if (flags.fast && !flags.deep) {
|
|
61
|
-
filtered = allPrompts.filter(p => p.source === 'fast');
|
|
62
|
+
filtered = allPrompts.filter((p) => p.source === 'fast');
|
|
62
63
|
}
|
|
63
64
|
else if (flags.deep && !flags.fast) {
|
|
64
|
-
filtered = allPrompts.filter(p => p.source === 'deep');
|
|
65
|
+
filtered = allPrompts.filter((p) => p.source === 'deep');
|
|
65
66
|
}
|
|
66
67
|
if (filtered.length === 0) {
|
|
67
68
|
const source = flags.fast ? 'fast' : flags.deep ? 'deep' : 'any';
|
|
@@ -89,7 +90,7 @@ export default class Execute extends Command {
|
|
|
89
90
|
}
|
|
90
91
|
async selectPromptInteractively(prompts) {
|
|
91
92
|
console.log(chalk.bold.cyan('\nš Available Prompts\n'));
|
|
92
|
-
const choices = prompts.map(p => {
|
|
93
|
+
const choices = prompts.map((p) => {
|
|
93
94
|
const status = p.executed ? chalk.green('ā') : chalk.gray('ā');
|
|
94
95
|
const age = p.ageInDays === 0 ? 'today' : `${p.ageInDays}d ago`;
|
|
95
96
|
const ageColor = (p.ageInDays || 0) > 30 ? chalk.red : (p.ageInDays || 0) > 7 ? chalk.yellow : chalk.gray;
|
|
@@ -108,7 +109,7 @@ export default class Execute extends Command {
|
|
|
108
109
|
pageSize: 15,
|
|
109
110
|
},
|
|
110
111
|
]);
|
|
111
|
-
return prompts.find(p => p.id === promptId) || null;
|
|
112
|
+
return prompts.find((p) => p.id === promptId) || null;
|
|
112
113
|
}
|
|
113
114
|
async executePrompt(prompt, manager) {
|
|
114
115
|
const promptData = await manager.loadPrompt(prompt.id);
|
|
@@ -126,20 +127,39 @@ export default class Execute extends Command {
|
|
|
126
127
|
console.log(promptData.content);
|
|
127
128
|
console.log(chalk.dim('ā'.repeat(80)));
|
|
128
129
|
console.log();
|
|
130
|
+
// Parse and display checklist summary
|
|
131
|
+
const checklistParser = new ChecklistParser();
|
|
132
|
+
const checklist = checklistParser.parse(promptData.content);
|
|
133
|
+
if (checklist.hasChecklist) {
|
|
134
|
+
const summary = checklistParser.getSummary(checklist);
|
|
135
|
+
console.log(chalk.bold.cyan('š Checklist Summary:'));
|
|
136
|
+
console.log(chalk.gray(` Validation items: ${summary.validation}`));
|
|
137
|
+
console.log(chalk.gray(` Edge cases: ${summary.edgeCases}`));
|
|
138
|
+
console.log(chalk.gray(` Risks: ${summary.risks}`));
|
|
139
|
+
console.log(chalk.gray(` Total: ${checklist.totalItems} items to verify`));
|
|
140
|
+
console.log();
|
|
141
|
+
}
|
|
129
142
|
// Mark as executed
|
|
130
143
|
if (!prompt.executed) {
|
|
131
144
|
await manager.markExecuted(prompt.id);
|
|
132
145
|
console.log(chalk.green('ā Prompt marked as executed\n'));
|
|
133
146
|
}
|
|
147
|
+
// Display REQUIRED verification notice
|
|
148
|
+
console.log(chalk.bgYellow.black(' ā ļø VERIFICATION REQUIRED '));
|
|
149
|
+
console.log(chalk.yellow('After implementing, run verification:'));
|
|
150
|
+
console.log(chalk.cyan(` clavix verify --id ${prompt.id}`));
|
|
151
|
+
console.log(chalk.cyan(' Or: /clavix:verify'));
|
|
152
|
+
console.log();
|
|
134
153
|
// Suggest cleanup
|
|
135
154
|
const stats = await manager.getStorageStats();
|
|
136
155
|
if (stats.executedPrompts >= 5) {
|
|
137
|
-
console.log(chalk.
|
|
138
|
-
console.log(chalk.
|
|
139
|
-
console.log(chalk.yellow(` Run /clavix:prompts clear to clean up.`));
|
|
156
|
+
console.log(chalk.gray(`š” You have ${stats.executedPrompts} executed prompts.`));
|
|
157
|
+
console.log(chalk.gray(` Clean up after verification: clavix prompts clear --executed`));
|
|
140
158
|
console.log();
|
|
141
159
|
}
|
|
142
|
-
console.log(chalk.cyan('š” Next:
|
|
160
|
+
console.log(chalk.cyan('š” Next steps:'));
|
|
161
|
+
console.log(chalk.cyan(' 1. Implement the requirements described above'));
|
|
162
|
+
console.log(chalk.cyan(' 2. Run: clavix verify --latest'));
|
|
143
163
|
console.log();
|
|
144
164
|
}
|
|
145
165
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Verify extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
latest: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
fast: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
deep: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
id: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
status: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
'retry-failed': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
export: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
'run-hooks': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
private promptManager;
|
|
16
|
+
private verificationManager;
|
|
17
|
+
private checklistParser;
|
|
18
|
+
private basicChecklistGenerator;
|
|
19
|
+
private intentDetector;
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
private selectPromptInteractively;
|
|
22
|
+
private showStatus;
|
|
23
|
+
private exportReport;
|
|
24
|
+
private runVerification;
|
|
25
|
+
private verifyItemInteractively;
|
|
26
|
+
private formatStatus;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { PromptManager } from '../../core/prompt-manager.js';
|
|
5
|
+
import { VerificationManager } from '../../core/verification-manager.js';
|
|
6
|
+
import { ChecklistParser } from '../../core/checklist-parser.js';
|
|
7
|
+
import { BasicChecklistGenerator } from '../../core/basic-checklist-generator.js';
|
|
8
|
+
import { IntentDetector } from '../../core/intelligence/intent-detector.js';
|
|
9
|
+
export default class Verify extends Command {
|
|
10
|
+
static description = 'Verify implementation against checklist from deep/fast mode';
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --latest',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> --latest --deep',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> --id deep-20250117-143022-a3f2',
|
|
15
|
+
'<%= config.bin %> <%= command.id %> --status',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> --retry-failed',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
latest: Flags.boolean({
|
|
20
|
+
description: 'Verify latest executed prompt',
|
|
21
|
+
default: false,
|
|
22
|
+
}),
|
|
23
|
+
fast: Flags.boolean({
|
|
24
|
+
description: 'Filter to fast prompts only (use with --latest)',
|
|
25
|
+
default: false,
|
|
26
|
+
}),
|
|
27
|
+
deep: Flags.boolean({
|
|
28
|
+
description: 'Filter to deep prompts only (use with --latest)',
|
|
29
|
+
default: false,
|
|
30
|
+
}),
|
|
31
|
+
id: Flags.string({
|
|
32
|
+
description: 'Verify specific prompt by ID',
|
|
33
|
+
}),
|
|
34
|
+
status: Flags.boolean({
|
|
35
|
+
description: 'Show verification status only',
|
|
36
|
+
default: false,
|
|
37
|
+
}),
|
|
38
|
+
'retry-failed': Flags.boolean({
|
|
39
|
+
description: 'Re-run only failed items',
|
|
40
|
+
default: false,
|
|
41
|
+
}),
|
|
42
|
+
export: Flags.string({
|
|
43
|
+
description: 'Export report format',
|
|
44
|
+
options: ['markdown', 'json'],
|
|
45
|
+
}),
|
|
46
|
+
'run-hooks': Flags.boolean({
|
|
47
|
+
description: 'Run automated hooks during verification',
|
|
48
|
+
default: true,
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
promptManager;
|
|
52
|
+
verificationManager;
|
|
53
|
+
checklistParser;
|
|
54
|
+
basicChecklistGenerator;
|
|
55
|
+
intentDetector;
|
|
56
|
+
async run() {
|
|
57
|
+
const { flags } = await this.parse(Verify);
|
|
58
|
+
this.promptManager = new PromptManager();
|
|
59
|
+
this.verificationManager = new VerificationManager();
|
|
60
|
+
this.checklistParser = new ChecklistParser();
|
|
61
|
+
this.basicChecklistGenerator = new BasicChecklistGenerator();
|
|
62
|
+
this.intentDetector = new IntentDetector();
|
|
63
|
+
try {
|
|
64
|
+
// Get all prompts
|
|
65
|
+
const allPrompts = await this.promptManager.listPrompts();
|
|
66
|
+
if (allPrompts.length === 0) {
|
|
67
|
+
console.log(chalk.yellow('\nā ļø No prompts found\n'));
|
|
68
|
+
console.log(chalk.cyan('Generate an optimized prompt first:'));
|
|
69
|
+
console.log(chalk.cyan(' /clavix:fast "your requirement"'));
|
|
70
|
+
console.log(chalk.cyan(' /clavix:deep "your requirement"'));
|
|
71
|
+
console.log();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
let selectedPrompt = null;
|
|
75
|
+
// Select prompt by ID
|
|
76
|
+
if (flags.id) {
|
|
77
|
+
selectedPrompt = allPrompts.find((p) => p.id === flags.id) || null;
|
|
78
|
+
if (!selectedPrompt) {
|
|
79
|
+
console.log(chalk.red(`\nā Prompt not found: ${flags.id}\n`));
|
|
80
|
+
console.log(chalk.cyan('Run clavix prompts list to see available prompts'));
|
|
81
|
+
console.log();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Auto-select latest with optional filtering
|
|
86
|
+
else if (flags.latest) {
|
|
87
|
+
let filtered = allPrompts;
|
|
88
|
+
// Filter by source
|
|
89
|
+
if (flags.fast && !flags.deep) {
|
|
90
|
+
filtered = allPrompts.filter((p) => p.source === 'fast');
|
|
91
|
+
}
|
|
92
|
+
else if (flags.deep && !flags.fast) {
|
|
93
|
+
filtered = allPrompts.filter((p) => p.source === 'deep');
|
|
94
|
+
}
|
|
95
|
+
// Filter to executed prompts preferably
|
|
96
|
+
const executedFiltered = filtered.filter((p) => p.executed);
|
|
97
|
+
if (executedFiltered.length > 0) {
|
|
98
|
+
filtered = executedFiltered;
|
|
99
|
+
}
|
|
100
|
+
if (filtered.length === 0) {
|
|
101
|
+
const source = flags.fast ? 'fast' : flags.deep ? 'deep' : 'any';
|
|
102
|
+
console.log(chalk.yellow(`\nā ļø No ${source} prompts found\n`));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
selectedPrompt = filtered[0];
|
|
106
|
+
}
|
|
107
|
+
// Interactive selection
|
|
108
|
+
else {
|
|
109
|
+
selectedPrompt = await this.selectPromptInteractively(allPrompts);
|
|
110
|
+
if (!selectedPrompt)
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Handle status-only flag
|
|
114
|
+
if (flags.status) {
|
|
115
|
+
await this.showStatus(selectedPrompt);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Handle export flag
|
|
119
|
+
if (flags.export) {
|
|
120
|
+
await this.exportReport(selectedPrompt, flags.export);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Run verification
|
|
124
|
+
await this.runVerification(selectedPrompt, {
|
|
125
|
+
retryFailed: flags['retry-failed'],
|
|
126
|
+
runHooks: flags['run-hooks'],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.log(chalk.red(`\nā Error: ${error}\n`));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async selectPromptInteractively(prompts) {
|
|
134
|
+
console.log(chalk.bold.cyan('\nš Select Prompt to Verify\n'));
|
|
135
|
+
const choices = prompts.map((p) => {
|
|
136
|
+
const executed = p.executed ? chalk.green('ā') : chalk.gray('ā');
|
|
137
|
+
const age = p.ageInDays === 0 ? 'today' : `${p.ageInDays}d ago`;
|
|
138
|
+
const ageColor = (p.ageInDays || 0) > 30 ? chalk.red : (p.ageInDays || 0) > 7 ? chalk.yellow : chalk.gray;
|
|
139
|
+
return {
|
|
140
|
+
name: `${executed} [${p.source}] ${p.originalPrompt.substring(0, 50)}... ${ageColor(`(${age})`)}`,
|
|
141
|
+
value: p.id,
|
|
142
|
+
short: p.id,
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
const { promptId } = await inquirer.prompt([
|
|
146
|
+
{
|
|
147
|
+
type: 'list',
|
|
148
|
+
name: 'promptId',
|
|
149
|
+
message: 'Select a prompt to verify:',
|
|
150
|
+
choices,
|
|
151
|
+
pageSize: 15,
|
|
152
|
+
},
|
|
153
|
+
]);
|
|
154
|
+
return prompts.find((p) => p.id === promptId) || null;
|
|
155
|
+
}
|
|
156
|
+
async showStatus(prompt) {
|
|
157
|
+
console.log(chalk.bold.cyan(`\nš Verification Status: ${prompt.id}\n`));
|
|
158
|
+
const status = await this.verificationManager.getVerificationStatus(prompt.id);
|
|
159
|
+
if (!status.hasReport) {
|
|
160
|
+
console.log(chalk.yellow('No verification report found.'));
|
|
161
|
+
console.log(chalk.cyan('\nRun: clavix verify --latest'));
|
|
162
|
+
console.log();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
console.log(chalk.gray(`Status: ${this.formatStatus(status.status)}`));
|
|
166
|
+
console.log();
|
|
167
|
+
if (status.summary) {
|
|
168
|
+
console.log(chalk.bold('Summary:'));
|
|
169
|
+
console.log(` Total: ${status.summary.total} items`);
|
|
170
|
+
console.log(` Passed: ${chalk.green(status.summary.passed)} (${status.summary.coveragePercent}%)`);
|
|
171
|
+
console.log(` Failed: ${chalk.red(status.summary.failed)}`);
|
|
172
|
+
console.log(` Skipped: ${chalk.gray(status.summary.skipped)}`);
|
|
173
|
+
console.log();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async exportReport(prompt, format) {
|
|
177
|
+
const report = await this.verificationManager.loadReport(prompt.id);
|
|
178
|
+
if (!report) {
|
|
179
|
+
console.log(chalk.yellow('No verification report found.'));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (format === 'json') {
|
|
183
|
+
console.log(JSON.stringify(report, null, 2));
|
|
184
|
+
}
|
|
185
|
+
else if (format === 'markdown') {
|
|
186
|
+
console.log(this.verificationManager.formatReportForDisplay(report));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async runVerification(prompt, options) {
|
|
190
|
+
console.log(chalk.bold.cyan(`\nš Verifying: ${prompt.id}\n`));
|
|
191
|
+
console.log(chalk.gray(`Source: ${prompt.source}`));
|
|
192
|
+
console.log(chalk.gray(`Created: ${new Date(prompt.timestamp).toLocaleDateString()}`));
|
|
193
|
+
console.log();
|
|
194
|
+
// Load prompt content
|
|
195
|
+
const promptData = await this.promptManager.loadPrompt(prompt.id);
|
|
196
|
+
if (!promptData) {
|
|
197
|
+
console.log(chalk.red('Could not load prompt content.'));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
// Parse checklist from prompt
|
|
201
|
+
let checklist = this.checklistParser.parse(promptData.content);
|
|
202
|
+
// Handle fast mode - generate basic checklist if none exists
|
|
203
|
+
if (!checklist.hasChecklist && prompt.source === 'fast') {
|
|
204
|
+
console.log(chalk.yellow('ā ļø No checklist found (fast mode prompt)'));
|
|
205
|
+
console.log(chalk.cyan('Generating basic checklist based on intent...\n'));
|
|
206
|
+
// Detect intent from original prompt
|
|
207
|
+
const intent = this.intentDetector.analyze(prompt.originalPrompt);
|
|
208
|
+
checklist = this.basicChecklistGenerator.generateFromPrompt(prompt.originalPrompt, intent.primaryIntent);
|
|
209
|
+
console.log(chalk.gray(`Intent: ${intent.primaryIntent} (${intent.confidence}% confidence)`));
|
|
210
|
+
console.log(chalk.gray(`Generated ${checklist.totalItems} checklist items\n`));
|
|
211
|
+
console.log(chalk.yellow('š” For comprehensive checklists, use /clavix:deep\n'));
|
|
212
|
+
}
|
|
213
|
+
if (!checklist.hasChecklist) {
|
|
214
|
+
console.log(chalk.yellow('No checklist items to verify.'));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// Initialize or load existing report
|
|
218
|
+
let report = await this.verificationManager.loadReport(prompt.id);
|
|
219
|
+
if (!report) {
|
|
220
|
+
report = await this.verificationManager.initializeVerification(prompt.id);
|
|
221
|
+
// Update with parsed checklist if from fast mode
|
|
222
|
+
if (prompt.source === 'fast') {
|
|
223
|
+
report.items = [...checklist.validationItems, ...checklist.edgeCases, ...checklist.risks];
|
|
224
|
+
report.results = report.items.map((item) => ({
|
|
225
|
+
itemId: item.id,
|
|
226
|
+
status: 'pending',
|
|
227
|
+
method: item.verificationType === 'automated' ? 'automated' : 'manual',
|
|
228
|
+
confidence: 'low',
|
|
229
|
+
verifiedAt: '',
|
|
230
|
+
}));
|
|
231
|
+
await this.verificationManager.saveReport(report);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Run automated hooks if requested
|
|
235
|
+
if (options.runHooks) {
|
|
236
|
+
console.log(chalk.cyan('Running automated verification hooks...\n'));
|
|
237
|
+
report = await this.verificationManager.runAutomatedVerification(prompt.id);
|
|
238
|
+
// Display hook results
|
|
239
|
+
const automatedResults = report.results.filter((r) => r.method === 'automated' && r.status !== 'pending');
|
|
240
|
+
for (const result of automatedResults) {
|
|
241
|
+
const item = report.items.find((i) => i.id === result.itemId);
|
|
242
|
+
if (item) {
|
|
243
|
+
const icon = result.status === 'passed' ? chalk.green('ā') : chalk.red('ā');
|
|
244
|
+
console.log(`${icon} [automated] ${item.content}`);
|
|
245
|
+
if (result.evidence) {
|
|
246
|
+
console.log(chalk.gray(` Evidence: ${result.evidence.substring(0, 60)}...`));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (automatedResults.length > 0) {
|
|
251
|
+
console.log();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Get pending items for manual verification
|
|
255
|
+
const pendingItems = this.verificationManager.getPendingItems(report);
|
|
256
|
+
if (pendingItems.length > 0) {
|
|
257
|
+
console.log(chalk.cyan(`Manual verification needed for ${pendingItems.length} items:\n`));
|
|
258
|
+
for (const item of pendingItems) {
|
|
259
|
+
report = await this.verifyItemInteractively(report, item);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Show final report
|
|
263
|
+
console.log();
|
|
264
|
+
console.log(this.verificationManager.formatReportForDisplay(report));
|
|
265
|
+
// Mark prompt as verified if complete
|
|
266
|
+
if (this.verificationManager.isComplete(report)) {
|
|
267
|
+
console.log(chalk.green('\nā Verification complete!\n'));
|
|
268
|
+
}
|
|
269
|
+
else if (this.verificationManager.requiresAttention(report)) {
|
|
270
|
+
console.log(chalk.yellow('\nā ļø Some items require attention.\n'));
|
|
271
|
+
console.log(chalk.cyan('Fix issues and re-run: clavix verify --retry-failed --id ' + prompt.id));
|
|
272
|
+
console.log();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async verifyItemInteractively(report, item) {
|
|
276
|
+
console.log(chalk.bold(`\nš ${item.content}`));
|
|
277
|
+
if (item.group) {
|
|
278
|
+
console.log(chalk.gray(` Category: ${item.group}`));
|
|
279
|
+
}
|
|
280
|
+
console.log();
|
|
281
|
+
const { status } = await inquirer.prompt([
|
|
282
|
+
{
|
|
283
|
+
type: 'list',
|
|
284
|
+
name: 'status',
|
|
285
|
+
message: 'Verification status:',
|
|
286
|
+
choices: [
|
|
287
|
+
{ name: 'ā Passed - Item is verified', value: 'passed' },
|
|
288
|
+
{ name: 'ā Failed - Item is not covered', value: 'failed' },
|
|
289
|
+
{ name: 'āļø Skip - Will verify later', value: 'skipped' },
|
|
290
|
+
{ name: 'ā N/A - Does not apply', value: 'not-applicable' },
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
]);
|
|
294
|
+
let evidence;
|
|
295
|
+
let reason;
|
|
296
|
+
if (status === 'passed') {
|
|
297
|
+
const { evidenceInput } = await inquirer.prompt([
|
|
298
|
+
{
|
|
299
|
+
type: 'input',
|
|
300
|
+
name: 'evidenceInput',
|
|
301
|
+
message: 'Evidence (optional):',
|
|
302
|
+
},
|
|
303
|
+
]);
|
|
304
|
+
evidence = evidenceInput || undefined;
|
|
305
|
+
}
|
|
306
|
+
else if (status === 'failed') {
|
|
307
|
+
const { reasonInput } = await inquirer.prompt([
|
|
308
|
+
{
|
|
309
|
+
type: 'input',
|
|
310
|
+
name: 'reasonInput',
|
|
311
|
+
message: 'Why is it not covered?',
|
|
312
|
+
},
|
|
313
|
+
]);
|
|
314
|
+
reason = reasonInput || 'Not specified';
|
|
315
|
+
}
|
|
316
|
+
else if (status === 'skipped') {
|
|
317
|
+
const { reasonInput } = await inquirer.prompt([
|
|
318
|
+
{
|
|
319
|
+
type: 'input',
|
|
320
|
+
name: 'reasonInput',
|
|
321
|
+
message: 'Reason for skipping:',
|
|
322
|
+
},
|
|
323
|
+
]);
|
|
324
|
+
reason = reasonInput || 'Will verify later';
|
|
325
|
+
}
|
|
326
|
+
return this.verificationManager.markItemVerified(report.promptId, item.id, status, {
|
|
327
|
+
evidence,
|
|
328
|
+
reason,
|
|
329
|
+
confidence: 'medium',
|
|
330
|
+
method: 'manual',
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
formatStatus(status) {
|
|
334
|
+
switch (status) {
|
|
335
|
+
case 'completed':
|
|
336
|
+
return chalk.green('Completed');
|
|
337
|
+
case 'in-progress':
|
|
338
|
+
return chalk.yellow('In Progress');
|
|
339
|
+
case 'requires-attention':
|
|
340
|
+
return chalk.red('Requires Attention');
|
|
341
|
+
case 'pending':
|
|
342
|
+
default:
|
|
343
|
+
return chalk.gray('Pending');
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -13,6 +13,9 @@ export declare class AmpAdapter extends BaseAdapter {
|
|
|
13
13
|
supportsSubdirectories: boolean;
|
|
14
14
|
supportsFrontmatter: boolean;
|
|
15
15
|
supportsExecutableCommands: boolean;
|
|
16
|
+
commandFormat: {
|
|
17
|
+
separator: "-";
|
|
18
|
+
};
|
|
16
19
|
};
|
|
17
20
|
/**
|
|
18
21
|
* Detect if Amp is available in the project
|
|
@@ -14,6 +14,9 @@ export declare class CodeBuddyAdapter extends BaseAdapter {
|
|
|
14
14
|
supportsFrontmatter: boolean;
|
|
15
15
|
argumentPlaceholder: string;
|
|
16
16
|
frontmatterFields: string[];
|
|
17
|
+
commandFormat: {
|
|
18
|
+
separator: "-";
|
|
19
|
+
};
|
|
17
20
|
};
|
|
18
21
|
detectProject(): Promise<boolean>;
|
|
19
22
|
getCommandPath(): string;
|
|
@@ -16,6 +16,7 @@ export class CodeBuddyAdapter extends BaseAdapter {
|
|
|
16
16
|
supportsFrontmatter: true,
|
|
17
17
|
argumentPlaceholder: '$1',
|
|
18
18
|
frontmatterFields: ['description', 'argument-hint'],
|
|
19
|
+
commandFormat: { separator: '-' },
|
|
19
20
|
};
|
|
20
21
|
async detectProject() {
|
|
21
22
|
if (await FileSystem.exists('.codebuddy')) {
|
|
@@ -14,6 +14,9 @@ export declare class CodexAdapter extends BaseAdapter {
|
|
|
14
14
|
supportsFrontmatter: boolean;
|
|
15
15
|
argumentPlaceholder: string;
|
|
16
16
|
frontmatterFields: string[];
|
|
17
|
+
commandFormat: {
|
|
18
|
+
separator: "-";
|
|
19
|
+
};
|
|
17
20
|
};
|
|
18
21
|
detectProject(): Promise<boolean>;
|
|
19
22
|
getCommandPath(): string;
|
|
@@ -16,6 +16,7 @@ export class CodexAdapter extends BaseAdapter {
|
|
|
16
16
|
supportsFrontmatter: true,
|
|
17
17
|
argumentPlaceholder: '$ARGUMENTS',
|
|
18
18
|
frontmatterFields: ['description', 'argument-hint'],
|
|
19
|
+
commandFormat: { separator: '-' },
|
|
19
20
|
};
|
|
20
21
|
async detectProject() {
|
|
21
22
|
const codexDir = path.join(this.getHomeDir(), '.codex');
|
|
@@ -15,6 +15,9 @@ export declare class DroidAdapter extends BaseAdapter {
|
|
|
15
15
|
supportsFrontmatter: boolean;
|
|
16
16
|
frontmatterFields: string[];
|
|
17
17
|
argumentPlaceholder: string;
|
|
18
|
+
commandFormat: {
|
|
19
|
+
separator: "-";
|
|
20
|
+
};
|
|
18
21
|
};
|
|
19
22
|
/**
|
|
20
23
|
* Detect if Droid CLI is available in the project
|
|
@@ -15,6 +15,7 @@ export class DroidAdapter extends BaseAdapter {
|
|
|
15
15
|
supportsFrontmatter: true,
|
|
16
16
|
frontmatterFields: ['description', 'argument-hint'],
|
|
17
17
|
argumentPlaceholder: '$ARGUMENTS',
|
|
18
|
+
commandFormat: { separator: '-' },
|
|
18
19
|
};
|
|
19
20
|
/**
|
|
20
21
|
* Detect if Droid CLI is available in the project
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FileSystem } from '../../utils/file-system.js';
|
|
2
2
|
import { TemplateAssembler } from '../template-assembler.js';
|
|
3
|
+
import { CommandTransformer } from '../command-transformer.js';
|
|
3
4
|
import * as path from 'path';
|
|
4
5
|
import { fileURLToPath } from 'url';
|
|
5
6
|
import { dirname } from 'path';
|
|
@@ -79,17 +80,23 @@ export class InstructionsGenerator {
|
|
|
79
80
|
// Copy all .md files from canonical, resolving includes
|
|
80
81
|
const entries = await FileSystem.readdir(canonicalPath, { withFileTypes: true });
|
|
81
82
|
const mdFiles = entries.filter((f) => f.isFile() && f.name.endsWith('.md'));
|
|
83
|
+
// v4.8.1: Generic integrations use hyphen format for slash commands
|
|
84
|
+
const genericFeatures = { commandFormat: { separator: '-' } };
|
|
82
85
|
for (const file of mdFiles) {
|
|
83
86
|
const destPath = path.join(workflowsTarget, file.name);
|
|
84
87
|
try {
|
|
85
88
|
// v4.5: Use TemplateAssembler to resolve {{INCLUDE:}} markers
|
|
86
89
|
const result = await assembler.assembleTemplate(file.name);
|
|
87
|
-
|
|
90
|
+
// v4.8.1: Transform command references to hyphen format for generic integrations
|
|
91
|
+
const transformedContent = CommandTransformer.transform(result.content, genericFeatures);
|
|
92
|
+
await FileSystem.writeFileAtomic(destPath, transformedContent);
|
|
88
93
|
}
|
|
89
94
|
catch {
|
|
90
95
|
// Fallback: copy without include resolution if assembly fails
|
|
91
96
|
const srcPath = path.join(canonicalPath, file.name);
|
|
92
|
-
|
|
97
|
+
let content = await FileSystem.readFile(srcPath);
|
|
98
|
+
// v4.8.1: Still transform command references in fallback path
|
|
99
|
+
content = CommandTransformer.transform(content, genericFeatures);
|
|
93
100
|
await FileSystem.writeFileAtomic(destPath, content);
|
|
94
101
|
}
|
|
95
102
|
}
|
|
@@ -19,6 +19,9 @@ export declare class KilocodeAdapter extends BaseAdapter {
|
|
|
19
19
|
readonly features: {
|
|
20
20
|
supportsSubdirectories: boolean;
|
|
21
21
|
supportsFrontmatter: boolean;
|
|
22
|
+
commandFormat: {
|
|
23
|
+
separator: "-";
|
|
24
|
+
};
|
|
22
25
|
};
|
|
23
26
|
/**
|
|
24
27
|
* Detect if Kilocode is available in the project
|
|
@@ -15,6 +15,9 @@ export declare class OpenCodeAdapter extends BaseAdapter {
|
|
|
15
15
|
supportsFrontmatter: boolean;
|
|
16
16
|
frontmatterFields: string[];
|
|
17
17
|
argumentPlaceholder: string;
|
|
18
|
+
commandFormat: {
|
|
19
|
+
separator: "-";
|
|
20
|
+
};
|
|
18
21
|
};
|
|
19
22
|
/**
|
|
20
23
|
* Detect if OpenCode is available in the project
|
|
@@ -15,6 +15,7 @@ export class OpenCodeAdapter extends BaseAdapter {
|
|
|
15
15
|
supportsFrontmatter: true,
|
|
16
16
|
frontmatterFields: ['description', 'agent', 'model'],
|
|
17
17
|
argumentPlaceholder: '$ARGUMENTS',
|
|
18
|
+
commandFormat: { separator: '-' },
|
|
18
19
|
};
|
|
19
20
|
/**
|
|
20
21
|
* Detect if OpenCode is available in the project
|