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.
Files changed (45) hide show
  1. package/dist/cli/commands/execute.js +29 -9
  2. package/dist/cli/commands/verify.d.ts +28 -0
  3. package/dist/cli/commands/verify.js +347 -0
  4. package/dist/core/adapters/amp-adapter.d.ts +3 -0
  5. package/dist/core/adapters/amp-adapter.js +1 -0
  6. package/dist/core/adapters/cline-adapter.d.ts +3 -0
  7. package/dist/core/adapters/cline-adapter.js +1 -0
  8. package/dist/core/adapters/codebuddy-adapter.d.ts +3 -0
  9. package/dist/core/adapters/codebuddy-adapter.js +1 -0
  10. package/dist/core/adapters/codex-adapter.d.ts +3 -0
  11. package/dist/core/adapters/codex-adapter.js +1 -0
  12. package/dist/core/adapters/cursor-adapter.d.ts +3 -0
  13. package/dist/core/adapters/cursor-adapter.js +1 -0
  14. package/dist/core/adapters/droid-adapter.d.ts +3 -0
  15. package/dist/core/adapters/droid-adapter.js +1 -0
  16. package/dist/core/adapters/instructions-generator.js +9 -2
  17. package/dist/core/adapters/kilocode-adapter.d.ts +3 -0
  18. package/dist/core/adapters/kilocode-adapter.js +1 -0
  19. package/dist/core/adapters/opencode-adapter.d.ts +3 -0
  20. package/dist/core/adapters/opencode-adapter.js +1 -0
  21. package/dist/core/adapters/roocode-adapter.d.ts +3 -0
  22. package/dist/core/adapters/roocode-adapter.js +1 -0
  23. package/dist/core/adapters/windsurf-adapter.d.ts +3 -0
  24. package/dist/core/adapters/windsurf-adapter.js +1 -0
  25. package/dist/core/basic-checklist-generator.d.ts +35 -0
  26. package/dist/core/basic-checklist-generator.js +344 -0
  27. package/dist/core/checklist-parser.d.ts +48 -0
  28. package/dist/core/checklist-parser.js +238 -0
  29. package/dist/core/command-transformer.d.ts +55 -0
  30. package/dist/core/command-transformer.js +65 -0
  31. package/dist/core/prompt-manager.d.ts +7 -0
  32. package/dist/core/prompt-manager.js +47 -22
  33. package/dist/core/verification-hooks.d.ts +67 -0
  34. package/dist/core/verification-hooks.js +309 -0
  35. package/dist/core/verification-manager.d.ts +106 -0
  36. package/dist/core/verification-manager.js +422 -0
  37. package/dist/templates/slash-commands/_canonical/execute.md +72 -1
  38. package/dist/templates/slash-commands/_canonical/verify.md +292 -0
  39. package/dist/templates/slash-commands/_components/agent-protocols/verification-methods.md +184 -0
  40. package/dist/types/agent.d.ts +4 -0
  41. package/dist/types/verification.d.ts +204 -0
  42. package/dist/types/verification.js +8 -0
  43. package/dist/utils/template-loader.d.ts +1 -1
  44. package/dist/utils/template-loader.js +5 -1
  45. package/package.json +1 -1
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Clavix v4.8: Verification Hooks
3
+ *
4
+ * Detects and executes CLI hooks for automated verification of checklist items.
5
+ * Supports npm, yarn, and pnpm package managers.
6
+ */
7
+ import { spawn } from 'child_process';
8
+ import fs from 'fs-extra';
9
+ import * as path from 'path';
10
+ /**
11
+ * Default timeout for hooks (60 seconds)
12
+ */
13
+ const DEFAULT_TIMEOUT = 60000;
14
+ /**
15
+ * Built-in hook definitions
16
+ */
17
+ const HOOK_DEFINITIONS = {
18
+ test: {
19
+ displayName: 'Tests',
20
+ commands: ['npm test', 'npm run test', 'yarn test', 'pnpm test'],
21
+ successPatterns: [
22
+ /(\d+)\s+(passing|passed)/i,
23
+ /tests?\s+passed/i,
24
+ /all\s+tests?\s+passed/i,
25
+ /0\s+failed/i,
26
+ /test\s+suites?:\s+\d+\s+passed/i,
27
+ ],
28
+ failurePatterns: [/(\d+)\s+failed/i, /test\s+failed/i, /FAIL/i, /error/i],
29
+ },
30
+ build: {
31
+ displayName: 'Build',
32
+ commands: ['npm run build', 'yarn build', 'pnpm build', 'tsc'],
33
+ successPatterns: [/successfully/i, /done/i, /built/i, /compiled/i],
34
+ failurePatterns: [/error/i, /failed/i, /TS\d{4}:/],
35
+ },
36
+ lint: {
37
+ displayName: 'Lint',
38
+ commands: ['npm run lint', 'yarn lint', 'pnpm lint', 'eslint .'],
39
+ successPatterns: [/0\s+errors?/i, /no\s+errors?/i, /all\s+files?\s+pass/i],
40
+ failurePatterns: [/(\d+)\s+errors?/i, /error/i],
41
+ },
42
+ typecheck: {
43
+ displayName: 'Type Check',
44
+ commands: ['tsc --noEmit', 'npm run typecheck', 'yarn typecheck'],
45
+ successPatterns: [/^$/], // Empty output means success for tsc
46
+ failurePatterns: [/error\s+TS\d{4}/i, /Type\s+error/i],
47
+ },
48
+ custom: {
49
+ displayName: 'Custom',
50
+ commands: [],
51
+ successPatterns: [],
52
+ failurePatterns: [],
53
+ },
54
+ };
55
+ /**
56
+ * Verification Hooks Manager
57
+ */
58
+ export class VerificationHooks {
59
+ cwd;
60
+ detectedHooks = null;
61
+ constructor(cwd) {
62
+ this.cwd = cwd || process.cwd();
63
+ }
64
+ /**
65
+ * Detect available hooks in the project
66
+ */
67
+ async detectHooks() {
68
+ if (this.detectedHooks) {
69
+ return this.detectedHooks;
70
+ }
71
+ const packageJsonPath = path.join(this.cwd, 'package.json');
72
+ const hasPackageJson = await fs.pathExists(packageJsonPath);
73
+ const packageManager = await this.detectPackageManager();
74
+ const hooks = [];
75
+ if (hasPackageJson) {
76
+ try {
77
+ const packageJson = await fs.readJson(packageJsonPath);
78
+ const scripts = packageJson.scripts || {};
79
+ // Check for test script
80
+ if (scripts.test) {
81
+ hooks.push(this.createHook('test', `${packageManager} test`, packageManager));
82
+ }
83
+ // Check for build script
84
+ if (scripts.build) {
85
+ hooks.push(this.createHook('build', `${packageManager} run build`, packageManager));
86
+ }
87
+ // Check for lint script
88
+ if (scripts.lint) {
89
+ hooks.push(this.createHook('lint', `${packageManager} run lint`, packageManager));
90
+ }
91
+ // Check for typecheck script
92
+ if (scripts.typecheck || scripts['type-check']) {
93
+ const cmd = scripts.typecheck ? 'typecheck' : 'type-check';
94
+ hooks.push(this.createHook('typecheck', `${packageManager} run ${cmd}`, packageManager));
95
+ }
96
+ else {
97
+ // Check for TypeScript
98
+ const hasTsConfig = await fs.pathExists(path.join(this.cwd, 'tsconfig.json'));
99
+ if (hasTsConfig) {
100
+ hooks.push(this.createHook('typecheck', 'npx tsc --noEmit', packageManager));
101
+ }
102
+ }
103
+ }
104
+ catch {
105
+ // Ignore errors reading package.json
106
+ }
107
+ }
108
+ this.detectedHooks = {
109
+ hooks,
110
+ packageManager,
111
+ hasPackageJson,
112
+ };
113
+ return this.detectedHooks;
114
+ }
115
+ /**
116
+ * Detect package manager used in the project
117
+ */
118
+ async detectPackageManager() {
119
+ // Check for lock files
120
+ if (await fs.pathExists(path.join(this.cwd, 'pnpm-lock.yaml'))) {
121
+ return 'pnpm';
122
+ }
123
+ if (await fs.pathExists(path.join(this.cwd, 'yarn.lock'))) {
124
+ return 'yarn';
125
+ }
126
+ if (await fs.pathExists(path.join(this.cwd, 'package-lock.json'))) {
127
+ return 'npm';
128
+ }
129
+ return 'unknown';
130
+ }
131
+ /**
132
+ * Create a hook definition
133
+ */
134
+ createHook(type, command, _packageManager) {
135
+ const def = HOOK_DEFINITIONS[type];
136
+ return {
137
+ name: type,
138
+ displayName: def.displayName,
139
+ command,
140
+ successPattern: def.successPatterns[0],
141
+ failurePattern: def.failurePatterns[0],
142
+ timeout: DEFAULT_TIMEOUT,
143
+ };
144
+ }
145
+ /**
146
+ * Run a specific hook
147
+ */
148
+ async runHook(hook) {
149
+ const startTime = Date.now();
150
+ try {
151
+ const { exitCode, output } = await this.executeCommand(hook.command, hook.timeout);
152
+ const executionTimeMs = Date.now() - startTime;
153
+ // Determine success based on exit code and patterns
154
+ const success = this.determineSuccess(hook, exitCode, output);
155
+ const confidence = this.determineConfidence(hook, exitCode, output, success);
156
+ return {
157
+ hook,
158
+ success,
159
+ exitCode,
160
+ output,
161
+ confidence,
162
+ executionTimeMs,
163
+ };
164
+ }
165
+ catch (error) {
166
+ const executionTimeMs = Date.now() - startTime;
167
+ return {
168
+ hook,
169
+ success: false,
170
+ exitCode: -1,
171
+ output: '',
172
+ confidence: 'low',
173
+ executionTimeMs,
174
+ error: error instanceof Error ? error.message : String(error),
175
+ };
176
+ }
177
+ }
178
+ /**
179
+ * Run all detected hooks
180
+ */
181
+ async runAllHooks() {
182
+ const detected = await this.detectHooks();
183
+ const results = [];
184
+ for (const hook of detected.hooks) {
185
+ const result = await this.runHook(hook);
186
+ results.push(result);
187
+ }
188
+ return results;
189
+ }
190
+ /**
191
+ * Run a hook by type
192
+ */
193
+ async runHookByType(type) {
194
+ const detected = await this.detectHooks();
195
+ const hook = detected.hooks.find((h) => h.name === type);
196
+ if (!hook) {
197
+ return null;
198
+ }
199
+ return this.runHook(hook);
200
+ }
201
+ /**
202
+ * Execute a command and capture output
203
+ */
204
+ executeCommand(command, timeout) {
205
+ return new Promise((resolve, reject) => {
206
+ const [cmd, ...args] = command.split(' ');
207
+ let output = '';
208
+ const proc = spawn(cmd, args, {
209
+ cwd: this.cwd,
210
+ shell: true,
211
+ env: { ...process.env, CI: 'true', FORCE_COLOR: '0' },
212
+ });
213
+ const timeoutId = setTimeout(() => {
214
+ proc.kill('SIGTERM');
215
+ reject(new Error(`Command timed out after ${timeout}ms`));
216
+ }, timeout);
217
+ proc.stdout?.on('data', (data) => {
218
+ output += data.toString();
219
+ });
220
+ proc.stderr?.on('data', (data) => {
221
+ output += data.toString();
222
+ });
223
+ proc.on('close', (code) => {
224
+ clearTimeout(timeoutId);
225
+ resolve({
226
+ exitCode: code ?? 0,
227
+ output: output.trim(),
228
+ });
229
+ });
230
+ proc.on('error', (error) => {
231
+ clearTimeout(timeoutId);
232
+ reject(error);
233
+ });
234
+ });
235
+ }
236
+ /**
237
+ * Determine if the hook succeeded
238
+ */
239
+ determineSuccess(hook, exitCode, output) {
240
+ // Exit code 0 is primary success indicator
241
+ if (exitCode !== 0) {
242
+ return false;
243
+ }
244
+ // Check for explicit failure patterns
245
+ const def = HOOK_DEFINITIONS[hook.name];
246
+ for (const pattern of def.failurePatterns) {
247
+ if (pattern.test(output)) {
248
+ // Check if it's a "0 errors" type match
249
+ const match = output.match(pattern);
250
+ if (match && match[1] === '0') {
251
+ continue; // "0 errors" is success
252
+ }
253
+ return false;
254
+ }
255
+ }
256
+ return true;
257
+ }
258
+ /**
259
+ * Determine confidence level in the result
260
+ */
261
+ determineConfidence(hook, exitCode, output, success) {
262
+ const def = HOOK_DEFINITIONS[hook.name];
263
+ // Clear exit code with matching success patterns = high confidence
264
+ if (exitCode === 0 && success) {
265
+ for (const pattern of def.successPatterns) {
266
+ if (pattern.test(output)) {
267
+ return 'high';
268
+ }
269
+ }
270
+ // Exit 0 but no explicit success pattern
271
+ return 'medium';
272
+ }
273
+ // Clear failure indicators
274
+ if (exitCode !== 0 || !success) {
275
+ for (const pattern of def.failurePatterns) {
276
+ if (pattern.test(output)) {
277
+ return 'high';
278
+ }
279
+ }
280
+ return 'medium';
281
+ }
282
+ return 'low';
283
+ }
284
+ /**
285
+ * Get hook by type
286
+ */
287
+ async getHook(type) {
288
+ const detected = await this.detectHooks();
289
+ return detected.hooks.find((h) => h.name === type) || null;
290
+ }
291
+ /**
292
+ * Check if a hook type is available
293
+ */
294
+ async hasHook(type) {
295
+ const detected = await this.detectHooks();
296
+ return detected.hooks.some((h) => h.name === type);
297
+ }
298
+ /**
299
+ * Get summary of available hooks
300
+ */
301
+ async getHookSummary() {
302
+ const detected = await this.detectHooks();
303
+ const allTypes = ['test', 'build', 'lint', 'typecheck'];
304
+ const available = detected.hooks.map((h) => h.name);
305
+ const unavailable = allTypes.filter((t) => !available.includes(t));
306
+ return { available, unavailable };
307
+ }
308
+ }
309
+ //# sourceMappingURL=verification-hooks.js.map
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Clavix v4.8: Verification Manager
3
+ *
4
+ * Manages verification state, execution flow, and persistence.
5
+ * Coordinates between checklist parsing, hook execution, and result storage.
6
+ */
7
+ import { VerificationReport, VerificationResult, VerificationSummary, ChecklistItem, ReportStatus, VerificationStatus, VerificationConfidence, VerificationMethod } from '../types/verification.js';
8
+ /**
9
+ * Verification Manager
10
+ */
11
+ export declare class VerificationManager {
12
+ private readonly promptManager;
13
+ private readonly checklistParser;
14
+ private readonly verificationHooks;
15
+ private readonly outputDir;
16
+ constructor(baseDir?: string);
17
+ /**
18
+ * Initialize verification for a prompt
19
+ */
20
+ initializeVerification(promptId: string): Promise<VerificationReport>;
21
+ /**
22
+ * Get verification report path for a prompt
23
+ */
24
+ getReportPath(promptId: string, source: 'fast' | 'deep'): string;
25
+ /**
26
+ * Load verification report
27
+ */
28
+ loadReport(promptId: string): Promise<VerificationReport | null>;
29
+ /**
30
+ * Save verification report
31
+ */
32
+ saveReport(report: VerificationReport): Promise<void>;
33
+ /**
34
+ * Mark a single item as verified
35
+ */
36
+ markItemVerified(promptId: string, itemId: string, status: VerificationStatus, options?: {
37
+ evidence?: string;
38
+ reason?: string;
39
+ confidence?: VerificationConfidence;
40
+ method?: VerificationMethod;
41
+ }): Promise<VerificationReport>;
42
+ /**
43
+ * Run automated verification for a prompt
44
+ */
45
+ runAutomatedVerification(promptId: string): Promise<VerificationReport>;
46
+ /**
47
+ * Match checklist item content to hook type
48
+ */
49
+ private matchItemToHook;
50
+ /**
51
+ * Truncate output for storage
52
+ */
53
+ private truncateOutput;
54
+ /**
55
+ * Calculate summary from results
56
+ */
57
+ calculateSummary(results: VerificationResult[]): VerificationSummary;
58
+ /**
59
+ * Calculate overall report status
60
+ */
61
+ private calculateReportStatus;
62
+ /**
63
+ * Get pending items from report
64
+ */
65
+ getPendingItems(report: VerificationReport): ChecklistItem[];
66
+ /**
67
+ * Get failed items from report
68
+ */
69
+ getFailedItems(report: VerificationReport): Array<{
70
+ item: ChecklistItem;
71
+ result: VerificationResult;
72
+ }>;
73
+ /**
74
+ * Check if verification is complete
75
+ */
76
+ isComplete(report: VerificationReport): boolean;
77
+ /**
78
+ * Check if verification requires attention (has failures)
79
+ */
80
+ requiresAttention(report: VerificationReport): boolean;
81
+ /**
82
+ * Delete verification report
83
+ */
84
+ deleteReport(promptId: string): Promise<boolean>;
85
+ /**
86
+ * Get all verification reports
87
+ */
88
+ listReports(): Promise<VerificationReport[]>;
89
+ /**
90
+ * Get verification status for a prompt
91
+ */
92
+ getVerificationStatus(promptId: string): Promise<{
93
+ hasReport: boolean;
94
+ status: ReportStatus | null;
95
+ summary: VerificationSummary | null;
96
+ }>;
97
+ /**
98
+ * Format verification report for display
99
+ */
100
+ formatReportForDisplay(report: VerificationReport): string;
101
+ /**
102
+ * Get status icon for display
103
+ */
104
+ private getStatusIcon;
105
+ }
106
+ //# sourceMappingURL=verification-manager.d.ts.map