wogiflow 1.0.12 → 1.0.13

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/.workflow/specs/architecture.md.template +24 -0
  2. package/.workflow/specs/stack.md.template +33 -0
  3. package/.workflow/specs/testing.md.template +36 -0
  4. package/README.md +90 -1
  5. package/package.json +1 -1
  6. package/scripts/MEMORY-ARCHITECTURE.md +150 -0
  7. package/scripts/flow +20 -19
  8. package/scripts/flow-auto-context.js +97 -3
  9. package/scripts/flow-conflict-resolver.js +735 -0
  10. package/scripts/flow-context-gatherer.js +520 -0
  11. package/scripts/flow-context-monitor.js +148 -19
  12. package/scripts/flow-damage-control.js +5 -1
  13. package/scripts/flow-export-profile +168 -1
  14. package/scripts/flow-import-profile +257 -6
  15. package/scripts/flow-instruction-richness.js +182 -18
  16. package/scripts/flow-knowledge-router.js +2 -0
  17. package/scripts/flow-knowledge-sync.js +2 -0
  18. package/scripts/{flow-transcript-chunking.js → flow-long-input-chunking.js} +4 -2
  19. package/scripts/{flow-transcript-parsing.js → flow-long-input-parsing.js} +35 -0
  20. package/scripts/{flow-transcript-stories.js → flow-long-input-stories.js} +86 -38
  21. package/scripts/{flow-transcript-digest.js → flow-long-input.js} +231 -15
  22. package/scripts/flow-memory-db.js +386 -1
  23. package/scripts/flow-memory-sync.js +2 -0
  24. package/scripts/flow-model-adapter.js +53 -29
  25. package/scripts/flow-model-router.js +246 -1
  26. package/scripts/flow-morning.js +94 -0
  27. package/scripts/flow-onboard +223 -10
  28. package/scripts/flow-orchestrate-validation.js +539 -0
  29. package/scripts/flow-orchestrate.js +16 -507
  30. package/scripts/flow-pattern-extractor.js +1265 -0
  31. package/scripts/flow-prompt-composer.js +222 -2
  32. package/scripts/flow-quality-guard.js +594 -0
  33. package/scripts/flow-section-index.js +713 -0
  34. package/scripts/flow-section-resolver.js +484 -0
  35. package/scripts/flow-session-end.js +188 -2
  36. package/scripts/flow-skill-create.js +19 -3
  37. package/scripts/flow-skill-matcher.js +122 -7
  38. package/scripts/flow-statusline-setup.js +218 -0
  39. package/scripts/flow-step-review.js +19 -0
  40. package/scripts/flow-tech-debt.js +734 -0
  41. package/scripts/flow-utils.js +2 -0
  42. package/scripts/hooks/core/long-input-gate.js +293 -0
  43. package/scripts/flow-parallel-detector.js +0 -399
  44. package/scripts/flow-parallel-dispatch.js +0 -987
  45. /package/scripts/{flow-transcript-language.js → flow-long-input-language.js} +0 -0
@@ -28,12 +28,23 @@ const {
28
28
  safeJsonParse,
29
29
  getConfig,
30
30
  printHeader,
31
- printSection
31
+ printSection,
32
+ estimateTokens
32
33
  } = require('./flow-utils');
33
34
 
34
35
  const { analyzeTask } = require('./flow-task-analyzer');
35
36
  const { loadRegistry, loadStats } = require('./flow-models');
36
37
 
38
+ // Smart Context System integration
39
+ let contextGatherer = null;
40
+ let instructionRichness = null;
41
+ try {
42
+ contextGatherer = require('./flow-context-gatherer');
43
+ instructionRichness = require('./flow-instruction-richness');
44
+ } catch (err) {
45
+ // Smart Context modules not available
46
+ }
47
+
37
48
  // Phase 3: Import cascade fallback (cached singleton)
38
49
  let cascadeModule = null;
39
50
  try {
@@ -654,6 +665,236 @@ function getRoutingConfig() {
654
665
  };
655
666
  }
