minovative-mind-cli 2.9.1 → 2.11.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.
Files changed (34) hide show
  1. package/README.md +14 -6
  2. package/dist/services/agent/commandApproval.js +5 -2
  3. package/dist/services/agent/slashCommands.js +90 -53
  4. package/dist/services/agent-tools.d.ts +4 -3
  5. package/dist/services/agent-tools.js +32 -79
  6. package/dist/services/agent.d.ts +5 -6
  7. package/dist/services/agent.js +11 -15
  8. package/dist/services/ai.d.ts +21 -1
  9. package/dist/services/ai.js +236 -11
  10. package/dist/services/chatHistoryService.d.ts +95 -2
  11. package/dist/services/chatHistoryService.js +236 -9
  12. package/dist/services/contextAgent.js +196 -81
  13. package/dist/services/investigationComplexity.d.ts +1 -1
  14. package/dist/services/investigationComplexity.js +1 -1
  15. package/dist/services/orchestration/investigationAgent.js +101 -84
  16. package/dist/services/orchestration/investigationCache.d.ts +80 -5
  17. package/dist/services/orchestration/investigationCache.js +570 -41
  18. package/dist/services/orchestration/investigationOrchestrator.js +17 -4
  19. package/dist/services/orchestration/orchestrator.js +6 -3
  20. package/dist/services/orchestration/scopedTools.js +5 -0
  21. package/dist/services/orchestration/subAgent.d.ts +31 -1
  22. package/dist/services/orchestration/subAgent.js +153 -2
  23. package/dist/utils/analysisRunner.d.ts +29 -0
  24. package/dist/utils/analysisRunner.js +200 -5
  25. package/dist/utils/contextPrompts.d.ts +20 -4
  26. package/dist/utils/contextPrompts.js +158 -23
  27. package/dist/utils/historyPrompt.d.ts +92 -1
  28. package/dist/utils/historyPrompt.js +166 -2
  29. package/dist/utils/symbolExtractor.d.ts +12 -0
  30. package/dist/utils/symbolExtractor.js +946 -0
  31. package/dist/utils/systemPrompts.d.ts +5 -4
  32. package/dist/utils/systemPrompts.js +46 -14
  33. package/oclif.manifest.json +1 -1
  34. package/package.json +2 -2
@@ -369,3 +369,949 @@ export function extractSymbols(content, filePath, targetElements) {
369
369
  }
370
370
  return output.join('\n');
371
371
  }
