musubi-sdd 3.7.1 → 3.8.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/README.ja.md CHANGED
@@ -71,14 +71,14 @@ musubi init --windsurf # Windsurf IDE
71
71
 
72
72
  ---
73
73
 
74
- ## 📊 v2.1.0 の新機能
75
-
76
- - 🔄 **ワークフローエンジン** - ステージ管理とメトリクス収集の新CLI `musubi-workflow`
77
- - 📊 **メトリクス収集** - ステージごとの所要時間、イテレーション回数、フィードバックループを追跡
78
- - 🔬 **Spike/PoCステージ** - 要件定義前の調査・プロトタイピング用ステージ0
79
- - 👀 **コードレビューステージ** - 実装とテストの間のステージ5.5
80
- - 🔄 **振り返りステージ** - 継続的改善のためのステージ9
81
- - **ステージ検証ガイド** - ステージ遷移の検証チェックリスト
74
+ ## 📊 v3.7.1 の新機能
75
+
76
+ - 🌐 **WebSocketリアルタイムGUI** - `musubi-browser`ダッシュボードでライブ更新
77
+ - 📋 **GUIクイックアクション** - 新規要件モーダル、プロジェクト検証、レポートエクスポート
78
+ - 🔄 **GitHub Actions統合** - `musubi-action`でCI/CD検証
79
+ - 🔧 **OpenAPIコンバーター** - OpenAPI 3.x/Swagger 2.xスペックをMUSUBI形式に変換
80
+ - 🌍 **多言語テンプレート** - 7言語対応(EN, JA, ZH, KO, ES, DE, FR)
81
+ - 🤖 **Ollama統合** - 9つのモデルプリセットでローカルLLMをサポート
82
82
 
83
83
  ### 以前のバージョン (v2.0.0)
84
84
 
package/README.md CHANGED
@@ -71,13 +71,14 @@ musubi init --windsurf # Windsurf IDE
71
71
 
72
72
  ---
73
73
 
74
- ## 📊 What's New in v3.6.1
75
-
76
- - 🚀 **ProactivePathOptimizer** - Continuous path optimization even during successful execution
77
- - 🎯 **GoalProgressTracker** - Real-time goal progress monitoring with milestone management
78
- - 🔄 **AdaptiveGoalModifier** - Dynamic goal adjustment based on execution context
79
- - 🛠️ **New CLI Commands** - `replan`, `goal`, `optimize`, `path` subcommands for orchestration
80
- - 📚 **Updated Agent Templates** - All 7 platforms with replanning command documentation
74
+ ## 📊 What's New in v3.7.1
75
+
76
+ - 🌐 **WebSocket Real-time GUI** - Live replanning updates with `musubi-browser` dashboard
77
+ - 📋 **GUI Quick Actions** - Modal dialog for New Requirement, Validate Project, Export Report
78
+ - 🔄 **GitHub Actions Integration** - `musubi-action` for CI/CD with MUSUBI validation
79
+ - 🔧 **OpenAPI Converter** - Convert OpenAPI 3.x/Swagger 2.x specs to MUSUBI format
80
+ - 🌍 **Multi-language Templates** - 7 language support (EN, JA, ZH, KO, ES, DE, FR)
81
+ - 🤖 **Ollama Integration** - Local LLM support with 9 model presets
81
82
 
82
83
  ### Previous (v3.6.0)
83
84
 
@@ -9,6 +9,8 @@
9
9
  * musubi-orchestrate run <pattern> --skills <skills...> # Execute pattern with skills
10
10
  * musubi-orchestrate auto <task> # Auto-select and execute skill
11
11
  * musubi-orchestrate sequential --skills <skills...> # Execute skills sequentially
12
+ * musubi-orchestrate handoff --from <agent> --to <agent> # Delegate to another agent
13
+ * musubi-orchestrate triage --message <msg> # Classify and route request
12
14
  * musubi-orchestrate list-patterns # List available patterns
13
15
  * musubi-orchestrate list-skills # List available skills
14
16
  * musubi-orchestrate status # Show orchestration status
@@ -23,7 +25,15 @@ const {
23
25
  createOrchestrationEngine,
24
26
  PatternType,
25
27
  ExecutionStatus,
26
- Priority
28
+ Priority,
29
+ HandoffPattern,
30
+ HandoffFilters,
31
+ HandoffConfig,
32
+ handoff,
33
+ TriagePattern,
34
+ TriageCategory,
35
+ TriageStrategy,
36
+ AgentCapability
27
37
  } = require('../src/orchestration');
