@girardmedia/bootspring 2.0.36 → 2.0.37
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/cli/plan.js +602 -2
- package/core/planning/adaptive-engine.js +958 -0
- package/core/planning/feature-decomposer.js +772 -0
- package/core/planning/index.js +49 -0
- package/core/planning/simulator.js +1328 -0
- package/core/planning/stage-planner.js +624 -0
- package/intelligence/agent-router.js +795 -0
- package/intelligence/index.js +10 -0
- package/mcp/contracts/mcp-contract.v1.json +1 -1
- package/package.json +1 -1
package/cli/plan.js
CHANGED
|
@@ -17,6 +17,11 @@ let ContinuousAnalyzer = null;
|
|
|
17
17
|
let DocumentCoherenceEngine = null;
|
|
18
18
|
let DynamicContextGenerator = null;
|
|
19
19
|
let DecisionIntelligence = null;
|
|
20
|
+
let FeatureDecomposer = null;
|
|
21
|
+
let StagePlanner = null;
|
|
22
|
+
let AdaptivePlanningEngine = null;
|
|
23
|
+
let PlanningSimulator = null;
|
|
24
|
+
let IntelligentAgentRouter = null;
|
|
20
25
|
|
|
21
26
|
function getAnalyzer(root) {
|
|
22
27
|
if (!ContinuousAnalyzer) {
|
|
@@ -46,6 +51,41 @@ function getDecisionEngine(root) {
|
|
|
46
51
|
return new DecisionIntelligence(root);
|
|
47
52
|
}
|
|
48
53
|
|
|
54
|
+
function getFeatureDecomposer(root) {
|
|
55
|
+
if (!FeatureDecomposer) {
|
|
56
|
+
FeatureDecomposer = require('../core/planning').FeatureDecomposer;
|
|
57
|
+
}
|
|
58
|
+
return new FeatureDecomposer({ projectRoot: root });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getStagePlanner(root) {
|
|
62
|
+
if (!StagePlanner) {
|
|
63
|
+
StagePlanner = require('../core/planning').StagePlanner;
|
|
64
|
+
}
|
|
65
|
+
return new StagePlanner({ projectRoot: root });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getAdaptiveEngine(root) {
|
|
69
|
+
if (!AdaptivePlanningEngine) {
|
|
70
|
+
AdaptivePlanningEngine = require('../core/planning').AdaptivePlanningEngine;
|
|
71
|
+
}
|
|
72
|
+
return new AdaptivePlanningEngine({ projectRoot: root });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getSimulator(root) {
|
|
76
|
+
if (!PlanningSimulator) {
|
|
77
|
+
PlanningSimulator = require('../core/planning').PlanningSimulator;
|
|
78
|
+
}
|
|
79
|
+
return new PlanningSimulator({ projectRoot: root });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getAgentRouter(root) {
|
|
83
|
+
if (!IntelligentAgentRouter) {
|
|
84
|
+
IntelligentAgentRouter = require('../intelligence/agent-router').IntelligentAgentRouter;
|
|
85
|
+
}
|
|
86
|
+
return new IntelligentAgentRouter({ projectRoot: root });
|
|
87
|
+
}
|
|
88
|
+
|
|
49
89
|
// Get project root
|
|
50
90
|
const projectRoot = process.cwd();
|
|
51
91
|
|
|
@@ -59,11 +99,16 @@ Intelligent planning and analysis for project development
|
|
|
59
99
|
|
|
60
100
|
${utils.COLORS.bold}Usage:${utils.COLORS.reset}
|
|
61
101
|
bootspring plan Interactive planning overview
|
|
102
|
+
bootspring plan status Current planning state and drift
|
|
103
|
+
bootspring plan stage Detect and manage planning stage
|
|
104
|
+
bootspring plan refresh Re-analyze and update plans
|
|
105
|
+
bootspring plan simulate "What if" scenario planning
|
|
62
106
|
bootspring plan analyze Deep project analysis
|
|
63
107
|
bootspring plan suggest Get planning suggestions
|
|
64
108
|
bootspring plan decompose Break down a feature
|
|
65
109
|
bootspring plan dependencies Map feature dependencies
|
|
66
110
|
bootspring plan risks Analyze feature risks
|
|
111
|
+
bootspring plan route Get agent routing recommendation
|
|
67
112
|
bootspring plan coherence Check document coherence
|
|
68
113
|
bootspring plan drift Detect documentation drift
|
|
69
114
|
bootspring plan decisions Get decision recommendations
|
|
@@ -72,14 +117,22 @@ ${utils.COLORS.bold}Options:${utils.COLORS.reset}
|
|
|
72
117
|
--feature=<name> Feature name (required for some commands)
|
|
73
118
|
--context=<text> Additional context
|
|
74
119
|
--depth=<level> Analysis depth: quick, standard, deep
|
|
120
|
+
--type=<scenario> Simulation type: feature, refactor, timeline, resource
|
|
121
|
+
--complexity=<level> Complexity: trivial, simple, moderate, complex, very_complex
|
|
122
|
+
--all Refresh all documents
|
|
75
123
|
--json Output as JSON
|
|
76
124
|
|
|
77
125
|
${utils.COLORS.bold}Examples:${utils.COLORS.reset}
|
|
78
126
|
bootspring plan Overview
|
|
127
|
+
bootspring plan status Show planning drift
|
|
128
|
+
bootspring plan stage Detect current stage
|
|
129
|
+
bootspring plan stage --set=execution Set planning stage
|
|
130
|
+
bootspring plan refresh Refresh drifted docs
|
|
131
|
+
bootspring plan simulate --type=feature --feature="Payment" --complexity=complex
|
|
79
132
|
bootspring plan analyze --depth=deep Deep analysis
|
|
80
133
|
bootspring plan decompose --feature="User authentication"
|
|
134
|
+
bootspring plan route --feature="Add real-time chat"
|
|
81
135
|
bootspring plan risks --feature="Payment integration"
|
|
82
|
-
bootspring plan suggest --context="adding real-time features"
|
|
83
136
|
`);
|
|
84
137
|
}
|
|
85
138
|
|
|
@@ -703,6 +756,536 @@ async function planDecisions(args) {
|
|
|
703
756
|
}
|
|
704
757
|
}
|
|
705
758
|
|
|
759
|
+
/**
|
|
760
|
+
* Show planning status
|
|
761
|
+
*/
|
|
762
|
+
async function planStatus(args) {
|
|
763
|
+
utils.print.header('Planning Status');
|
|
764
|
+
console.log('');
|
|
765
|
+
|
|
766
|
+
const spinner = utils.createSpinner('Loading planning state...').start();
|
|
767
|
+
|
|
768
|
+
try {
|
|
769
|
+
const engine = getAdaptiveEngine(projectRoot);
|
|
770
|
+
await engine.initialize();
|
|
771
|
+
const status = await engine.getStatus();
|
|
772
|
+
|
|
773
|
+
spinner.succeed('Status loaded');
|
|
774
|
+
console.log('');
|
|
775
|
+
|
|
776
|
+
// Current stage
|
|
777
|
+
console.log(`${utils.COLORS.bold}Current Stage:${utils.COLORS.reset} ${status.stage}`);
|
|
778
|
+
console.log(`${utils.COLORS.bold}Last Refresh:${utils.COLORS.reset} ${status.lastRefresh || 'Never'}`);
|
|
779
|
+
console.log('');
|
|
780
|
+
|
|
781
|
+
// Drift indicator
|
|
782
|
+
const driftPercent = Math.round(status.drift.overall * 100);
|
|
783
|
+
const driftColor = driftPercent > 50 ? utils.COLORS.red :
|
|
784
|
+
driftPercent > 25 ? utils.COLORS.yellow :
|
|
785
|
+
utils.COLORS.green;
|
|
786
|
+
console.log(`${utils.COLORS.bold}Documentation Drift:${utils.COLORS.reset} ${driftColor}${driftPercent}%${utils.COLORS.reset} (${status.drift.severity.label})`);
|
|
787
|
+
|
|
788
|
+
if (status.pendingChanges > 0) {
|
|
789
|
+
console.log(`${utils.COLORS.bold}Pending Changes:${utils.COLORS.reset} ${status.pendingChanges}`);
|
|
790
|
+
}
|
|
791
|
+
console.log('');
|
|
792
|
+
|
|
793
|
+
// Planning layers
|
|
794
|
+
console.log(`${utils.COLORS.bold}Planning Layers:${utils.COLORS.reset}`);
|
|
795
|
+
for (const layer of status.layers) {
|
|
796
|
+
const layerDrift = Math.round(layer.drift * 100);
|
|
797
|
+
const icon = layerDrift > 40 ? utils.COLORS.red + '!' :
|
|
798
|
+
layerDrift > 20 ? utils.COLORS.yellow + '●' :
|
|
799
|
+
utils.COLORS.green + '✓';
|
|
800
|
+
console.log(` ${icon}${utils.COLORS.reset} ${layer.name} (${layer.horizon}): ${layerDrift}% drift`);
|
|
801
|
+
}
|
|
802
|
+
console.log('');
|
|
803
|
+
|
|
804
|
+
// Recommendations
|
|
805
|
+
if (status.recommendations.length > 0) {
|
|
806
|
+
console.log(`${utils.COLORS.bold}Recommendations:${utils.COLORS.reset}`);
|
|
807
|
+
for (const rec of status.recommendations.slice(0, 3)) {
|
|
808
|
+
const icon = rec.priority === 'critical' ? utils.COLORS.red + '!' :
|
|
809
|
+
rec.priority === 'high' ? utils.COLORS.yellow + '●' :
|
|
810
|
+
utils.COLORS.dim + '○';
|
|
811
|
+
console.log(` ${icon}${utils.COLORS.reset} ${rec.action}`);
|
|
812
|
+
if (rec.suggestedCommand) {
|
|
813
|
+
console.log(` ${utils.COLORS.cyan}→${utils.COLORS.reset} ${rec.suggestedCommand}`);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (args.json) {
|
|
819
|
+
console.log('');
|
|
820
|
+
console.log(JSON.stringify(status, null, 2));
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
} catch (error) {
|
|
824
|
+
spinner.fail(`Error: ${error.message}`);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Manage planning stage
|
|
830
|
+
*/
|
|
831
|
+
async function planStage(args) {
|
|
832
|
+
utils.print.header('Planning Stage');
|
|
833
|
+
console.log('');
|
|
834
|
+
|
|
835
|
+
const spinner = utils.createSpinner('Analyzing project stage...').start();
|
|
836
|
+
|
|
837
|
+
try {
|
|
838
|
+
const stagePlanner = getStagePlanner(projectRoot);
|
|
839
|
+
await stagePlanner.initialize();
|
|
840
|
+
|
|
841
|
+
if (args.set) {
|
|
842
|
+
// Transition to new stage
|
|
843
|
+
const transition = await stagePlanner.transitionTo(args.set, {
|
|
844
|
+
reason: args.reason || 'Manual transition via CLI'
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
spinner.succeed(`Transitioned to ${args.set} stage`);
|
|
848
|
+
console.log('');
|
|
849
|
+
|
|
850
|
+
console.log(`${utils.COLORS.bold}Stage Transition:${utils.COLORS.reset}`);
|
|
851
|
+
console.log(` From: ${transition.previousStage}`);
|
|
852
|
+
console.log(` To: ${transition.newStage}`);
|
|
853
|
+
console.log('');
|
|
854
|
+
|
|
855
|
+
// Show new stage context
|
|
856
|
+
const context = await stagePlanner.getStageContext();
|
|
857
|
+
console.log(`${utils.COLORS.bold}New Stage Documents:${utils.COLORS.reset}`);
|
|
858
|
+
for (const doc of context.documents) {
|
|
859
|
+
console.log(` ${utils.COLORS.cyan}□${utils.COLORS.reset} ${doc.toUpperCase()}.md`);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
} else {
|
|
863
|
+
// Detect current stage
|
|
864
|
+
const detection = await stagePlanner.detectStage();
|
|
865
|
+
spinner.succeed('Stage detected');
|
|
866
|
+
console.log('');
|
|
867
|
+
|
|
868
|
+
console.log(`${utils.COLORS.bold}Current Stage:${utils.COLORS.reset} ${detection.stage}`);
|
|
869
|
+
console.log(`${utils.COLORS.bold}Confidence:${utils.COLORS.reset} ${Math.round(detection.confidence * 100)}%`);
|
|
870
|
+
console.log('');
|
|
871
|
+
|
|
872
|
+
// Show signals
|
|
873
|
+
if (detection.signals) {
|
|
874
|
+
console.log(`${utils.COLORS.bold}Detection Signals:${utils.COLORS.reset}`);
|
|
875
|
+
for (const [signal, value] of Object.entries(detection.signals)) {
|
|
876
|
+
const icon = value ? utils.COLORS.green + '✓' : utils.COLORS.dim + '○';
|
|
877
|
+
console.log(` ${icon}${utils.COLORS.reset} ${signal}`);
|
|
878
|
+
}
|
|
879
|
+
console.log('');
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Show stage context
|
|
883
|
+
const context = await stagePlanner.getStageContext();
|
|
884
|
+
console.log(`${utils.COLORS.bold}Stage Focus:${utils.COLORS.reset}`);
|
|
885
|
+
console.log(` AI Prompt Style: ${context.aiPromptStyle}`);
|
|
886
|
+
console.log(` Analysis Depth: ${context.analysisDepth}`);
|
|
887
|
+
console.log('');
|
|
888
|
+
|
|
889
|
+
console.log(`${utils.COLORS.bold}Key Questions:${utils.COLORS.reset}`);
|
|
890
|
+
for (const q of context.questions.slice(0, 4)) {
|
|
891
|
+
console.log(` ${utils.COLORS.cyan}?${utils.COLORS.reset} ${q}`);
|
|
892
|
+
}
|
|
893
|
+
console.log('');
|
|
894
|
+
|
|
895
|
+
console.log(`${utils.COLORS.bold}Expected Documents:${utils.COLORS.reset}`);
|
|
896
|
+
for (const doc of context.documents) {
|
|
897
|
+
console.log(` ${utils.COLORS.cyan}□${utils.COLORS.reset} ${doc.toUpperCase()}.md`);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (args.json) {
|
|
902
|
+
const fullContext = await stagePlanner.getStageContext();
|
|
903
|
+
console.log('');
|
|
904
|
+
console.log(JSON.stringify(fullContext, null, 2));
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
} catch (error) {
|
|
908
|
+
spinner.fail(`Error: ${error.message}`);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Refresh planning documents
|
|
914
|
+
*/
|
|
915
|
+
async function planRefresh(args) {
|
|
916
|
+
utils.print.header('Planning Refresh');
|
|
917
|
+
console.log('');
|
|
918
|
+
|
|
919
|
+
const spinner = utils.createSpinner('Analyzing drift...').start();
|
|
920
|
+
|
|
921
|
+
try {
|
|
922
|
+
const engine = getAdaptiveEngine(projectRoot);
|
|
923
|
+
await engine.initialize();
|
|
924
|
+
|
|
925
|
+
// First show what would be refreshed
|
|
926
|
+
const drift = await engine.calculateDrift();
|
|
927
|
+
|
|
928
|
+
spinner.succeed('Drift analysis complete');
|
|
929
|
+
console.log('');
|
|
930
|
+
|
|
931
|
+
console.log(`${utils.COLORS.bold}Overall Drift:${utils.COLORS.reset} ${Math.round(drift.overall * 100)}%`);
|
|
932
|
+
console.log('');
|
|
933
|
+
|
|
934
|
+
if (Object.keys(drift.byDocument).length > 0) {
|
|
935
|
+
console.log(`${utils.COLORS.bold}Documents to Refresh:${utils.COLORS.reset}`);
|
|
936
|
+
for (const [doc, data] of Object.entries(drift.byDocument)) {
|
|
937
|
+
if (data.drift > 0.2 || args.all) {
|
|
938
|
+
const driftPercent = Math.round(data.drift * 100);
|
|
939
|
+
const icon = data.severity.level === 'critical' ? utils.COLORS.red + '!' :
|
|
940
|
+
data.severity.level === 'significant' ? utils.COLORS.yellow + '●' :
|
|
941
|
+
utils.COLORS.dim + '○';
|
|
942
|
+
console.log(` ${icon}${utils.COLORS.reset} ${doc.toUpperCase()}.md (${driftPercent}% drift, ${data.changesAffecting} changes)`);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
console.log('');
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Perform refresh
|
|
949
|
+
const refreshSpinner = utils.createSpinner('Refreshing documents...').start();
|
|
950
|
+
|
|
951
|
+
const result = await engine.refresh({
|
|
952
|
+
all: args.all,
|
|
953
|
+
documents: args.docs?.split(',')
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
if (result.documentsRefreshed.length > 0) {
|
|
957
|
+
refreshSpinner.succeed(`Refreshed ${result.documentsRefreshed.length} documents`);
|
|
958
|
+
console.log('');
|
|
959
|
+
|
|
960
|
+
console.log(`${utils.COLORS.bold}Refreshed:${utils.COLORS.reset}`);
|
|
961
|
+
for (const change of result.changes) {
|
|
962
|
+
console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${change.document.toUpperCase()}.md (v${change.newVersion}, ${change.changesIncorporated} changes)`);
|
|
963
|
+
}
|
|
964
|
+
} else {
|
|
965
|
+
refreshSpinner.info('No documents needed refresh');
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
if (result.errors.length > 0) {
|
|
969
|
+
console.log('');
|
|
970
|
+
console.log(`${utils.COLORS.bold}Errors:${utils.COLORS.reset}`);
|
|
971
|
+
for (const err of result.errors) {
|
|
972
|
+
console.log(` ${utils.COLORS.red}✗${utils.COLORS.reset} ${err.document}: ${err.error}`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
if (args.json) {
|
|
977
|
+
console.log('');
|
|
978
|
+
console.log(JSON.stringify(result, null, 2));
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
} catch (error) {
|
|
982
|
+
spinner.fail(`Error: ${error.message}`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Run planning simulation
|
|
988
|
+
*/
|
|
989
|
+
async function planSimulate(args) {
|
|
990
|
+
const type = args.type || 'feature';
|
|
991
|
+
const feature = args.feature || args.name;
|
|
992
|
+
|
|
993
|
+
utils.print.header('Planning Simulation');
|
|
994
|
+
console.log(`Type: ${type}`);
|
|
995
|
+
console.log('');
|
|
996
|
+
|
|
997
|
+
const spinner = utils.createSpinner('Running simulation...').start();
|
|
998
|
+
|
|
999
|
+
try {
|
|
1000
|
+
const simulator = getSimulator(projectRoot);
|
|
1001
|
+
await simulator.initialize();
|
|
1002
|
+
|
|
1003
|
+
// Build scenario based on type
|
|
1004
|
+
const scenario = { type };
|
|
1005
|
+
|
|
1006
|
+
switch (type) {
|
|
1007
|
+
case 'feature':
|
|
1008
|
+
if (!feature) {
|
|
1009
|
+
spinner.fail('Feature name required for feature simulation');
|
|
1010
|
+
console.log('Usage: bootspring plan simulate --type=feature --feature="Feature name"');
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
scenario.featureName = feature;
|
|
1014
|
+
scenario.complexity = args.complexity || 'moderate';
|
|
1015
|
+
scenario.dependencies = args.dependencies?.split(',') || [];
|
|
1016
|
+
break;
|
|
1017
|
+
|
|
1018
|
+
case 'refactor':
|
|
1019
|
+
scenario.scope = args.scope || 'module';
|
|
1020
|
+
scenario.target = args.target || feature || 'unknown';
|
|
1021
|
+
break;
|
|
1022
|
+
|
|
1023
|
+
case 'timeline':
|
|
1024
|
+
scenario.change = args.change || 'compress';
|
|
1025
|
+
scenario.amount = parseInt(args.amount) || 20;
|
|
1026
|
+
break;
|
|
1027
|
+
|
|
1028
|
+
case 'resource':
|
|
1029
|
+
scenario.action = args.action || 'add';
|
|
1030
|
+
scenario.count = parseInt(args.count) || 1;
|
|
1031
|
+
break;
|
|
1032
|
+
|
|
1033
|
+
default:
|
|
1034
|
+
spinner.fail(`Unknown simulation type: ${type}`);
|
|
1035
|
+
console.log('Valid types: feature, refactor, timeline, resource');
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
const result = await simulator.simulate(scenario);
|
|
1040
|
+
|
|
1041
|
+
spinner.succeed('Simulation complete');
|
|
1042
|
+
console.log('');
|
|
1043
|
+
|
|
1044
|
+
// Summary
|
|
1045
|
+
console.log(`${utils.COLORS.bold}Summary:${utils.COLORS.reset}`);
|
|
1046
|
+
console.log(` ${result.summary.overallAssessment}`);
|
|
1047
|
+
console.log('');
|
|
1048
|
+
|
|
1049
|
+
// Key points
|
|
1050
|
+
if (result.summary.keyPoints.length > 0) {
|
|
1051
|
+
console.log(`${utils.COLORS.bold}Key Points:${utils.COLORS.reset}`);
|
|
1052
|
+
for (const point of result.summary.keyPoints) {
|
|
1053
|
+
console.log(` ${utils.COLORS.cyan}→${utils.COLORS.reset} ${point}`);
|
|
1054
|
+
}
|
|
1055
|
+
console.log('');
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// Results by category
|
|
1059
|
+
for (const [category, data] of Object.entries(result.results)) {
|
|
1060
|
+
if (typeof data === 'object' && data !== null) {
|
|
1061
|
+
console.log(`${utils.COLORS.bold}${category.charAt(0).toUpperCase() + category.slice(1)}:${utils.COLORS.reset}`);
|
|
1062
|
+
|
|
1063
|
+
if (data.estimatedDays) {
|
|
1064
|
+
console.log(` Estimated: ${data.estimatedDays} days (${data.range?.optimistic}-${data.range?.pessimistic} range)`);
|
|
1065
|
+
}
|
|
1066
|
+
if (data.overall) {
|
|
1067
|
+
const icon = data.overall === 'high' ? utils.COLORS.red + '!' :
|
|
1068
|
+
data.overall === 'medium' ? utils.COLORS.yellow + '●' :
|
|
1069
|
+
utils.COLORS.green + '✓';
|
|
1070
|
+
console.log(` Level: ${icon}${utils.COLORS.reset} ${data.overall}`);
|
|
1071
|
+
}
|
|
1072
|
+
if (data.impact) {
|
|
1073
|
+
console.log(` Impact: ${data.impact}`);
|
|
1074
|
+
}
|
|
1075
|
+
if (Array.isArray(data.factors)) {
|
|
1076
|
+
for (const factor of data.factors.slice(0, 3)) {
|
|
1077
|
+
console.log(` ${utils.COLORS.dim}•${utils.COLORS.reset} ${factor.description || factor}`);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
console.log('');
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// Recommendations
|
|
1085
|
+
if (result.recommendations.length > 0) {
|
|
1086
|
+
console.log(`${utils.COLORS.bold}Recommendations:${utils.COLORS.reset}`);
|
|
1087
|
+
for (const rec of result.recommendations.slice(0, 5)) {
|
|
1088
|
+
const icon = rec.priority === 'high' ? utils.COLORS.yellow + '!' :
|
|
1089
|
+
utils.COLORS.dim + '●';
|
|
1090
|
+
console.log(` ${icon}${utils.COLORS.reset} ${rec.action}`);
|
|
1091
|
+
if (rec.command) {
|
|
1092
|
+
console.log(` ${utils.COLORS.cyan}→${utils.COLORS.reset} ${rec.command}`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
if (args.json) {
|
|
1098
|
+
console.log('');
|
|
1099
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
spinner.fail(`Error: ${error.message}`);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* Get agent routing recommendation
|
|
1109
|
+
*/
|
|
1110
|
+
async function planRoute(args) {
|
|
1111
|
+
const task = args.feature || args.task || args.context;
|
|
1112
|
+
|
|
1113
|
+
if (!task) {
|
|
1114
|
+
utils.print.error('Task description required');
|
|
1115
|
+
console.log('Usage: bootspring plan route --task="Implement user authentication"');
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
utils.print.header('Agent Routing');
|
|
1120
|
+
console.log(`Task: ${task}`);
|
|
1121
|
+
console.log('');
|
|
1122
|
+
|
|
1123
|
+
const spinner = utils.createSpinner('Analyzing task...').start();
|
|
1124
|
+
|
|
1125
|
+
try {
|
|
1126
|
+
const router = getAgentRouter(projectRoot);
|
|
1127
|
+
await router.initialize();
|
|
1128
|
+
|
|
1129
|
+
const routing = await router.route(task, {
|
|
1130
|
+
affectedFiles: args.files?.split(',') || []
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
spinner.succeed('Routing analysis complete');
|
|
1134
|
+
console.log('');
|
|
1135
|
+
|
|
1136
|
+
// Mode
|
|
1137
|
+
console.log(`${utils.COLORS.bold}Mode:${utils.COLORS.reset} ${routing.mode === 'single' ? 'Single Agent' : 'Multi-Agent Collaboration'}`);
|
|
1138
|
+
console.log('');
|
|
1139
|
+
|
|
1140
|
+
// Complexity
|
|
1141
|
+
console.log(`${utils.COLORS.bold}Complexity:${utils.COLORS.reset} ${routing.complexity.level}`);
|
|
1142
|
+
console.log(` Scope: ${routing.complexity.factors.scope}`);
|
|
1143
|
+
console.log(` Risk: ${routing.complexity.factors.risk}`);
|
|
1144
|
+
console.log('');
|
|
1145
|
+
|
|
1146
|
+
if (routing.mode === 'single') {
|
|
1147
|
+
// Single agent recommendation
|
|
1148
|
+
console.log(`${utils.COLORS.bold}Recommended Agent:${utils.COLORS.reset} ${routing.primaryAgent}`);
|
|
1149
|
+
if (routing.fallbackAgents?.length > 0) {
|
|
1150
|
+
console.log(`${utils.COLORS.bold}Fallbacks:${utils.COLORS.reset} ${routing.fallbackAgents.join(', ')}`);
|
|
1151
|
+
}
|
|
1152
|
+
console.log('');
|
|
1153
|
+
|
|
1154
|
+
console.log(`${utils.COLORS.bold}Approach:${utils.COLORS.reset}`);
|
|
1155
|
+
for (const step of routing.suggestedApproach.steps) {
|
|
1156
|
+
console.log(` ${utils.COLORS.cyan}→${utils.COLORS.reset} ${step}`);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
} else {
|
|
1160
|
+
// Multi-agent collaboration
|
|
1161
|
+
console.log(`${utils.COLORS.bold}Collaboration Pattern:${utils.COLORS.reset} ${routing.pattern.name}`);
|
|
1162
|
+
console.log(` ${routing.pattern.description}`);
|
|
1163
|
+
console.log('');
|
|
1164
|
+
|
|
1165
|
+
console.log(`${utils.COLORS.bold}Agent Sequence:${utils.COLORS.reset}`);
|
|
1166
|
+
for (const agent of routing.agents) {
|
|
1167
|
+
console.log(` ${utils.COLORS.cyan}${agent.phase}.${utils.COLORS.reset} ${agent.agent}`);
|
|
1168
|
+
console.log(` Focus: ${agent.focus}`);
|
|
1169
|
+
if (agent.input) console.log(` Input: ${agent.input}`);
|
|
1170
|
+
console.log(` Output: ${agent.output}`);
|
|
1171
|
+
}
|
|
1172
|
+
console.log('');
|
|
1173
|
+
|
|
1174
|
+
if (routing.handoffPoints?.length > 0) {
|
|
1175
|
+
console.log(`${utils.COLORS.bold}Handoff Points:${utils.COLORS.reset}`);
|
|
1176
|
+
for (const handoff of routing.handoffPoints) {
|
|
1177
|
+
console.log(` ${utils.COLORS.yellow}→${utils.COLORS.reset} ${handoff.from} → ${handoff.to}: ${handoff.artifact}`);
|
|
1178
|
+
}
|
|
1179
|
+
console.log('');
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
console.log(`${utils.COLORS.bold}Coordinator:${utils.COLORS.reset} ${routing.coordinatorAgent}`);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// Estimated effort
|
|
1186
|
+
console.log('');
|
|
1187
|
+
console.log(`${utils.COLORS.bold}Estimated Effort:${utils.COLORS.reset} ${routing.estimatedEffort?.range || 'Unknown'}`);
|
|
1188
|
+
|
|
1189
|
+
if (args.json) {
|
|
1190
|
+
console.log('');
|
|
1191
|
+
console.log(JSON.stringify(routing, null, 2));
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
spinner.fail(`Error: ${error.message}`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Enhanced feature decomposition using FeatureDecomposer
|
|
1201
|
+
*/
|
|
1202
|
+
async function planDecomposeEnhanced(args) {
|
|
1203
|
+
const feature = args.feature;
|
|
1204
|
+
|
|
1205
|
+
if (!feature) {
|
|
1206
|
+
utils.print.error('Feature name required');
|
|
1207
|
+
console.log('Usage: bootspring plan decompose --feature="Feature name"');
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
utils.print.header(`Feature Decomposition: ${feature}`);
|
|
1212
|
+
console.log('');
|
|
1213
|
+
|
|
1214
|
+
const spinner = utils.createSpinner('Breaking down feature...').start();
|
|
1215
|
+
|
|
1216
|
+
try {
|
|
1217
|
+
const decomposer = getFeatureDecomposer(projectRoot);
|
|
1218
|
+
|
|
1219
|
+
const decomposition = await decomposer.decompose(feature, {
|
|
1220
|
+
depth: args.depth || 'standard',
|
|
1221
|
+
includePatterns: !args.noPatterns
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
spinner.succeed('Decomposition complete');
|
|
1225
|
+
console.log('');
|
|
1226
|
+
|
|
1227
|
+
// Classification
|
|
1228
|
+
console.log(`${utils.COLORS.bold}Classification:${utils.COLORS.reset} ${decomposition.classification || 'Custom'}`);
|
|
1229
|
+
console.log(`${utils.COLORS.bold}Complexity:${utils.COLORS.reset} ${decomposition.complexity || 'medium'}`);
|
|
1230
|
+
console.log('');
|
|
1231
|
+
|
|
1232
|
+
// Metrics summary
|
|
1233
|
+
if (decomposition.metrics) {
|
|
1234
|
+
console.log(`${utils.COLORS.bold}Metrics:${utils.COLORS.reset}`);
|
|
1235
|
+
console.log(` Total Tasks: ${decomposition.metrics.totalTasks}`);
|
|
1236
|
+
console.log(` Estimated Points: ${decomposition.metrics.totalPoints}`);
|
|
1237
|
+
console.log(` Estimated Time: ${decomposition.metrics.estimatedTime}`);
|
|
1238
|
+
console.log('');
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// Layers
|
|
1242
|
+
console.log(`${utils.COLORS.bold}Task Breakdown:${utils.COLORS.reset}`);
|
|
1243
|
+
for (const [layer, tasks] of Object.entries(decomposition.layers)) {
|
|
1244
|
+
if (tasks.length > 0) {
|
|
1245
|
+
console.log(`\n ${utils.COLORS.bold}${layer.charAt(0).toUpperCase() + layer.slice(1)}:${utils.COLORS.reset}`);
|
|
1246
|
+
for (const task of tasks) {
|
|
1247
|
+
const deps = task.deps?.length > 0 ? ` ${utils.COLORS.dim}(after: ${task.deps.join(', ')})${utils.COLORS.reset}` : '';
|
|
1248
|
+
console.log(` ${utils.COLORS.cyan}□${utils.COLORS.reset} ${task.task} [${task.effort}]${deps}`);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
console.log('');
|
|
1253
|
+
|
|
1254
|
+
// Critical path
|
|
1255
|
+
if (decomposition.criticalPath?.length > 0) {
|
|
1256
|
+
console.log(`${utils.COLORS.bold}Critical Path:${utils.COLORS.reset}`);
|
|
1257
|
+
console.log(` ${decomposition.criticalPath.join(' → ')}`);
|
|
1258
|
+
console.log('');
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// Risks
|
|
1262
|
+
if (decomposition.risks?.length > 0) {
|
|
1263
|
+
console.log(`${utils.COLORS.bold}Risks:${utils.COLORS.reset}`);
|
|
1264
|
+
for (const risk of decomposition.risks) {
|
|
1265
|
+
console.log(` ${utils.COLORS.yellow}⚠${utils.COLORS.reset} ${risk.risk}`);
|
|
1266
|
+
console.log(` Mitigation: ${risk.mitigation}`);
|
|
1267
|
+
}
|
|
1268
|
+
console.log('');
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// Recommended patterns
|
|
1272
|
+
if (decomposition.recommendedPatterns?.length > 0) {
|
|
1273
|
+
console.log(`${utils.COLORS.bold}Recommended Patterns:${utils.COLORS.reset}`);
|
|
1274
|
+
for (const pattern of decomposition.recommendedPatterns) {
|
|
1275
|
+
console.log(` ${utils.COLORS.green}●${utils.COLORS.reset} ${pattern}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (args.json) {
|
|
1280
|
+
console.log('');
|
|
1281
|
+
console.log(JSON.stringify(decomposition, null, 2));
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
} catch (error) {
|
|
1285
|
+
spinner.fail(`Error: ${error.message}`);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
706
1289
|
/**
|
|
707
1290
|
* Main entry point
|
|
708
1291
|
*/
|
|
@@ -711,6 +1294,19 @@ async function run(args) {
|
|
|
711
1294
|
const subcommand = parsedArgs._[0];
|
|
712
1295
|
|
|
713
1296
|
switch (subcommand) {
|
|
1297
|
+
case 'status':
|
|
1298
|
+
return planStatus(parsedArgs);
|
|
1299
|
+
|
|
1300
|
+
case 'stage':
|
|
1301
|
+
return planStage(parsedArgs);
|
|
1302
|
+
|
|
1303
|
+
case 'refresh':
|
|
1304
|
+
return planRefresh(parsedArgs);
|
|
1305
|
+
|
|
1306
|
+
case 'simulate':
|
|
1307
|
+
case 'sim':
|
|
1308
|
+
return planSimulate(parsedArgs);
|
|
1309
|
+
|
|
714
1310
|
case 'analyze':
|
|
715
1311
|
return planAnalyze(parsedArgs);
|
|
716
1312
|
|
|
@@ -720,7 +1316,7 @@ async function run(args) {
|
|
|
720
1316
|
|
|
721
1317
|
case 'decompose':
|
|
722
1318
|
case 'breakdown':
|
|
723
|
-
return
|
|
1319
|
+
return planDecomposeEnhanced(parsedArgs);
|
|
724
1320
|
|
|
725
1321
|
case 'dependencies':
|
|
726
1322
|
case 'deps':
|
|
@@ -730,6 +1326,10 @@ async function run(args) {
|
|
|
730
1326
|
case 'risk':
|
|
731
1327
|
return planRisks(parsedArgs);
|
|
732
1328
|
|
|
1329
|
+
case 'route':
|
|
1330
|
+
case 'routing':
|
|
1331
|
+
return planRoute(parsedArgs);
|
|
1332
|
+
|
|
733
1333
|
case 'coherence':
|
|
734
1334
|
return planCoherence(parsedArgs);
|
|
735
1335
|
|