656
667
 
668
+ // ============================================================
669
+ // Phase 4: Single Model Evaluation (Smart Context Integration)
670
+ // ============================================================
671
+
672
+ /**
673
+ * Evaluate if a single model can handle a task.
674
+ * Used when user has only one additional model configured.
675
+ *
676
+ * @param {Object} params - Evaluation parameters
677
+ * @param {string} params.modelId - Model identifier
678
+ * @param {Object} params.analysis - Task analysis
679
+ * @param {string} params.taskDescription - Task description for context estimation
680
+ * @returns {Promise<Object>} Evaluation result
681
+ */
682
+ async function evaluateSingleModel(params) {
683
+ const { modelId, analysis, taskDescription = '' } = params;
684
+
685
+ // Load registry
686
+ const registry = loadRegistry();
687
+ if (!registry) {
688
+ return { canHandle: false, reason: 'Model registry not found' };
689
+ }
690
+
691
+ // Find model
692
+ const model = registry.models?.[modelId];
693
+ if (!model) {
694
+ return { canHandle: false, reason: `Model not found: ${modelId}` };
695
+ }
696
+
697
+ // 1. Check capabilities
698
+ const requiredCaps = new Set(analysis.capabilities || []);
699
+ const modelCaps = new Set(model.capabilities || []);
700
+ const missingCaps = [];
701
+
702
+ for (const cap of requiredCaps) {
703
+ if (!modelCaps.has(cap)) {
704
+ missingCaps.push(cap);
705
+ }
706
+ }
707
+
708
+ if (missingCaps.length > 0) {
709
+ return {
710
+ canHandle: false,
711
+ reason: 'Missing capabilities',
712
+ missing: missingCaps,
713
+ modelCapabilities: model.capabilities,
714
+ requiredCapabilities: [...requiredCaps]
715
+ };
716
+ }
717
+
718
+ // 2. Check language proficiency
719
+ const primaryLang = analysis.languages?.primary;
720
+ if (primaryLang) {
721
+ const langCheck = checkLanguageProficiency(model, primaryLang);
722
+ if (!langCheck.meets) {
723
+ return {
724
+ canHandle: false,
725
+ reason: langCheck.reason,
726
+ proficiency: langCheck.proficiency,
727
+ required: langCheck.required
728
+ };
729
+ }
730
+ }
731
+
732
+ // 3. Estimate context requirements
733
+ let contextRequirements = null;
734
+ let estimatedTaskTokens = 0;
735
+
736
+ if (contextGatherer && taskDescription) {
737
+ // Use Smart Context to estimate what context this task needs
738
+ const contextResult = await contextGatherer.gatherContext({
739
+ task: taskDescription,
740
+ model: modelId,
741
+ format: 'summary' // Use summary for estimation
742
+ });
743
+
744
+ contextRequirements = {
745
+ sectionsNeeded: contextResult.stats?.sectionsIncluded || 0,
746
+ tokensEstimated: contextResult.stats?.totalTokens || 0,
747
+ budgetUsed: contextResult.stats?.budgetUsed || '0%',
748
+ modelDensity: contextResult.stats?.modelPrefs?.density || 'standard'
749
+ };
750
+
751
+ // Estimate total task tokens (context + task + buffer for output)
752
+ const taskTextTokens = estimateTokens?.(taskDescription) || Math.ceil(taskDescription.length / 4);
753
+ const outputBuffer = model.maxOutputTokens ? model.maxOutputTokens * 0.5 : 4000;
754
+
755
+ estimatedTaskTokens = contextRequirements.tokensEstimated + taskTextTokens + outputBuffer;
756
+ } else {
757
+ // Fallback estimation without Smart Context
758
+ const taskTextTokens = estimateTokens?.(taskDescription) || Math.ceil(taskDescription.length / 4);
759
+ const baseContextEstimate = 5000; // Conservative base estimate
760
+ const outputBuffer = model.maxOutputTokens ? model.maxOutputTokens * 0.5 : 4000;
761
+
762
+ estimatedTaskTokens = taskTextTokens + baseContextEstimate + outputBuffer;
763
+
764
+ contextRequirements = {
765
+ sectionsNeeded: 'unknown',
766
+ tokensEstimated: baseContextEstimate,
767
+ budgetUsed: 'estimated',
768
+ modelDensity: 'standard'
769
+ };
770
+ }
771
+
772
+ // 4. Check if task fits in context window
773
+ const contextWindow = model.contextWindow || 128000;
774
+ const usableContext = contextWindow * 0.7; // Reserve 30% buffer
775
+
776
+ if (estimatedTaskTokens > usableContext) {
777
+ return {
778
+ canHandle: false,
779
+ reason: 'Context too large for model',
780
+ estimatedTokens: estimatedTaskTokens,
781
+ contextWindow,
782
+ usableContext: Math.floor(usableContext),
783
+ overflow: estimatedTaskTokens - usableContext
784
+ };
785
+ }
786
+
787
+ // 5. Calculate estimated cost
788
+ let estimatedCost = null;
789
+ if (model.pricing) {
790
+ const inputCost = (estimatedTaskTokens / 1000) * (model.pricing.inputPer1kTokens || 0);
791
+ const outputCost = ((model.maxOutputTokens || 4000) / 1000) * (model.pricing.outputPer1kTokens || 0);
792
+ estimatedCost = {
793
+ input: inputCost.toFixed(4),
794
+ output: outputCost.toFixed(4),
795
+ total: (inputCost + outputCost).toFixed(4),
796
+ currency: model.pricing.currency || 'USD'
797
+ };
798
+ }
799
+
800
+ // Model can handle the task
801
+ return {
802
+ canHandle: true,
803
+ modelId,
804
+ displayName: model.displayName,
805
+ costTier: model.costTier,
806
+ contextRequirements,
807
+ estimatedTokens: estimatedTaskTokens,
808
+ contextWindow,
809
+ contextUsage: `${((estimatedTaskTokens / contextWindow) * 100).toFixed(1)}%`,
810
+ estimatedCost,
811
+ // Include model preferences for caller
812
+ modelPreferences: model.contextPreferences || {
813
+ density: 'standard',
814
+ explicitExamples: true,
815
+ patternHints: true,
816
+ minContextForQuality: 0.5
817
+ }
818
+ };
819
+ }
820
+
821
+ /**
822
+ * Evaluate multiple models for a task and recommend the best one.
823
+ * Useful when user wants to compare options.
824
+ *
825
+ * @param {Object} params - Evaluation parameters
826
+ * @param {Object} params.analysis - Task analysis
827
+ * @param {string} params.taskDescription - Task description
828
+ * @param {string[]} params.modelIds - Models to evaluate (if not provided, evaluates all)
829
+ * @returns {Promise<Object>} Comparison result
830
+ */
831
+ async function evaluateModelsForTask(params) {
832
+ const { analysis, taskDescription, modelIds = null } = params;
833
+
834
+ const registry = loadRegistry();
835
+ if (!registry) {
836
+ return { success: false, error: 'Model registry not found' };
837
+ }
838
+
839
+ // Get models to evaluate
840
+ let models;
841
+ if (modelIds && modelIds.length > 0) {
842
+ models = modelIds.filter(id => registry.models?.[id]);
843
+ } else {
844
+ models = Object.keys(registry.models || {});
845
+ }
846
+
847
+ if (models.length === 0) {
848
+ return { success: false, error: 'No models to evaluate' };
849
+ }
850
+
851
+ // Evaluate each model
852
+ const evaluations = await Promise.all(
853
+ models.map(async modelId => {
854
+ const result = await evaluateSingleModel({
855
+ modelId,
856
+ analysis,
857
+ taskDescription
858
+ });
859
+ return { modelId, ...result };
860
+ })
861
+ );
862
+
863
+ // Separate capable and incapable models
864
+ const capable = evaluations.filter(e => e.canHandle);
865
+ const incapable = evaluations.filter(e => !e.canHandle);
866
+
867
+ // Rank capable models by quality (capability + cost efficiency)
868
+ const ranked = capable.sort((a, b) => {
869
+ // Prefer models with better context efficiency
870
+ const efficiencyA = parseFloat(a.contextUsage) || 100;
871
+ const efficiencyB = parseFloat(b.contextUsage) || 100;
872
+
873
+ // Lower context usage is better
874
+ if (Math.abs(efficiencyA - efficiencyB) > 10) {
875
+ return efficiencyA - efficiencyB;
876
+ }
877
+
878
+ // Then by cost tier (quality-first)
879
+ const tierOrder = { premium: 0, standard: 1, economy: 2 };
880
+ return (tierOrder[a.costTier] || 1) - (tierOrder[b.costTier] || 1);
881
+ });
882
+
883
+ return {
884
+ success: true,
885
+ taskDescription,
886
+ totalEvaluated: models.length,
887
+ capableCount: capable.length,
888
+ recommended: ranked[0] || null,
889
+ alternatives: ranked.slice(1),
890
+ incapable: incapable.map(e => ({
891
+ modelId: e.modelId,
892
+ reason: e.reason,
893
+ details: e.missing || e.overflow || null
894
+ }))
895
+ };
896
+ }
897
+
657
898
  // ============================================================
