qa360 2.1.6 → 2.1.7

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.
@@ -30,6 +30,8 @@ export declare function aiGenerateCommand(prompt: string, options?: {
30
30
  provider?: string;
31
31
  type?: string;
32
32
  json?: boolean;
33
+ pack?: boolean;
34
+ output?: string;
33
35
  }): Promise<void>;
34
36
  /**
35
37
  * Show AI configuration
@@ -236,6 +236,11 @@ export async function aiBenchmarkCommand(options = {}) {
236
236
  export async function aiGenerateCommand(prompt, options = {}) {
237
237
  let spinner;
238
238
  try {
239
+ // Use pack generation if --pack flag is set
240
+ if (options.pack) {
241
+ await generatePackCommand(prompt, options);
242
+ return;
243
+ }
239
244
  const systemPrompt = buildSystemPrompt(options.type || 'api');
240
245
  const provider = options.provider
241
246
  ? await createLLMProvider({ preferred: options.provider })
@@ -289,10 +294,61 @@ export async function aiGenerateCommand(prompt, options = {}) {
289
294
  console.error(chalk.red('\nAnthropic Error:'), error.message);
290
295
  }
291
296
  else {
292
- console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
297
+ const errMsg = error instanceof Error ? error.message : String(error);
298
+ console.error(chalk.red('Error:'), errMsg);
293
299
  }
294
300
  }
295
301
  }
302
+ /**
303
+ * Generate a QA360 pack YAML using AI
304
+ */
305
+ async function generatePackCommand(prompt, options = {}) {
306
+ const spinner = ora('Generating QA360 pack...').start();
307
+ try {
308
+ const systemPrompt = buildPackSystemPrompt();
309
+ const provider = options.provider
310
+ ? await createLLMProvider({ preferred: options.provider })
311
+ : await createBest();
312
+ const providerType = provider.getProviderType();
313
+ const enhancedPrompt = `Generate a QA360 v2 pack YAML for: ${prompt}
314
+
315
+ Important: Return ONLY valid YAML starting with "version: 2". No code blocks, no explanations, just the YAML.`;
316
+ const response = await provider.generate({
317
+ prompt: enhancedPrompt,
318
+ systemPrompt,
319
+ maxTokens: 4096,
320
+ temperature: 0.3, // Lower temperature for more structured output
321
+ });
322
+ spinner.succeed(`Generated pack using ${chalk.cyan(providerType)}!\n`);
323
+ // Extract YAML from response (remove code blocks if present)
324
+ let yamlContent = response.content;
325
+ // Remove markdown code blocks
326
+ yamlContent = yamlContent.replace(/```yaml\n?/g, '').replace(/```\n?/g, '');
327
+ // Remove leading/trailing whitespace
328
+ yamlContent = yamlContent.trim();
329
+ // Determine output path
330
+ const outputPath = options.output || './qa360-pack.yml';
331
+ // Save the pack
332
+ const { writeFileSync } = await import('fs');
333
+ writeFileSync(outputPath, yamlContent, 'utf-8');
334
+ console.log(chalk.bold('Generated QA360 Pack:\n'));
335
+ console.log(chalk.gray('─'.repeat(70)));
336
+ console.log(yamlContent);
337
+ console.log(chalk.gray('─'.repeat(70)));
338
+ console.log(chalk.green(`\n✓ Pack saved to: ${outputPath}`));
339
+ console.log(chalk.gray(`\n[INFO] Tokens: ${response.usage.totalTokens} (${response.usage.promptTokens} in + ${response.usage.completionTokens} out)`));
340
+ console.log(chalk.gray(`[INFO] Provider: ${providerType} (${response.model})\n`));
341
+ // Show usage instructions
342
+ console.log(chalk.yellow('Next steps:'));
343
+ console.log(chalk.gray(` 1. Review the pack: cat ${outputPath}`));
344
+ console.log(chalk.gray(` 2. Run tests: qa360 run ${outputPath}`));
345
+ console.log(chalk.gray(` 3. Or validate: qa360 pack validate ${outputPath}\n`));
346
+ }
347
+ catch (error) {
348
+ spinner.fail('Pack generation failed');
349
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
350
+ }
351
+ }
296
352
  /**
297
353
  * Show AI configuration
298
354
  */
@@ -436,6 +492,53 @@ For accessibility tests:
436
492
  };
437
493
  return typePrompts[type] || typePrompts.api;
438
494
  }
495
+ /**
496
+ * Build system prompt for QA360 pack YAML generation
497
+ */
498
+ function buildPackSystemPrompt() {
499
+ return `You are a QA360 pack YAML generator. Generate VALID QA360 v2 pack YAML files.
500
+
501
+ QA360 Pack v2 Structure:
502
+ \`\`\`yaml
503
+ version: 2
504
+ name: test-pack-name
505
+ description: Test pack description
506
+ gates:
507
+ gate-name:
508
+ adapter: playwright-api|playwright-ui|k6-perf
509
+ enabled: true
510
+ config:
511
+ baseUrl: "https://example.com"
512
+ # API adapter: use "smoke" array with "METHOD path -> status" format
513
+ smoke:
514
+ - "GET /api/health -> 200"
515
+ - "POST /api/users -> 201"
516
+ # UI adapter: use "scenario" array or "pages" array
517
+ scenario:
518
+ - action: navigate
519
+ url: /login
520
+ - action: fill
521
+ selector: "#email"
522
+ value: "test@example.com"
523
+ - action: click
524
+ selector: "button[type='submit']"
525
+ options:
526
+ timeout: 10000
527
+ budgets:
528
+ a11y_min: 70
529
+ perf_p95_ms: 3000
530
+ \`\`\`
531
+
532
+ Rules:
533
+ 1. ALWAYS start with "version: 2"
534
+ 2. Use "adapter:" not "type:"
535
+ 3. For API tests: use adapter: playwright-api with smoke: array
536
+ 4. For UI tests: use adapter: playwright-ui with scenario: array or pages: array
537
+ 5. Smoke format: "METHOD path -> status" (e.g., "GET /users -> 200")
538
+ 6. Scenario actions: navigate, fill, click, waitForSelector, assertText, assertVisible
539
+ 7. Return ONLY the YAML, no markdown code blocks, no explanations
540
+ 8. Make sure YAML is valid and properly indented`;
541
+ }
439
542
  /**
440
543
  * Create AI commands
441
544
  */
@@ -486,6 +589,8 @@ export function createAICommands() {
486
589
  .option('-P, --provider <provider>', 'Use specific provider (deepseek, ollama, openai, anthropic)')
487
590
  .option('-t, --type <type>', 'Test type (api, ui, perf, a11y)', 'api')
488
591
  .option('--json', 'Output as JSON')
592
+ .option('--pack', 'Generate a QA360 pack YAML (instead of test code)')
593
+ .option('-o, --output <path>', 'Output file path (for --pack: ./qa360-pack.yml)')
489
594
  .action(async (prompt, options) => {
490
595
  try {
491
596
  await aiGenerateCommand(prompt, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qa360",
3
- "version": "2.1.6",
3
+ "version": "2.1.7",
4
4
  "description": "QA360 Proof CLI - Quality as Cryptographic Proof",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",