sessioncast-cli 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.
- package/LICENSE +21 -0
- package/README.md +137 -0
- package/dist/agent/api-client.d.ts +27 -0
- package/dist/agent/api-client.js +295 -0
- package/dist/agent/exec-service.d.ts +6 -0
- package/dist/agent/exec-service.js +126 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.js +24 -0
- package/dist/agent/llm-service.d.ts +9 -0
- package/dist/agent/llm-service.js +156 -0
- package/dist/agent/runner.d.ts +16 -0
- package/dist/agent/runner.js +187 -0
- package/dist/agent/session-handler.d.ts +28 -0
- package/dist/agent/session-handler.js +184 -0
- package/dist/agent/tmux.d.ts +29 -0
- package/dist/agent/tmux.js +157 -0
- package/dist/agent/types.d.ts +72 -0
- package/dist/agent/types.js +2 -0
- package/dist/agent/websocket.d.ts +45 -0
- package/dist/agent/websocket.js +288 -0
- package/dist/api.d.ts +31 -0
- package/dist/api.js +78 -0
- package/dist/commands/agent.d.ts +5 -0
- package/dist/commands/agent.js +19 -0
- package/dist/commands/agents.d.ts +1 -0
- package/dist/commands/agents.js +77 -0
- package/dist/commands/login.d.ts +5 -0
- package/dist/commands/login.js +41 -0
- package/dist/commands/project.d.ts +33 -0
- package/dist/commands/project.js +359 -0
- package/dist/commands/sendkeys.d.ts +3 -0
- package/dist/commands/sendkeys.js +66 -0
- package/dist/commands/sessions.d.ts +1 -0
- package/dist/commands/sessions.js +89 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +37 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +125 -0
- package/dist/project/executor.d.ts +118 -0
- package/dist/project/executor.js +893 -0
- package/dist/project/index.d.ts +4 -0
- package/dist/project/index.js +20 -0
- package/dist/project/manager.d.ts +79 -0
- package/dist/project/manager.js +397 -0
- package/dist/project/relay-client.d.ts +87 -0
- package/dist/project/relay-client.js +200 -0
- package/dist/project/types.d.ts +43 -0
- package/dist/project/types.js +3 -0
- package/package.json +59 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.startAgent = startAgent;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const runner_1 = require("../agent/runner");
|
|
9
|
+
async function startAgent(options) {
|
|
10
|
+
try {
|
|
11
|
+
const config = runner_1.AgentRunner.loadConfig(options.config);
|
|
12
|
+
const runner = new runner_1.AgentRunner(config);
|
|
13
|
+
await runner.start();
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error(chalk_1.default.red(`Error: ${error.message}`));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function listAgents(): Promise<void>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.listAgents = listAgents;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const api_1 = require("../api");
|
|
10
|
+
const config_1 = require("../config");
|
|
11
|
+
async function listAgents() {
|
|
12
|
+
if (!(0, config_1.isLoggedIn)()) {
|
|
13
|
+
console.log(chalk_1.default.red('Not logged in. Run: sessioncast login <api-key>'));
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const spinner = (0, ora_1.default)('Fetching agents...').start();
|
|
17
|
+
try {
|
|
18
|
+
const agents = await api_1.api.listAgents();
|
|
19
|
+
spinner.stop();
|
|
20
|
+
if (agents.length === 0) {
|
|
21
|
+
console.log(chalk_1.default.yellow('No agents found.'));
|
|
22
|
+
console.log(chalk_1.default.gray('Create an agent at https://account.sessioncast.io'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(chalk_1.default.bold('\nYour Agents:\n'));
|
|
26
|
+
// Table header
|
|
27
|
+
console.log(chalk_1.default.gray(padRight('NAME', 20) +
|
|
28
|
+
padRight('STATUS', 12) +
|
|
29
|
+
padRight('API', 8) +
|
|
30
|
+
padRight('LAST SEEN', 20) +
|
|
31
|
+
'ID'));
|
|
32
|
+
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
33
|
+
// Table rows
|
|
34
|
+
for (const agent of agents) {
|
|
35
|
+
const name = agent.label || agent.machineId || 'unnamed';
|
|
36
|
+
const status = agent.isActive ? chalk_1.default.green('● online') : chalk_1.default.gray('○ offline');
|
|
37
|
+
const apiStatus = agent.apiEnabled ? chalk_1.default.green('yes') : chalk_1.default.gray('no');
|
|
38
|
+
const lastSeen = agent.lastConnectedAt
|
|
39
|
+
? formatRelativeTime(new Date(agent.lastConnectedAt))
|
|
40
|
+
: chalk_1.default.gray('never');
|
|
41
|
+
console.log(padRight(name, 20) +
|
|
42
|
+
padRight(status, 12) +
|
|
43
|
+
padRight(apiStatus, 8) +
|
|
44
|
+
padRight(lastSeen, 20) +
|
|
45
|
+
chalk_1.default.gray(agent.id.substring(0, 8)));
|
|
46
|
+
}
|
|
47
|
+
console.log();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
spinner.stop();
|
|
51
|
+
console.log(chalk_1.default.red(`Error: ${error.message}`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function padRight(str, len) {
|
|
56
|
+
// Remove ANSI codes for length calculation
|
|
57
|
+
const plainStr = str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
58
|
+
const padding = Math.max(0, len - plainStr.length);
|
|
59
|
+
return str + ' '.repeat(padding);
|
|
60
|
+
}
|
|
61
|
+
function formatRelativeTime(date) {
|
|
62
|
+
const now = new Date();
|
|
63
|
+
const diff = now.getTime() - date.getTime();
|
|
64
|
+
const seconds = Math.floor(diff / 1000);
|
|
65
|
+
const minutes = Math.floor(seconds / 60);
|
|
66
|
+
const hours = Math.floor(minutes / 60);
|
|
67
|
+
const days = Math.floor(hours / 24);
|
|
68
|
+
if (seconds < 60)
|
|
69
|
+
return 'just now';
|
|
70
|
+
if (minutes < 60)
|
|
71
|
+
return `${minutes}m ago`;
|
|
72
|
+
if (hours < 24)
|
|
73
|
+
return `${hours}h ago`;
|
|
74
|
+
if (days < 7)
|
|
75
|
+
return `${days}d ago`;
|
|
76
|
+
return date.toLocaleDateString();
|
|
77
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.login = login;
|
|
7
|
+
exports.logout = logout;
|
|
8
|
+
exports.status = status;
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const config_1 = require("../config");
|
|
11
|
+
async function login(apiKey, options) {
|
|
12
|
+
if (options.url) {
|
|
13
|
+
(0, config_1.setApiUrl)(options.url);
|
|
14
|
+
console.log(chalk_1.default.gray(`API URL set to: ${options.url}`));
|
|
15
|
+
}
|
|
16
|
+
// Validate API key format
|
|
17
|
+
if (!apiKey.startsWith('sk-')) {
|
|
18
|
+
console.log(chalk_1.default.red('Invalid API key format. Key should start with "sk-"'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
(0, config_1.setApiKey)(apiKey);
|
|
22
|
+
console.log(chalk_1.default.green('✓ Logged in successfully!'));
|
|
23
|
+
console.log(chalk_1.default.gray('Your API key has been saved.'));
|
|
24
|
+
}
|
|
25
|
+
async function logout() {
|
|
26
|
+
if (!(0, config_1.isLoggedIn)()) {
|
|
27
|
+
console.log(chalk_1.default.yellow('Not logged in.'));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
(0, config_1.clearApiKey)();
|
|
31
|
+
console.log(chalk_1.default.green('✓ Logged out successfully!'));
|
|
32
|
+
}
|
|
33
|
+
function status() {
|
|
34
|
+
if ((0, config_1.isLoggedIn)()) {
|
|
35
|
+
console.log(chalk_1.default.green('✓ Logged in'));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.log(chalk_1.default.yellow('Not logged in'));
|
|
39
|
+
console.log(chalk_1.default.gray('Run: sessioncast login <api-key>'));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize a new project
|
|
3
|
+
*/
|
|
4
|
+
export declare function projectInit(projectPath: string, options: {
|
|
5
|
+
name?: string;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Run workflow
|
|
9
|
+
*/
|
|
10
|
+
export declare function projectRun(projectPath: string, options: {
|
|
11
|
+
watch?: boolean;
|
|
12
|
+
noClaude?: boolean;
|
|
13
|
+
relayUrl?: string;
|
|
14
|
+
relayToken?: string;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Show project status
|
|
18
|
+
*/
|
|
19
|
+
export declare function projectStatus(projectPath: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Stop workflow and kill sessions
|
|
22
|
+
*/
|
|
23
|
+
export declare function projectStop(projectPath: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* List agents and send commands
|
|
26
|
+
*/
|
|
27
|
+
export declare function projectSend(projectPath: string, agentId: string, message: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Create a sample workflow
|
|
30
|
+
*/
|
|
31
|
+
export declare function projectCreateWorkflow(projectPath: string, options: {
|
|
32
|
+
template?: string;
|
|
33
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,359 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.projectInit = projectInit;
|
|
40
|
+
exports.projectRun = projectRun;
|
|
41
|
+
exports.projectStatus = projectStatus;
|
|
42
|
+
exports.projectStop = projectStop;
|
|
43
|
+
exports.projectSend = projectSend;
|
|
44
|
+
exports.projectCreateWorkflow = projectCreateWorkflow;
|
|
45
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const project_1 = require("../project");
|
|
48
|
+
/**
|
|
49
|
+
* Initialize a new project
|
|
50
|
+
*/
|
|
51
|
+
async function projectInit(projectPath, options) {
|
|
52
|
+
const resolvedPath = path.resolve(projectPath || '.');
|
|
53
|
+
console.log(chalk_1.default.blue('Initializing SessionCast project...'));
|
|
54
|
+
console.log(chalk_1.default.gray(`Path: ${resolvedPath}`));
|
|
55
|
+
const manager = new project_1.ProjectManager(resolvedPath);
|
|
56
|
+
const project = manager.init(options.name);
|
|
57
|
+
console.log(chalk_1.default.green('\nProject initialized successfully!'));
|
|
58
|
+
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
59
|
+
console.log(` Name: ${chalk_1.default.bold(project.name)}`);
|
|
60
|
+
console.log(` Path: ${project.path}`);
|
|
61
|
+
console.log(` Status: ${project.status}`);
|
|
62
|
+
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
63
|
+
console.log(chalk_1.default.yellow('\nFolder structure created:'));
|
|
64
|
+
console.log(' mission/ - Mission history and refined mission');
|
|
65
|
+
console.log(' flow/ - Workflow definitions');
|
|
66
|
+
console.log(' shared/ - Shared context between agents');
|
|
67
|
+
console.log(' tools/ - Meta tools (mission-refiner, pm-agent)');
|
|
68
|
+
console.log(' work/ - Work agents');
|
|
69
|
+
console.log(chalk_1.default.cyan('\nNext steps:'));
|
|
70
|
+
console.log(' 1. Define your workflow in flow/workflow.yml');
|
|
71
|
+
console.log(' 2. Or start mission refinement:');
|
|
72
|
+
console.log(chalk_1.default.gray(` cd ${resolvedPath}/tools/mission-refiner && claude`));
|
|
73
|
+
console.log(' 3. Run the workflow:');
|
|
74
|
+
console.log(chalk_1.default.gray(` sessioncast project run ${resolvedPath}`));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Run workflow
|
|
78
|
+
*/
|
|
79
|
+
async function projectRun(projectPath, options) {
|
|
80
|
+
const resolvedPath = path.resolve(projectPath || '.');
|
|
81
|
+
console.log(chalk_1.default.blue('Running SessionCast workflow...'));
|
|
82
|
+
console.log(chalk_1.default.gray(`Path: ${resolvedPath}`));
|
|
83
|
+
const manager = new project_1.ProjectManager(resolvedPath);
|
|
84
|
+
const project = manager.load();
|
|
85
|
+
if (!project) {
|
|
86
|
+
console.error(chalk_1.default.red('Error: Not a SessionCast project. Run `sessioncast project init` first.'));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const workflow = manager.loadWorkflow();
|
|
90
|
+
if (!workflow) {
|
|
91
|
+
console.error(chalk_1.default.red('Error: No workflow.yml found. Define your workflow first.'));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
// Use default dev token for local development
|
|
95
|
+
let relayToken = options.relayToken;
|
|
96
|
+
if (options.relayUrl && !relayToken) {
|
|
97
|
+
const isDevRelay = options.relayUrl.includes('localhost') || options.relayUrl.includes('127.0.0.1');
|
|
98
|
+
if (isDevRelay) {
|
|
99
|
+
relayToken = 'dev@localhost';
|
|
100
|
+
console.log(chalk_1.default.gray(' Using default dev token: dev@localhost'));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
104
|
+
console.log(` Workflow: ${chalk_1.default.bold(workflow.name)}`);
|
|
105
|
+
console.log(` Mission: ${workflow.mission}`);
|
|
106
|
+
console.log(` Agents: ${workflow.agents.map(a => a.id).join(', ')}`);
|
|
107
|
+
console.log(` Auto-launch Claude: ${options.noClaude ? 'No' : 'Yes'}`);
|
|
108
|
+
if (options.relayUrl) {
|
|
109
|
+
console.log(` Relay: ${options.relayUrl}`);
|
|
110
|
+
}
|
|
111
|
+
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
112
|
+
const executor = new project_1.WorkflowExecutor(manager, {
|
|
113
|
+
autoLaunchClaude: !options.noClaude,
|
|
114
|
+
relayUrl: options.relayUrl,
|
|
115
|
+
relayToken: relayToken
|
|
116
|
+
});
|
|
117
|
+
executor.on('agent-started', ({ agentId, sessionName }) => {
|
|
118
|
+
console.log(chalk_1.default.cyan(`[${agentId}] Started - tmux session: ${sessionName}`));
|
|
119
|
+
});
|
|
120
|
+
executor.on('agent-completed', ({ agentId, output }) => {
|
|
121
|
+
console.log(chalk_1.default.green(`[${agentId}] Completed`));
|
|
122
|
+
if (output) {
|
|
123
|
+
console.log(chalk_1.default.gray(` Output: ${output.substring(0, 100)}...`));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
executor.on('workflow-completed', () => {
|
|
127
|
+
console.log(chalk_1.default.green.bold('\nWorkflow completed successfully!'));
|
|
128
|
+
if (!options.watch) {
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
executor.on('workflow-failed', () => {
|
|
133
|
+
console.log(chalk_1.default.red.bold('\nWorkflow failed!'));
|
|
134
|
+
const status = manager.loadStatus();
|
|
135
|
+
if (status) {
|
|
136
|
+
for (const [agentId, agentStatus] of Object.entries(status.agents)) {
|
|
137
|
+
if (agentStatus.status === 'failed') {
|
|
138
|
+
console.log(chalk_1.default.red(` [${agentId}] ${agentStatus.error || 'Unknown error'}`));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (!options.watch) {
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
// Handle shutdown
|
|
147
|
+
process.on('SIGINT', () => {
|
|
148
|
+
console.log(chalk_1.default.yellow('\nStopping workflow...'));
|
|
149
|
+
executor.stop();
|
|
150
|
+
process.exit(0);
|
|
151
|
+
});
|
|
152
|
+
await executor.start();
|
|
153
|
+
if (options.watch) {
|
|
154
|
+
console.log(chalk_1.default.gray('\nWatching for changes... (Ctrl+C to stop)'));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Show project status
|
|
159
|
+
*/
|
|
160
|
+
async function projectStatus(projectPath) {
|
|
161
|
+
const resolvedPath = path.resolve(projectPath || '.');
|
|
162
|
+
const manager = new project_1.ProjectManager(resolvedPath);
|
|
163
|
+
const project = manager.load();
|
|
164
|
+
if (!project) {
|
|
165
|
+
console.error(chalk_1.default.red('Error: Not a SessionCast project.'));
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
const workflow = manager.loadWorkflow();
|
|
169
|
+
const status = manager.loadStatus();
|
|
170
|
+
const executor = new project_1.WorkflowExecutor(manager);
|
|
171
|
+
const sessions = executor.listSessions();
|
|
172
|
+
console.log(chalk_1.default.blue('SessionCast Project Status'));
|
|
173
|
+
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
174
|
+
console.log(` Project: ${chalk_1.default.bold(project.name)}`);
|
|
175
|
+
console.log(` Path: ${project.path}`);
|
|
176
|
+
console.log(` Status: ${colorStatus(project.status)}`);
|
|
177
|
+
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
178
|
+
if (workflow) {
|
|
179
|
+
console.log(chalk_1.default.yellow('\nWorkflow:'));
|
|
180
|
+
console.log(` Name: ${workflow.name}`);
|
|
181
|
+
console.log(` Mission: ${workflow.mission}`);
|
|
182
|
+
console.log(` Agents: ${workflow.agents.length}`);
|
|
183
|
+
if (status) {
|
|
184
|
+
console.log(chalk_1.default.yellow('\nAgent Status:'));
|
|
185
|
+
for (const agent of workflow.agents) {
|
|
186
|
+
const agentStatus = status.agents[agent.id];
|
|
187
|
+
const statusStr = agentStatus ? colorStatus(agentStatus.status) : chalk_1.default.gray('not started');
|
|
188
|
+
const isRunning = sessions.includes(agent.id);
|
|
189
|
+
const sessionIndicator = isRunning ? chalk_1.default.green(' [tmux]') : '';
|
|
190
|
+
console.log(` ${agent.id}: ${statusStr}${sessionIndicator}`);
|
|
191
|
+
if (agentStatus?.currentTask) {
|
|
192
|
+
console.log(chalk_1.default.gray(` → ${agentStatus.currentTask}`));
|
|
193
|
+
}
|
|
194
|
+
if (agentStatus?.error) {
|
|
195
|
+
console.log(chalk_1.default.red(` ! ${agentStatus.error}`));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
console.log(chalk_1.default.yellow('\nNo workflow defined yet.'));
|
|
202
|
+
console.log(chalk_1.default.gray('Create flow/workflow.yml to define your workflow.'));
|
|
203
|
+
}
|
|
204
|
+
if (sessions.length > 0) {
|
|
205
|
+
console.log(chalk_1.default.yellow('\nActive Sessions:'));
|
|
206
|
+
for (const session of sessions) {
|
|
207
|
+
console.log(` ${session}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Stop workflow and kill sessions
|
|
213
|
+
*/
|
|
214
|
+
async function projectStop(projectPath) {
|
|
215
|
+
const resolvedPath = path.resolve(projectPath || '.');
|
|
216
|
+
console.log(chalk_1.default.blue('Stopping SessionCast workflow...'));
|
|
217
|
+
const manager = new project_1.ProjectManager(resolvedPath);
|
|
218
|
+
const executor = new project_1.WorkflowExecutor(manager);
|
|
219
|
+
executor.killAllSessions();
|
|
220
|
+
console.log(chalk_1.default.green('All sessions stopped.'));
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* List agents and send commands
|
|
224
|
+
*/
|
|
225
|
+
async function projectSend(projectPath, agentId, message) {
|
|
226
|
+
const resolvedPath = path.resolve(projectPath || '.');
|
|
227
|
+
const manager = new project_1.ProjectManager(resolvedPath);
|
|
228
|
+
const executor = new project_1.WorkflowExecutor(manager);
|
|
229
|
+
if (executor.sendToAgent(agentId, message)) {
|
|
230
|
+
console.log(chalk_1.default.green(`Sent to ${agentId}: ${message}`));
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
console.error(chalk_1.default.red(`Failed to send to ${agentId}. Is the session running?`));
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Create a sample workflow
|
|
239
|
+
*/
|
|
240
|
+
async function projectCreateWorkflow(projectPath, options) {
|
|
241
|
+
const resolvedPath = path.resolve(projectPath || '.');
|
|
242
|
+
const manager = new project_1.ProjectManager(resolvedPath);
|
|
243
|
+
const project = manager.load();
|
|
244
|
+
if (!project) {
|
|
245
|
+
console.error(chalk_1.default.red('Error: Not a SessionCast project.'));
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
const template = options.template || 'basic';
|
|
249
|
+
const workflow = getWorkflowTemplate(template, project.name);
|
|
250
|
+
manager.saveWorkflow(workflow);
|
|
251
|
+
// Create work folders
|
|
252
|
+
for (const agent of workflow.agents) {
|
|
253
|
+
manager.createWorkAgent(agent.id, agent.name, agent.tasks);
|
|
254
|
+
}
|
|
255
|
+
console.log(chalk_1.default.green(`Created workflow from template: ${template}`));
|
|
256
|
+
console.log(chalk_1.default.gray(`File: ${resolvedPath}/flow/workflow.yml`));
|
|
257
|
+
console.log(chalk_1.default.yellow('\nAgents created:'));
|
|
258
|
+
for (const agent of workflow.agents) {
|
|
259
|
+
console.log(` ${agent.id} - ${agent.name}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function getWorkflowTemplate(template, projectName) {
|
|
263
|
+
switch (template) {
|
|
264
|
+
case 'android':
|
|
265
|
+
return {
|
|
266
|
+
name: projectName,
|
|
267
|
+
mission: 'Android app development',
|
|
268
|
+
created: new Date().toISOString(),
|
|
269
|
+
agents: [
|
|
270
|
+
{
|
|
271
|
+
id: 'android',
|
|
272
|
+
name: 'Android Development',
|
|
273
|
+
workDir: 'work/android',
|
|
274
|
+
tasks: ['Feature implementation', 'UI development'],
|
|
275
|
+
dependsOn: []
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: 'qa',
|
|
279
|
+
name: 'QA Testing',
|
|
280
|
+
workDir: 'work/qa',
|
|
281
|
+
tasks: ['Unit tests', 'Integration tests'],
|
|
282
|
+
dependsOn: ['android']
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: 'release',
|
|
286
|
+
name: 'Release',
|
|
287
|
+
workDir: 'work/release',
|
|
288
|
+
tasks: ['Version tagging', 'Release notes'],
|
|
289
|
+
dependsOn: ['qa']
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
};
|
|
293
|
+
case 'fullstack':
|
|
294
|
+
return {
|
|
295
|
+
name: projectName,
|
|
296
|
+
mission: 'Fullstack development',
|
|
297
|
+
created: new Date().toISOString(),
|
|
298
|
+
agents: [
|
|
299
|
+
{
|
|
300
|
+
id: 'backend',
|
|
301
|
+
name: 'Backend Development',
|
|
302
|
+
workDir: 'work/backend',
|
|
303
|
+
tasks: ['API implementation', 'Database schema'],
|
|
304
|
+
dependsOn: []
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
id: 'frontend',
|
|
308
|
+
name: 'Frontend Development',
|
|
309
|
+
workDir: 'work/frontend',
|
|
310
|
+
tasks: ['UI components', 'API integration'],
|
|
311
|
+
dependsOn: ['backend']
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
id: 'qa',
|
|
315
|
+
name: 'QA Testing',
|
|
316
|
+
workDir: 'work/qa',
|
|
317
|
+
tasks: ['E2E tests', 'Performance tests'],
|
|
318
|
+
dependsOn: ['frontend']
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
};
|
|
322
|
+
default: // basic
|
|
323
|
+
return {
|
|
324
|
+
name: projectName,
|
|
325
|
+
mission: 'Project mission (edit this)',
|
|
326
|
+
created: new Date().toISOString(),
|
|
327
|
+
agents: [
|
|
328
|
+
{
|
|
329
|
+
id: 'dev',
|
|
330
|
+
name: 'Development',
|
|
331
|
+
workDir: 'work/dev',
|
|
332
|
+
tasks: ['Implement features'],
|
|
333
|
+
dependsOn: []
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
id: 'test',
|
|
337
|
+
name: 'Testing',
|
|
338
|
+
workDir: 'work/test',
|
|
339
|
+
tasks: ['Write tests'],
|
|
340
|
+
dependsOn: ['dev']
|
|
341
|
+
}
|
|
342
|
+
]
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function colorStatus(status) {
|
|
347
|
+
switch (status) {
|
|
348
|
+
case 'completed':
|
|
349
|
+
return chalk_1.default.green(status);
|
|
350
|
+
case 'running':
|
|
351
|
+
return chalk_1.default.cyan(status);
|
|
352
|
+
case 'failed':
|
|
353
|
+
return chalk_1.default.red(status);
|
|
354
|
+
case 'pending':
|
|
355
|
+
return chalk_1.default.yellow(status);
|
|
356
|
+
default:
|
|
357
|
+
return chalk_1.default.gray(status);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sendKeys = sendKeys;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const api_1 = require("../api");
|
|
10
|
+
const config_1 = require("../config");
|
|
11
|
+
async function sendKeys(target, keys, options) {
|
|
12
|
+
if (!(0, config_1.isLoggedIn)()) {
|
|
13
|
+
console.log(chalk_1.default.red('Not logged in. Run: sessioncast login <api-key>'));
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
// Parse target: "agent:session" or "agent:session:window"
|
|
17
|
+
const parts = target.split(':');
|
|
18
|
+
if (parts.length < 2) {
|
|
19
|
+
console.log(chalk_1.default.red('Invalid target format.'));
|
|
20
|
+
console.log(chalk_1.default.gray('Expected: <agent>:<session> or <agent>:<session>:<window>'));
|
|
21
|
+
console.log(chalk_1.default.gray('Example: macbook:dev or server:main:0'));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const agentName = parts[0];
|
|
25
|
+
const sessionTarget = parts.slice(1).join(':'); // session:window or just session
|
|
26
|
+
const spinner = (0, ora_1.default)('Finding agent...').start();
|
|
27
|
+
try {
|
|
28
|
+
// Find agent by name/label/machineId
|
|
29
|
+
const agent = await api_1.api.findAgentByName(agentName);
|
|
30
|
+
if (!agent) {
|
|
31
|
+
spinner.stop();
|
|
32
|
+
console.log(chalk_1.default.red(`Agent not found: ${agentName}`));
|
|
33
|
+
console.log(chalk_1.default.gray('Run: sessioncast agents'));
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (!agent.isActive) {
|
|
37
|
+
spinner.stop();
|
|
38
|
+
console.log(chalk_1.default.red(`Agent is offline: ${agentName}`));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
if (!agent.apiEnabled) {
|
|
42
|
+
spinner.stop();
|
|
43
|
+
console.log(chalk_1.default.red(`API is not enabled for agent: ${agentName}`));
|
|
44
|
+
console.log(chalk_1.default.gray('Enable API in agent settings at https://account.sessioncast.io'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
spinner.text = 'Sending keys...';
|
|
48
|
+
const result = await api_1.api.sendKeys(agent.id, sessionTarget, keys, !options.noEnter);
|
|
49
|
+
spinner.stop();
|
|
50
|
+
if (result.success) {
|
|
51
|
+
console.log(chalk_1.default.green(`✓ Keys sent to ${target}`));
|
|
52
|
+
if (!options.noEnter) {
|
|
53
|
+
console.log(chalk_1.default.gray('(Enter key was pressed)'));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(chalk_1.default.red(`Failed to send keys: ${result.error || 'Unknown error'}`));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
spinner.stop();
|
|
63
|
+
console.log(chalk_1.default.red(`Error: ${error.message}`));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function listSessions(agentName?: string): Promise<void>;
|