claudehq 1.0.3 → 1.0.5
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/lib/core/claude-events.js +2 -1
- package/lib/core/config.js +31 -17
- package/lib/core/event-bus.js +0 -18
- package/lib/index.js +181 -74
- package/lib/routes/api.js +0 -399
- package/lib/routes/orchestration.js +417 -0
- package/lib/routes/spawner.js +335 -0
- package/lib/sessions/manager.js +36 -9
- package/lib/spawner/index.js +51 -0
- package/lib/spawner/path-validator.js +366 -0
- package/lib/spawner/projects-manager.js +421 -0
- package/lib/spawner/session-spawner.js +1010 -0
- package/package.json +1 -1
- package/public/index.html +512 -1371
|
@@ -175,12 +175,13 @@ function loadEventsFromFile() {
|
|
|
175
175
|
console.log(` Loaded ${claudeEvents.length} Claude events from: ${EVENTS_FILE}`);
|
|
176
176
|
|
|
177
177
|
// Discover sessions from loaded events (process unique session IDs)
|
|
178
|
+
// Pass skipAutoUnhide: true to prevent unhiding sessions during initialization
|
|
178
179
|
if (sessionUpdateCallback) {
|
|
179
180
|
const sessionIds = new Set();
|
|
180
181
|
for (const event of claudeEvents) {
|
|
181
182
|
if (event.sessionId && !sessionIds.has(event.sessionId)) {
|
|
182
183
|
sessionIds.add(event.sessionId);
|
|
183
|
-
sessionUpdateCallback(event);
|
|
184
|
+
sessionUpdateCallback(event, { skipAutoUnhide: true });
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
187
|
}
|
package/lib/core/config.js
CHANGED
|
@@ -16,7 +16,6 @@ const TODOS_DIR = path.join(CLAUDE_DIR, 'todos');
|
|
|
16
16
|
const PLANS_DIR = path.join(CLAUDE_DIR, 'plans');
|
|
17
17
|
const PROJECTS_DIR = path.join(CLAUDE_DIR, 'projects');
|
|
18
18
|
const EVENTS_DIR = path.join(CLAUDE_DIR, 'tasks-board');
|
|
19
|
-
const ORCHESTRATIONS_DIR = path.join(CLAUDE_DIR, 'tasks-board', 'orchestrations');
|
|
20
19
|
|
|
21
20
|
// Data files
|
|
22
21
|
const CUSTOM_NAMES_FILE = path.join(TASKS_DIR, 'session-names.json');
|
|
@@ -36,7 +35,20 @@ const SESSION_STATUS = {
|
|
|
36
35
|
OFFLINE: 'offline'
|
|
37
36
|
};
|
|
38
37
|
|
|
39
|
-
//
|
|
38
|
+
// Timeouts and intervals
|
|
39
|
+
const HEALTH_CHECK_INTERVAL = 5000; // 5 seconds
|
|
40
|
+
const WORKING_TIMEOUT = 5 * 60 * 1000; // 5 minutes
|
|
41
|
+
const PERMISSION_POLL_INTERVAL = 1000; // 1 second
|
|
42
|
+
const EVENT_DEBOUNCE_DELAY = 100; // 100ms
|
|
43
|
+
|
|
44
|
+
// Limits
|
|
45
|
+
const MAX_EVENTS_IN_MEMORY = 1000;
|
|
46
|
+
const MAX_EVENTS_TO_BROADCAST = 500;
|
|
47
|
+
|
|
48
|
+
// Orchestration directories and status
|
|
49
|
+
const ORCHESTRATIONS_DIR = path.join(EVENTS_DIR, 'orchestrations');
|
|
50
|
+
|
|
51
|
+
// Agent status constants
|
|
40
52
|
const AGENT_STATUS = {
|
|
41
53
|
PENDING: 'pending',
|
|
42
54
|
SPAWNING: 'spawning',
|
|
@@ -51,20 +63,17 @@ const AGENT_STATUS = {
|
|
|
51
63
|
const ORCHESTRATION_STATUS = {
|
|
52
64
|
DRAFT: 'draft',
|
|
53
65
|
RUNNING: 'running',
|
|
54
|
-
PAUSED: 'paused',
|
|
55
66
|
COMPLETED: 'completed',
|
|
56
|
-
FAILED: 'failed'
|
|
67
|
+
FAILED: 'failed',
|
|
68
|
+
PAUSED: 'paused'
|
|
57
69
|
};
|
|
58
70
|
|
|
59
|
-
//
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// Limits
|
|
66
|
-
const MAX_EVENTS_IN_MEMORY = 1000;
|
|
67
|
-
const MAX_EVENTS_TO_BROADCAST = 500;
|
|
71
|
+
// Spawner configuration
|
|
72
|
+
const SPAWNER_CONFIG = {
|
|
73
|
+
SESSION_PREFIX: 'tasks-board',
|
|
74
|
+
MAX_TRACKED_PROJECTS: 100,
|
|
75
|
+
MAX_AUTOCOMPLETE_RESULTS: 15
|
|
76
|
+
};
|
|
68
77
|
|
|
69
78
|
module.exports = {
|
|
70
79
|
// Directories
|
|
@@ -74,7 +83,6 @@ module.exports = {
|
|
|
74
83
|
PLANS_DIR,
|
|
75
84
|
PROJECTS_DIR,
|
|
76
85
|
EVENTS_DIR,
|
|
77
|
-
ORCHESTRATIONS_DIR,
|
|
78
86
|
|
|
79
87
|
// Files
|
|
80
88
|
CUSTOM_NAMES_FILE,
|
|
@@ -88,8 +96,6 @@ module.exports = {
|
|
|
88
96
|
|
|
89
97
|
// Status
|
|
90
98
|
SESSION_STATUS,
|
|
91
|
-
AGENT_STATUS,
|
|
92
|
-
ORCHESTRATION_STATUS,
|
|
93
99
|
|
|
94
100
|
// Timing
|
|
95
101
|
HEALTH_CHECK_INTERVAL,
|
|
@@ -99,5 +105,13 @@ module.exports = {
|
|
|
99
105
|
|
|
100
106
|
// Limits
|
|
101
107
|
MAX_EVENTS_IN_MEMORY,
|
|
102
|
-
MAX_EVENTS_TO_BROADCAST
|
|
108
|
+
MAX_EVENTS_TO_BROADCAST,
|
|
109
|
+
|
|
110
|
+
// Orchestration
|
|
111
|
+
ORCHESTRATIONS_DIR,
|
|
112
|
+
AGENT_STATUS,
|
|
113
|
+
ORCHESTRATION_STATUS,
|
|
114
|
+
|
|
115
|
+
// Spawner
|
|
116
|
+
SPAWNER_CONFIG
|
|
103
117
|
};
|
package/lib/core/event-bus.js
CHANGED
|
@@ -46,24 +46,6 @@ const EventTypes = {
|
|
|
46
46
|
// Attention events
|
|
47
47
|
ATTENTION_NEEDED: 'attention:needed',
|
|
48
48
|
ATTENTION_CLEARED: 'attention:cleared',
|
|
49
|
-
|
|
50
|
-
// Orchestration events
|
|
51
|
-
ORCHESTRATION_CREATED: 'orchestration:created',
|
|
52
|
-
ORCHESTRATION_UPDATED: 'orchestration:updated',
|
|
53
|
-
ORCHESTRATION_STARTED: 'orchestration:started',
|
|
54
|
-
ORCHESTRATION_PAUSED: 'orchestration:paused',
|
|
55
|
-
ORCHESTRATION_COMPLETED: 'orchestration:completed',
|
|
56
|
-
ORCHESTRATION_FAILED: 'orchestration:failed',
|
|
57
|
-
ORCHESTRATION_DELETED: 'orchestration:deleted',
|
|
58
|
-
|
|
59
|
-
// Agent events (within orchestrations)
|
|
60
|
-
AGENT_CREATED: 'agent:created',
|
|
61
|
-
AGENT_SPAWNED: 'agent:spawned',
|
|
62
|
-
AGENT_STATUS_CHANGED: 'agent:status_changed',
|
|
63
|
-
AGENT_OUTPUT: 'agent:output',
|
|
64
|
-
AGENT_COMPLETED: 'agent:completed',
|
|
65
|
-
AGENT_FAILED: 'agent:failed',
|
|
66
|
-
AGENT_KILLED: 'agent:killed',
|
|
67
49
|
};
|
|
68
50
|
|
|
69
51
|
class EventBus {
|
package/lib/index.js
CHANGED
|
@@ -25,13 +25,18 @@ const tasks = require('./data/tasks');
|
|
|
25
25
|
const todos = require('./data/todos');
|
|
26
26
|
const plans = require('./data/plans');
|
|
27
27
|
const conversation = require('./data/conversation');
|
|
28
|
-
const orchestrationData = require('./data/orchestration');
|
|
29
|
-
|
|
30
|
-
// Orchestration
|
|
31
|
-
const orchestrationExecutor = require('./orchestration/executor');
|
|
32
28
|
|
|
33
29
|
// Routes
|
|
34
30
|
const { createRoutes } = require('./routes/api');
|
|
31
|
+
const { createSpawnerRoutes } = require('./routes/spawner');
|
|
32
|
+
const { createOrchestrationRoutes } = require('./routes/orchestration');
|
|
33
|
+
|
|
34
|
+
// Spawner
|
|
35
|
+
const { createSessionSpawner } = require('./spawner');
|
|
36
|
+
|
|
37
|
+
// Orchestration
|
|
38
|
+
const orchestrationData = require('./data/orchestration');
|
|
39
|
+
const orchestrationExecutor = require('./orchestration/executor');
|
|
35
40
|
|
|
36
41
|
// =============================================================================
|
|
37
42
|
// Module Wiring - Connect modules that need callbacks from other modules
|
|
@@ -174,14 +179,37 @@ const routes = createRoutes({
|
|
|
174
179
|
updatePlan: plans.updatePlan,
|
|
175
180
|
loadConversation: conversation.loadConversation,
|
|
176
181
|
|
|
177
|
-
// Orchestration
|
|
178
|
-
orchestrationData,
|
|
179
|
-
orchestrationExecutor,
|
|
180
|
-
|
|
181
182
|
// Utils
|
|
182
183
|
sendToTmux: sessionManager.sendToTmux
|
|
183
184
|
});
|
|
184
185
|
|
|
186
|
+
// =============================================================================
|
|
187
|
+
// Session Spawner Setup
|
|
188
|
+
// =============================================================================
|
|
189
|
+
|
|
190
|
+
// Create session spawner instance
|
|
191
|
+
const spawner = createSessionSpawner({
|
|
192
|
+
dataDir: config.EVENTS_DIR
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Wire spawner to session manager broadcasts
|
|
196
|
+
spawner.setOnSessionUpdate((sessions) => {
|
|
197
|
+
broadcastUpdate('spawned_sessions', { sessions });
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
spawner.setOnPermissionDetected((sessionId, permission) => {
|
|
201
|
+
broadcastUpdate('spawner_permission', { sessionId, permission });
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Create spawner routes
|
|
205
|
+
const spawnerRoutes = createSpawnerRoutes({ spawner });
|
|
206
|
+
|
|
207
|
+
// Create orchestration routes
|
|
208
|
+
const orchestrationRoutes = createOrchestrationRoutes({
|
|
209
|
+
orchestrationData,
|
|
210
|
+
orchestrationExecutor
|
|
211
|
+
});
|
|
212
|
+
|
|
185
213
|
// =============================================================================
|
|
186
214
|
// HTTP Server
|
|
187
215
|
// =============================================================================
|
|
@@ -330,101 +358,175 @@ const server = http.createServer((req, res) => {
|
|
|
330
358
|
return routes.handleRenameSession(req, res, renameMatch[1]);
|
|
331
359
|
}
|
|
332
360
|
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
361
|
+
// Task routes
|
|
362
|
+
const taskMatch = url.pathname.match(/^\/api\/tasks\/([^/]+)\/(\d+)$/);
|
|
363
|
+
if (taskMatch && req.method === 'PATCH') {
|
|
364
|
+
return routes.handleUpdateTask(req, res, taskMatch[1], taskMatch[2]);
|
|
336
365
|
}
|
|
337
|
-
|
|
338
|
-
|
|
366
|
+
|
|
367
|
+
const createMatch = url.pathname.match(/^\/api\/tasks\/([^/]+)$/);
|
|
368
|
+
if (createMatch && req.method === 'POST') {
|
|
369
|
+
return routes.handleCreateTask(req, res, createMatch[1]);
|
|
339
370
|
}
|
|
340
371
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
372
|
+
// ==========================================================================
|
|
373
|
+
// Spawner Routes - New session spawning API
|
|
374
|
+
// ==========================================================================
|
|
375
|
+
|
|
376
|
+
// Sessions
|
|
377
|
+
if (url.pathname === '/api/spawner/sessions' && req.method === 'POST') {
|
|
378
|
+
return spawnerRoutes.handleSpawnSession(req, res);
|
|
344
379
|
}
|
|
345
|
-
if (
|
|
346
|
-
return
|
|
380
|
+
if (url.pathname === '/api/spawner/sessions' && req.method === 'GET') {
|
|
381
|
+
return spawnerRoutes.handleListSessions(req, res);
|
|
347
382
|
}
|
|
348
|
-
if (
|
|
349
|
-
return
|
|
383
|
+
if (url.pathname === '/api/spawner/refresh' && req.method === 'POST') {
|
|
384
|
+
return spawnerRoutes.handleRefresh(req, res);
|
|
350
385
|
}
|
|
351
386
|
|
|
352
|
-
const
|
|
353
|
-
if (
|
|
354
|
-
return
|
|
387
|
+
const spawnerSessionMatch = url.pathname.match(/^\/api\/spawner\/sessions\/([^/]+)$/);
|
|
388
|
+
if (spawnerSessionMatch && req.method === 'GET') {
|
|
389
|
+
return spawnerRoutes.handleGetSession(req, res, spawnerSessionMatch[1]);
|
|
390
|
+
}
|
|
391
|
+
if (spawnerSessionMatch && req.method === 'PATCH') {
|
|
392
|
+
return spawnerRoutes.handleUpdateSession(req, res, spawnerSessionMatch[1]);
|
|
393
|
+
}
|
|
394
|
+
if (spawnerSessionMatch && req.method === 'DELETE') {
|
|
395
|
+
return spawnerRoutes.handleKillSession(req, res, spawnerSessionMatch[1]);
|
|
355
396
|
}
|
|
356
397
|
|
|
357
|
-
const
|
|
358
|
-
if (
|
|
359
|
-
return
|
|
398
|
+
const spawnerRestartMatch = url.pathname.match(/^\/api\/spawner\/sessions\/([^/]+)\/restart$/);
|
|
399
|
+
if (spawnerRestartMatch && req.method === 'POST') {
|
|
400
|
+
return spawnerRoutes.handleRestartSession(req, res, spawnerRestartMatch[1]);
|
|
360
401
|
}
|
|
361
402
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return routes.handleAddAgent(req, res, agentsMatch[1]);
|
|
403
|
+
const spawnerPromptMatch = url.pathname.match(/^\/api\/spawner\/sessions\/([^/]+)\/prompt$/);
|
|
404
|
+
if (spawnerPromptMatch && req.method === 'POST') {
|
|
405
|
+
return spawnerRoutes.handleSendPrompt(req, res, spawnerPromptMatch[1]);
|
|
366
406
|
}
|
|
367
407
|
|
|
368
|
-
const
|
|
369
|
-
if (
|
|
370
|
-
return
|
|
408
|
+
const spawnerCancelMatch = url.pathname.match(/^\/api\/spawner\/sessions\/([^/]+)\/cancel$/);
|
|
409
|
+
if (spawnerCancelMatch && req.method === 'POST') {
|
|
410
|
+
return spawnerRoutes.handleCancelSession(req, res, spawnerCancelMatch[1]);
|
|
371
411
|
}
|
|
372
|
-
|
|
373
|
-
|
|
412
|
+
|
|
413
|
+
const spawnerPermissionMatch = url.pathname.match(/^\/api\/spawner\/sessions\/([^/]+)\/permission$/);
|
|
414
|
+
if (spawnerPermissionMatch && req.method === 'POST') {
|
|
415
|
+
return spawnerRoutes.handlePermissionResponse(req, res, spawnerPermissionMatch[1]);
|
|
374
416
|
}
|
|
375
417
|
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
return
|
|
418
|
+
// Projects
|
|
419
|
+
if (url.pathname === '/api/spawner/projects' && req.method === 'GET') {
|
|
420
|
+
return spawnerRoutes.handleListProjects(req, res, url);
|
|
421
|
+
}
|
|
422
|
+
if (url.pathname === '/api/spawner/projects' && req.method === 'POST') {
|
|
423
|
+
return spawnerRoutes.handleTrackProject(req, res);
|
|
424
|
+
}
|
|
425
|
+
if (url.pathname === '/api/spawner/projects' && req.method === 'DELETE') {
|
|
426
|
+
return spawnerRoutes.handleRemoveProject(req, res);
|
|
427
|
+
}
|
|
428
|
+
if (url.pathname === '/api/spawner/projects/autocomplete' && req.method === 'GET') {
|
|
429
|
+
return spawnerRoutes.handleAutocomplete(req, res, url);
|
|
430
|
+
}
|
|
431
|
+
if (url.pathname === '/api/spawner/projects/common' && req.method === 'GET') {
|
|
432
|
+
return spawnerRoutes.handleGetCommonDirectories(req, res);
|
|
379
433
|
}
|
|
380
434
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
435
|
+
// ==========================================================================
|
|
436
|
+
// Orchestration Routes
|
|
437
|
+
// ==========================================================================
|
|
438
|
+
|
|
439
|
+
// Orchestrations CRUD
|
|
440
|
+
if (url.pathname === '/api/orchestrations' && req.method === 'GET') {
|
|
441
|
+
return orchestrationRoutes.handleListOrchestrations(req, res);
|
|
442
|
+
}
|
|
443
|
+
if (url.pathname === '/api/orchestrations' && req.method === 'POST') {
|
|
444
|
+
return orchestrationRoutes.handleCreateOrchestration(req, res);
|
|
384
445
|
}
|
|
385
446
|
|
|
386
|
-
const
|
|
387
|
-
if (
|
|
388
|
-
return
|
|
447
|
+
const orchIdMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)$/);
|
|
448
|
+
if (orchIdMatch && req.method === 'GET') {
|
|
449
|
+
return orchestrationRoutes.handleGetOrchestration(req, res, orchIdMatch[1]);
|
|
450
|
+
}
|
|
451
|
+
if (orchIdMatch && req.method === 'PATCH') {
|
|
452
|
+
return orchestrationRoutes.handleUpdateOrchestration(req, res, orchIdMatch[1]);
|
|
453
|
+
}
|
|
454
|
+
if (orchIdMatch && req.method === 'DELETE') {
|
|
455
|
+
return orchestrationRoutes.handleDeleteOrchestration(req, res, orchIdMatch[1]);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Orchestration execution
|
|
459
|
+
const orchStartMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/start$/);
|
|
460
|
+
if (orchStartMatch && req.method === 'POST') {
|
|
461
|
+
return orchestrationRoutes.handleStartOrchestration(req, res, orchStartMatch[1]);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const orchStopMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/stop$/);
|
|
465
|
+
if (orchStopMatch && req.method === 'POST') {
|
|
466
|
+
return orchestrationRoutes.handleStopOrchestration(req, res, orchStopMatch[1]);
|
|
389
467
|
}
|
|
390
468
|
|
|
391
|
-
const
|
|
469
|
+
const orchStatsMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/stats$/);
|
|
470
|
+
if (orchStatsMatch && req.method === 'GET') {
|
|
471
|
+
return orchestrationRoutes.handleGetStats(req, res, orchStatsMatch[1]);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Agent routes
|
|
475
|
+
const agentAddMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents$/);
|
|
476
|
+
if (agentAddMatch && req.method === 'POST') {
|
|
477
|
+
return orchestrationRoutes.handleAddAgent(req, res, agentAddMatch[1]);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const agentIdMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents\/([a-z0-9-]+)$/);
|
|
481
|
+
if (agentIdMatch && req.method === 'PATCH') {
|
|
482
|
+
return orchestrationRoutes.handleUpdateAgent(req, res, agentIdMatch[1], agentIdMatch[2]);
|
|
483
|
+
}
|
|
484
|
+
if (agentIdMatch && req.method === 'DELETE') {
|
|
485
|
+
return orchestrationRoutes.handleRemoveAgent(req, res, agentIdMatch[1], agentIdMatch[2]);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const agentStatusMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents\/([a-z0-9-]+)\/status$/);
|
|
392
489
|
if (agentStatusMatch && req.method === 'GET') {
|
|
393
|
-
return
|
|
490
|
+
return orchestrationRoutes.handleGetAgentStatus(req, res, agentStatusMatch[1], agentStatusMatch[2]);
|
|
394
491
|
}
|
|
395
492
|
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
398
|
-
return
|
|
493
|
+
const agentSpawnMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents\/([a-z0-9-]+)\/spawn$/);
|
|
494
|
+
if (agentSpawnMatch && req.method === 'POST') {
|
|
495
|
+
return orchestrationRoutes.handleSpawnAgent(req, res, agentSpawnMatch[1], agentSpawnMatch[2]);
|
|
399
496
|
}
|
|
400
497
|
|
|
401
|
-
const
|
|
402
|
-
if (
|
|
403
|
-
return
|
|
498
|
+
const agentKillMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents\/([a-z0-9-]+)\/kill$/);
|
|
499
|
+
if (agentKillMatch && req.method === 'POST') {
|
|
500
|
+
return orchestrationRoutes.handleKillAgent(req, res, agentKillMatch[1], agentKillMatch[2]);
|
|
404
501
|
}
|
|
405
502
|
|
|
406
|
-
|
|
407
|
-
if (
|
|
408
|
-
return
|
|
503
|
+
const agentPromptMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents\/([a-z0-9-]+)\/prompt$/);
|
|
504
|
+
if (agentPromptMatch && req.method === 'POST') {
|
|
505
|
+
return orchestrationRoutes.handleSendAgentPrompt(req, res, agentPromptMatch[1], agentPromptMatch[2]);
|
|
409
506
|
}
|
|
410
507
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
508
|
+
// Dependencies
|
|
509
|
+
const depAddMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents\/([a-z0-9-]+)\/dependencies$/);
|
|
510
|
+
if (depAddMatch && req.method === 'POST') {
|
|
511
|
+
return orchestrationRoutes.handleAddDependency(req, res, depAddMatch[1], depAddMatch[2]);
|
|
414
512
|
}
|
|
415
|
-
|
|
416
|
-
|
|
513
|
+
|
|
514
|
+
const depRemoveMatch = url.pathname.match(/^\/api\/orchestrations\/([a-z0-9-]+)\/agents\/([a-z0-9-]+)\/dependencies\/([a-z0-9-]+)$/);
|
|
515
|
+
if (depRemoveMatch && req.method === 'DELETE') {
|
|
516
|
+
return orchestrationRoutes.handleRemoveDependency(req, res, depRemoveMatch[1], depRemoveMatch[2], depRemoveMatch[3]);
|
|
417
517
|
}
|
|
418
518
|
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
return routes.handleUpdateTask(req, res, taskMatch[1], taskMatch[2]);
|
|
519
|
+
// Templates
|
|
520
|
+
if (url.pathname === '/api/orchestration-templates' && req.method === 'GET') {
|
|
521
|
+
return orchestrationRoutes.handleListTemplates(req, res);
|
|
423
522
|
}
|
|
424
523
|
|
|
425
|
-
const
|
|
426
|
-
if (
|
|
427
|
-
return
|
|
524
|
+
const templateIdMatch = url.pathname.match(/^\/api\/orchestration-templates\/([a-z0-9-]+)$/);
|
|
525
|
+
if (templateIdMatch && req.method === 'GET') {
|
|
526
|
+
return orchestrationRoutes.handleGetTemplate(req, res, templateIdMatch[1]);
|
|
527
|
+
}
|
|
528
|
+
if (templateIdMatch && req.method === 'POST') {
|
|
529
|
+
return orchestrationRoutes.handleCreateFromTemplate(req, res, templateIdMatch[1]);
|
|
428
530
|
}
|
|
429
531
|
|
|
430
532
|
// Serve HTML
|
|
@@ -453,14 +555,11 @@ function start() {
|
|
|
453
555
|
registerAllHandlers();
|
|
454
556
|
console.log(` EventBus initialized with ${eventBus.getHandlerCount()} handlers`);
|
|
455
557
|
|
|
456
|
-
// Initialize
|
|
457
|
-
claudeEvents.init();
|
|
458
|
-
|
|
459
|
-
// Initialize session manager
|
|
558
|
+
// Initialize session manager (must be before claudeEvents so sessions are loaded before discovery)
|
|
460
559
|
sessionManager.init();
|
|
461
560
|
|
|
462
|
-
// Initialize
|
|
463
|
-
|
|
561
|
+
// Initialize Claude events module
|
|
562
|
+
claudeEvents.init();
|
|
464
563
|
|
|
465
564
|
// Set up file watchers
|
|
466
565
|
setupWatchers();
|
|
@@ -468,12 +567,20 @@ function start() {
|
|
|
468
567
|
// Build plan session cache
|
|
469
568
|
plans.buildPlanSessionCache();
|
|
470
569
|
|
|
570
|
+
// Initialize session spawner
|
|
571
|
+
spawner.init();
|
|
572
|
+
console.log(` Session spawner initialized`);
|
|
573
|
+
|
|
574
|
+
// Initialize orchestration executor
|
|
575
|
+
orchestrationExecutor.init();
|
|
576
|
+
console.log(` Orchestration executor initialized`);
|
|
577
|
+
|
|
471
578
|
console.log(` Press Ctrl+C to stop\n`);
|
|
472
579
|
});
|
|
473
580
|
}
|
|
474
581
|
|
|
475
582
|
// Export for testing
|
|
476
|
-
module.exports = { server, start };
|
|
583
|
+
module.exports = { server, start, spawner };
|
|
477
584
|
|
|
478
585
|
// Start if run directly
|
|
479
586
|
if (require.main === module) {
|