@xagent-ai/cli 1.3.7 → 1.4.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 (65) hide show
  1. package/README.md +9 -0
  2. package/README_CN.md +9 -0
  3. package/dist/cli.js +26 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/mcp.d.ts +8 -1
  6. package/dist/mcp.d.ts.map +1 -1
  7. package/dist/mcp.js +53 -20
  8. package/dist/mcp.js.map +1 -1
  9. package/dist/sdk-output-adapter.d.ts +79 -0
  10. package/dist/sdk-output-adapter.d.ts.map +1 -1
  11. package/dist/sdk-output-adapter.js +118 -0
  12. package/dist/sdk-output-adapter.js.map +1 -1
  13. package/dist/session.d.ts +88 -1
  14. package/dist/session.d.ts.map +1 -1
  15. package/dist/session.js +351 -5
  16. package/dist/session.js.map +1 -1
  17. package/dist/smart-approval.d.ts.map +1 -1
  18. package/dist/smart-approval.js +1 -0
  19. package/dist/smart-approval.js.map +1 -1
  20. package/dist/system-prompt-generator.d.ts +15 -1
  21. package/dist/system-prompt-generator.d.ts.map +1 -1
  22. package/dist/system-prompt-generator.js +36 -27
  23. package/dist/system-prompt-generator.js.map +1 -1
  24. package/dist/team-manager/index.d.ts +6 -0
  25. package/dist/team-manager/index.d.ts.map +1 -0
  26. package/dist/team-manager/index.js +6 -0
  27. package/dist/team-manager/index.js.map +1 -0
  28. package/dist/team-manager/message-broker.d.ts +128 -0
  29. package/dist/team-manager/message-broker.d.ts.map +1 -0
  30. package/dist/team-manager/message-broker.js +638 -0
  31. package/dist/team-manager/message-broker.js.map +1 -0
  32. package/dist/team-manager/team-coordinator.d.ts +45 -0
  33. package/dist/team-manager/team-coordinator.d.ts.map +1 -0
  34. package/dist/team-manager/team-coordinator.js +887 -0
  35. package/dist/team-manager/team-coordinator.js.map +1 -0
  36. package/dist/team-manager/team-store.d.ts +49 -0
  37. package/dist/team-manager/team-store.d.ts.map +1 -0
  38. package/dist/team-manager/team-store.js +436 -0
  39. package/dist/team-manager/team-store.js.map +1 -0
  40. package/dist/team-manager/teammate-spawner.d.ts +86 -0
  41. package/dist/team-manager/teammate-spawner.d.ts.map +1 -0
  42. package/dist/team-manager/teammate-spawner.js +605 -0
  43. package/dist/team-manager/teammate-spawner.js.map +1 -0
  44. package/dist/team-manager/types.d.ts +164 -0
  45. package/dist/team-manager/types.d.ts.map +1 -0
  46. package/dist/team-manager/types.js +27 -0
  47. package/dist/team-manager/types.js.map +1 -0
  48. package/dist/tools.d.ts +41 -1
  49. package/dist/tools.d.ts.map +1 -1
  50. package/dist/tools.js +288 -32
  51. package/dist/tools.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/cli.ts +20 -0
  54. package/src/mcp.ts +64 -25
  55. package/src/sdk-output-adapter.ts +177 -0
  56. package/src/session.ts +423 -15
  57. package/src/smart-approval.ts +1 -0
  58. package/src/system-prompt-generator.ts +59 -26
  59. package/src/team-manager/index.ts +5 -0
  60. package/src/team-manager/message-broker.ts +751 -0
  61. package/src/team-manager/team-coordinator.ts +1117 -0
  62. package/src/team-manager/team-store.ts +558 -0
  63. package/src/team-manager/teammate-spawner.ts +800 -0
  64. package/src/team-manager/types.ts +206 -0
  65. package/src/tools.ts +316 -33
