sessioncast-cli 2.0.2 → 2.0.3

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 (45) hide show
  1. package/dist/agent/runner.js +23 -0
  2. package/dist/agent/session-handler.d.ts +1 -2
  3. package/dist/agent/session-handler.js +34 -79
  4. package/dist/agent/tmux-executor.d.ts +3 -33
  5. package/dist/agent/tmux-executor.js +3 -50
  6. package/dist/agent/tmux.d.ts +2 -6
  7. package/dist/agent/tmux.js +2 -9
  8. package/dist/agent/types.d.ts +0 -10
  9. package/dist/agent/websocket.d.ts +2 -21
  10. package/dist/agent/websocket.js +10 -46
  11. package/dist/commands/agent.js +3 -0
  12. package/dist/index.js +14 -0
  13. package/dist/sentry.d.ts +4 -0
  14. package/dist/sentry.js +87 -0
  15. package/package.json +2 -1
  16. package/dist/autopilot/index.d.ts +0 -94
  17. package/dist/autopilot/index.js +0 -322
  18. package/dist/autopilot/mission-analyzer.d.ts +0 -27
  19. package/dist/autopilot/mission-analyzer.js +0 -232
  20. package/dist/autopilot/project-detector.d.ts +0 -12
  21. package/dist/autopilot/project-detector.js +0 -326
  22. package/dist/autopilot/source-scanner.d.ts +0 -26
  23. package/dist/autopilot/source-scanner.js +0 -285
  24. package/dist/autopilot/speckit-generator.d.ts +0 -60
  25. package/dist/autopilot/speckit-generator.js +0 -511
  26. package/dist/autopilot/types.d.ts +0 -110
  27. package/dist/autopilot/types.js +0 -6
  28. package/dist/autopilot/workflow-generator.d.ts +0 -33
  29. package/dist/autopilot/workflow-generator.js +0 -278
  30. package/dist/commands/autopilot.d.ts +0 -30
  31. package/dist/commands/autopilot.js +0 -262
  32. package/dist/commands/project.d.ts +0 -33
  33. package/dist/commands/project.js +0 -350
  34. package/dist/project/executor.d.ts +0 -73
  35. package/dist/project/executor.js +0 -437
  36. package/dist/project/index.d.ts +0 -4
  37. package/dist/project/index.js +0 -20
  38. package/dist/project/manager.d.ts +0 -66
  39. package/dist/project/manager.js +0 -290
  40. package/dist/project/relay-client.d.ts +0 -37
  41. package/dist/project/relay-client.js +0 -204
  42. package/dist/project/types.d.ts +0 -48
  43. package/dist/project/types.js +0 -3
  44. package/dist/utils/fileUtils.d.ts +0 -28
  45. package/dist/utils/fileUtils.js +0 -159