28
38
 
29
39
  const {
@@ -758,6 +768,312 @@ program
758
768
  }
759
769
  });
760
770
 
771
+ // Handoff command - Explicit agent-to-agent delegation
772
+ program
773
+ .command('handoff')
774
+ .description('Execute handoff pattern - Delegate task to another agent')
775
+ .requiredOption('-t, --task <task>', 'Task to handoff')
776
+ .requiredOption('--from <agent>', 'Source agent')
777
+ .requiredOption('--to <agent>', 'Target agent')
778
+ .option('-s, --skills <skills...>', 'Available skills/agents')
779
+ .option('--filter <filter>', 'Input filter (removeAllTools|userMessagesOnly|lastN|summarize|keepAll)', 'keepAll')
780
+ .option('--filter-n <n>', 'N value for lastN filter', '10')
781
+ .option('--reason <reason>', 'Handoff reason')
782
+ .option('--priority <priority>', 'Priority (low|normal|high|urgent)', 'normal')
783
+ .option('-i, --input <json>', 'Additional input data as JSON')
784
+ .option('-f, --format <type>', 'Output format (text|json)', 'text')
785
+ .action(async (options) => {
786
+ try {
787
+ console.log(chalk.bold('\n🤝 Handoff Pattern - Agent Delegation\n'));
788
+ console.log(chalk.dim(`From: ${options.from} → To: ${options.to}\n`));
789
+
790
+ const engine = await createEngine(process.cwd());
791
+
792
+ // Parse additional input
793
+ const additionalInput = options.input ? JSON.parse(options.input) : {};
794
+
795
+ // Select input filter
796
+ let inputFilter;
797
+ switch (options.filter) {
798
+ case 'removeAllTools':
799
+ inputFilter = HandoffFilters.removeAllTools;
800
+ break;
801
+ case 'userMessagesOnly':
802
+ inputFilter = HandoffFilters.userMessagesOnly;
803
+ break;
804
+ case 'lastN':
805
+ inputFilter = HandoffFilters.lastN(parseInt(options.filterN, 10));
806
+ break;
807
+ case 'summarize':
808
+ inputFilter = HandoffFilters.summarize;
809
+ break;
810
+ default:
811
+ inputFilter = HandoffFilters.keepAll;
812
+ }
813
+
814
+ // Create handoff configuration
815
+ const handoffConfig = new HandoffConfig({
816
+ targetAgent: options.to,
817
+ reason: options.reason || `Handoff from ${options.from} to ${options.to}`,
818
+ inputFilter,
819
+ priority: options.priority
820
+ });
821
+
822
+ // Prepare agent definitions
823
+ const agents = [];
824
+ const skills = options.skills || [options.from, options.to];
825
+
826
+ for (const skillName of skills) {
827
+ const skill = engine.getSkill(skillName);
828
+ if (skill) {
829
+ agents.push({
830
+ name: skillName,
831
+ ...skill,
832
+ handoffs: skillName === options.from ? [handoffConfig] : []
833
+ });
834
+ } else {
835
+ // Create placeholder agent
836
+ agents.push({
837
+ name: skillName,
838
+ description: `${skillName} agent`,
839
+ execute: async (input) => ({ agent: skillName, input, executed: true }),
840
+ handoffs: skillName === options.from ? [handoffConfig] : []
841
+ });
842
+ }
843
+ }
844
+
845
+ // Create target agents array as required by HandoffPattern
846
+ const targetAgent = agents.find(a => a.name === options.to) || {
847
+ name: options.to,
848
+ description: `${options.to} agent`,
849
+ execute: async (input) => ({ agent: options.to, input, executed: true })
850
+ };
851
+
852
+ const context = await engine.execute(PatternType.HANDOFF, {
853
+ task: options.task,
854
+ input: {
855
+ sourceAgent: options.from,
856
+ targetAgents: [targetAgent], // Array of target agents
857
+ agents,
858
+ reason: options.reason || `Handoff from ${options.from} to ${options.to}`,
859
+ ...additionalInput
860
+ }
861
+ });
862
+
863
+ if (options.format === 'json') {
864
+ console.log(JSON.stringify({
865
+ success: context.status === ExecutionStatus.COMPLETED,
866
+ sourceAgent: options.from,
867
+ targetAgent: options.to,
868
+ result: context.output,
869
+ handoffChain: context.output?.handoffChain || []
870
+ }, null, 2));
871
+ } else {
872
+ if (context.status === ExecutionStatus.COMPLETED) {
873
+ console.log(chalk.green('✓ Handoff completed successfully\n'));
874
+
875
+ if (context.output?.handoffChain) {
876
+ console.log(chalk.bold('Handoff Chain:'));
877
+ for (const hop of context.output.handoffChain) {
878
+ console.log(` ${chalk.cyan(hop.from)} → ${chalk.yellow(hop.to)}`);
879
+ if (hop.reason) {
880
+ console.log(chalk.dim(` Reason: ${hop.reason}`));
881
+ }
882
+ }
883
+ console.log('');
884
+ }
885
+
886
+ console.log(chalk.bold('Result:'));
887
+ console.log(` Final Agent: ${chalk.cyan(context.output?.finalAgent || options.to)}`);
888
+ console.log(` Status: ${chalk.green('Completed')}`);
889
+ } else {
890
+ console.log(chalk.red(`✗ Handoff failed: ${context.error}\n`));
891
+ process.exit(1);
892
+ }
893
+ }
894
+
895
+ console.log('');
896
+
897
+ } catch (error) {
898
+ console.error(chalk.red(`\n✗ Error: ${error.message}\n`));
899
+ if (process.env.DEBUG) {
900
+ console.error(error.stack);
901
+ }
902
+ process.exit(1);
903
+ }
904
+ });
905
+
906
+ // Triage command - Request classification and routing
907
+ program
908
+ .command('triage')
909
+ .description('Execute triage pattern - Classify and route request to appropriate agent')
910
+ .requiredOption('-m, --message <message>', 'Message/request to classify')
911
+ .option('-s, --skills <skills...>', 'Available agents/skills to route to')
912
+ .option('--strategy <strategy>', 'Classification strategy (keyword|intent|capability|hybrid|llm)', 'hybrid')
913
+ .option('--default-category <category>', 'Default category if no match', 'general')
914
+ .option('--threshold <threshold>', 'Confidence threshold (0-1)', '0.3')
915
+ .option('--auto-handoff', 'Automatically handoff to selected agent', false)
916
+ .option('-f, --format <type>', 'Output format (text|json)', 'text')
917
+ .action(async (options) => {
918
+ try {
919
+ console.log(chalk.bold('\n🎯 Triage Pattern - Request Classification\n'));
920
+ console.log(chalk.dim(`Message: "${options.message.substring(0, 50)}${options.message.length > 50 ? '...' : ''}"\n`));
921
+
922
+ const engine = await createEngine(process.cwd());
923
+
924
+ // Map strategy string to enum
925
+ const strategyMap = {
926
+ 'keyword': TriageStrategy.KEYWORD,
927
+ 'intent': TriageStrategy.INTENT,
928
+ 'capability': TriageStrategy.CAPABILITY,
929
+ 'hybrid': TriageStrategy.HYBRID,
930
+ 'llm': TriageStrategy.LLM
931
+ };
932
+
933
+ const strategy = strategyMap[options.strategy] || TriageStrategy.HYBRID;
934
+
935
+ // Prepare agents with capabilities
936
+ const agents = [];
937
+ const defaultSkills = [
938
+ { name: 'billing-agent', categories: [TriageCategory.BILLING, TriageCategory.REFUND], keywords: ['invoice', 'payment', 'refund', 'charge', 'billing'] },
939
+ { name: 'support-agent', categories: [TriageCategory.SUPPORT], keywords: ['help', 'issue', 'problem', 'broken', 'support'] },
940
+ { name: 'sales-agent', categories: [TriageCategory.SALES], keywords: ['buy', 'purchase', 'pricing', 'discount', 'order'] },
941
+ { name: 'technical-agent', categories: [TriageCategory.TECHNICAL], keywords: ['api', 'bug', 'error', 'integration', 'code'] },
942
+ { name: 'general-agent', categories: [TriageCategory.GENERAL], keywords: [] }
943
+ ];
944
+
945
+ const skillNames = options.skills || defaultSkills.map(s => s.name);
946
+
947
+ for (const skillName of skillNames) {
948
+ const skill = engine.getSkill(skillName);
949
+ const defaultSkill = defaultSkills.find(s => s.name === skillName);
950
+
951
+ const agentObj = {
952
+ name: skillName,
953
+ description: skill?.description || `${skillName} agent`,
954
+ execute: skill?.execute || (async (input) => ({ agent: skillName, input, executed: true }))
955
+ };
956
+
957
+ agentObj.capability = new AgentCapability({
958
+ agent: agentObj, // Reference to agent object
959
+ categories: defaultSkill?.categories || [TriageCategory.GENERAL],
960
+ keywords: defaultSkill?.keywords || [],
961
+ priority: 1
962
+ });
963
+
964
+ agents.push(agentObj);
965
+ }
966
+
967
+ const context = await engine.execute(PatternType.TRIAGE, {
968
+ task: 'Classify and route request',
969
+ input: {
970
+ message: options.message,
971
+ agents,
972
+ strategy,
973
+ defaultCategory: options.defaultCategory.toUpperCase(),
974
+ confidenceThreshold: parseFloat(options.threshold),
975
+ enableHandoff: options.autoHandoff // Only handoff if explicitly requested
976
+ }
977
+ });
978
+
979
+ if (options.format === 'json') {
980
+ console.log(JSON.stringify({
981
+ success: context.status === ExecutionStatus.COMPLETED,
982
+ classification: context.output?.classification,
983
+ selectedAgent: context.output?.selectedAgent,
984
+ confidence: context.output?.confidence,
985
+ category: context.output?.category
986
+ }, null, 2));
987
+ } else {
988
+ if (context.status === ExecutionStatus.COMPLETED) {
989
+ console.log(chalk.green('✓ Triage completed\n'));
990
+
991
+ const classification = context.output?.classification || context.output;
992
+
993
+ console.log(chalk.bold('Classification Result:'));
994
+ console.log(` Category: ${chalk.cyan(classification?.category || 'N/A')}`);
995
+ console.log(` Confidence: ${formatConfidence(classification?.confidence || 0)}`);
996
+ if (classification?.reasoning) {
997
+ console.log(` Reasoning: ${chalk.dim(classification.reasoning)}`);
998
+ }
999
+ console.log('');
1000
+
1001
+ if (context.output?.selectedAgent) {
1002
+ console.log(chalk.bold('Routing Decision:'));
1003
+ console.log(` Selected Agent: ${chalk.yellow(context.output.selectedAgent)}`);
1004
+ console.log(` Agent Score: ${(context.output.agentScore || 0).toFixed(2)}`);
1005
+ }
1006
+
1007
+ if (options.autoHandoff && context.output?.handoffResult) {
1008
+ console.log('');
1009
+ console.log(chalk.bold('Handoff Result:'));
1010
+ console.log(` Status: ${chalk.green('Executed')}`);
1011
+ }
1012
+ } else {
1013
+ console.log(chalk.red(`✗ Triage failed: ${context.error}\n`));
1014
+ process.exit(1);
1015
+ }
1016
+ }
1017
+
1018
+ console.log('');
1019
+
1020
+ } catch (error) {
1021
+ console.error(chalk.red(`\n✗ Error: ${error.message}\n`));
1022
+ if (process.env.DEBUG) {
1023
+ console.error(error.stack);
1024
+ }
1025
+ process.exit(1);
1026
+ }
1027
+ });
1028
+
1029
+ // Triage categories command - List available categories
1030
+ program
1031
+ .command('triage-categories')
1032
+ .description('List available triage categories')
1033
+ .option('-f, --format <type>', 'Output format (text|json)', 'text')
1034
+ .action(async (options) => {
1035
+ try {
1036
+ console.log(chalk.bold('\n📋 Triage Categories\n'));
1037
+
1038
+ const categories = Object.entries(TriageCategory).map(([key, value]) => ({
1039
+ key,
1040
+ value,
1041
+ description: getCategoryDescription(value)
1042
+ }));
1043
+
1044
+ if (options.format === 'json') {
1045
+ console.log(JSON.stringify(categories, null, 2));
1046
+ } else {
1047
+ for (const cat of categories) {
1048
+ console.log(` ${chalk.cyan(cat.value.padEnd(12))} - ${cat.description}`);
1049
+ }
1050
+ }
1051
+
1052
+ console.log('');
1053
+
1054
+ } catch (error) {
1055
+ console.error(chalk.red(`\n✗ Error: ${error.message}\n`));
1056
+ process.exit(1);
1057
+ }
1058
+ });
1059
+
1060
+ /**
1061
+ * Get category description
1062
+ */
1063
+ function getCategoryDescription(category) {
1064
+ const descriptions = {
1065
+ [TriageCategory.BILLING]: 'Billing, invoices, payments, refunds',
1066
+ [TriageCategory.SUPPORT]: 'General support, help requests, issues',
1067
+ [TriageCategory.SALES]: 'Sales inquiries, purchases, pricing',
1068
+ [TriageCategory.TECHNICAL]: 'Technical issues, bugs, API, integrations',
1069
+ [TriageCategory.REFUND]: 'Refund requests and processing',
1070
+ [TriageCategory.GENERAL]: 'General inquiries, catch-all category',
1071
+ [TriageCategory.ESCALATION]: 'Escalated issues requiring supervisor attention',
1072
+ [TriageCategory.UNKNOWN]: 'Unclassified requests'
1073
+ };
1074
+ return descriptions[category] || 'Unknown category';
1075
+ }
1076
+
761
1077
  program.parse(process.argv);
