claude-flow 1.0.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +612 -0
  3. package/bin/claude-flow +0 -0
  4. package/bin/claude-flow-simple +0 -0
  5. package/bin/claude-flow-typecheck +0 -0
  6. package/deno.json +84 -0
  7. package/package.json +45 -0
  8. package/scripts/check-links.ts +274 -0
  9. package/scripts/check-performance-regression.ts +168 -0
  10. package/scripts/claude-sparc.sh +562 -0
  11. package/scripts/coverage-report.ts +692 -0
  12. package/scripts/demo-task-system.ts +224 -0
  13. package/scripts/install.js +72 -0
  14. package/scripts/test-batch-tasks.ts +29 -0
  15. package/scripts/test-coordination-features.ts +238 -0
  16. package/scripts/test-mcp.ts +251 -0
  17. package/scripts/test-runner.ts +571 -0
  18. package/scripts/validate-examples.ts +288 -0
  19. package/src/cli/cli-core.ts +273 -0
  20. package/src/cli/commands/agent.ts +83 -0
  21. package/src/cli/commands/config.ts +442 -0
  22. package/src/cli/commands/help.ts +765 -0
  23. package/src/cli/commands/index.ts +963 -0
  24. package/src/cli/commands/mcp.ts +191 -0
  25. package/src/cli/commands/memory.ts +74 -0
  26. package/src/cli/commands/monitor.ts +403 -0
  27. package/src/cli/commands/session.ts +595 -0
  28. package/src/cli/commands/start.ts +156 -0
  29. package/src/cli/commands/status.ts +345 -0
  30. package/src/cli/commands/task.ts +79 -0
  31. package/src/cli/commands/workflow.ts +763 -0
  32. package/src/cli/completion.ts +553 -0
  33. package/src/cli/formatter.ts +310 -0
  34. package/src/cli/index.ts +211 -0
  35. package/src/cli/main.ts +23 -0
  36. package/src/cli/repl.ts +1050 -0
  37. package/src/cli/simple-cli.js +211 -0
  38. package/src/cli/simple-cli.ts +211 -0
  39. package/src/coordination/README.md +400 -0
  40. package/src/coordination/advanced-scheduler.ts +487 -0
  41. package/src/coordination/circuit-breaker.ts +366 -0
  42. package/src/coordination/conflict-resolution.ts +490 -0
  43. package/src/coordination/dependency-graph.ts +475 -0
  44. package/src/coordination/index.ts +63 -0
  45. package/src/coordination/manager.ts +460 -0
  46. package/src/coordination/messaging.ts +290 -0
  47. package/src/coordination/metrics.ts +585 -0
  48. package/src/coordination/resources.ts +322 -0
  49. package/src/coordination/scheduler.ts +390 -0
  50. package/src/coordination/work-stealing.ts +224 -0
  51. package/src/core/config.ts +627 -0
  52. package/src/core/event-bus.ts +186 -0
  53. package/src/core/json-persistence.ts +183 -0
  54. package/src/core/logger.ts +262 -0
  55. package/src/core/orchestrator-fixed.ts +312 -0
  56. package/src/core/orchestrator.ts +1234 -0
  57. package/src/core/persistence.ts +276 -0
  58. package/src/mcp/auth.ts +438 -0
  59. package/src/mcp/claude-flow-tools.ts +1280 -0
  60. package/src/mcp/load-balancer.ts +510 -0
  61. package/src/mcp/router.ts +240 -0
  62. package/src/mcp/server.ts +548 -0
  63. package/src/mcp/session-manager.ts +418 -0
  64. package/src/mcp/tools.ts +180 -0
  65. package/src/mcp/transports/base.ts +21 -0
  66. package/src/mcp/transports/http.ts +457 -0
  67. package/src/mcp/transports/stdio.ts +254 -0
  68. package/src/memory/backends/base.ts +22 -0
  69. package/src/memory/backends/markdown.ts +283 -0
  70. package/src/memory/backends/sqlite.ts +329 -0
  71. package/src/memory/cache.ts +238 -0
  72. package/src/memory/indexer.ts +238 -0
  73. package/src/memory/manager.ts +572 -0
  74. package/src/terminal/adapters/base.ts +29 -0
  75. package/src/terminal/adapters/native.ts +504 -0
  76. package/src/terminal/adapters/vscode.ts +340 -0
  77. package/src/terminal/manager.ts +308 -0
  78. package/src/terminal/pool.ts +271 -0
  79. package/src/terminal/session.ts +250 -0
  80. package/src/terminal/vscode-bridge.ts +242 -0
  81. package/src/utils/errors.ts +231 -0
  82. package/src/utils/helpers.ts +476 -0
  83. package/src/utils/types.ts +493 -0
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Terminal pool management
3
+ */
4
+
5
+ import { Terminal, ITerminalAdapter } from './adapters/base.ts';
6
+ import { ILogger } from '../core/logger.ts';
7
+ import { TerminalError } from '../utils/errors.ts';
8
+ import { delay } from '../utils/helpers.ts';
9
+
10
+ interface PooledTerminal {
11
+ terminal: Terminal;
12
+ useCount: number;
13
+ lastUsed: Date;
14
+ inUse: boolean;
15
+ }
16
+
17
+ /**
18
+ * Terminal pool for efficient resource management
19
+ */
20
+ export class TerminalPool {
21
+ private terminals = new Map<string, PooledTerminal>();
22
+ private availableQueue: string[] = [];
23
+ private initializationPromise?: Promise<void>;
24
+
25
+ constructor(
26
+ private maxSize: number,
27
+ private recycleAfter: number,
28
+ private adapter: ITerminalAdapter,
29
+ private logger: ILogger,
30
+ ) {}
31
+
32
+ async initialize(): Promise<void> {
33
+ if (this.initializationPromise) {
34
+ return this.initializationPromise;
35
+ }
36
+
37
+ this.initializationPromise = this.doInitialize();
38
+ return this.initializationPromise;
39
+ }
40
+
41
+ private async doInitialize(): Promise<void> {
42
+ this.logger.info('Initializing terminal pool', {
43
+ maxSize: this.maxSize,
44
+ recycleAfter: this.recycleAfter,
45
+ });
46
+
47
+ // Pre-create some terminals
48
+ const preCreateCount = Math.min(2, this.maxSize);
49
+ const promises: Promise<void>[] = [];
50
+
51
+ for (let i = 0; i < preCreateCount; i++) {
52
+ promises.push(this.createPooledTerminal());
53
+ }
54
+
55
+ await Promise.all(promises);
56
+
57
+ this.logger.info('Terminal pool initialized', {
58
+ created: preCreateCount,
59
+ });
60
+ }
61
+
62
+ async shutdown(): Promise<void> {
63
+ this.logger.info('Shutting down terminal pool');
64
+
65
+ // Destroy all terminals
66
+ const terminals = Array.from(this.terminals.values());
67
+ await Promise.all(
68
+ terminals.map(({ terminal }) => this.adapter.destroyTerminal(terminal)),
69
+ );
70
+
71
+ this.terminals.clear();
72
+ this.availableQueue = [];
73
+ }
74
+
75
+ async acquire(): Promise<Terminal> {
76
+ // Try to get an available terminal
77
+ while (this.availableQueue.length > 0) {
78
+ const terminalId = this.availableQueue.shift()!;
79
+ const pooled = this.terminals.get(terminalId);
80
+
81
+ if (pooled && pooled.terminal.isAlive()) {
82
+ pooled.inUse = true;
83
+ pooled.lastUsed = new Date();
84
+
85
+ this.logger.debug('Terminal acquired from pool', {
86
+ terminalId,
87
+ useCount: pooled.useCount,
88
+ });
89
+
90
+ return pooled.terminal;
91
+ }
92
+
93
+ // Terminal is dead, remove it
94
+ if (pooled) {
95
+ this.terminals.delete(terminalId);
96
+ }
97
+ }
98
+
99
+ // No available terminals, create new one if under limit
100
+ if (this.terminals.size < this.maxSize) {
101
+ await this.createPooledTerminal();
102
+ return this.acquire(); // Recursive call to get the newly created terminal
103
+ }
104
+
105
+ // Pool is full, wait for a terminal to become available
106
+ this.logger.info('Terminal pool full, waiting for available terminal');
107
+
108
+ const startTime = Date.now();
109
+ const timeout = 30000; // 30 seconds
110
+
111
+ while (Date.now() - startTime < timeout) {
112
+ await delay(100);
113
+
114
+ // Check if any terminal became available
115
+ const available = Array.from(this.terminals.values()).find(
116
+ (pooled) => !pooled.inUse && pooled.terminal.isAlive(),
117
+ );
118
+
119
+ if (available) {
120
+ available.inUse = true;
121
+ available.lastUsed = new Date();
122
+ return available.terminal;
123
+ }
124
+ }
125
+
126
+ throw new TerminalError('No terminal available in pool (timeout)');
127
+ }
128
+
129
+ async release(terminal: Terminal): Promise<void> {
130
+ const pooled = this.terminals.get(terminal.id);
131
+ if (!pooled) {
132
+ this.logger.warn('Attempted to release unknown terminal', {
133
+ terminalId: terminal.id,
134
+ });
135
+ return;
136
+ }
137
+
138
+ pooled.useCount++;
139
+ pooled.inUse = false;
140
+
141
+ // Check if terminal should be recycled
142
+ if (pooled.useCount >= this.recycleAfter || !terminal.isAlive()) {
143
+ this.logger.info('Recycling terminal', {
144
+ terminalId: terminal.id,
145
+ useCount: pooled.useCount,
146
+ });
147
+
148
+ // Destroy old terminal
149
+ this.terminals.delete(terminal.id);
150
+ await this.adapter.destroyTerminal(terminal);
151
+
152
+ // Create replacement if under limit
153
+ if (this.terminals.size < this.maxSize) {
154
+ await this.createPooledTerminal();
155
+ }
156
+ } else {
157
+ // Return to available queue
158
+ this.availableQueue.push(terminal.id);
159
+
160
+ this.logger.debug('Terminal returned to pool', {
161
+ terminalId: terminal.id,
162
+ useCount: pooled.useCount,
163
+ });
164
+ }
165
+ }
166
+
167
+ async getHealthStatus(): Promise<{
168
+ healthy: boolean;
169
+ size: number;
170
+ available: number;
171
+ recycled: number;
172
+ }> {
173
+ const aliveTerminals = Array.from(this.terminals.values()).filter(
174
+ (pooled) => pooled.terminal.isAlive(),
175
+ );
176
+
177
+ const available = aliveTerminals.filter((pooled) => !pooled.inUse).length;
178
+ const recycled = Array.from(this.terminals.values()).filter(
179
+ (pooled) => pooled.useCount >= this.recycleAfter,
180
+ ).length;
181
+
182
+ return {
183
+ healthy: aliveTerminals.length > 0,
184
+ size: this.terminals.size,
185
+ available,
186
+ recycled,
187
+ };
188
+ }
189
+
190
+ async performMaintenance(): Promise<void> {
191
+ this.logger.debug('Performing terminal pool maintenance');
192
+
193
+ // Remove dead terminals
194
+ const deadTerminals: string[] = [];
195
+ for (const [id, pooled] of this.terminals.entries()) {
196
+ if (!pooled.terminal.isAlive()) {
197
+ deadTerminals.push(id);
198
+ }
199
+ }
200
+
201
+ // Clean up dead terminals
202
+ for (const id of deadTerminals) {
203
+ this.logger.warn('Removing dead terminal from pool', { terminalId: id });
204
+ this.terminals.delete(id);
205
+ const index = this.availableQueue.indexOf(id);
206
+ if (index !== -1) {
207
+ this.availableQueue.splice(index, 1);
208
+ }
209
+ }
210
+
211
+ // Ensure minimum pool size
212
+ const currentSize = this.terminals.size;
213
+ const minSize = Math.min(2, this.maxSize);
214
+
215
+ if (currentSize < minSize) {
216
+ const toCreate = minSize - currentSize;
217
+ this.logger.info('Replenishing terminal pool', {
218
+ currentSize,
219
+ minSize,
220
+ creating: toCreate,
221
+ });
222
+
223
+ const promises: Promise<void>[] = [];
224
+ for (let i = 0; i < toCreate; i++) {
225
+ promises.push(this.createPooledTerminal());
226
+ }
227
+
228
+ await Promise.all(promises);
229
+ }
230
+
231
+ // Check for stale terminals that should be recycled
232
+ const now = Date.now();
233
+ const staleTimeout = 300000; // 5 minutes
234
+
235
+ for (const [id, pooled] of this.terminals.entries()) {
236
+ if (!pooled.inUse && pooled.terminal.isAlive()) {
237
+ const idleTime = now - pooled.lastUsed.getTime();
238
+ if (idleTime > staleTimeout) {
239
+ this.logger.info('Recycling stale terminal', {
240
+ terminalId: id,
241
+ idleTime,
242
+ });
243
+
244
+ // Mark for recycling
245
+ pooled.useCount = this.recycleAfter;
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ private async createPooledTerminal(): Promise<void> {
252
+ try {
253
+ const terminal = await this.adapter.createTerminal();
254
+
255
+ const pooled: PooledTerminal = {
256
+ terminal,
257
+ useCount: 0,
258
+ lastUsed: new Date(),
259
+ inUse: false,
260
+ };
261
+
262
+ this.terminals.set(terminal.id, pooled);
263
+ this.availableQueue.push(terminal.id);
264
+
265
+ this.logger.debug('Created pooled terminal', { terminalId: terminal.id });
266
+ } catch (error) {
267
+ this.logger.error('Failed to create pooled terminal', error);
268
+ throw error;
269
+ }
270
+ }
271
+ }
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Terminal session management
3
+ */
4
+
5
+ import { Terminal } from './adapters/base.ts';
6
+ import { AgentProfile } from '../utils/types.ts';
7
+ import { ILogger } from '../core/logger.ts';
8
+ import { TerminalCommandError } from '../utils/errors.ts';
9
+ import { generateId, timeout } from '../utils/helpers.ts';
10
+
11
+ /**
12
+ * Terminal session wrapper
13
+ */
14
+ export class TerminalSession {
15
+ readonly id: string;
16
+ readonly startTime: Date;
17
+ private initialized = false;
18
+ private commandHistory: string[] = [];
19
+ private lastCommandTime?: Date;
20
+ private outputListeners = new Set<(output: string) => void>();
21
+
22
+ constructor(
23
+ public readonly terminal: Terminal,
24
+ public readonly profile: AgentProfile,
25
+ private commandTimeout: number,
26
+ private logger: ILogger,
27
+ ) {
28
+ this.id = generateId('session');
29
+ this.startTime = new Date();
30
+ }
31
+
32
+ get lastActivity(): Date {
33
+ return this.lastCommandTime || this.startTime;
34
+ }
35
+
36
+ async initialize(): Promise<void> {
37
+ if (this.initialized) {
38
+ return;
39
+ }
40
+
41
+ this.logger.debug('Initializing terminal session', {
42
+ sessionId: this.id,
43
+ agentId: this.profile.id,
44
+ });
45
+
46
+ try {
47
+ // Set up environment
48
+ await this.setupEnvironment();
49
+
50
+ // Run initialization commands
51
+ await this.runInitializationCommands();
52
+
53
+ this.initialized = true;
54
+
55
+ this.logger.info('Terminal session initialized', {
56
+ sessionId: this.id,
57
+ agentId: this.profile.id,
58
+ });
59
+ } catch (error) {
60
+ this.logger.error('Failed to initialize terminal session', error);
61
+ throw error;
62
+ }
63
+ }
64
+
65
+ async executeCommand(command: string): Promise<string> {
66
+ if (!this.initialized) {
67
+ throw new TerminalCommandError('Session not initialized');
68
+ }
69
+
70
+ if (!this.terminal.isAlive()) {
71
+ throw new TerminalCommandError('Terminal is not alive');
72
+ }
73
+
74
+ this.logger.debug('Executing command', {
75
+ sessionId: this.id,
76
+ command: command.substring(0, 100),
77
+ });
78
+
79
+ try {
80
+ // Notify listeners of command
81
+ this.notifyOutputListeners(`$ ${command}\n`);
82
+
83
+ // Execute with timeout
84
+ const result = await timeout(
85
+ this.terminal.executeCommand(command),
86
+ this.commandTimeout,
87
+ `Command timeout after ${this.commandTimeout}ms`,
88
+ );
89
+
90
+ // Notify listeners of output
91
+ this.notifyOutputListeners(result);
92
+
93
+ // Update history
94
+ this.commandHistory.push(command);
95
+ this.lastCommandTime = new Date();
96
+
97
+ this.logger.debug('Command executed successfully', {
98
+ sessionId: this.id,
99
+ outputLength: result.length,
100
+ });
101
+
102
+ return result;
103
+ } catch (error) {
104
+ this.logger.error('Command execution failed', {
105
+ sessionId: this.id,
106
+ command,
107
+ error,
108
+ });
109
+ throw new TerminalCommandError('Command execution failed', {
110
+ command,
111
+ error,
112
+ });
113
+ }
114
+ }
115
+
116
+ async cleanup(): Promise<void> {
117
+ this.logger.debug('Cleaning up terminal session', { sessionId: this.id });
118
+
119
+ try {
120
+ // Run cleanup commands
121
+ await this.runCleanupCommands();
122
+ } catch (error) {
123
+ this.logger.warn('Error during session cleanup', {
124
+ sessionId: this.id,
125
+ error,
126
+ });
127
+ }
128
+ }
129
+
130
+ isHealthy(): boolean {
131
+ if (!this.terminal.isAlive()) {
132
+ return false;
133
+ }
134
+
135
+ // Check if terminal is responsive
136
+ if (this.lastCommandTime) {
137
+ const timeSinceLastCommand = Date.now() - this.lastCommandTime.getTime();
138
+ if (timeSinceLastCommand > 300000) { // 5 minutes
139
+ // Terminal might be stale, do a health check
140
+ this.performHealthCheck().catch((error) => {
141
+ this.logger.warn('Health check failed', { sessionId: this.id, error });
142
+ });
143
+ }
144
+ }
145
+
146
+ return true;
147
+ }
148
+
149
+ getCommandHistory(): string[] {
150
+ return [...this.commandHistory];
151
+ }
152
+
153
+ private async setupEnvironment(): Promise<void> {
154
+ // Set environment variables
155
+ const envVars = {
156
+ CLAUDE_FLOW_SESSION: this.id,
157
+ CLAUDE_FLOW_AGENT: this.profile.id,
158
+ CLAUDE_FLOW_AGENT_TYPE: this.profile.type,
159
+ };
160
+
161
+ for (const [key, value] of Object.entries(envVars)) {
162
+ await this.terminal.executeCommand(`export ${key}="${value}"`);
163
+ }
164
+
165
+ // Set working directory if specified
166
+ if (this.profile.metadata?.workingDirectory) {
167
+ await this.terminal.executeCommand(
168
+ `cd "${this.profile.metadata.workingDirectory}"`,
169
+ );
170
+ }
171
+ }
172
+
173
+ private async runInitializationCommands(): Promise<void> {
174
+ // Run any profile-specific initialization commands
175
+ if (this.profile.metadata?.initCommands) {
176
+ const commands = this.profile.metadata.initCommands as string[];
177
+ for (const command of commands) {
178
+ await this.terminal.executeCommand(command);
179
+ }
180
+ }
181
+
182
+ // Set up command prompt
183
+ await this.terminal.executeCommand('export PS1="[claude-flow]$ "');
184
+ }
185
+
186
+ private async runCleanupCommands(): Promise<void> {
187
+ // Run any profile-specific cleanup commands
188
+ if (this.profile.metadata?.cleanupCommands) {
189
+ const commands = this.profile.metadata.cleanupCommands as string[];
190
+ for (const command of commands) {
191
+ try {
192
+ await this.terminal.executeCommand(command);
193
+ } catch {
194
+ // Ignore cleanup errors
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ private async performHealthCheck(): Promise<void> {
201
+ try {
202
+ const result = await timeout(
203
+ this.terminal.executeCommand('echo "HEALTH_CHECK_OK"'),
204
+ 5000,
205
+ 'Health check timeout',
206
+ );
207
+
208
+ if (!result.includes('HEALTH_CHECK_OK')) {
209
+ throw new Error('Invalid health check response');
210
+ }
211
+
212
+ this.lastCommandTime = new Date();
213
+ } catch (error) {
214
+ throw new Error(`Health check failed: ${error instanceof Error ? error.message : String(error)}`);
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Stream terminal output
220
+ */
221
+ streamOutput(callback: (output: string) => void): () => void {
222
+ this.outputListeners.add(callback);
223
+
224
+ // Set up terminal output listener if supported
225
+ if (this.terminal.addOutputListener) {
226
+ this.terminal.addOutputListener(callback);
227
+ }
228
+
229
+ // Return unsubscribe function
230
+ return () => {
231
+ this.outputListeners.delete(callback);
232
+ if (this.terminal.removeOutputListener) {
233
+ this.terminal.removeOutputListener(callback);
234
+ }
235
+ };
236
+ }
237
+
238
+ /**
239
+ * Notify output listeners
240
+ */
241
+ private notifyOutputListeners(output: string): void {
242
+ this.outputListeners.forEach(listener => {
243
+ try {
244
+ listener(output);
245
+ } catch (error) {
246
+ this.logger.error('Error in output listener', { sessionId: this.id, error });
247
+ }
248
+ });
249
+ }
250
+ }