@@ -1,437 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.WorkflowExecutor = void 0;
37
- const child_process_1 = require("child_process");
38
- const path = __importStar(require("path"));
39
- const events_1 = require("events");
40
- const relay_client_1 = require("./relay-client");
41
- const POLL_INTERVAL_MS = 2000;
42
- const MAX_RETRIES = 3;
43
- const CLAUDE_START_DELAY_MS = 1000;
44
- class WorkflowExecutor extends events_1.EventEmitter {
45
- constructor(manager, options = {}) {
46
- super();
47
- this.workflow = null;
48
- this.running = false;
49
- this.pollTimer = null;
50
- this.relayClient = null;
51
- this.manager = manager;
52
- this.options = {
53
- autoLaunchClaude: options.autoLaunchClaude ?? true,
54
- claudeCommand: options.claudeCommand ?? 'claude',
55
- relayUrl: options.relayUrl,
56
- relayToken: options.relayToken
57
- };
58
- }
59
- /**
60
- * Start workflow execution
61
- */
62
- async start() {
63
- this.workflow = this.manager.loadWorkflow();
64
- if (!this.workflow) {
65
- throw new Error('No workflow found. Run project init first.');
66
- }
67
- this.running = true;
68
- console.log(`Starting workflow: ${this.workflow.name}`);
69
- // Connect to relay if configured
70
- if (this.options.relayUrl && this.options.relayToken) {
71
- await this.connectToRelay();
72
- }
73
- // Initialize status
74
- const status = {
75
- workflow: this.workflow.name,
76
- startedAt: new Date().toISOString(),
77
- status: 'running',
78
- agents: {}
79
- };
80
- for (const agent of this.workflow.agents) {
81
- status.agents[agent.id] = { status: 'pending' };
82
- }
83
- this.manager.saveStatus(status);
84
- // Update relay with initial agents list
85
- this.updateRelayAgents();
86
- // Start PM Agent first
87
- await this.startPMAgent();
88
- // Then start the workflow execution loop
89
- this.runExecutionLoop();
90
- }
91
- /**
92
- * Connect to relay server and register project
93
- */
94
- async connectToRelay() {
95
- if (!this.options.relayUrl || !this.options.relayToken) {
96
- return;
97
- }
98
- const project = this.manager.load();
99
- this.relayClient = new relay_client_1.ProjectRelayClient({
100
- relayUrl: this.options.relayUrl,
101
- token: this.options.relayToken,
102
- projectId: this.manager.getProjectId(),
103
- projectName: project?.name || this.manager.getProjectId(),
104
- projectPath: this.manager.getProjectPath()
105
- });
106
- // Setup event handlers
107
- this.relayClient.on('connected', () => {
108
- console.log('[Relay] Connected and project registered');
109
- this.relayClient?.updateStatus('running');
110
- });
111
- this.relayClient.on('addSource', (meta) => {
112
- console.log('[Relay] Add source request:', meta);
113
- this.emit('addSourceRequest', meta);
114
- });
115
- this.relayClient.on('analyzeMission', (meta) => {
116
- console.log('[Relay] Analyze mission request:', meta);
117
- this.emit('analyzeMissionRequest', meta);
118
- });
119
- this.relayClient.on('startWorkflow', (meta) => {
120
- console.log('[Relay] Start workflow request:', meta);
121
- this.emit('startWorkflowRequest', meta);
122
- });
123
- this.relayClient.on('error', (error) => {
124
- console.error('[Relay] Error:', error.message);
125
- });
126
- this.relayClient.connect();
127
- // Wait a bit for connection
128
- await new Promise(resolve => setTimeout(resolve, 1000));
129
- }
130
- /**
131
- * Update relay with current agents list
132
- */
133
- updateRelayAgents() {
134
- if (!this.relayClient || !this.workflow)
135
- return;
136
- const status = this.manager.loadStatus();
137
- const agents = this.workflow.agents.map(agent => ({
138
- id: agent.id,
139
- name: agent.name,
140
- status: status?.agents[agent.id]?.status || 'pending'
141
- }));
142
- // Add PM agent
143
- agents.unshift({
144
- id: 'pm',
145
- name: 'PM',
146
- status: status?.agents['pm']?.status || 'pending'
147
- });
148
- this.relayClient.updateAgents(agents);
149
- }
150
- /**
151
- * Start PM Agent tmux session
152
- */
153
- async startPMAgent() {
154
- const sessionName = this.manager.getTmuxSessionName('pm');
155
- const pmAgentPath = path.join(this.manager.getProjectPath(), 'tools', 'pm-agent');
156
- console.log(`Starting PM Agent: ${sessionName}`);
157
- try {
158
- // Check if session already exists
159
- try {
160
- (0, child_process_1.execSync)(`tmux has-session -t "${sessionName}" 2>/dev/null`);
161
- console.log(`PM Agent session already exists: ${sessionName}`);
162
- return;
163
- }
164
- catch {
165
- // Session doesn't exist, create it
166
- }
167
- // Create new tmux session
168
- (0, child_process_1.execSync)(`tmux new-session -d -s "${sessionName}" -c "${pmAgentPath}"`, { stdio: 'pipe' });
169
- console.log(`Created PM Agent session: ${sessionName}`);
170
- // Auto-launch Claude Code CLI
171
- if (this.options.autoLaunchClaude) {
172
- await this.launchClaudeInSession(sessionName, 'pm');
173
- }
174
- // Update status
175
- this.manager.updateAgentStatus('pm', {
176
- status: 'running',
177
- startedAt: new Date().toISOString()
178
- });
179
- this.emit('agent-started', { agentId: 'pm', sessionName });
180
- }
181
- catch (error) {
182
- console.error('Failed to start PM Agent:', error);
183
- throw error;
184
- }
185
- }
186
- /**
187
- * Start a work agent
188
- */
189
- async startAgent(agent) {
190
- const sessionName = this.manager.getTmuxSessionName(agent.id);
191
- const agentPath = path.join(this.manager.getProjectPath(), agent.workDir);
192
- console.log(`Starting agent: ${agent.id} (${agent.name})`);
193
- try {
194
- // Check if session already exists
195
- try {
196
- (0, child_process_1.execSync)(`tmux has-session -t "${sessionName}" 2>/dev/null`);
197
- console.log(`Agent session already exists: ${sessionName}`);
198
- return;
199
- }
200
- catch {
201
- // Session doesn't exist, create it
202
- }
203
- // Ensure work folder exists with CLAUDE.md
204
- this.manager.createWorkAgent(agent.id, agent.name, agent.tasks);
205
- // Create new tmux session
206
- (0, child_process_1.execSync)(`tmux new-session -d -s "${sessionName}" -c "${agentPath}"`, { stdio: 'pipe' });
207
- console.log(`Created agent session: ${sessionName}`);
208
- // Auto-launch Claude Code CLI with task prompt
209
- if (this.options.autoLaunchClaude) {
210
- const taskPrompt = this.buildTaskPrompt(agent);
211
- await this.launchClaudeInSession(sessionName, agent.id, taskPrompt);
212
- }
213
- // Update status
214
- this.manager.updateAgentStatus(agent.id, {
215
- status: 'running',
216
- startedAt: new Date().toISOString(),
217
- currentTask: agent.tasks[0] || 'Starting...'
218
- });
219
- this.emit('agent-started', { agentId: agent.id, sessionName });
220
- }
221
- catch (error) {
222
- console.error(`Failed to start agent ${agent.id}:`, error);
223
- this.manager.updateAgentStatus(agent.id, {
224
- status: 'failed',
225
- error: String(error)
226
- });
227
- }
228
- }
229
- /**
230
- * Build task prompt for agent
231
- */
232
- buildTaskPrompt(agent) {
233
- const tasks = agent.tasks.map((t, i) => `${i + 1}. ${t}`).join('\n');
234
- return `다음 태스크를 수행해주세요:\n${tasks}\n\n완료 후 반드시:\n1. output.md에 결과 기록\n2. touch DONE 실행`;
235
- }
236
- /**
237
- * Launch Claude Code CLI in a tmux session
238
- */
239
- async launchClaudeInSession(sessionName, agentId, initialPrompt) {
240
- // Wait for shell to be ready
241
- await this.sleep(CLAUDE_START_DELAY_MS);
242
- try {
243
- // Send claude command
244
- (0, child_process_1.execSync)(`tmux send-keys -t "${sessionName}" "${this.options.claudeCommand}" Enter`, {
245
- stdio: 'pipe'
246
- });
247
- console.log(`Launched Claude Code in ${agentId}`);
248
- // If there's an initial prompt, send it after claude starts
249
- if (initialPrompt) {
250
- // Wait for claude to initialize
251
- await this.sleep(3000);
252
- // Send the initial prompt
253
- const escapedPrompt = initialPrompt.replace(/"/g, '\\"').replace(/\n/g, '\\n');
254
- (0, child_process_1.execSync)(`tmux send-keys -t "${sessionName}" "${escapedPrompt}" Enter`, {
255
- stdio: 'pipe'
256
- });
257
- console.log(`Sent initial prompt to ${agentId}`);
258
- }
259
- }
260
- catch (error) {
261
- console.error(`Failed to launch Claude in ${agentId}:`, error);
262
- }
263
- }
264
- /**
265
- * Sleep helper
266
- */
267
- sleep(ms) {
268
- return new Promise(resolve => setTimeout(resolve, ms));
269
- }
270
- /**
271
- * Main execution loop
272
- */
273
- runExecutionLoop() {
274
- const check = () => {
275
- if (!this.running || !this.workflow) {
276
- return;
277
- }
278
- const status = this.manager.loadStatus();
279
- if (!status)
280
- return;
281
- // Check each agent
282
- for (const agent of this.workflow.agents) {
283
- const agentStatus = status.agents[agent.id];
284
- // Skip completed or failed agents
285
- if (agentStatus?.status === 'completed' || agentStatus?.status === 'failed') {
286
- continue;
287
- }
288
- // Check if dependencies are met
289
- const dependenciesMet = agent.dependsOn.every(depId => {
290
- return status.agents[depId]?.status === 'completed';
291
- });
292
- if (!dependenciesMet) {
293
- continue;
294
- }
295
- // Check if agent is pending (not started yet)
296
- if (agentStatus?.status === 'pending') {
297
- this.startAgent(agent);
298
- continue;
299
- }
300
- // Check if running agent is completed
301
- if (agentStatus?.status === 'running') {
302
- if (this.manager.isAgentCompleted(agent.id)) {
303
- const output = this.manager.getAgentOutput(agent.id);
304
- this.manager.updateAgentStatus(agent.id, {
305
- status: 'completed',
306
- completedAt: new Date().toISOString(),
307
- output: output || undefined
308
- });
309
- // Append output to shared context
310
- if (output) {
311
- this.manager.appendToContext(`\n## ${agent.name} Output\n${output}\n`);
312
- }
313
- console.log(`Agent completed: ${agent.id}`);
314
- this.emit('agent-completed', { agentId: agent.id, output });
315
- }
316
- }
317
- }
318
- // Check if workflow is complete
319
- const updatedStatus = this.manager.loadStatus();
320
- if (updatedStatus) {
321
- const allCompleted = this.workflow.agents.every(a => updatedStatus.agents[a.id]?.status === 'completed');
322
- if (allCompleted) {
323
- console.log('Workflow completed!');
324
- updatedStatus.status = 'completed';
325
- this.manager.saveStatus(updatedStatus);
326
- this.emit('workflow-completed', updatedStatus);
327
- this.stop();
328
- return;
329
- }
330
- const anyFailed = this.workflow.agents.some(a => updatedStatus.agents[a.id]?.status === 'failed');
331
- if (anyFailed) {
332
- console.log('Workflow failed!');
333
- updatedStatus.status = 'failed';
334
- this.manager.saveStatus(updatedStatus);
335
- this.emit('workflow-failed', updatedStatus);
336
- this.stop();
337
- return;
338
- }
339
- }
340
- // Continue polling
341
- this.pollTimer = setTimeout(check, POLL_INTERVAL_MS);
342
- };
343
- check();
344
- }
345
- /**
346
- * Stop workflow execution
347
- */
348
- stop() {
349
- this.running = false;
350
- if (this.pollTimer) {
351
- clearTimeout(this.pollTimer);
352
- this.pollTimer = null;
353
- }
354
- // Disconnect from relay
355
- if (this.relayClient) {
356
- this.relayClient.updateStatus('completed');
357
- this.relayClient.destroy();
358
- this.relayClient = null;
359
- }
360
- }
361
- /**
362
- * Kill all project tmux sessions
363
- */
364
- killAllSessions() {
365
- const projectId = this.manager.getProjectId().replace(/[^a-zA-Z0-9_-]/g, '_');
366
- const prefix = `proj_${projectId}_`;
367
- try {
368
- const sessions = (0, child_process_1.execSync)(`tmux ls -F "#{session_name}" 2>/dev/null || true`, {
369
- encoding: 'utf-8'
370
- });
371
- for (const session of sessions.split('\n')) {
372
- if (session.startsWith(prefix)) {
373
- try {
374
- (0, child_process_1.execSync)(`tmux kill-session -t "${session}"`, { stdio: 'pipe' });
375
- console.log(`Killed session: ${session}`);
376
- }
377
- catch {
378
- // Ignore errors
379
- }
380
- }
381
- }
382
- }
383
- catch {
384
- // Ignore errors
385
- }
386
- }
387
- /**
388
- * Send keys to an agent session
389
- */
390
- sendToAgent(agentId, keys) {
391
- const sessionName = this.manager.getTmuxSessionName(agentId);
392
- try {
393
- (0, child_process_1.execSync)(`tmux send-keys -t "${sessionName}" "${keys.replace(/"/g, '\\"')}" Enter`, {
394
- stdio: 'pipe'
395
- });
396
- return true;
397
- }
398
- catch {
399
- return false;
400
- }
401
- }
402
- /**
403
- * Capture agent terminal output
404
- */
405
- captureAgent(agentId) {
406
- const sessionName = this.manager.getTmuxSessionName(agentId);
407
- try {
408
- return (0, child_process_1.execSync)(`tmux capture-pane -t "${sessionName}" -p -e`, {
409
- encoding: 'utf-8',
410
- stdio: ['pipe', 'pipe', 'pipe']
411
- });
412
- }
413
- catch {
414
- return null;
415
- }
416
- }
417
- /**
418
- * List all agent sessions for this project
419
- */
420
- listSessions() {
421
- const projectId = this.manager.getProjectId().replace(/[^a-zA-Z0-9_-]/g, '_');
422
- const prefix = `proj_${projectId}_`;
423
- try {
424
- const sessions = (0, child_process_1.execSync)(`tmux ls -F "#{session_name}" 2>/dev/null || true`, {
425
- encoding: 'utf-8'
426
- });
427
- return sessions
428
- .split('\n')
429
- .filter(s => s.startsWith(prefix))
430
- .map(s => s.substring(prefix.length));
431
- }
432
- catch {
433
- return [];
434
- }
435
- }
436
- }
437
- exports.WorkflowExecutor = WorkflowExecutor;
@@ -1,4 +0,0 @@
1
- export * from './types';
2
- export * from './manager';
3
- export * from './executor';
4
- export * from './relay-client';
@@ -1,20 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./types"), exports);
18
- __exportStar(require("./manager"), exports);
19
- __exportStar(require("./executor"), exports);
20
- __exportStar(require("./relay-client"), exports);
@@ -1,66 +0,0 @@
1
- import { Project, Workflow, WorkflowStatus, ProjectConfig, AgentStatus } from './types';
2
- export declare class ProjectManager {
3
- private projectPath;
4
- private config;
5
- constructor(projectPath: string, config?: Partial<ProjectConfig>);
6
- /**
7
- * Initialize a new project with folder structure
8
- */
9
- init(projectName?: string): Project;
10
- private copyTemplateClaude;
11
- private createInitialFiles;
12
- private saveProjectConfig;
13
- /**
14
- * Load existing project
15
- */
16
- load(): Project | null;
17
- /**
18
- * Load workflow definition
19
- */
20
- loadWorkflow(): Workflow | null;
21
- /**
22
- * Save workflow definition
23
- */
24
- saveWorkflow(workflow: Workflow): void;
25
- /**
26
- * Load workflow status
27
- */
28
- loadStatus(): WorkflowStatus | null;
29
- /**
30
- * Save workflow status
31
- */
32
- saveStatus(status: WorkflowStatus): void;
33
- /**
34
- * Update agent status
35
- */
36
- updateAgentStatus(agentId: string, agentStatus: Partial<AgentStatus>): void;
37
- /**
38
- * Create work agent folder with CLAUDE.md
39
- */
40
- createWorkAgent(agentId: string, agentName: string, tasks: string[]): void;
41
- /**
42
- * Get tmux session name for an agent
43
- * Note: tmux doesn't allow colons in session names, so we use underscores
44
- */
45
- getTmuxSessionName(agentId: string): string;
46
- /**
47
- * Check if agent is completed (DONE file exists)
48
- */
49
- isAgentCompleted(agentId: string): boolean;
50
- /**
51
- * Get agent output
52
- */
53
- getAgentOutput(agentId: string): string | null;
54
- /**
55
- * Append to shared context
56
- */
57
- appendToContext(content: string): void;
58
- /**
59
- * Get project path
60
- */
61
- getProjectPath(): string;
62
- /**
63
- * Get project ID
64
- */
65
- getProjectId(): string;
66
- }