claude-autopm 2.2.1 ā 2.3.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/lib/ai-providers/ClaudeProvider.js +15 -0
- package/lib/cli/commands/prd.js +223 -63
- package/lib/services/PRDService.js +49 -0
- package/package.json +1 -1
|
@@ -396,6 +396,21 @@ class ClaudeProvider extends AbstractAIProvider {
|
|
|
396
396
|
// BACKWARD COMPATIBILITY METHODS
|
|
397
397
|
// ============================================================
|
|
398
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Generate text completion (alias for complete)
|
|
401
|
+
*
|
|
402
|
+
* Provides a more generic interface name for consistency with other services.
|
|
403
|
+
* This is an alias for complete() with identical functionality.
|
|
404
|
+
*
|
|
405
|
+
* @param {string} prompt - The prompt to complete
|
|
406
|
+
* @param {Object} [options={}] - Optional configuration
|
|
407
|
+
* @returns {Promise<string>} The completed text
|
|
408
|
+
* @throws {AIProviderError} On API errors
|
|
409
|
+
*/
|
|
410
|
+
async generate(prompt, options = {}) {
|
|
411
|
+
return await this.complete(prompt, options);
|
|
412
|
+
}
|
|
413
|
+
|
|
399
414
|
/**
|
|
400
415
|
* Get the current model being used (legacy method for backward compatibility)
|
|
401
416
|
*
|
package/lib/cli/commands/prd.js
CHANGED
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
const PRDService = require('../../services/PRDService');
|
|
16
|
+
const ClaudeProvider = require('../../ai-providers/ClaudeProvider');
|
|
16
17
|
const fs = require('fs-extra');
|
|
17
18
|
const ora = require('ora');
|
|
18
19
|
const chalk = require('chalk');
|
|
19
20
|
const path = require('path');
|
|
20
21
|
const { spawn } = require('child_process');
|
|
22
|
+
const readline = require('readline');
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* Get PRD file path
|
|
@@ -304,6 +306,12 @@ async function prdStatus(argv) {
|
|
|
304
306
|
* @param {Object} argv - Command arguments
|
|
305
307
|
*/
|
|
306
308
|
async function prdNew(argv) {
|
|
309
|
+
// Check if AI mode is enabled
|
|
310
|
+
if (argv.ai) {
|
|
311
|
+
return await prdNewWithAI(argv);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Standard mode: spawn prd-new.js
|
|
307
315
|
const spinner = ora(`Creating PRD: ${argv.name}`).start();
|
|
308
316
|
|
|
309
317
|
try {
|
|
@@ -397,6 +405,171 @@ async function prdNew(argv) {
|
|
|
397
405
|
}
|
|
398
406
|
}
|
|
399
407
|
|
|
408
|
+
/**
|
|
409
|
+
* Create new PRD with AI assistance
|
|
410
|
+
* @param {Object} argv - Command arguments
|
|
411
|
+
*/
|
|
412
|
+
async function prdNewWithAI(argv) {
|
|
413
|
+
console.log(chalk.cyan(`\nš¤ AI-Powered PRD Creation: ${argv.name}`));
|
|
414
|
+
console.log(chalk.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
415
|
+
|
|
416
|
+
const spinner = ora('Initializing...').start();
|
|
417
|
+
|
|
418
|
+
try {
|
|
419
|
+
// Check if PRD already exists
|
|
420
|
+
const prdPath = getPrdPath(argv.name);
|
|
421
|
+
const exists = await fs.pathExists(prdPath);
|
|
422
|
+
if (exists) {
|
|
423
|
+
spinner.fail(chalk.red('PRD already exists'));
|
|
424
|
+
console.error(chalk.red(`\nError: PRD file already exists: ${prdPath}`));
|
|
425
|
+
console.error(chalk.yellow('Use: autopm prd edit ' + argv.name + ' to modify it'));
|
|
426
|
+
process.exit(1);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Create PRDs directory if needed
|
|
430
|
+
const prdsDir = path.join(process.cwd(), '.claude', 'prds');
|
|
431
|
+
await fs.ensureDir(prdsDir);
|
|
432
|
+
|
|
433
|
+
spinner.stop();
|
|
434
|
+
|
|
435
|
+
// Gather information from user
|
|
436
|
+
const rl = readline.createInterface({
|
|
437
|
+
input: process.stdin,
|
|
438
|
+
output: process.stdout
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
const prompt = (question) => new Promise((resolve) => {
|
|
442
|
+
rl.question(question, resolve);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
console.log(chalk.cyan('š§ Let\'s gather some information for AI...\n'));
|
|
446
|
+
|
|
447
|
+
const context = {};
|
|
448
|
+
|
|
449
|
+
// Product Vision
|
|
450
|
+
console.log(chalk.bold('š Product Vision'));
|
|
451
|
+
console.log(chalk.gray('What problem are you solving? What\'s the vision?'));
|
|
452
|
+
context.vision = await prompt(chalk.cyan('Vision: '));
|
|
453
|
+
|
|
454
|
+
// Target Users
|
|
455
|
+
console.log(chalk.bold('\nš„ Target Users'));
|
|
456
|
+
console.log(chalk.gray('Who will use this? What are their needs?'));
|
|
457
|
+
context.users = await prompt(chalk.cyan('Target users: '));
|
|
458
|
+
|
|
459
|
+
// Key Features (simplified - just high level)
|
|
460
|
+
console.log(chalk.bold('\n⨠Key Features'));
|
|
461
|
+
console.log(chalk.gray('What are the main capabilities? (brief description)'));
|
|
462
|
+
context.features = await prompt(chalk.cyan('Features: '));
|
|
463
|
+
|
|
464
|
+
// Success Metrics
|
|
465
|
+
console.log(chalk.bold('\nš Success Metrics'));
|
|
466
|
+
console.log(chalk.gray('How will you measure success?'));
|
|
467
|
+
context.metrics = await prompt(chalk.cyan('Metrics: '));
|
|
468
|
+
|
|
469
|
+
// Priority
|
|
470
|
+
console.log(chalk.bold('\nšÆ Priority'));
|
|
471
|
+
const priority = await prompt(chalk.cyan('Priority (P0/P1/P2/P3) [P2]: '));
|
|
472
|
+
context.priority = priority || 'P2';
|
|
473
|
+
|
|
474
|
+
// Timeline
|
|
475
|
+
console.log(chalk.bold('\nā° Timeline'));
|
|
476
|
+
const timeline = await prompt(chalk.cyan('Timeline [Q1 2025]: '));
|
|
477
|
+
context.timeline = timeline || 'Q1 2025';
|
|
478
|
+
|
|
479
|
+
rl.close();
|
|
480
|
+
|
|
481
|
+
// Build AI prompt
|
|
482
|
+
const aiPrompt = `Generate a comprehensive Product Requirements Document (PRD) based on the following information:
|
|
483
|
+
|
|
484
|
+
**PRD Name**: ${argv.name}
|
|
485
|
+
**Priority**: ${context.priority}
|
|
486
|
+
**Timeline**: ${context.timeline}
|
|
487
|
+
|
|
488
|
+
**Product Vision**:
|
|
489
|
+
${context.vision}
|
|
490
|
+
|
|
491
|
+
**Target Users**:
|
|
492
|
+
${context.users}
|
|
493
|
+
|
|
494
|
+
**Key Features**:
|
|
495
|
+
${context.features}
|
|
496
|
+
|
|
497
|
+
**Success Metrics**:
|
|
498
|
+
${context.metrics}
|
|
499
|
+
|
|
500
|
+
Please generate a complete, professional PRD with the following sections:
|
|
501
|
+
1. Executive Summary
|
|
502
|
+
2. Problem Statement (with Background, Current State, Desired State)
|
|
503
|
+
3. Target Users (with User Personas and User Stories)
|
|
504
|
+
4. Key Features (organized by priority: Must Have, Should Have, Nice to Have)
|
|
505
|
+
5. Success Metrics (with KPIs and Measurement Plan)
|
|
506
|
+
6. Technical Requirements (Architecture, Non-Functional Requirements, Dependencies)
|
|
507
|
+
7. Implementation Plan (broken into phases)
|
|
508
|
+
8. Risks and Mitigation
|
|
509
|
+
9. Open Questions
|
|
510
|
+
10. Appendix (References, Glossary, Changelog)
|
|
511
|
+
|
|
512
|
+
Format the output as a proper markdown document with frontmatter (status, priority, created, author, timeline).
|
|
513
|
+
|
|
514
|
+
Make it comprehensive, actionable, and professional. Expand on the provided information with industry best practices.`;
|
|
515
|
+
|
|
516
|
+
// Initialize AI provider and PRD service
|
|
517
|
+
const provider = new ClaudeProvider();
|
|
518
|
+
const prdService = new PRDService({ provider });
|
|
519
|
+
let prdContent = '';
|
|
520
|
+
|
|
521
|
+
if (argv.stream) {
|
|
522
|
+
// Streaming mode
|
|
523
|
+
const genSpinner = ora('Generating PRD with AI...').start();
|
|
524
|
+
genSpinner.stop();
|
|
525
|
+
|
|
526
|
+
console.log(chalk.cyan('\n\nš¤ AI is generating your PRD...\n'));
|
|
527
|
+
console.log(chalk.gray('ā'.repeat(80)) + '\n');
|
|
528
|
+
|
|
529
|
+
for await (const chunk of prdService.generatePRDStream(aiPrompt)) {
|
|
530
|
+
process.stdout.write(chunk);
|
|
531
|
+
prdContent += chunk;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
console.log('\n\n' + chalk.gray('ā'.repeat(80)));
|
|
535
|
+
} else {
|
|
536
|
+
// Non-streaming mode
|
|
537
|
+
const genSpinner = ora('Generating PRD with AI...').start();
|
|
538
|
+
prdContent = await prdService.generatePRD(aiPrompt);
|
|
539
|
+
genSpinner.succeed(chalk.green('PRD generated'));
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Save to file
|
|
543
|
+
const saveSpinner = ora('Saving PRD...').start();
|
|
544
|
+
await fs.writeFile(prdPath, prdContent);
|
|
545
|
+
saveSpinner.succeed(chalk.green('PRD saved'));
|
|
546
|
+
|
|
547
|
+
console.log(chalk.green('\nā
AI-powered PRD created successfully!'));
|
|
548
|
+
console.log(chalk.cyan(`š File: ${prdPath}\n`));
|
|
549
|
+
|
|
550
|
+
// Show next steps
|
|
551
|
+
console.log(chalk.bold('š What You Can Do Next:\n'));
|
|
552
|
+
console.log(` ${chalk.cyan('1.')} Review and edit: ${chalk.yellow('autopm prd edit ' + argv.name)}`);
|
|
553
|
+
console.log(` ${chalk.cyan('2.')} Check status: ${chalk.yellow('autopm prd status ' + argv.name)}`);
|
|
554
|
+
console.log(` ${chalk.cyan('3.')} Parse to epic: ${chalk.yellow('autopm prd parse ' + argv.name + ' --ai')}`);
|
|
555
|
+
console.log(` ${chalk.cyan('4.')} Extract epics: ${chalk.yellow('autopm prd extract-epics ' + argv.name)}\n`);
|
|
556
|
+
|
|
557
|
+
} catch (error) {
|
|
558
|
+
console.error(chalk.red(`\nā Error: ${error.message}`));
|
|
559
|
+
|
|
560
|
+
if (error.message.includes('ANTHROPIC_API_KEY') || error.message.includes('API key')) {
|
|
561
|
+
console.error(chalk.red('\nā Error: API key not configured'));
|
|
562
|
+
console.error(chalk.yellow('\nš” Set your API key in .env file:'));
|
|
563
|
+
console.error(chalk.cyan(' ANTHROPIC_API_KEY=sk-ant-api03-...'));
|
|
564
|
+
} else if (process.env.DEBUG) {
|
|
565
|
+
console.error(chalk.gray('\nStack trace:'));
|
|
566
|
+
console.error(chalk.gray(error.stack));
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
process.exit(1);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
400
573
|
/**
|
|
401
574
|
* Parse PRD with AI
|
|
402
575
|
* @param {Object} argv - Command arguments
|
|
@@ -612,57 +785,6 @@ async function prdValidate(argv) {
|
|
|
612
785
|
}
|
|
613
786
|
}
|
|
614
787
|
|
|
615
|
-
/**
|
|
616
|
-
* Main command handler
|
|
617
|
-
* @param {Object} argv - Command arguments
|
|
618
|
-
*/
|
|
619
|
-
async function handler(argv) {
|
|
620
|
-
// Validate action
|
|
621
|
-
const validActions = ['list', 'new', 'show', 'edit', 'status', 'parse', 'extract-epics', 'summarize', 'validate'];
|
|
622
|
-
|
|
623
|
-
if (!validActions.includes(argv.action)) {
|
|
624
|
-
console.error(chalk.red(`\nError: Unknown action: ${argv.action}`));
|
|
625
|
-
console.error(chalk.yellow(`Valid actions: ${validActions.join(', ')}`));
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// Route to appropriate handler
|
|
630
|
-
try {
|
|
631
|
-
switch (argv.action) {
|
|
632
|
-
case 'list':
|
|
633
|
-
await prdList(argv);
|
|
634
|
-
break;
|
|
635
|
-
case 'new':
|
|
636
|
-
await prdNew(argv);
|
|
637
|
-
break;
|
|
638
|
-
case 'show':
|
|
639
|
-
await prdShow(argv);
|
|
640
|
-
break;
|
|
641
|
-
case 'edit':
|
|
642
|
-
await prdEdit(argv);
|
|
643
|
-
break;
|
|
644
|
-
case 'status':
|
|
645
|
-
await prdStatus(argv);
|
|
646
|
-
break;
|
|
647
|
-
case 'parse':
|
|
648
|
-
await prdParse(argv);
|
|
649
|
-
break;
|
|
650
|
-
case 'extract-epics':
|
|
651
|
-
await prdExtractEpics(argv);
|
|
652
|
-
break;
|
|
653
|
-
case 'summarize':
|
|
654
|
-
await prdSummarize(argv);
|
|
655
|
-
break;
|
|
656
|
-
case 'validate':
|
|
657
|
-
await prdValidate(argv);
|
|
658
|
-
break;
|
|
659
|
-
}
|
|
660
|
-
} catch (error) {
|
|
661
|
-
// Global error handler for unexpected errors
|
|
662
|
-
console.error(chalk.red(`\nUnexpected error: ${error.message}`));
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
788
|
/**
|
|
667
789
|
* Command builder - registers all subcommands
|
|
668
790
|
* @param {Object} yargs - Yargs instance
|
|
@@ -676,7 +798,8 @@ function builder(yargs) {
|
|
|
676
798
|
(yargs) => {
|
|
677
799
|
return yargs
|
|
678
800
|
.example('autopm prd list', 'Show all PRDs');
|
|
679
|
-
}
|
|
801
|
+
},
|
|
802
|
+
prdList // Handler
|
|
680
803
|
)
|
|
681
804
|
.command(
|
|
682
805
|
'new <name>',
|
|
@@ -692,9 +815,22 @@ function builder(yargs) {
|
|
|
692
815
|
type: 'string',
|
|
693
816
|
alias: 't'
|
|
694
817
|
})
|
|
818
|
+
.option('ai', {
|
|
819
|
+
describe: 'Use AI to generate PRD content (requires ANTHROPIC_API_KEY)',
|
|
820
|
+
type: 'boolean',
|
|
821
|
+
default: false
|
|
822
|
+
})
|
|
823
|
+
.option('stream', {
|
|
824
|
+
describe: 'Stream AI output in real-time (only with --ai)',
|
|
825
|
+
type: 'boolean',
|
|
826
|
+
default: false
|
|
827
|
+
})
|
|
695
828
|
.example('autopm prd new my-feature', 'Create PRD with wizard')
|
|
696
|
-
.example('autopm prd new payment-api --template api-feature', 'Create PRD from template')
|
|
697
|
-
|
|
829
|
+
.example('autopm prd new payment-api --template api-feature', 'Create PRD from template')
|
|
830
|
+
.example('autopm prd new my-feature --ai', 'AI-powered PRD generation')
|
|
831
|
+
.example('autopm prd new my-feature --ai --stream', 'AI generation with streaming');
|
|
832
|
+
},
|
|
833
|
+
prdNew // Handler
|
|
698
834
|
)
|
|
699
835
|
.command(
|
|
700
836
|
'show <name>',
|
|
@@ -706,7 +842,8 @@ function builder(yargs) {
|
|
|
706
842
|
type: 'string'
|
|
707
843
|
})
|
|
708
844
|
.example('autopm prd show my-feature', 'Display PRD content');
|
|
709
|
-
}
|
|
845
|
+
},
|
|
846
|
+
prdShow // Handler
|
|
710
847
|
)
|
|
711
848
|
.command(
|
|
712
849
|
'edit <name>',
|
|
@@ -719,7 +856,8 @@ function builder(yargs) {
|
|
|
719
856
|
})
|
|
720
857
|
.example('autopm prd edit my-feature', 'Open PRD in editor')
|
|
721
858
|
.example('EDITOR=code autopm prd edit my-feature', 'Open PRD in VS Code');
|
|
722
|
-
}
|
|
859
|
+
},
|
|
860
|
+
prdEdit // Handler
|
|
723
861
|
)
|
|
724
862
|
.command(
|
|
725
863
|
'status <name>',
|
|
@@ -731,7 +869,8 @@ function builder(yargs) {
|
|
|
731
869
|
type: 'string'
|
|
732
870
|
})
|
|
733
871
|
.example('autopm prd status my-feature', 'Show PRD status report');
|
|
734
|
-
}
|
|
872
|
+
},
|
|
873
|
+
prdStatus // Handler
|
|
735
874
|
)
|
|
736
875
|
.command(
|
|
737
876
|
'parse <name>',
|
|
@@ -752,7 +891,8 @@ function builder(yargs) {
|
|
|
752
891
|
type: 'boolean',
|
|
753
892
|
default: true
|
|
754
893
|
});
|
|
755
|
-
}
|
|
894
|
+
},
|
|
895
|
+
prdParse // Handler
|
|
756
896
|
)
|
|
757
897
|
.command(
|
|
758
898
|
'extract-epics <name>',
|
|
@@ -768,7 +908,8 @@ function builder(yargs) {
|
|
|
768
908
|
type: 'boolean',
|
|
769
909
|
default: false
|
|
770
910
|
});
|
|
771
|
-
}
|
|
911
|
+
},
|
|
912
|
+
prdExtractEpics // Handler
|
|
772
913
|
)
|
|
773
914
|
.command(
|
|
774
915
|
'summarize <name>',
|
|
@@ -784,7 +925,8 @@ function builder(yargs) {
|
|
|
784
925
|
type: 'boolean',
|
|
785
926
|
default: false
|
|
786
927
|
});
|
|
787
|
-
}
|
|
928
|
+
},
|
|
929
|
+
prdSummarize // Handler
|
|
788
930
|
)
|
|
789
931
|
.command(
|
|
790
932
|
'validate <name>',
|
|
@@ -795,7 +937,8 @@ function builder(yargs) {
|
|
|
795
937
|
describe: 'PRD name (without .md extension)',
|
|
796
938
|
type: 'string'
|
|
797
939
|
});
|
|
798
|
-
}
|
|
940
|
+
},
|
|
941
|
+
prdValidate // Handler
|
|
799
942
|
)
|
|
800
943
|
.demandCommand(1, 'You must specify a PRD action')
|
|
801
944
|
.strictCommands()
|
|
@@ -806,10 +949,27 @@ function builder(yargs) {
|
|
|
806
949
|
* Command export
|
|
807
950
|
*/
|
|
808
951
|
module.exports = {
|
|
809
|
-
command: 'prd
|
|
952
|
+
command: 'prd',
|
|
810
953
|
describe: 'Manage PRD (Product Requirements Documents)',
|
|
811
954
|
builder,
|
|
812
|
-
handler
|
|
955
|
+
handler: (argv) => {
|
|
956
|
+
// This is just for catching the base command without subcommand
|
|
957
|
+
if (!argv._.includes('prd') || argv._.length === 1) {
|
|
958
|
+
console.log(chalk.yellow('\nPlease specify a PRD command\n'));
|
|
959
|
+
console.log('Usage: autopm prd <command>\n');
|
|
960
|
+
console.log('Available commands:');
|
|
961
|
+
console.log(' list List all PRDs');
|
|
962
|
+
console.log(' new <name> Create new PRD');
|
|
963
|
+
console.log(' show <name> Display PRD');
|
|
964
|
+
console.log(' edit <name> Edit PRD');
|
|
965
|
+
console.log(' status <name> Show PRD status');
|
|
966
|
+
console.log(' parse <name> Parse PRD with AI');
|
|
967
|
+
console.log(' extract-epics <name> Extract epics');
|
|
968
|
+
console.log(' summarize <name> Generate summary');
|
|
969
|
+
console.log(' validate <name> Validate structure');
|
|
970
|
+
console.log('\nUse: autopm prd <command> --help for more info\n');
|
|
971
|
+
}
|
|
972
|
+
},
|
|
813
973
|
handlers: {
|
|
814
974
|
list: prdList,
|
|
815
975
|
new: prdNew,
|
|
@@ -880,6 +880,55 @@ ${content}`;
|
|
|
880
880
|
// TIER 4: AI STREAMING METHODS
|
|
881
881
|
// ==========================================
|
|
882
882
|
|
|
883
|
+
/**
|
|
884
|
+
* Generate PRD from prompt (non-streaming)
|
|
885
|
+
*
|
|
886
|
+
* Uses AI to generate a complete PRD from a high-level description or prompt.
|
|
887
|
+
* Returns the generated PRD as markdown text.
|
|
888
|
+
*
|
|
889
|
+
* @param {string} prompt - Prompt describing what PRD to generate
|
|
890
|
+
* @param {Object} [options] - Generation options
|
|
891
|
+
* @returns {Promise<string>} Generated PRD markdown
|
|
892
|
+
* @throws {Error} If provider is not available
|
|
893
|
+
*
|
|
894
|
+
* @example
|
|
895
|
+
* const prd = await service.generatePRD('Create a PRD for user authentication');
|
|
896
|
+
* console.log(prd); // Full PRD markdown
|
|
897
|
+
*/
|
|
898
|
+
async generatePRD(prompt, options = {}) {
|
|
899
|
+
if (!this.provider || !this.provider.generate) {
|
|
900
|
+
throw new Error('PRD generation requires an AI provider with generate() support');
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
return await this.provider.generate(prompt, options);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* Generate PRD from prompt with streaming output
|
|
908
|
+
*
|
|
909
|
+
* Uses AI to generate a complete PRD from a high-level description,
|
|
910
|
+
* streaming the output in real-time as it's generated.
|
|
911
|
+
*
|
|
912
|
+
* @param {string} prompt - Prompt describing what PRD to generate
|
|
913
|
+
* @param {Object} [options] - Streaming options
|
|
914
|
+
* @returns {AsyncGenerator<string>} Stream of PRD markdown chunks
|
|
915
|
+
* @throws {Error} If provider is not available or lacks stream() support
|
|
916
|
+
*
|
|
917
|
+
* @example
|
|
918
|
+
* for await (const chunk of service.generatePRDStream('Create a PRD for...')) {
|
|
919
|
+
* process.stdout.write(chunk); // Display PRD as it's generated
|
|
920
|
+
* }
|
|
921
|
+
*/
|
|
922
|
+
async *generatePRDStream(prompt, options = {}) {
|
|
923
|
+
if (!this.provider || !this.provider.stream) {
|
|
924
|
+
throw new Error('Streaming PRD generation requires an AI provider with stream() support');
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
for await (const chunk of this.provider.stream(prompt, options)) {
|
|
928
|
+
yield chunk;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
883
932
|
/**
|
|
884
933
|
* Parse PRD with streaming AI analysis
|
|
885
934
|
*
|