package/src/mcp.ts CHANGED
@@ -16,6 +16,11 @@ export class MCPServer {
16
16
  private tools: Map<string, MCPTool> = new Map();
17
17
  private isConnected: boolean = false;
18
18
  private sessionId: string | null = null; // Save MCP session-id
19
+ private hasLoggedParseWarning: boolean = false; // Whether parse failure warning has been logged
20
+ private connectionAttempted: boolean = false; // Whether connection has been attempted
21
+ private toolsCheckInterval: NodeJS.Timeout | null = null; // Timer ID for tools check
22
+ private toolsCheckStartTime: number = 0; // Start time of tools check
23
+ private pendingToolsPromise: Promise<boolean> | null = null; // Pending promise for tools check
19
24
 
20
25
  constructor(config: MCPServerConfig) {
21
26
  this.config = config;
@@ -30,10 +35,18 @@ export class MCPServer {
30
35
  }
31
36
 
32
37
  async connect(): Promise<void> {
33
- if (this.isConnected) {
34
- return;
35
- }
36
-
38
+ // If already connected, return early
39
+ if (this.isConnected) {
40
+ return;
41
+ }
42
+
43
+ // If connection attempt is in progress (waitForTools not completed), don't start another
44
+ if (this.connectionAttempted) {
45
+ return;
46
+ }
47
+
48
+ // Mark as connection attempt started
49
+ this.connectionAttempted = true;
37
50
  const transportType = this.getTransportType();
38
51
 
39
52
  try {
@@ -44,14 +57,22 @@ export class MCPServer {
44
57
  }
45
58
 
46
59
  // Wait for tools to be loaded (max 10 seconds)
47
- await this.waitForTools(10000);
48
-
49
- this.isConnected = true;
60
+ const toolsLoaded = await this.waitForTools(10000);
50
61
  const session = getSingletonSession();
51
- if (session?.getIsSdkMode()) {
52
- // SDK 模式下不输出
62
+ const isSdkMode = session?.getIsSdkMode();
63
+ const serverInfo = this.config.command || this.config.url || 'unknown';
64
+
65
+ if (toolsLoaded) {
66
+ this.isConnected = true;
67
+ if (!isSdkMode) {
68
+ await logOutput('success', `MCP Server connected`);
69
+ }
53
70
  } else {
54
- await logOutput('success', `MCP Server connected`);
71
+ // Disconnect after timeout
72
+ this.disconnect();
73
+ if (!isSdkMode) {
74
+ await logOutput('warning', `[MCP] Server '${serverInfo}' timed out, skipping`);
75
+ }
55
76
  }
56
77
  } catch (error) {
57
78
  await logOutput('error', `[mcp] Failed to connect MCP Server`, { error: error instanceof Error ? error.message : String(error) });
@@ -62,32 +83,48 @@ export class MCPServer {
62
83
  /**
63
84
  * Wait for tools to be loaded from MCP server
64
85
  * @param timeoutMs Maximum time to wait in milliseconds
86
+ * @returns Promise<boolean> - true if tools loaded, false if timeout
65
87
  */
66
- async waitForTools(timeoutMs: number = 10000): Promise<void> {
88
+ async waitForTools(timeoutMs: number = 10000): Promise<boolean> {
67
89
  if (this.tools.size > 0) {
68
- return; // Tools already loaded
90
+ return true;
91
+ }
92
+
93
+ // If there's already a pending Promise, reuse the previous startTime
94
+ if (this.pendingToolsPromise) {
95
+ return this.pendingToolsPromise;
69
96
  }
70
97
 
71
- return new Promise((resolve, _reject) => {
98
+ this.toolsCheckStartTime = Date.now();
99
+
100
+ this.pendingToolsPromise = new Promise((resolve) => {
72
101
  const checkInterval = 100;
73
- const startTime = Date.now();
74
102
 
75
103
  const check = () => {
76
104
  if (this.tools.size > 0) {
77
- clearInterval(checkInterval);
78
- resolve();
79
- } else if (Date.now() - startTime > timeoutMs) {
80
- clearInterval(checkInterval);
81
- logOutput('warning', `[MCP] Timeout waiting for tools (${timeoutMs}ms), proceeding anyway`);
82
- resolve(); // Don't reject, just proceed without tools
83
- } else {
84
- // Continue checking
105
+ this.cleanupToolsCheck();
106
+ resolve(true);
107
+ } else if (Date.now() - this.toolsCheckStartTime > timeoutMs) {
108
+ this.cleanupToolsCheck();
109
+ const serverInfo = this.config.command || this.config.url || 'unknown';
110
+ logOutput('warning', `[MCP] Server '${serverInfo}' timed out(${timeoutMs}ms), skipping`);
111
+ resolve(false);
85
112
  }
86
113
  };
87
114
 
88
- const _intervalId = setInterval(check, checkInterval);
89
- check(); // Check immediately first
115
+ this.toolsCheckInterval = setInterval(check, checkInterval);
116
+ check();
90
117
  });
118
+
119
+ return this.pendingToolsPromise;
120
+ }
121
+
122
+ private cleanupToolsCheck(): void {
123
+ if (this.toolsCheckInterval) {
124
+ clearInterval(this.toolsCheckInterval);
125
+ this.toolsCheckInterval = null;
126
+ }
127
+ this.pendingToolsPromise = null;
91
128
  }
92
129
 
93
130
  private async connectStdio(): Promise<void> {
@@ -341,7 +378,7 @@ export class MCPServer {
341
378
  }
342
379
  const session = getSingletonSession();
343
380
  if (session?.getIsSdkMode()) {
344
- // SDK 模式下不输出
381
+ // Skip output in SDK mode
345
382
  } else {
346
383
  console.log(`Loaded ${result.tools.length} tools from MCP Server`);
347
384
  }
@@ -654,7 +691,9 @@ export class MCPServer {
654
691
  this.process = null;
655
692
  }
656
693
  this.isConnected = false;
694
+ this.connectionAttempted = false;
657
695
  this.tools.clear();
696
+ this.cleanupToolsCheck();
658
697
  }
659
698
 
660
699
  isServerConnected(): boolean {
@@ -804,6 +804,183 @@ export class SdkOutputAdapter {
804
804
  return modeConfigs[mode.toLowerCase()] || modeConfigs.default;
805
805
  }
806
806
 
807
+ // ==================== Team Output Methods ====================
808
+
809
+ /**
810
+ * Format and output team creation.
811
+ */
812
+ outputTeamCreate(params: {
813
+ teamId: string;
814
+ teamName: string;
815
+ brokerPort: number;
816
+ members: Array<{
817
+ id: string;
818
+ name: string;
819
+ role: string;
820
+ taskId?: string;
821
+ taskTitle?: string;
822
+ }>;
823
+ }): void {
824
+ this.output({
825
+ type: 'system',
826
+ subtype: 'team_create',
827
+ timestamp: Date.now(),
828
+ data: {
829
+ teamId: params.teamId,
830
+ teamName: params.teamName,
831
+ brokerPort: params.brokerPort,
832
+ members: params.members
833
+ }
834
+ });
835
+ }
836
+
837
+ /**
838
+ * Format and output team member spawn.
839
+ */
840
+ outputTeamMemberSpawn(params: {
841
+ memberId: string;
842
+ memberName: string;
843
+ memberRole: string;
844
+ displayMode: string;
845
+ }): void {
846
+ this.output({
847
+ type: 'system',
848
+ subtype: 'team_member_spawn',
849
+ timestamp: Date.now(),
850
+ data: {
851
+ memberId: params.memberId,
852
+ memberName: params.memberName,
853
+ memberRole: params.memberRole,
854
+ displayMode: params.displayMode
855
+ }
856
+ });
857
+ }
858
+
859
+ /**
860
+ * Format and output team member output (filtered/formatted).
861
+ */
862
+ outputTeamMemberOutput(params: {
863
+ memberId: string;
864
+ memberName: string;
865
+ content: string;
866
+ type: 'info' | 'success' | 'error' | 'warning' | 'tool' | 'result';
867
+ }): void {
868
+ this.output({
869
+ type: 'output',
870
+ subtype: 'team_member_output',
871
+ timestamp: Date.now(),
872
+ data: {
873
+ memberId: params.memberId,
874
+ memberName: params.memberName,
875
+ content: params.content,
876
+ outputType: params.type
877
+ }
878
+ });
879
+ }
880
+
881
+ /**
882
+ * Format and output team task update.
883
+ */
884
+ outputTeamTaskUpdate(params: {
885
+ taskId: string;
886
+ taskTitle?: string;
887
+ status: 'created' | 'claimed' | 'in_progress' | 'completed' | 'released' | 'deleted';
888
+ assignee?: string;
889
+ assigneeName?: string;
890
+ result?: string;
891
+ }): void {
892
+ this.output({
893
+ type: 'system',
894
+ subtype: 'team_task_update',
895
+ timestamp: Date.now(),
896
+ data: {
897
+ taskId: params.taskId,
898
+ taskTitle: params.taskTitle,
899
+ status: params.status,
900
+ assignee: params.assignee,
901
+ assigneeName: params.assigneeName,
902
+ result: params.result
903
+ }
904
+ });
905
+ }
906
+
907
+ /**
908
+ * Format and output team message.
909
+ */
910
+ outputTeamMessage(params: {
911
+ messageId: string;
912
+ fromMemberId: string;
913
+ fromMemberName?: string;
914
+ toMemberId: string | 'broadcast';
915
+ content: string;
916
+ }): void {
917
+ this.output({
918
+ type: 'system',
919
+ subtype: 'team_message',
920
+ timestamp: Date.now(),
921
+ data: {
922
+ messageId: params.messageId,
923
+ fromMemberId: params.fromMemberId,
924
+ fromMemberName: params.fromMemberName,
925
+ toMemberId: params.toMemberId,
926
+ content: params.content
927
+ }
928
+ });
929
+ }
930
+
931
+ /**
932
+ * Format and output team cleanup.
933
+ */
934
+ outputTeamCleanup(params: {
935
+ teamId: string;
936
+ teamName?: string;
937
+ shutdownCount: number;
938
+ totalCount: number;
939
+ }): void {
940
+ this.output({
941
+ type: 'system',
942
+ subtype: 'team_cleanup',
943
+ timestamp: Date.now(),
944
+ data: {
945
+ teamId: params.teamId,
946
+ teamName: params.teamName,
947
+ shutdownCount: params.shutdownCount,
948
+ totalCount: params.totalCount
949
+ }
950
+ });
951
+ }
952
+
953
+ /**
954
+ * Format and output team status summary.
955
+ */
956
+ outputTeamStatus(params: {
957
+ teamId: string;
958
+ teamName: string;
959
+ memberCount: number;
960
+ activeTaskCount: number;
961
+ completedTaskCount: number;
962
+ members: Array<{
963
+ id: string;
964
+ name: string;
965
+ role: string;
966
+ status: string;
967
+ }>;
968
+ }): void {
969
+ this.output({
970
+ type: 'system',
971
+ subtype: 'team_status',
972
+ timestamp: Date.now(),
973
+ data: {
974
+ teamId: params.teamId,
975
+ teamName: params.teamName,
976
+ memberCount: params.memberCount,
977
+ activeTaskCount: params.activeTaskCount,
978
+ completedTaskCount: params.completedTaskCount,
979
+ members: params.members
980
+ }
981
+ });
982
+ }
983
+
807
984
  /**
808
985
  * Convert a SessionInput to SDK format.
809
986
  */