@iservu-inc/adf-cli 0.14.6 ā 0.17.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/.project/chats/current/SESSION-STATUS.md +25 -279
- package/.project/docs/PHASE-6-ADVANCED-LEARNING.md +46 -0
- package/.project/docs/ROADMAP.md +72 -157
- package/.project/docs/designs/CUSTOM-ARTIFACT-UPLOAD.md +259 -0
- package/.project/docs/designs/LEARNING-RULES-EXCHANGE.md +77 -0
- package/CHANGELOG.md +2054 -2995
- package/README.md +4 -7
- package/bin/adf.js +80 -0
- package/conductor/tracks/session_resume_review_20260113/plan.md +18 -0
- package/conductor/tracks.md +4 -0
- package/gemini.md +3 -0
- package/lib/ai/ai-client.js +9 -9
- package/lib/commands/deploy.js +14 -0
- package/lib/commands/guide.js +32 -0
- package/lib/commands/import.js +439 -0
- package/lib/commands/init.js +17 -4
- package/lib/frameworks/interviewer.js +277 -85
- package/lib/frameworks/progress-tracker.js +18 -0
- package/lib/generators/a2a-generator.js +289 -0
- package/lib/generators/index.js +11 -0
- package/lib/learning/learning-manager.js +107 -8
- package/lib/learning/rules-exporter.js +103 -0
- package/lib/learning/rules-importer.js +141 -0
- package/lib/templates/shared/agents/analyst.md +1 -1
- package/lib/templates/shared/agents/architect.md +1 -1
- package/lib/templates/shared/agents/dev.md +1 -1
- package/lib/templates/shared/agents/pm.md +2 -2
- package/lib/templates/shared/agents/qa.md +1 -1
- package/lib/templates/shared/agents/sm.md +3 -3
- package/lib/templates/shared/memory/constitution.md +2 -2
- package/lib/templates/shared/templates/README.md +14 -14
- package/lib/templates/shared/templates/prd-template.md +1 -1
- package/lib/utils/artifact-detector.js +253 -0
- package/lib/utils/tool-feature-registry.js +6 -0
- package/package.json +1 -1
- package/tests/a2a-generator.test.js +288 -0
- package/tests/progress-tracker.test.js +16 -0
package/lib/commands/init.js
CHANGED
|
@@ -159,10 +159,14 @@ async function init(options) {
|
|
|
159
159
|
const interviewer = new Interviewer(existingSession.progress.framework || 'balanced', cwd, existingSession, aiConfig);
|
|
160
160
|
const sessionPath = await interviewer.start();
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
if (sessionPath === 'back') {
|
|
163
|
+
// User requested to go back to main menu
|
|
164
|
+
// Fall through to existing content check
|
|
165
|
+
} else {
|
|
166
|
+
console.log(chalk.green.bold('\n⨠Requirements gathering complete!\n'));
|
|
167
|
+
console.log(chalk.cyan(`š Session saved to: ${sessionPath}\n`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
// Check if already initialized with actual content
|
|
@@ -318,6 +322,15 @@ async function init(options) {
|
|
|
318
322
|
console.log(chalk.gray(` ā Files saved to: ${sessionPath}/outputs/`));
|
|
319
323
|
console.log(chalk.gray(` ā You can review your requirements anytime\n`));
|
|
320
324
|
|
|
325
|
+
// Generate A2A agent cards
|
|
326
|
+
try {
|
|
327
|
+
const { generateA2A } = require('../generators');
|
|
328
|
+
await generateA2A(sessionPath, cwd, workflow);
|
|
329
|
+
console.log(chalk.gray(' ā A2A agent cards generated'));
|
|
330
|
+
} catch (error) {
|
|
331
|
+
console.warn(chalk.yellow(` ā Could not generate A2A cards: ${error.message}`));
|
|
332
|
+
}
|
|
333
|
+
|
|
321
334
|
// Optional: Deploy to tool
|
|
322
335
|
if (options.tool) {
|
|
323
336
|
console.log('');
|
|
@@ -344,6 +344,14 @@ class Interviewer {
|
|
|
344
344
|
const resumeInfo = this.progressTracker.getResumeInfo();
|
|
345
345
|
console.log(chalk.gray(`Last updated: ${new Date(resumeInfo.lastUpdated).toLocaleString()}`));
|
|
346
346
|
console.log(chalk.gray(`Progress: ${resumeInfo.completedBlocks}/${resumeInfo.totalBlocks} blocks | ${resumeInfo.totalQuestionsAnswered} questions\n`));
|
|
347
|
+
|
|
348
|
+
// Offer to review existing answers
|
|
349
|
+
const reviewAction = await this.reviewProgress();
|
|
350
|
+
if (reviewAction === 'back') {
|
|
351
|
+
return 'back';
|
|
352
|
+
} else if (reviewAction === 'exit') {
|
|
353
|
+
process.exit(0);
|
|
354
|
+
}
|
|
347
355
|
}
|
|
348
356
|
|
|
349
357
|
console.log(chalk.cyan(`\nā¹ļø Total question blocks: ${questionBlocks.length}\n`));
|
|
@@ -436,6 +444,158 @@ class Interviewer {
|
|
|
436
444
|
return this.sessionPath;
|
|
437
445
|
}
|
|
438
446
|
|
|
447
|
+
async reviewProgress() {
|
|
448
|
+
const answeredIds = Object.keys(this.answers);
|
|
449
|
+
if (answeredIds.length === 0) return 'continue';
|
|
450
|
+
|
|
451
|
+
const { shouldReview } = await inquirer.prompt([
|
|
452
|
+
{
|
|
453
|
+
type: 'confirm',
|
|
454
|
+
name: 'shouldReview',
|
|
455
|
+
message: `Review ${answeredIds.length} previously answered questions?`,
|
|
456
|
+
default: true
|
|
457
|
+
}
|
|
458
|
+
]);
|
|
459
|
+
|
|
460
|
+
if (!shouldReview) return 'continue';
|
|
461
|
+
|
|
462
|
+
// Collect and format Q/A pairs
|
|
463
|
+
const questions = this.customQuestions || getQuestionsForFramework(this.framework);
|
|
464
|
+
const pairs = [];
|
|
465
|
+
|
|
466
|
+
for (const id of answeredIds) {
|
|
467
|
+
const q = questions.find(q => q.id === id);
|
|
468
|
+
if (q) {
|
|
469
|
+
const answerText = typeof this.answers[id] === 'string' ? this.answers[id] : this.answers[id].text;
|
|
470
|
+
pairs.push({
|
|
471
|
+
id: id,
|
|
472
|
+
question: q.text,
|
|
473
|
+
answer: answerText
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Pagination logic
|
|
479
|
+
const terminalHeight = process.stdout.rows || 24;
|
|
480
|
+
const availableHeight = terminalHeight - 6; // Reserve lines for instructions
|
|
481
|
+
|
|
482
|
+
let currentIndex = 0;
|
|
483
|
+
|
|
484
|
+
while (currentIndex < pairs.length) {
|
|
485
|
+
console.clear();
|
|
486
|
+
console.log(chalk.cyan.bold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
487
|
+
console.log(chalk.cyan.bold('Previously Answered Questions'));
|
|
488
|
+
console.log(chalk.cyan.bold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
489
|
+
|
|
490
|
+
let linesUsed = 0;
|
|
491
|
+
let displayedCount = 0;
|
|
492
|
+
|
|
493
|
+
// Calculate how many pairs fit
|
|
494
|
+
for (let i = currentIndex; i < pairs.length; i++) {
|
|
495
|
+
const pair = pairs[i];
|
|
496
|
+
const qNum = (i + 1).toString().padStart(2, '0');
|
|
497
|
+
|
|
498
|
+
// Estimate lines: Question (2) + Answer lines + Spacing (2)
|
|
499
|
+
const answerLines = Math.ceil(pair.answer.length / (process.stdout.columns || 80));
|
|
500
|
+
const pairHeight = 2 + answerLines + 2;
|
|
501
|
+
|
|
502
|
+
if (linesUsed + pairHeight > availableHeight && displayedCount > 0) {
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
console.log(chalk.white.bold(`Q-${qNum}: ${pair.question}`));
|
|
507
|
+
console.log(chalk.green(`A-${qNum}: ${pair.answer}`));
|
|
508
|
+
console.log(chalk.cyan.bold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
509
|
+
|
|
510
|
+
linesUsed += pairHeight;
|
|
511
|
+
displayedCount++;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const nextIndex = currentIndex + displayedCount;
|
|
515
|
+
const isEnd = nextIndex >= pairs.length;
|
|
516
|
+
|
|
517
|
+
console.log('');
|
|
518
|
+
if (isEnd) {
|
|
519
|
+
console.log(chalk.yellow('End of review.'));
|
|
520
|
+
} else {
|
|
521
|
+
console.log(chalk.gray(`... ${pairs.length - nextIndex} more items ...`));
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Navigation prompt
|
|
525
|
+
const { action } = await inquirer.prompt([
|
|
526
|
+
{
|
|
527
|
+
type: 'expand',
|
|
528
|
+
name: 'action',
|
|
529
|
+
message: 'Navigation:',
|
|
530
|
+
choices: [
|
|
531
|
+
{ key: ' ', name: 'Next page', value: 'next' },
|
|
532
|
+
{ key: 'e', name: 'Edit an answer', value: 'edit' },
|
|
533
|
+
{ key: 'c', name: 'Continue interview', value: 'continue' },
|
|
534
|
+
{ key: 'q', name: 'Quit review (Back to menu)', value: 'back' },
|
|
535
|
+
{ key: 'x', name: 'Exit CLI', value: 'exit' }
|
|
536
|
+
],
|
|
537
|
+
default: isEnd ? 1 : 0 // Default to Continue if end, else Next
|
|
538
|
+
}
|
|
539
|
+
]);
|
|
540
|
+
|
|
541
|
+
if (action === 'next') {
|
|
542
|
+
if (isEnd) return 'continue'; // 'Next' at end means continue
|
|
543
|
+
currentIndex = nextIndex;
|
|
544
|
+
} else if (action === 'continue') {
|
|
545
|
+
return 'continue';
|
|
546
|
+
} else if (action === 'back') {
|
|
547
|
+
return 'back';
|
|
548
|
+
} else if (action === 'exit') {
|
|
549
|
+
return 'exit';
|
|
550
|
+
} else if (action === 'edit') {
|
|
551
|
+
// Show list of currently visible questions to edit
|
|
552
|
+
const pagePairs = pairs.slice(currentIndex, nextIndex);
|
|
553
|
+
const { questionToEdit } = await inquirer.prompt([
|
|
554
|
+
{
|
|
555
|
+
type: 'list',
|
|
556
|
+
name: 'questionToEdit',
|
|
557
|
+
message: 'Select a question to edit:',
|
|
558
|
+
choices: [
|
|
559
|
+
...pagePairs.map((p, idx) => ({
|
|
560
|
+
name: p.question.length > 60 ? p.question.substring(0, 57) + '...' : p.question,
|
|
561
|
+
value: currentIndex + idx
|
|
562
|
+
})),
|
|
563
|
+
{ name: 'ā Cancel', value: -1 }
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
]);
|
|
567
|
+
|
|
568
|
+
if (questionToEdit !== -1) {
|
|
569
|
+
const targetPair = pairs[questionToEdit];
|
|
570
|
+
|
|
571
|
+
const { newAnswer } = await inquirer.prompt([
|
|
572
|
+
{
|
|
573
|
+
type: 'editor',
|
|
574
|
+
name: 'newAnswer',
|
|
575
|
+
message: 'Edit your answer:',
|
|
576
|
+
default: targetPair.answer
|
|
577
|
+
}
|
|
578
|
+
]);
|
|
579
|
+
|
|
580
|
+
if (newAnswer && newAnswer.trim()) {
|
|
581
|
+
const trimmedAnswer = newAnswer.trim();
|
|
582
|
+
// Update local state
|
|
583
|
+
this.answers[targetPair.id] = trimmedAnswer;
|
|
584
|
+
pairs[questionToEdit].answer = trimmedAnswer;
|
|
585
|
+
|
|
586
|
+
// Save progress
|
|
587
|
+
await this.progressTracker.updateAnswer(targetPair.id, trimmedAnswer);
|
|
588
|
+
|
|
589
|
+
console.log(chalk.green('ā Answer updated'));
|
|
590
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return 'continue';
|
|
597
|
+
}
|
|
598
|
+
|
|
439
599
|
async promptAIConfiguration() {
|
|
440
600
|
console.log(chalk.cyan.bold('ā'.repeat(60)));
|
|
441
601
|
console.log(chalk.cyan.bold('\nš¤ AI Provider Configuration (Pre-Interview)\n'));
|
|
@@ -557,11 +717,14 @@ class Interviewer {
|
|
|
557
717
|
? this.answers[question.id]
|
|
558
718
|
: this.answers[question.id].text;
|
|
559
719
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
console.log(chalk.
|
|
563
|
-
console.log(chalk.
|
|
564
|
-
console.log(chalk.
|
|
720
|
+
const qNum = (i + 1).toString().padStart(2, '0');
|
|
721
|
+
|
|
722
|
+
console.log(chalk.cyan.bold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
723
|
+
console.log(chalk.cyan.bold('Previously Answered Questions'));
|
|
724
|
+
console.log(chalk.cyan.bold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
725
|
+
console.log(chalk.white.bold(`Q-${qNum}: ${question.text}`));
|
|
726
|
+
console.log(chalk.green(`A-${qNum}: ${answerText}`));
|
|
727
|
+
console.log(chalk.cyan.bold('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
565
728
|
|
|
566
729
|
questionsAnswered++;
|
|
567
730
|
continue;
|
|
@@ -640,13 +803,15 @@ class Interviewer {
|
|
|
640
803
|
console.log(chalk.gray('ā'.repeat(60)));
|
|
641
804
|
console.log(chalk.yellow('š” Type "skip" to skip ⢠Type "exit" or press Ctrl+C to save & exit (resume with: adf init)'));
|
|
642
805
|
console.log(chalk.gray('ā'.repeat(60)));
|
|
806
|
+
console.log(chalk.cyan('Your answer:'));
|
|
643
807
|
|
|
644
808
|
const { answer } = await inquirer.prompt([
|
|
645
809
|
{
|
|
646
810
|
type: 'input',
|
|
647
811
|
name: 'answer',
|
|
648
|
-
message: '
|
|
649
|
-
prefix: ''
|
|
812
|
+
message: ' ',
|
|
813
|
+
prefix: '',
|
|
814
|
+
transformer: (input) => input
|
|
650
815
|
}
|
|
651
816
|
]);
|
|
652
817
|
|
|
@@ -724,103 +889,130 @@ class Interviewer {
|
|
|
724
889
|
});
|
|
725
890
|
}
|
|
726
891
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
await this.dynamicPipeline.processAnswer(question.id, question.text, answer);
|
|
730
|
-
}
|
|
892
|
+
const spinner = ora('Processing reply...').start();
|
|
893
|
+
const startTime = Date.now();
|
|
731
894
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
895
|
+
try {
|
|
896
|
+
// Process answer with Dynamic Pipeline (Phase 4.4)
|
|
897
|
+
if (this.dynamicPipeline) {
|
|
898
|
+
await this.dynamicPipeline.processAnswer(question.id, question.text, answer);
|
|
899
|
+
}
|
|
737
900
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
901
|
+
// Check if answer is comprehensive enough to skip follow-ups
|
|
902
|
+
if (qualityMetrics.canSkipFollowUps) {
|
|
903
|
+
// Ensure minimum 1s duration for UX consistency
|
|
904
|
+
const elapsed = Date.now() - startTime;
|
|
905
|
+
if (elapsed < 1000) {
|
|
906
|
+
await new Promise(resolve => setTimeout(resolve, 1000 - elapsed));
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
spinner.succeed(chalk.green('Saved'));
|
|
910
|
+
console.log('');
|
|
911
|
+
return answer;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Check if answer needs follow-up (only if follow-up questions are enabled)
|
|
915
|
+
let followUp = null;
|
|
916
|
+
|
|
917
|
+
if (this.analysisConfig.features.followUpQuestions) {
|
|
918
|
+
// Try AI-generated follow-up first
|
|
919
|
+
if (this.aiClient && qualityMetrics.issues && qualityMetrics.issues.length > 0 && qualityMetrics.qualityScore < 70) {
|
|
920
|
+
try {
|
|
921
|
+
const aiFollowUp = await this.aiClient.generateFollowUp(question.text, answer, qualityMetrics.issues);
|
|
922
|
+
if (aiFollowUp) {
|
|
923
|
+
followUp = {
|
|
924
|
+
message: "Let me ask a more specific question:",
|
|
925
|
+
question: aiFollowUp
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
} catch (error) {
|
|
929
|
+
// If AI fails, use heuristic fallback
|
|
930
|
+
followUp = this.determineFollowUp(question, answer);
|
|
751
931
|
}
|
|
752
|
-
}
|
|
753
|
-
//
|
|
932
|
+
} else {
|
|
933
|
+
// Use heuristic follow-up
|
|
754
934
|
followUp = this.determineFollowUp(question, answer);
|
|
755
935
|
}
|
|
756
|
-
} else {
|
|
757
|
-
// Use heuristic follow-up
|
|
758
|
-
followUp = this.determineFollowUp(question, answer);
|
|
759
936
|
}
|
|
760
|
-
}
|
|
761
937
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
938
|
+
// Ensure minimum 1s duration for UX consistency
|
|
939
|
+
const elapsed = Date.now() - startTime;
|
|
940
|
+
if (elapsed < 1000) {
|
|
941
|
+
await new Promise(resolve => setTimeout(resolve, 1000 - elapsed));
|
|
942
|
+
}
|
|
765
943
|
|
|
766
|
-
|
|
767
|
-
console.log(chalk.yellow('š” Type "exit" or press Ctrl+C to save & exit (resume with: adf init)'));
|
|
768
|
-
console.log(chalk.gray('ā'.repeat(60)));
|
|
944
|
+
spinner.stop();
|
|
769
945
|
|
|
770
|
-
|
|
771
|
-
{
|
|
772
|
-
|
|
773
|
-
name: 'followUpAnswer',
|
|
774
|
-
message: 'Follow-up answer:',
|
|
775
|
-
prefix: ''
|
|
776
|
-
}
|
|
777
|
-
]);
|
|
946
|
+
if (followUp) {
|
|
947
|
+
console.log(chalk.yellow(`\nš¤ ${followUp.message}`));
|
|
948
|
+
console.log(chalk.yellow(` ${followUp.question}\n`));
|
|
778
949
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
console.log(chalk.
|
|
950
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
951
|
+
console.log(chalk.yellow('š” Type "exit" or press Ctrl+C to save & exit (resume with: adf init)'));
|
|
952
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
782
953
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
954
|
+
console.log(chalk.cyan('Follow-up answer:'));
|
|
955
|
+
const { followUpAnswer } = await inquirer.prompt([
|
|
956
|
+
{
|
|
957
|
+
type: 'input',
|
|
958
|
+
name: 'followUpAnswer',
|
|
959
|
+
message: ' ',
|
|
960
|
+
prefix: '',
|
|
961
|
+
transformer: (input) => input
|
|
962
|
+
}
|
|
963
|
+
]);
|
|
787
964
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
}
|
|
965
|
+
// Handle "exit" keyword - save progress and exit gracefully
|
|
966
|
+
if (followUpAnswer && followUpAnswer.toLowerCase().trim() === 'exit') {
|
|
967
|
+
console.log(chalk.yellow('\nš¾ Saving progress and exiting...'));
|
|
792
968
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
// Re-analyze combined answer
|
|
798
|
-
let combinedMetrics;
|
|
799
|
-
try {
|
|
800
|
-
if (this.aiClient) {
|
|
801
|
-
const aiAnalysis = await this.aiClient.analyzeAnswerQuality(question.text, combined);
|
|
802
|
-
combinedMetrics = {
|
|
803
|
-
wordCount: combined.trim().split(/\s+/).length,
|
|
804
|
-
qualityScore: aiAnalysis.score,
|
|
805
|
-
isComprehensive: aiAnalysis.score >= 70,
|
|
806
|
-
canSkipFollowUps: aiAnalysis.score >= 85
|
|
807
|
-
};
|
|
808
|
-
} else {
|
|
809
|
-
combinedMetrics = AnswerQualityAnalyzer.analyze(combined, question);
|
|
969
|
+
// Ensure progress is saved
|
|
970
|
+
if (this.progressTracker) {
|
|
971
|
+
await this.progressTracker.save();
|
|
810
972
|
}
|
|
811
|
-
|
|
812
|
-
|
|
973
|
+
|
|
974
|
+
console.log(chalk.green('ā Progress saved!'));
|
|
975
|
+
console.log(chalk.cyan('Resume anytime with: adf init\n'));
|
|
976
|
+
process.exit(0);
|
|
813
977
|
}
|
|
814
978
|
|
|
815
|
-
|
|
979
|
+
if (followUpAnswer && followUpAnswer.trim()) {
|
|
980
|
+
// Combine answers
|
|
981
|
+
const combined = `${answer} | Follow-up: ${followUpAnswer}`;
|
|
982
|
+
|
|
983
|
+
// Re-analyze combined answer
|
|
984
|
+
let combinedMetrics;
|
|
985
|
+
try {
|
|
986
|
+
if (this.aiClient) {
|
|
987
|
+
const aiAnalysis = await this.aiClient.analyzeAnswerQuality(question.text, combined);
|
|
988
|
+
combinedMetrics = {
|
|
989
|
+
wordCount: combined.trim().split(/\s+/).length,
|
|
990
|
+
qualityScore: aiAnalysis.score,
|
|
991
|
+
isComprehensive: aiAnalysis.score >= 70,
|
|
992
|
+
canSkipFollowUps: aiAnalysis.score >= 85
|
|
993
|
+
};
|
|
994
|
+
} else {
|
|
995
|
+
combinedMetrics = AnswerQualityAnalyzer.analyze(combined, question);
|
|
996
|
+
}
|
|
997
|
+
} catch {
|
|
998
|
+
combinedMetrics = AnswerQualityAnalyzer.analyze(combined, question);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
await this.progressTracker.answerQuestion(question.id, question.text, combined, combinedMetrics);
|
|
816
1002
|
|
|
817
|
-
|
|
818
|
-
|
|
1003
|
+
console.log(chalk.green('\nā Saved\n'));
|
|
1004
|
+
return combined;
|
|
1005
|
+
}
|
|
819
1006
|
}
|
|
820
|
-
}
|
|
821
1007
|
|
|
822
|
-
|
|
823
|
-
|
|
1008
|
+
console.log(chalk.green('\nā Saved\n'));
|
|
1009
|
+
return answer;
|
|
1010
|
+
|
|
1011
|
+
} catch (err) {
|
|
1012
|
+
spinner.fail('Error processing reply');
|
|
1013
|
+
console.error(err);
|
|
1014
|
+
return answer; // Return original answer on error
|
|
1015
|
+
}
|
|
824
1016
|
}
|
|
825
1017
|
|
|
826
1018
|
determineFollowUp(question, answer) {
|
|
@@ -147,6 +147,24 @@ class ProgressTracker {
|
|
|
147
147
|
await this.saveWithBackup();
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
async updateAnswer(questionId, newText) {
|
|
151
|
+
if (this.progress.answers[questionId]) {
|
|
152
|
+
// Update word count stats
|
|
153
|
+
const oldWordCount = this.progress.answers[questionId].quality.wordCount || 0;
|
|
154
|
+
const newWordCount = newText.trim().split(/\s+/).length;
|
|
155
|
+
this.progress.totalWordCount = this.progress.totalWordCount - oldWordCount + newWordCount;
|
|
156
|
+
|
|
157
|
+
this.progress.answers[questionId].text = newText;
|
|
158
|
+
this.progress.answers[questionId].timestamp = new Date().toISOString();
|
|
159
|
+
|
|
160
|
+
// Update word count in quality metrics
|
|
161
|
+
this.progress.answers[questionId].quality.wordCount = newWordCount;
|
|
162
|
+
|
|
163
|
+
this.progress.lastUpdated = new Date().toISOString();
|
|
164
|
+
await this.saveWithBackup();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
150
168
|
async saveWithBackup() {
|
|
151
169
|
try {
|
|
152
170
|
// Save 1: Main progress file
|