658
899
  // Main Router
659
900
  // ============================================================
@@ -864,6 +1105,10 @@ module.exports = {
864
1105
  checkCascadeFallback,
865
1106
  getRoutingConfig,
866
1107
 
1108
+ // Phase 4: Single model evaluation (Smart Context integration)
1109
+ evaluateSingleModel,
1110
+ evaluateModelsForTask,
1111
+
867
1112
  // Registry/stats access
868
1113
  loadRegistry,
869
1114
  loadStats,
@@ -16,6 +16,7 @@ const path = require('path');
16
16
  const { execSync } = require('child_process');
17
17
  const {
18
18
  PATHS,
19
+ PROJECT_ROOT,
19
20
  fileExists,
20
21
  readJson,
21
22
  readFile,
@@ -421,6 +422,99 @@ function printBriefing(briefing) {
421
422
  console.log('');
422
423
  }
423
424
 
425
+ // Knowledge Sync Check
426
+ if (morningConfig.checkKnowledgeSync !== false) {
427
+ try {
428
+ const { checkAllDrift, markAsSynced } = require('./flow-knowledge-sync');
429
+ const driftStatus = checkAllDrift();
430
+
431
+ if (driftStatus.anyDrift) {
432
+ printSection('KNOWLEDGE SYNC');
433
+
434
+ // Show what drifted
435
+ const driftedCategories = [];
436
+ for (const [category, status] of Object.entries(driftStatus.categories)) {
437
+ if (status.status === 'drifted') {
438
+ console.log(` ${color('yellow', '\u26a0')} ${category}.md out of sync (${status.reason})`);
439
+ driftedCategories.push(category);
440
+ }
441
+ }
442
+
443
+ // Auto-regenerate if enabled
444
+ if (morningConfig.autoRegenerateKnowledge !== false) {
445
+ try {
446
+ const { spawnSync } = require('child_process');
447
+ const scriptPath = path.join(PROJECT_ROOT, 'scripts', 'flow-onboard');
448
+ const result = spawnSync('node', [scriptPath, '--update-knowledge'], {
449
+ cwd: PROJECT_ROOT,
450
+ stdio: 'pipe',
451
+ timeout: 30000
452
+ });
453
+
454
+ if (result.status === 0) {
455
+ markAsSynced();
456
+ console.log(` ${color('green', '\u2713')} Auto-regenerated knowledge files`);
457
+ } else {
458
+ console.log(` ${color('yellow', '!')} Could not auto-regenerate`);
459
+ console.log(` Run: ${color('cyan', 'flow knowledge-sync regenerate')}`);
460
+ }
461
+ } catch (err) {
462
+ console.log(` ${color('yellow', '!')} Could not auto-regenerate: ${err.message}`);
463
+ console.log(` Run: ${color('cyan', 'flow knowledge-sync regenerate')}`);
464
+ }
465
+ } else {
466
+ console.log(` ${color('dim', 'Run:')} ${color('cyan', 'flow knowledge-sync regenerate')}`);
467
+ }
468
+
469
+ console.log('');
470
+ }
471
+ } catch {
472
+ // Knowledge sync not available - skip silently
473
+ }
474
+ }
475
+
476
+ // Technical Debt Summary
477
+ if (morningConfig.showTechDebt !== false) {
478
+ try {
479
+ const { TechDebtManager } = require('./flow-tech-debt');
480
+ const debtManager = new TechDebtManager();
481
+ const stats = debtManager.getStats();
482
+
483
+ if (stats.totalOpen > 0) {
484
+ printSection('TECHNICAL DEBT');
485
+
486
+ // Summary line
487
+ const severityParts = [];
488
+ if (stats.bySeverity.critical > 0) severityParts.push(color('red', `${stats.bySeverity.critical} critical`));
489
+ if (stats.bySeverity.high > 0) severityParts.push(color('yellow', `${stats.bySeverity.high} high`));
490
+ if (stats.bySeverity.medium > 0) severityParts.push(color('blue', `${stats.bySeverity.medium} medium`));
491
+ if (stats.bySeverity.low > 0) severityParts.push(color('dim', `${stats.bySeverity.low} low`));
492
+
493
+ console.log(` Open issues: ${stats.totalOpen} (${severityParts.join(', ')})`);
494
+
495
+ // Aging warning
496
+ if (stats.agingCount > 0) {
497
+ console.log(` ${color('yellow', '\u26a0')} ${stats.agingCount} item${stats.agingCount !== 1 ? 's' : ''} aging (seen 3+ sessions)`);
498
+
499
+ // Auto-promote aging items to tasks
500
+ const promoted = debtManager.promoteAgingToTasks();
501
+ if (promoted.length > 0) {
502
+ console.log(` ${color('green', '\u2713')} ${promoted.length} aging item${promoted.length !== 1 ? 's' : ''} added to task queue`);
503
+ }
504
+ }
505
+
506
+ // Auto-fixable hint
507
+ if (stats.autoFixable > 0) {
508
+ console.log(` ${color('green', '\u2713')} ${stats.autoFixable} auto-fixable - run ${color('cyan', '/wogi-debt fix')}`);
509
+ }
510
+
511
+ console.log('');
512
+ }
513
+ } catch {
514
+ // Tech debt manager not available - skip silently
515
+ }
516
+ }
517
+
424
518
  // Changes since last session
425
519
  if (morningConfig.showChanges !== false) {
426
520
  const changes = briefing.changesSinceLastSession;
@@ -940,9 +940,176 @@ print_summary() {
940
940
  echo ""
941
941
  }
942
942
 
943
+ ask_onboard_mode() {
944
+ echo -e "${BOLD}How would you like to set up this project?${NC}"
945
+ echo ""
946
+ echo " ${CYAN}[1]${NC} Fresh start - Analyze this project only"
947
+ echo " Scan project structure, detect patterns, generate workflow files"
948
+ echo ""
949
+ echo " ${CYAN}[2]${NC} Import profile - Load patterns from exported profile"
950
+ echo " Import from a .zip profile exported from another project"
951
+ echo ""
952
+ echo " ${CYAN}[3]${NC} Learn from project - Copy patterns from another folder"
953
+ echo " Point to another project folder to extract and apply its patterns"
954
+ echo ""
955
+ read -p "Choice [1]: " onboard_choice
956
+
957
+ case "$onboard_choice" in
958
+ 2) ONBOARD_MODE="import" ;;
959
+ 3) ONBOARD_MODE="learn" ;;
960
+ *) ONBOARD_MODE="fresh" ;;
961
+ esac
962
+ }
963
+
964
+ handle_import_profile() {
965
+ echo ""
966
+ echo -e "${BOLD}Import from Profile${NC}"
967
+ echo ""
968
+ read -p "Path to profile ZIP: " profile_path
969
+
970
+ if [ -z "$profile_path" ] || [ ! -f "$profile_path" ]; then
971
+ echo -e "${RED}Error: Profile not found: $profile_path${NC}"
972
+ return 1
973
+ fi
974
+
975
+ echo ""
976
+ echo -e "${CYAN}Importing profile...${NC}"
977
+ "$SCRIPT_DIR/flow-import-profile" "$profile_path" --force
978
+
979
+ echo ""
980
+ echo -e "${GREEN}✓${NC} Profile imported. Continuing with project scan..."
981
+ echo ""
982
+ }
983
+
984
+ handle_learn_from_project() {
985
+ echo ""
986
+ echo -e "${BOLD}Learn from Another Project${NC}"
987
+ echo ""
988
+ read -p "Path to reference project: " reference_path
989
+
990
+ if [ -z "$reference_path" ] || [ ! -d "$reference_path" ]; then
991
+ echo -e "${RED}Error: Project folder not found: $reference_path${NC}"
992
+ return 1
993
+ fi
994
+
995
+ echo ""
996
+ echo -e "${CYAN}Scanning reference project for patterns...${NC}"
997
+
998
+ # Check for conflicts
999
+ echo -e "${DIM}Do you want to resolve any pattern conflicts interactively?${NC}"
1000
+ echo " [Y] Yes - I'll choose which patterns to adopt"
1001
+ echo " [n] No - Auto-accept the recommended patterns"
1002
+ echo ""
1003
+ read -p "Resolve conflicts? [Y/n]: " resolve_conflicts
1004
+
1005
+ local resolve_flag=""
1006
+ if [[ ! "$resolve_conflicts" =~ ^[Nn]$ ]]; then
1007
+ resolve_flag="--resolve-conflicts"
1008
+ fi
1009
+
1010
+ "$SCRIPT_DIR/flow-import-profile" --scan "$reference_path" $resolve_flag --force
1011
+
1012
+ echo ""
1013
+ echo -e "${GREEN}✓${NC} Patterns imported. Continuing with project scan..."
1014
+ echo ""
1015
+ }
1016
+
1017
+ run_pattern_extraction() {
1018
+ # Run pattern extraction on current project to detect conflicts
1019
+ echo -e "${CYAN}Scanning for patterns in current project...${NC}"
1020
+
1021
+ local temp_patterns=$(mktemp)
1022
+ if node "$SCRIPT_DIR/flow-pattern-extractor.js" --format json --with-conflicts --output "$temp_patterns" 2>/dev/null; then
1023
+ local conflict_count=$(node -e "const p = require('$temp_patterns'); console.log(p.conflicts ? p.conflicts.length : 0)" 2>/dev/null || echo "0")
1024
+
1025
+ if [ "$conflict_count" -gt 0 ]; then
1026
+ echo -e "${YELLOW}!${NC} Found $conflict_count conflicting patterns in this codebase"
1027
+ echo ""
1028
+ echo "Some patterns in your codebase are inconsistent (e.g., old vs new code)."
1029
+ echo "Would you like to resolve these conflicts now?"
1030
+ echo ""
1031
+ read -p "Resolve conflicts? [y/N]: " resolve_now
1032
+
1033
+ if [[ "$resolve_now" =~ ^[Yy]$ ]]; then
1034
+ local conflicts_temp=$(mktemp)
1035
+ node -e "const p = require('$temp_patterns'); console.log(JSON.stringify(p.conflicts, null, 2))" > "$conflicts_temp" 2>/dev/null
1036
+
1037
+ local resolved_file=$(mktemp)
1038
+ if node "$SCRIPT_DIR/flow-conflict-resolver.js" --input "$conflicts_temp" --output "$resolved_file"; then
1039
+ # Apply resolved patterns to decisions.md
1040
+ local decisions_content=$(node "$SCRIPT_DIR/flow-conflict-resolver.js" --input "$resolved_file" --format decisions 2>/dev/null)
1041
+ if [ -n "$decisions_content" ]; then
1042
+ echo "" >> "$WORKFLOW_DIR/state/decisions.md"
1043
+ echo "---" >> "$WORKFLOW_DIR/state/decisions.md"
1044
+ echo "" >> "$WORKFLOW_DIR/state/decisions.md"
1045
+ echo "$decisions_content" >> "$WORKFLOW_DIR/state/decisions.md"
1046
+ echo -e "${GREEN}✓${NC} Pattern decisions saved to decisions.md"
1047
+ fi
1048
+ fi
1049
+ rm -f "$conflicts_temp" "$resolved_file"
1050
+ fi
1051
+ else
1052
+ echo -e "${GREEN}✓${NC} No conflicting patterns detected"
1053
+ fi
1054
+
1055
+ # Save patterns for reference
1056
+ mkdir -p "$WORKFLOW_DIR/extracted"
1057
+ mv "$temp_patterns" "$WORKFLOW_DIR/extracted/project-patterns.json"
1058
+ echo -e "${GREEN}✓${NC} Patterns saved to .workflow/extracted/project-patterns.json"
1059
+ else
1060
+ rm -f "$temp_patterns"
1061
+ fi
1062
+ echo ""
1063
+ }
1064
+
1065
+ ask_additional_docs() {
1066
+ echo ""
1067
+ echo -e "${BOLD}Additional Documentation${NC}"
1068
+ echo ""
1069
+ echo "Do you have any additional documentation to process?"
1070
+ echo "(PRD, roadmap, specs, architecture docs, etc.)"
1071
+ echo ""
1072
+ echo " ${CYAN}[1]${NC} Enter file path"
1073
+ echo " ${CYAN}[2]${NC} Paste content directly"
1074
+ echo " ${CYAN}[3]${NC} Skip"
1075
+ echo ""
1076
+ read -p "Choice [3]: " doc_choice
1077
+
1078
+ case "$doc_choice" in
1079
+ 1)
1080
+ read -p "Path to document: " doc_path
1081
+ if [ -f "$doc_path" ]; then
1082
+ # Check size
1083
+ local size=$(wc -c < "$doc_path")
1084
+ if [ "$size" -gt 50000 ]; then
1085
+ echo -e "${CYAN}Processing large document through long-input pipeline...${NC}"
1086
+ if [ -f "$SCRIPT_DIR/flow-long-input.js" ]; then
1087
+ node "$SCRIPT_DIR/flow-long-input.js" process "$doc_path" 2>/dev/null || true
1088
+ fi
1089
+ else
1090
+ ADDITIONAL_DOCS=$(cat "$doc_path" 2>/dev/null)
1091
+ echo -e "${GREEN}✓${NC} Document loaded"
1092
+ fi
1093
+ else
1094
+ echo -e "${YELLOW}File not found${NC}"
1095
+ fi
1096
+ ;;
1097
+ 2)
1098
+ echo "Paste your content (end with a line containing just 'END'):"
1099
+ local pasted=""
1100
+ while IFS= read -r line; do
1101
+ [[ "$line" == "END" ]] && break
1102
+ pasted+="$line"$'\n'
1103
+ done
1104
+ ADDITIONAL_DOCS="$pasted"
1105
+ echo -e "${GREEN}✓${NC} Content captured"
1106
+ ;;
1107
+ esac
1108
+ }
1109
+
943
1110
  main() {
944
1111
  print_header
945
-
1112
+
946
1113
  # Check if already onboarded
947
1114
  if [ -f "$WORKFLOW_DIR/specs/project.md" ] && grep -q "Tech Stack" "$WORKFLOW_DIR/specs/project.md" 2>/dev/null; then
948
1115
  echo -e "${YELLOW}⚠ This project appears to be already onboarded.${NC}"
@@ -954,14 +1121,30 @@ main() {
954
1121
  fi
955
1122
  echo ""
956
1123
  fi
957
-
1124
+
958
1125
  # Ensure workflow exists
959
1126
  if [ ! -d "$WORKFLOW_DIR" ]; then
960
1127
  echo -e "${YELLOW}Workflow not initialized. Running install first...${NC}"
961
1128
  "$SCRIPT_DIR/flow-install" --quick "$(basename "$(pwd)")"
962
1129
  echo ""
963
1130
  fi
964
-
1131
+
1132
+ # Ask how user wants to set up the project
1133
+ echo -e "${BOLD}━━━ Setup Mode ━━━${NC}"
1134
+ echo ""
1135
+ ask_onboard_mode
1136
+ echo ""
1137
+
1138
+ # Handle import/learn modes
1139
+ case "$ONBOARD_MODE" in
1140
+ import)
1141
+ handle_import_profile || exit 1
1142
+ ;;
1143
+ learn)
1144
+ handle_learn_from_project || exit 1
1145
+ ;;
1146
+ esac
1147
+
965
1148
  # Detection phase