372
+ /**
373
+ * Extracts a compact declarations outline for TypeScript/JavaScript source files.
374
+ *
375
+ * @param lines - File lines
376
+ * @returns Declarations outline
377
+ */
378
+ function extractTsJsOutline(lines) {
379
+ const output = [];
380
+ let docBuffer = [];
381
+ let i = 0;
382
+ const isDocOrDecorator = (line) => {
383
+ const trimmed = line.trim();
384
+ return (trimmed.startsWith('/**') ||
385
+ trimmed.startsWith('*') ||
386
+ trimmed.startsWith('*/') ||
387
+ trimmed.startsWith('//') ||
388
+ trimmed.startsWith('@'));
389
+ };
390
+ while (i < lines.length) {
391
+ const line = lines[i];
392
+ const trimmed = line.trim();
393
+ if (!trimmed) {
394
+ if (docBuffer.length > 0 && docBuffer.every((l) => l.trim().startsWith('//') || l.trim().startsWith('/*'))) {
395
+ docBuffer = [];
396
+ }
397
+ i++;
398
+ continue;
399
+ }
400
+ if (isDocOrDecorator(line)) {
401
+ docBuffer.push(line);
402
+ i++;
403
+ continue;
404
+ }
405
+ // Check for interface
406
+ if (/^(?:export\s+|declare\s+|default\s+)*interface\s+\w+/.test(trimmed)) {
407
+ if (docBuffer.length > 0) {
408
+ output.push(...docBuffer);
409
+ docBuffer = [];
410
+ }
411
+ let braces = 0;
412
+ let foundOpen = false;
413
+ while (i < lines.length) {
414
+ for (const ch of lines[i]) {
415
+ if (ch === '{') {
416
+ braces++;
417
+ foundOpen = true;
418
+ }
419
+ else if (ch === '}') {
420
+ braces--;
421
+ }
422
+ }
423
+ output.push(lines[i]);
424
+ i++;
425
+ if (foundOpen && braces <= 0)
426
+ break;
427
+ }
428
+ output.push('');
429
+ continue;
430
+ }
431
+ // Check for type alias
432
+ if (/^(?:export\s+|declare\s+)*type\s+\w+/.test(trimmed)) {
433
+ if (docBuffer.length > 0) {
434
+ output.push(...docBuffer);
435
+ docBuffer = [];
436
+ }
437
+ let braces = 0;
438
+ let parens = 0;
439
+ let brackets = 0;
440
+ while (i < lines.length) {
441
+ for (const ch of lines[i]) {
442
+ if (ch === '{')
443
+ braces++;
444
+ else if (ch === '}')
445
+ braces--;
446
+ else if (ch === '(')
447
+ parens++;
448
+ else if (ch === ')')
449
+ parens--;
450
+ else if (ch === '[')
451
+ brackets++;
452
+ else if (ch === ']')
453
+ brackets--;
454
+ }
455
+ output.push(lines[i]);
456
+ if (braces <= 0 && parens <= 0 && brackets <= 0 && lines[i].includes(';')) {
457
+ i++;
458
+ break;
459
+ }
460
+ i++;
461
+ }
462
+ output.push('');
463
+ continue;
464
+ }
465
+ // Check for enum
466
+ if (/^(?:export\s+|const\s+|declare\s+)*enum\s+\w+/.test(trimmed)) {
467
+ if (docBuffer.length > 0) {
468
+ output.push(...docBuffer);
469
+ docBuffer = [];
470
+ }
471
+ let braces = 0;
472
+ let foundOpen = false;
473
+ while (i < lines.length) {
474
+ for (const ch of lines[i]) {
475
+ if (ch === '{') {
476
+ braces++;
477
+ foundOpen = true;
478
+ }
479
+ else if (ch === '}') {
480
+ braces--;
481
+ }
482
+ }
483
+ output.push(lines[i]);
484
+ i++;
485
+ if (foundOpen && braces <= 0)
486
+ break;
487
+ }
488
+ output.push('');
489
+ continue;
490
+ }
491
+ // Check for class
492
+ if (/^(?:export\s+|default\s+|abstract\s+|declare\s+)*class\s+\w+/.test(trimmed)) {
493
+ if (docBuffer.length > 0) {
494
+ output.push(...docBuffer);
495
+ docBuffer = [];
496
+ }
497
+ const classHeaderLines = [];
498
+ while (i < lines.length) {
499
+ classHeaderLines.push(lines[i]);
500
+ if (lines[i].includes('{')) {
501
+ i++;
502
+ break;
503
+ }
504
+ i++;
505
+ }
506
+ output.push(classHeaderLines.join('\n'));
507
+ let classBraces = 1;
508
+ let memberDoc = [];
509
+ while (i < lines.length && classBraces > 0) {
510
+ const curLine = lines[i];
511
+ const curTrim = curLine.trim();
512
+ if (!curTrim) {
513
+ memberDoc = [];
514
+ i++;
515
+ continue;
516
+ }
517
+ if (isDocOrDecorator(curLine)) {
518
+ memberDoc.push(curLine);
519
+ i++;
520
+ continue;
521
+ }
522
+ if (curTrim === '}' && classBraces === 1) {
523
+ output.push(curLine);
524
+ i++;
525
+ break;
526
+ }
527
+ const isMethodOrCtor = /^(?:public\s+|private\s+|protected\s+|static\s+|async\s+|abstract\s+|override\s+|readonly\s+|get\s+|set\s+)*(?:constructor|[A-Za-z0-9_$]+)\s*(?:<[^>]+>)?\s*\(/.test(curTrim);
528
+ const isField = /^(?:public\s+|private\s+|protected\s+|static\s+|readonly\s+|declare\s+)*(?:[A-Za-z0-9_$#]+)\s*[:=;]/.test(curTrim);
529
+ if (isMethodOrCtor) {
530
+ if (memberDoc.length > 0) {
531
+ output.push(...memberDoc);
532
+ memberDoc = [];
533
+ }
534
+ const sigLines = [];
535
+ let methodHasBody = false;
536
+ let methodBraces = 0;
537
+ while (i < lines.length) {
538
+ const mLine = lines[i];
539
+ sigLines.push(mLine);
540
+ if (mLine.includes('{')) {
541
+ methodHasBody = true;
542
+ methodBraces = 1;
543
+ i++;
544
+ break;
545
+ }
546
+ if (mLine.trim().endsWith(';')) {
547
+ i++;
548
+ break;
549
+ }
550
+ i++;
551
+ }
552
+ if (methodHasBody) {
553
+ const sig = sigLines.join('\n');
554
+ const braceIdx = sig.lastIndexOf('{');
555
+ const cleanSig = sig.substring(0, braceIdx).trimEnd();
556
+ output.push(cleanSig + ' { ... }');
557
+ while (i < lines.length && methodBraces > 0) {
558
+ for (const ch of lines[i]) {
559
+ if (ch === '{')
560
+ methodBraces++;
561
+ else if (ch === '}')
562
+ methodBraces--;
563
+ }
564
+ i++;
565
+ }
566
+ }
567
+ else {
568
+ output.push(sigLines.join('\n'));
569
+ }
570
+ continue;
571
+ }
572
+ else if (isField) {
573
+ if (memberDoc.length > 0) {
574
+ output.push(...memberDoc);
575
+ memberDoc = [];
576
+ }
577
+ output.push(curLine);
578
+ i++;
579
+ continue;
580
+ }
581
+ else {
582
+ for (const ch of curLine) {
583
+ if (ch === '{')
584
+ classBraces++;
585
+ else if (ch === '}')
586
+ classBraces--;
587
+ }
588
+ if (classBraces === 0) {
589
+ output.push(curLine);
590
+ }
591
+ i++;
592
+ }
593
+ }
594
+ output.push('');
595
+ continue;
596
+ }
597
+ // Check for top-level function
598
+ if (/^(?:export\s+|default\s+|async\s+|declare\s+)*function(?:\s*\*|\s+\w+)/.test(trimmed)) {
599
+ if (docBuffer.length > 0) {
600
+ output.push(...docBuffer);
601
+ docBuffer = [];
602
+ }
603
+ const sigLines = [];
604
+ let fnBraces = 0;
605
+ let hasBody = false;
606
+ while (i < lines.length) {
607
+ const fLine = lines[i];
608
+ sigLines.push(fLine);
609
+ if (fLine.includes('{')) {
610
+ hasBody = true;
611
+ fnBraces = 1;
612
+ i++;
613
+ break;
614
+ }
615
+ if (fLine.trim().endsWith(';')) {
616
+ i++;
617
+ break;
618
+ }
619
+ i++;
620
+ }
621
+ if (hasBody) {
622
+ const sig = sigLines.join('\n');
623
+ const braceIdx = sig.lastIndexOf('{');
624
+ const cleanSig = sig.substring(0, braceIdx).trimEnd();
625
+ output.push(cleanSig + ' { ... }');
626
+ while (i < lines.length && fnBraces > 0) {
627
+ for (const ch of lines[i]) {
628
+ if (ch === '{')
629
+ fnBraces++;
630
+ else if (ch === '}')
631
+ fnBraces--;
632
+ }
633
+ i++;
634
+ }
635
+ }
636
+ else {
637
+ output.push(sigLines.join('\n'));
638
+ }
639
+ output.push('');
640
+ continue;
641
+ }
642
+ // Check for const / let / var function or export
643
+ if (/^(?:export\s+)?(?:const|let|var)\s+\w+/.test(trimmed)) {
644
+ if (docBuffer.length > 0) {
645
+ output.push(...docBuffer);
646
+ docBuffer = [];
647
+ }
648
+ if (trimmed.includes('=>') && trimmed.includes('{')) {
649
+ const sigLines = [];
650
+ let arrowBraces = 0;
651
+ while (i < lines.length) {
652
+ const aLine = lines[i];
653
+ sigLines.push(aLine);
654
+ if (aLine.includes('{')) {
655
+ arrowBraces = 1;
656
+ i++;
657
+ break;
658
+ }
659
+ i++;
660
+ }
661
+ const sig = sigLines.join('\n');
662
+ const braceIdx = sig.lastIndexOf('{');
663
+ output.push(sig.substring(0, braceIdx).trimEnd() + ' { ... };');
664
+ while (i < lines.length && arrowBraces > 0) {
665
+ for (const ch of lines[i]) {
666
+ if (ch === '{')
667
+ arrowBraces++;
668
+ else if (ch === '}')
669
+ arrowBraces--;
670
+ }
671
+ i++;
672
+ }
673
+ output.push('');
674
+ continue;
675
+ }
676
+ else if (trimmed.includes('=>')) {
677
+ output.push(line);
678
+ i++;
679
+ continue;
680
+ }
681
+ else {
682
+ output.push(line);
683
+ i++;
684
+ continue;
685
+ }
686
+ }
687
+ docBuffer = [];
688
+ i++;
689
+ }
690
+ return output.join('\n').trim();
691
+ }
692
+ /**
693
+ * Extracts a compact declarations outline for Python source files.
694
+ *
695
+ * @param lines - File lines
696
+ * @returns Declarations outline
697
+ */
698
+ function extractPythonOutline(lines) {
699
+ const output = [];
700
+ let docBuffer = [];
701
+ let i = 0;
702
+ const isDocOrDecorator = (line) => {
703
+ const trimmed = line.trim();
704
+ return trimmed.startsWith('#') || trimmed.startsWith('@');
705
+ };
706
+ while (i < lines.length) {
707
+ const line = lines[i];
708
+ const trimmed = line.trim();
709
+ if (!trimmed) {
710
+ if (docBuffer.length > 0 && docBuffer.every((l) => l.trim().startsWith('#'))) {
711
+ docBuffer = [];
712
+ }
713
+ i++;
714
+ continue;
715
+ }
716
+ if (isDocOrDecorator(line)) {
717
+ docBuffer.push(line);
718
+ i++;
719
+ continue;
720
+ }
721
+ // Class definition
722
+ if (/^class\s+\w+/.test(trimmed)) {
723
+ if (docBuffer.length > 0) {
724
+ output.push(...docBuffer);
725
+ docBuffer = [];
726
+ }
727
+ const classBaseIndent = getIndentation(line);
728
+ const classHeaderLines = [];
729
+ while (i < lines.length) {
730
+ classHeaderLines.push(lines[i]);
731
+ if (lines[i].trim().endsWith(':') || lines[i].includes(':')) {
732
+ i++;
733
+ break;
734
+ }
735
+ i++;
736
+ }
737
+ output.push(classHeaderLines.join('\n'));
738
+ let methodDoc = [];
739
+ let inClassDocstring = false;
740
+ let docstringChar = null;
741
+ while (i < lines.length) {
742
+ const cLine = lines[i];
743
+ const cTrim = cLine.trim();
744
+ const cIndent = getIndentation(cLine);
745
+ if (!cTrim) {
746
+ i++;
747
+ continue;
748
+ }
749
+ if (cIndent <= classBaseIndent && !inClassDocstring) {
750
+ break;
751
+ }
752
+ if (inClassDocstring) {
753
+ output.push(cLine);
754
+ if (docstringChar && (cTrim.endsWith(docstringChar) || cTrim.includes(docstringChar))) {
755
+ inClassDocstring = false;
756
+ }
757
+ i++;
758
+ continue;
759
+ }
760
+ if (cTrim.startsWith('"""') || cTrim.startsWith("'''")) {
761
+ const delim = cTrim.startsWith('"""') ? '"""' : "'''";
762
+ output.push(cLine);
763
+ if (cTrim.length > 3 && cTrim.endsWith(delim) && cTrim.indexOf(delim, 3) !== -1) {
764
+ // single line docstring
765
+ }
766
+ else {
767
+ inClassDocstring = true;
768
+ docstringChar = delim;
769
+ }
770
+ i++;
771
+ continue;
772
+ }
773
+ if (isDocOrDecorator(cLine)) {
774
+ methodDoc.push(cLine);
775
+ i++;
776
+ continue;
777
+ }
778
+ if (/^(?:async\s+)?def\s+\w+/.test(cTrim)) {
779
+ if (methodDoc.length > 0) {
780
+ output.push(...methodDoc);
781
+ methodDoc = [];
782
+ }
783
+ const methodIndent = cIndent;
784
+ const methodSigLines = [];
785
+ while (i < lines.length) {
786
+ methodSigLines.push(lines[i]);
787
+ if (lines[i].trim().endsWith(':') || lines[i].includes(':')) {
788
+ i++;
789
+ break;
790
+ }
791
+ i++;
792
+ }
793
+ output.push(methodSigLines.join('\n'));
794
+ const pad = ' '.repeat(methodIndent + 4);
795
+ output.push(`${pad}...`);
796
+ while (i < lines.length) {
797
+ const bLine = lines[i];
798
+ const bTrim = bLine.trim();
799
+ const bIndent = getIndentation(bLine);
800
+ if (!bTrim) {
801
+ i++;
802
+ continue;
803
+ }
804
+ if (bIndent <= methodIndent)
805
+ break;
806
+ i++;
807
+ }
808
+ continue;
809
+ }
810
+ if (cTrim.includes(':') || cTrim.includes('=')) {
811
+ if (methodDoc.length > 0) {
812
+ output.push(...methodDoc);
813
+ methodDoc = [];
814
+ }
815
+ output.push(cLine);
816
+ i++;
817
+ continue;
818
+ }
819
+ methodDoc = [];
820
+ i++;
821
+ }
822
+ output.push('');
823
+ continue;
824
+ }
825
+ // Top-level function
826
+ if (/^(?:async\s+)?def\s+\w+/.test(trimmed)) {
827
+ if (docBuffer.length > 0) {
828
+ output.push(...docBuffer);
829
+ docBuffer = [];
830
+ }
831
+ const fnIndent = getIndentation(line);
832
+ const fnSigLines = [];
833
+ while (i < lines.length) {
834
+ fnSigLines.push(lines[i]);
835
+ if (lines[i].trim().endsWith(':') || lines[i].includes(':')) {
836
+ i++;
837
+ break;
838
+ }
839
+ i++;
840
+ }
841
+ output.push(fnSigLines.join('\n'));
842
+ const pad = ' '.repeat(fnIndent + 4);
843
+ output.push(`${pad}...`);
844
+ while (i < lines.length) {
845
+ const bLine = lines[i];
846
+ const bTrim = bLine.trim();
847
+ const bIndent = getIndentation(bLine);
848
+ if (!bTrim) {
849
+ i++;
850
+ continue;
851
+ }
852
+ if (bIndent <= fnIndent)
853
+ break;
854
+ i++;
855
+ }
856
+ output.push('');
857
+ continue;
858
+ }
859
+ // Global variable / type alias
860
+ if (trimmed.includes(':') || trimmed.includes('=')) {
861
+ if (docBuffer.length > 0) {
862
+ output.push(...docBuffer);
863
+ docBuffer = [];
864
+ }
865
+ output.push(line);
866
+ i++;
867
+ continue;
868
+ }
869
+ docBuffer = [];
870
+ i++;
871
+ }
872
+ return output.join('\n').trim();
873
+ }
874
+ /**
875
+ * Extracts a compact declarations outline for Go source files.
876
+ *
877
+ * @param lines - File lines
878
+ * @returns Declarations outline
879
+ */
880
+ function extractGoOutline(lines) {
881
+ const output = [];
882
+ let docBuffer = [];
883
+ let i = 0;
884
+ const isComment = (line) => {
885
+ const trimmed = line.trim();
886
+ return trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*');
887
+ };
888
+ while (i < lines.length) {
889
+ const line = lines[i];
890
+ const trimmed = line.trim();
891
+ if (!trimmed) {
892
+ docBuffer = [];
893
+ i++;
894
+ continue;
895
+ }
896
+ if (isComment(line)) {
897
+ docBuffer.push(line);
898
+ i++;
899
+ continue;
900
+ }
901
+ // Package statement
902
+ if (/^package\s+\w+/.test(trimmed)) {
903
+ output.push(line);
904
+ output.push('');
905
+ docBuffer = [];
906
+ i++;
907
+ continue;
908
+ }
909
+ // Type definition (struct, interface, alias)
910
+ if (/^type\s+\w+/.test(trimmed)) {
911
+ if (docBuffer.length > 0) {
912
+ output.push(...docBuffer);
913
+ docBuffer = [];
914
+ }
915
+ let braces = 0;
916
+ let parens = 0;
917
+ let foundBlock = false;
918
+ while (i < lines.length) {
919
+ for (const ch of lines[i]) {
920
+ if (ch === '{') {
921
+ braces++;
922
+ foundBlock = true;
923
+ }
924
+ else if (ch === '}') {
925
+ braces--;
926
+ }
927
+ else if (ch === '(') {
928
+ parens++;
929
+ foundBlock = true;
930
+ }
931
+ else if (ch === ')') {
932
+ parens--;
933
+ }
934
+ }
935
+ output.push(lines[i]);
936
+ i++;
937
+ if (foundBlock && braces <= 0 && parens <= 0)
938
+ break;
939
+ if (!foundBlock && (lines[i - 1].trim().endsWith(';') || !lines[i - 1].includes('{')))
940
+ break;
941
+ }
942
+ output.push('');
943
+ continue;
944
+ }
945
+ // Const / Var blocks
946
+ if (/^(?:const|var)\s*(?:\(|$)/.test(trimmed)) {
947
+ if (docBuffer.length > 0) {
948
+ output.push(...docBuffer);
949
+ docBuffer = [];
950
+ }
951
+ let parens = 0;
952
+ let foundParen = false;
953
+ while (i < lines.length) {
954
+ for (const ch of lines[i]) {
955
+ if (ch === '(') {
956
+ parens++;
957
+ foundParen = true;
958
+ }
959
+ else if (ch === ')') {
960
+ parens--;
961
+ }
962
+ }
963
+ output.push(lines[i]);
964
+ i++;
965
+ if (foundParen && parens <= 0)
966
+ break;
967
+ if (!foundParen)
968
+ break;
969
+ }
970
+ output.push('');
971
+ continue;
972
+ }
973
+ // Single-line const / var
974
+ if (/^(?:const|var)\s+\w+/.test(trimmed)) {
975
+ if (docBuffer.length > 0) {
976
+ output.push(...docBuffer);
977
+ docBuffer = [];
978
+ }
979
+ output.push(line);
980
+ output.push('');
981
+ i++;
982
+ continue;
983
+ }
984
+ // Function or Method
985
+ if (/^func\s+(?:\([^)]+\)\s+)?\w+/.test(trimmed)) {
986
+ if (docBuffer.length > 0) {
987
+ output.push(...docBuffer);
988
+ docBuffer = [];
989
+ }
990
+ const sigLines = [];
991
+ let fnBraces = 0;
992
+ let hasBody = false;
993
+ while (i < lines.length) {
994
+ const fLine = lines[i];
995
+ sigLines.push(fLine);
996
+ if (fLine.includes('{')) {
997
+ hasBody = true;
998
+ fnBraces = 1;
999
+ i++;
1000
+ break;
1001
+ }
1002
+ i++;
1003
+ }
1004
+ if (hasBody) {
1005
+ const sig = sigLines.join('\n');
1006
+ const braceIdx = sig.lastIndexOf('{');
1007
+ const cleanSig = sig.substring(0, braceIdx).trimEnd();
1008
+ output.push(cleanSig + ' { ... }');
1009
+ while (i < lines.length && fnBraces > 0) {
1010
+ for (const ch of lines[i]) {
1011
+ if (ch === '{')
1012
+ fnBraces++;
1013
+ else if (ch === '}')
1014
+ fnBraces--;
1015
+ }
1016
+ i++;
1017
+ }
1018
+ }
1019
+ else {
1020
+ output.push(sigLines.join('\n'));
1021
+ }
1022
+ output.push('');
1023
+ continue;
1024
+ }
1025
+ docBuffer = [];
1026
+ i++;
1027
+ }
1028
+ return output.join('\n').trim();
1029
+ }
1030
+ /**
1031
+ * Extracts a compact declarations outline for Rust source files.
1032
+ *
1033
+ * @param lines - File lines
1034
+ * @returns Declarations outline
1035
+ */
1036
+ function extractRustOutline(lines) {
1037
+ const output = [];
1038
+ let docBuffer = [];
1039
+ let i = 0;
1040
+ const isDocOrAttr = (line) => {
1041
+ const trimmed = line.trim();
1042
+ return (trimmed.startsWith('///') ||
1043
+ trimmed.startsWith('//!') ||
1044
+ trimmed.startsWith('//') ||
1045
+ trimmed.startsWith('/*') ||
1046
+ trimmed.startsWith('*') ||
1047
+ trimmed.startsWith('#['));
1048
+ };
1049
+ while (i < lines.length) {
1050
+ const line = lines[i];
1051
+ const trimmed = line.trim();
1052
+ if (!trimmed) {
1053
+ if (docBuffer.length > 0 && docBuffer.every((l) => l.trim().startsWith('//'))) {
1054
+ docBuffer = [];
1055
+ }
1056
+ i++;
1057
+ continue;
1058
+ }
1059
+ if (isDocOrAttr(line)) {
1060
+ docBuffer.push(line);
1061
+ i++;
1062
+ continue;
1063
+ }
1064
+ // Struct, Enum, Trait
1065
+ if (/^(?:pub(?:\([^)]+\))?\s+)?(?:struct|enum|trait)\s+\w+/.test(trimmed)) {
1066
+ if (docBuffer.length > 0) {
1067
+ output.push(...docBuffer);
1068
+ docBuffer = [];
1069
+ }
1070
+ if (trimmed.endsWith(';')) {
1071
+ output.push(line);
1072
+ output.push('');
1073
+ i++;
1074
+ continue;
1075
+ }
1076
+ let braces = 0;
1077
+ let foundOpen = false;
1078
+ while (i < lines.length) {
1079
+ for (const ch of lines[i]) {
1080
+ if (ch === '{') {
1081
+ braces++;
1082
+ foundOpen = true;
1083
+ }
1084
+ else if (ch === '}') {
1085
+ braces--;
1086
+ }
1087
+ }
1088
+ output.push(lines[i]);
1089
+ i++;
1090
+ if (foundOpen && braces <= 0)
1091
+ break;
1092
+ if (!foundOpen && lines[i - 1].trim().endsWith(';'))
1093
+ break;
1094
+ }
1095
+ output.push('');
1096
+ continue;
1097
+ }
1098
+ // Type alias or Const / Static
1099
+ if (/^(?:pub(?:\([^)]+\))?\s+)?(?:type|const|static)\s+\w+/.test(trimmed)) {
1100
+ if (docBuffer.length > 0) {
1101
+ output.push(...docBuffer);
1102
+ docBuffer = [];
1103
+ }
1104
+ let braces = 0;
1105
+ let parens = 0;
1106
+ while (i < lines.length) {
1107
+ for (const ch of lines[i]) {
1108
+ if (ch === '{')
1109
+ braces++;
1110
+ else if (ch === '}')
1111
+ braces--;
1112
+ else if (ch === '(')
1113
+ parens++;
1114
+ else if (ch === ')')
1115
+ parens--;
1116
+ }
1117
+ output.push(lines[i]);
1118
+ if (braces <= 0 && parens <= 0 && lines[i].includes(';')) {
1119
+ i++;
1120
+ break;
1121
+ }
1122
+ i++;
1123
+ }
1124
+ output.push('');
1125
+ continue;
1126
+ }
1127
+ // Impl block
1128
+ if (/^(?:pub(?:\([^)]+\))?\s+)?impl(?:\s+<[^>]+>)?\s+/.test(trimmed)) {
1129
+ if (docBuffer.length > 0) {
1130
+ output.push(...docBuffer);
1131
+ docBuffer = [];
1132
+ }
1133
+ const implHeaderLines = [];
1134
+ while (i < lines.length) {
1135
+ implHeaderLines.push(lines[i]);
1136
+ if (lines[i].includes('{')) {
1137
+ i++;
1138
+ break;
1139
+ }
1140
+ i++;
1141
+ }
1142
+ output.push(implHeaderLines.join('\n'));
1143
+ let implBraces = 1;
1144
+ let memberDoc = [];
1145
+ while (i < lines.length && implBraces > 0) {
1146
+ const curLine = lines[i];
1147
+ const curTrim = curLine.trim();
1148
+ if (!curTrim) {
1149
+ memberDoc = [];
1150
+ i++;
1151
+ continue;
1152
+ }
1153
+ if (isDocOrAttr(curLine)) {
1154
+ memberDoc.push(curLine);
1155
+ i++;
1156
+ continue;
1157
+ }
1158
+ if (curTrim === '}' && implBraces === 1) {
1159
+ output.push(curLine);
1160
+ i++;
1161
+ break;
1162
+ }
1163
+ if (/^(?:pub(?:\([^)]+\))?\s+)?(?:async\s+|const\s+|unsafe\s+|extern\s+)*fn\s+\w+/.test(curTrim)) {
1164
+ if (memberDoc.length > 0) {
1165
+ output.push(...memberDoc);
1166
+ memberDoc = [];
1167
+ }
1168
+ const sigLines = [];
1169
+ let fnBraces = 0;
1170
+ let hasBody = false;
1171
+ while (i < lines.length) {
1172
+ const fLine = lines[i];
1173
+ sigLines.push(fLine);
1174
+ if (fLine.includes('{')) {
1175
+ hasBody = true;
1176
+ fnBraces = 1;
1177
+ i++;
1178
+ break;
1179
+ }
1180
+ if (fLine.trim().endsWith(';')) {
1181
+ i++;
1182
+ break;
1183
+ }
1184
+ i++;
1185
+ }
1186
+ if (hasBody) {
1187
+ const sig = sigLines.join('\n');
1188
+ const braceIdx = sig.lastIndexOf('{');
1189
+ const cleanSig = sig.substring(0, braceIdx).trimEnd();
1190
+ output.push(cleanSig + ' { ... }');
1191
+ while (i < lines.length && fnBraces > 0) {
1192
+ for (const ch of lines[i]) {
1193
+ if (ch === '{')
1194
+ fnBraces++;
1195
+ else if (ch === '}')
1196
+ fnBraces--;
1197
+ }
1198
+ i++;
1199
+ }
1200
+ }
1201
+ else {
1202
+ output.push(sigLines.join('\n'));
1203
+ }
1204
+ continue;
1205
+ }
1206
+ else if (/^(?:pub(?:\([^)]+\))?\s+)?(?:type|const)\s+\w+/.test(curTrim)) {
1207
+ if (memberDoc.length > 0) {
1208
+ output.push(...memberDoc);
1209
+ memberDoc = [];
1210
+ }
1211
+ output.push(curLine);
1212
+ i++;
1213
+ continue;
1214
+ }
1215
+ else {
1216
+ for (const ch of curLine) {
1217
+ if (ch === '{')
1218
+ implBraces++;
1219
+ else if (ch === '}')
1220
+ implBraces--;
1221
+ }
1222
+ if (implBraces === 0) {
1223
+ output.push(curLine);
1224
+ }
1225
+ i++;
1226
+ }
1227
+ }
1228
+ output.push('');
1229
+ continue;
1230
+ }
1231
+ // Free fn
1232
+ if (/^(?:pub(?:\([^)]+\))?\s+)?(?:async\s+|const\s+|unsafe\s+|extern\s+)*fn\s+\w+/.test(trimmed)) {
1233
+ if (docBuffer.length > 0) {
1234
+ output.push(...docBuffer);
1235
+ docBuffer = [];
1236
+ }
1237
+ const sigLines = [];
1238
+ let fnBraces = 0;
1239
+ let hasBody = false;
1240
+ while (i < lines.length) {
1241
+ const fLine = lines[i];
1242
+ sigLines.push(fLine);
1243
+ if (fLine.includes('{')) {
1244
+ hasBody = true;
1245
+ fnBraces = 1;
1246
+ i++;
1247
+ break;
1248
+ }
1249
+ if (fLine.trim().endsWith(';')) {
1250
+ i++;
1251
+ break;
1252
+ }
1253
+ i++;
1254
+ }
1255
+ if (hasBody) {
1256
+ const sig = sigLines.join('\n');
1257
+ const braceIdx = sig.lastIndexOf('{');
1258
+ const cleanSig = sig.substring(0, braceIdx).trimEnd();
1259
+ output.push(cleanSig + ' { ... }');
1260
+ while (i < lines.length && fnBraces > 0) {
1261
+ for (const ch of lines[i]) {
1262
+ if (ch === '{')
1263
+ fnBraces++;
1264
+ else if (ch === '}')
1265
+ fnBraces--;
1266
+ }
1267
+ i++;
1268
+ }
1269
+ }
1270
+ else {
1271
+ output.push(sigLines.join('\n'));
1272
+ }
1273
+ output.push('');
1274
+ continue;
1275
+ }
1276
+ docBuffer = [];
1277
+ i++;
1278
+ }
1279
+ return output.join('\n').trim();
1280
+ }
1281
+ /**
1282
+ * Extracts a compact declarations outline (type/interface definitions, class skeletons,
1283
+ * and function signatures without full implementation bodies) across TypeScript/JavaScript,
1284
+ * Python, Go, and Rust.
1285
+ *
1286
+ * This dramatically reduces token usage when injecting multi-file context into prompts.
1287
+ *
1288
+ * @param content - Raw source code content
1289
+ * @param filePath - File path used to infer language and syntax rules
1290
+ * @returns Compact declarations outline string
1291
+ */
1292
+ export function extractDeclarationsOutline(content, filePath) {
1293
+ if (!content || !content.trim())
1294
+ return '';
1295
+ const ext = path.extname(filePath).toLowerCase();
1296
+ const lines = content.split('\n');
1297
+ switch (ext) {
1298
+ case '.ts':
1299
+ case '.tsx':
1300
+ case '.js':
1301
+ case '.jsx':
1302
+ case '.mjs':
1303
+ case '.cjs':
1304
+ case '.mts':
1305
+ case '.cts':
1306
+ return extractTsJsOutline(lines);
1307
+ case '.py':
1308
+ case '.pyi':
1309
+ return extractPythonOutline(lines);
1310
+ case '.go':
1311
+ return extractGoOutline(lines);
1312
+ case '.rs':
1313
+ return extractRustOutline(lines);
1314
+ default:
1315
+ return content.trim();
1316
+ }
1317
+ }