762
1078
 
763
1079
  if (!process.argv.slice(2).length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musubi-sdd",
3
- "version": "3.7.1",
3
+ "version": "3.8.0",
4
4
  "description": "Ultimate Specification Driven Development Tool with 27 Agents for 7 AI Coding Platforms + MCP Integration (Claude Code, GitHub Copilot, Cursor, Gemini CLI, Windsurf, Codex, Qwen Code)",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -6,8 +6,10 @@
6
6
  * - Sequential: Linear skill execution
7
7
  * - Nested: Hierarchical skill delegation
8
8
  * - GroupChat: Multi-skill collaborative discussion
9
- * - Swarm: Parallel skill execution (coming soon)
9
+ * - Swarm: Parallel skill execution
10
10
  * - HumanInLoop: Validation gates
11
+ * - Handoff: Explicit agent-to-agent delegation (OpenAI Agents SDK inspired)
12
+ * - Triage: Request classification and routing (OpenAI Agents SDK inspired)
11
13
  */
12
14
 
13
15
  const {
@@ -63,6 +65,25 @@ const {
63
65
  createSwarmPattern
64
66
  } = require('./patterns/swarm');
65
67
 
68
+ const {
69
+ HandoffPattern,
70
+ HandoffFilters,
71
+ EscalationData,
72
+ HandoffConfig,
73
+ handoff,
74
+ createHandoffPattern
75
+ } = require('./patterns/handoff');
76
+
77
+ const {
78
+ TriagePattern,
79
+ TriageCategory,
80
+ TriageStrategy,
81
+ AgentCapability,
82
+ TriageResult,
83
+ DEFAULT_KEYWORD_MAPPINGS,
84
+ createTriagePattern
85
+ } = require('./patterns/triage');
86
+
66
87
  const {
67
88
  WorkflowOrchestrator,
68
89
  StepType,
@@ -102,6 +123,8 @@ function createOrchestrationEngine(options = {}) {
102
123
  registry.register(PatternType.GROUP_CHAT, createGroupChatPattern());
103
124
  registry.register(PatternType.HUMAN_IN_LOOP, createHumanInLoopPattern());
104
125
  registry.register(PatternType.SWARM, createSwarmPattern());
126
+ registry.register(PatternType.HANDOFF, createHandoffPattern());
127
+ registry.register(PatternType.TRIAGE, createTriagePattern());
105
128
 
106
129
  // Register patterns with engine
107
130
  registry.registerWithEngine(engine);
@@ -167,6 +190,21 @@ module.exports = {
167
190
  SwarmStrategy,
168
191
  createSwarmPattern,
169
192
 
193
+ HandoffPattern,
194
+ HandoffFilters,
195
+ EscalationData,
196
+ HandoffConfig,
197
+ handoff,
198
+ createHandoffPattern,
199
+
200
+ TriagePattern,
201
+ TriageCategory,
202
+ TriageStrategy,
203
+ AgentCapability,
204
+ TriageResult,
205
+ DEFAULT_KEYWORD_MAPPINGS,
206
+ createTriagePattern,
207
+
170
208
  // Workflow Orchestrator
171
209
  WorkflowOrchestrator,
172
210
  StepType,
@@ -8,6 +8,8 @@
8
8
  * - GroupChat: Multi-skill collaborative discussion
9
9
  * - Swarm: Parallel skill execution
10
10
  * - HumanInLoop: Validation gates
11
+ * - Handoff: Agent delegation (v3.8.0)
12
+ * - Triage: Request classification and routing (v3.8.0)
11
13
  */
12
14
 
13
15
  const EventEmitter = require('events');
@@ -21,7 +23,9 @@ const PatternType = {
21
23
  NESTED: 'nested',
22
24
  GROUP_CHAT: 'group-chat',
23
25
  SWARM: 'swarm',
24
- HUMAN_IN_LOOP: 'human-in-loop'
26
+ HUMAN_IN_LOOP: 'human-in-loop',
27
+ HANDOFF: 'handoff',
28
+ TRIAGE: 'triage'
25
29
  };
26
30
 
27
31
  /**