966
1149
  echo -e "${BOLD}━━━ Analyzing Project ━━━${NC}"
967
1150
  echo ""
@@ -986,7 +1169,29 @@ main() {
986
1169
  ask_current_state
987
1170
  ask_known_issues
988
1171
  ask_coding_preferences
989
-
1172
+
1173
+ # Pattern extraction - scan current project for patterns and conflicts
1174
+ # For fresh mode: detect internal conflicts in the codebase
1175
+ # For import/learn modes: detect conflicts between imported and local patterns
1176
+ echo ""
1177
+ echo -e "${BOLD}━━━ Pattern Analysis ━━━${NC}"
1178
+ echo ""
1179
+
1180
+ # Only run if there are enough files to analyze
1181
+ local file_count=$(find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.py" \) \
1182
+ -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" 2>/dev/null | wc -l | tr -d ' ')
1183
+
1184
+ if [ "$file_count" -gt 5 ]; then
1185
+ echo -e "${DIM}Found $file_count source files to analyze${NC}"
1186
+ run_pattern_extraction
1187
+ else
1188
+ echo -e "${DIM}Skipping pattern analysis (less than 5 source files)${NC}"
1189
+ fi
1190
+
1191
+ # Ask for additional documentation
1192
+ ask_additional_docs
1193
+
1194
+ echo ""
990
1195
  echo -e "${BOLD}━━━ Generating Workflow Files ━━━${NC}"
991
1196
  echo ""
992
1197
 
@@ -1031,13 +1236,21 @@ if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
1031
1236
  echo ""
1032
1237
  echo "Usage: flow onboard"
1033
1238
  echo ""
1239
+ echo "Setup Options:"
1240
+ echo " 1. Fresh start - Analyze this project only"
1241
+ echo " 2. Import profile - Load patterns from exported .zip profile"
1242
+ echo " 3. Learn from project - Extract patterns from another folder"
1243
+ echo ""
1034
1244
  echo "This will:"
1035
- echo " 1. Detect your tech stack (language, framework, database)"
1036
- echo " 2. Scan for components, pages, modules"
1037
- echo " 3. Ask about your project (PRD, goals, issues)"
1038
- echo " 4. Generate project.md, app-map.md, decisions.md"
1039
- echo " 5. Create initial tasks from known issues"
1040
- echo " 6. Suggest relevant skills to install"
1245
+ echo " 1. Ask how you want to set up (fresh/import/learn)"
1246
+ echo " 2. Detect your tech stack (language, framework, database)"
1247
+ echo " 3. Scan for components, pages, modules"
1248
+ echo " 4. Extract patterns and detect conflicts"
1249
+ echo " 5. Ask about your project (PRD, goals, issues)"
1250
+ echo " 6. Ask for additional documentation (PRD, roadmap)"
1251
+ echo " 7. Generate project.md, app-map.md, decisions.md"
1252
+ echo " 8. Create initial tasks from known issues"
1253
+ echo " 9. Suggest relevant skills to install"
1041
1254
  exit 0
1042
1255
  fi
1043
1256