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,89 @@
|
|
|
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.listSessions = listSessions;
|
|
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 listSessions(agentName) {
|
|
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 sessions...').start();
|
|
17
|
+
try {
|
|
18
|
+
const agents = await api_1.api.listAgents();
|
|
19
|
+
const onlineAgents = agents.filter(a => a.isActive && a.apiEnabled);
|
|
20
|
+
if (onlineAgents.length === 0) {
|
|
21
|
+
spinner.stop();
|
|
22
|
+
console.log(chalk_1.default.yellow('No online agents with API enabled.'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Filter by agent name if provided
|
|
26
|
+
let targetAgents = onlineAgents;
|
|
27
|
+
if (agentName) {
|
|
28
|
+
const found = onlineAgents.find(a => a.label?.toLowerCase() === agentName.toLowerCase() ||
|
|
29
|
+
a.machineId?.toLowerCase() === agentName.toLowerCase() ||
|
|
30
|
+
a.id.startsWith(agentName));
|
|
31
|
+
if (!found) {
|
|
32
|
+
spinner.stop();
|
|
33
|
+
console.log(chalk_1.default.red(`Agent not found: ${agentName}`));
|
|
34
|
+
console.log(chalk_1.default.gray('Run: sessioncast agents'));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
targetAgents = [found];
|
|
38
|
+
}
|
|
39
|
+
// Fetch sessions from all target agents
|
|
40
|
+
const allSessions = [];
|
|
41
|
+
for (const agent of targetAgents) {
|
|
42
|
+
try {
|
|
43
|
+
const sessions = await api_1.api.listSessions(agent.id);
|
|
44
|
+
allSessions.push({ agent, sessions });
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// Skip failed agents
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
spinner.stop();
|
|
51
|
+
if (allSessions.every(as => as.sessions.length === 0)) {
|
|
52
|
+
console.log(chalk_1.default.yellow('No tmux sessions found.'));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
console.log(chalk_1.default.bold('\nTmux Sessions:\n'));
|
|
56
|
+
// Table header
|
|
57
|
+
console.log(chalk_1.default.gray(padRight('AGENT', 16) +
|
|
58
|
+
padRight('SESSION', 16) +
|
|
59
|
+
padRight('WINDOWS', 10) +
|
|
60
|
+
padRight('ATTACHED', 10) +
|
|
61
|
+
'TARGET'));
|
|
62
|
+
console.log(chalk_1.default.gray('─'.repeat(70)));
|
|
63
|
+
// Table rows
|
|
64
|
+
for (const { agent, sessions } of allSessions) {
|
|
65
|
+
const agentName = agent.label || agent.machineId || agent.id.substring(0, 8);
|
|
66
|
+
for (const session of sessions) {
|
|
67
|
+
const attached = session.attached ? chalk_1.default.green('yes') : chalk_1.default.gray('no');
|
|
68
|
+
const target = `${agentName}:${session.name}`;
|
|
69
|
+
console.log(padRight(agentName, 16) +
|
|
70
|
+
padRight(session.name, 16) +
|
|
71
|
+
padRight(String(session.windows), 10) +
|
|
72
|
+
padRight(attached, 10) +
|
|
73
|
+
chalk_1.default.cyan(target));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(chalk_1.default.gray('Use: sessioncast send <target> "command"'));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
spinner.stop();
|
|
81
|
+
console.log(chalk_1.default.red(`Error: ${error.message}`));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function padRight(str, len) {
|
|
86
|
+
const plainStr = str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
87
|
+
const padding = Math.max(0, len - plainStr.length);
|
|
88
|
+
return str + ' '.repeat(padding);
|
|
89
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
interface ConfigSchema {
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
}
|
|
6
|
+
declare const config: Conf<ConfigSchema>;
|
|
7
|
+
export declare function getApiKey(): string | undefined;
|
|
8
|
+
export declare function setApiKey(key: string): void;
|
|
9
|
+
export declare function clearApiKey(): void;
|
|
10
|
+
export declare function getApiUrl(): string;
|
|
11
|
+
export declare function setApiUrl(url: string): void;
|
|
12
|
+
export declare function isLoggedIn(): boolean;
|
|
13
|
+
export default config;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
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.getApiKey = getApiKey;
|
|
7
|
+
exports.setApiKey = setApiKey;
|
|
8
|
+
exports.clearApiKey = clearApiKey;
|
|
9
|
+
exports.getApiUrl = getApiUrl;
|
|
10
|
+
exports.setApiUrl = setApiUrl;
|
|
11
|
+
exports.isLoggedIn = isLoggedIn;
|
|
12
|
+
const conf_1 = __importDefault(require("conf"));
|
|
13
|
+
const config = new conf_1.default({
|
|
14
|
+
projectName: 'sessioncast',
|
|
15
|
+
defaults: {
|
|
16
|
+
apiUrl: 'https://api.sessioncast.io'
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
function getApiKey() {
|
|
20
|
+
return config.get('apiKey');
|
|
21
|
+
}
|
|
22
|
+
function setApiKey(key) {
|
|
23
|
+
config.set('apiKey', key);
|
|
24
|
+
}
|
|
25
|
+
function clearApiKey() {
|
|
26
|
+
config.delete('apiKey');
|
|
27
|
+
}
|
|
28
|
+
function getApiUrl() {
|
|
29
|
+
return config.get('apiUrl');
|
|
30
|
+
}
|
|
31
|
+
function setApiUrl(url) {
|
|
32
|
+
config.set('apiUrl', url);
|
|
33
|
+
}
|
|
34
|
+
function isLoggedIn() {
|
|
35
|
+
return !!getApiKey();
|
|
36
|
+
}
|
|
37
|
+
exports.default = config;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const login_1 = require("./commands/login");
|
|
10
|
+
const agents_1 = require("./commands/agents");
|
|
11
|
+
const sessions_1 = require("./commands/sessions");
|
|
12
|
+
const sendkeys_1 = require("./commands/sendkeys");
|
|
13
|
+
const agent_1 = require("./commands/agent");
|
|
14
|
+
const project_1 = require("./commands/project");
|
|
15
|
+
const program = new commander_1.Command();
|
|
16
|
+
program
|
|
17
|
+
.name('sessioncast')
|
|
18
|
+
.description('SessionCast CLI - Control your agents from anywhere')
|
|
19
|
+
.version('1.0.0');
|
|
20
|
+
// Login command
|
|
21
|
+
program
|
|
22
|
+
.command('login <api-key>')
|
|
23
|
+
.description('Login with your API key')
|
|
24
|
+
.option('-u, --url <url>', 'Custom API URL')
|
|
25
|
+
.action(login_1.login);
|
|
26
|
+
// Logout command
|
|
27
|
+
program
|
|
28
|
+
.command('logout')
|
|
29
|
+
.description('Clear stored credentials')
|
|
30
|
+
.action(login_1.logout);
|
|
31
|
+
// Status command
|
|
32
|
+
program
|
|
33
|
+
.command('status')
|
|
34
|
+
.description('Check login status')
|
|
35
|
+
.action(login_1.status);
|
|
36
|
+
// Agents command
|
|
37
|
+
program
|
|
38
|
+
.command('agents')
|
|
39
|
+
.description('List your agents')
|
|
40
|
+
.action(agents_1.listAgents);
|
|
41
|
+
// List/Sessions command
|
|
42
|
+
program
|
|
43
|
+
.command('list [agent]')
|
|
44
|
+
.alias('ls')
|
|
45
|
+
.description('List tmux sessions on agents')
|
|
46
|
+
.action(sessions_1.listSessions);
|
|
47
|
+
// Send keys command
|
|
48
|
+
program
|
|
49
|
+
.command('send <target> <keys>')
|
|
50
|
+
.alias('sendkeys')
|
|
51
|
+
.description('Send keys to a tmux session')
|
|
52
|
+
.option('--no-enter', 'Do not press Enter after keys')
|
|
53
|
+
.action(sendkeys_1.sendKeys);
|
|
54
|
+
// Agent command
|
|
55
|
+
program
|
|
56
|
+
.command('agent')
|
|
57
|
+
.description('Start the SessionCast agent')
|
|
58
|
+
.option('-c, --config <path>', 'Path to config file')
|
|
59
|
+
.action(agent_1.startAgent);
|
|
60
|
+
// Project commands
|
|
61
|
+
const project = program
|
|
62
|
+
.command('project')
|
|
63
|
+
.description('Project mode commands');
|
|
64
|
+
project
|
|
65
|
+
.command('init [path]')
|
|
66
|
+
.description('Initialize a new SessionCast project')
|
|
67
|
+
.option('-n, --name <name>', 'Project name')
|
|
68
|
+
.action(project_1.projectInit);
|
|
69
|
+
project
|
|
70
|
+
.command('run [path]')
|
|
71
|
+
.description('Run the workflow')
|
|
72
|
+
.option('-w, --watch', 'Watch mode - keep running after completion')
|
|
73
|
+
.option('--no-claude', 'Do not auto-launch Claude Code CLI')
|
|
74
|
+
.option('--relay-url <url>', 'Relay server WebSocket URL')
|
|
75
|
+
.option('--relay-token <token>', 'Relay server authentication token')
|
|
76
|
+
.action(project_1.projectRun);
|
|
77
|
+
project
|
|
78
|
+
.command('status [path]')
|
|
79
|
+
.description('Show project and workflow status')
|
|
80
|
+
.action(project_1.projectStatus);
|
|
81
|
+
project
|
|
82
|
+
.command('stop [path]')
|
|
83
|
+
.description('Stop all agent sessions')
|
|
84
|
+
.action(project_1.projectStop);
|
|
85
|
+
project
|
|
86
|
+
.command('send <path> <agent> <message>')
|
|
87
|
+
.description('Send a message to an agent')
|
|
88
|
+
.action(project_1.projectSend);
|
|
89
|
+
project
|
|
90
|
+
.command('workflow [path]')
|
|
91
|
+
.description('Create workflow from template')
|
|
92
|
+
.option('-t, --template <template>', 'Template: basic, android, fullstack')
|
|
93
|
+
.action(project_1.projectCreateWorkflow);
|
|
94
|
+
// Help examples
|
|
95
|
+
program.on('--help', () => {
|
|
96
|
+
console.log('');
|
|
97
|
+
console.log('Examples:');
|
|
98
|
+
console.log(' $ sessioncast login sk-xxx-xxx-xxx');
|
|
99
|
+
console.log(' $ sessioncast agents');
|
|
100
|
+
console.log(' $ sessioncast list');
|
|
101
|
+
console.log(' $ sessioncast list macbook');
|
|
102
|
+
console.log(' $ sessioncast send macbook:dev "ls -la"');
|
|
103
|
+
console.log(' $ sessioncast send server:main:0 "npm run build"');
|
|
104
|
+
console.log(' $ sessioncast agent # Start agent with default config');
|
|
105
|
+
console.log(' $ sessioncast agent -c ~/.sessioncast.yml # Start with custom config');
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log('Project Mode:');
|
|
108
|
+
console.log(' $ sessioncast project init ./my-project # Initialize new project');
|
|
109
|
+
console.log(' $ sessioncast project workflow . -t android # Create workflow from template');
|
|
110
|
+
console.log(' $ sessioncast project run . # Run the workflow');
|
|
111
|
+
console.log(' $ sessioncast project status . # Check status');
|
|
112
|
+
console.log(' $ sessioncast project stop . # Stop all agents');
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log('Target format:');
|
|
115
|
+
console.log(' <agent>:<session> - Send to session');
|
|
116
|
+
console.log(' <agent>:<session>:<window> - Send to specific window');
|
|
117
|
+
console.log('');
|
|
118
|
+
});
|
|
119
|
+
// Default action (no command)
|
|
120
|
+
program.action(() => {
|
|
121
|
+
console.log(chalk_1.default.bold('\n SessionCast CLI\n'));
|
|
122
|
+
console.log(' Control your agents from anywhere.\n');
|
|
123
|
+
console.log(chalk_1.default.gray(' Run `sessioncast --help` for usage.\n'));
|
|
124
|
+
});
|
|
125
|
+
program.parse();
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { ProjectManager } from './manager';
|
|
3
|
+
export interface ExecutorOptions {
|
|
4
|
+
autoLaunchClaude?: boolean;
|
|
5
|
+
claudeCommand?: string;
|
|
6
|
+
relayUrl?: string;
|
|
7
|
+
relayToken?: string;
|
|
8
|
+
machineId?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class WorkflowExecutor extends EventEmitter {
|
|
11
|
+
private manager;
|
|
12
|
+
private workflow;
|
|
13
|
+
private running;
|
|
14
|
+
private pollTimer;
|
|
15
|
+
private options;
|
|
16
|
+
private relayClient;
|
|
17
|
+
constructor(manager: ProjectManager, options?: ExecutorOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Start workflow execution
|
|
20
|
+
*/
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Start PM Agent tmux session
|
|
24
|
+
*/
|
|
25
|
+
private startPMAgent;
|
|
26
|
+
/**
|
|
27
|
+
* Start a work agent
|
|
28
|
+
*/
|
|
29
|
+
private startAgent;
|
|
30
|
+
/**
|
|
31
|
+
* Build task prompt for agent
|
|
32
|
+
*/
|
|
33
|
+
private buildTaskPrompt;
|
|
34
|
+
/**
|
|
35
|
+
* Launch Claude Code CLI in a tmux session
|
|
36
|
+
*/
|
|
37
|
+
private launchClaudeInSession;
|
|
38
|
+
/**
|
|
39
|
+
* Sleep helper
|
|
40
|
+
*/
|
|
41
|
+
private sleep;
|
|
42
|
+
/**
|
|
43
|
+
* Main execution loop
|
|
44
|
+
*/
|
|
45
|
+
private runExecutionLoop;
|
|
46
|
+
/**
|
|
47
|
+
* Connect to relay server
|
|
48
|
+
*/
|
|
49
|
+
private connectToRelay;
|
|
50
|
+
/**
|
|
51
|
+
* Handle incoming messages from relay server
|
|
52
|
+
*/
|
|
53
|
+
private handleRelayMessage;
|
|
54
|
+
/**
|
|
55
|
+
* Handle mission analysis request - calls Claude Code to analyze
|
|
56
|
+
*/
|
|
57
|
+
private handleAnalyzeMission;
|
|
58
|
+
/**
|
|
59
|
+
* Handle addSource request - clone/copy source into work folder
|
|
60
|
+
*/
|
|
61
|
+
private handleAddSource;
|
|
62
|
+
/**
|
|
63
|
+
* Execute the source addition command
|
|
64
|
+
*/
|
|
65
|
+
private executeAddSource;
|
|
66
|
+
/**
|
|
67
|
+
* Use Claude to interpret a natural language prompt and add source
|
|
68
|
+
*/
|
|
69
|
+
private executeAddSourceWithAI;
|
|
70
|
+
/**
|
|
71
|
+
* Call Claude Code CLI to analyze mission and return steps and decisions
|
|
72
|
+
*/
|
|
73
|
+
private callClaudeForAnalysis;
|
|
74
|
+
/**
|
|
75
|
+
* Read source file contents from context paths for Claude analysis
|
|
76
|
+
*/
|
|
77
|
+
private readSourceContext;
|
|
78
|
+
/**
|
|
79
|
+
* Get key files from a source directory for context
|
|
80
|
+
*/
|
|
81
|
+
private getKeyFilesFromDirectory;
|
|
82
|
+
/**
|
|
83
|
+
* Build the prompt for Claude Code to analyze the mission
|
|
84
|
+
*/
|
|
85
|
+
private buildAnalysisPrompt;
|
|
86
|
+
/**
|
|
87
|
+
* Parse Claude's response to extract steps and decisions
|
|
88
|
+
*/
|
|
89
|
+
private parseAnalysisResponse;
|
|
90
|
+
/**
|
|
91
|
+
* Get default steps when analysis fails
|
|
92
|
+
*/
|
|
93
|
+
private getDefaultSteps;
|
|
94
|
+
/**
|
|
95
|
+
* Update relay with current status
|
|
96
|
+
*/
|
|
97
|
+
private updateRelayStatus;
|
|
98
|
+
/**
|
|
99
|
+
* Stop workflow execution
|
|
100
|
+
*/
|
|
101
|
+
stop(): void;
|
|
102
|
+
/**
|
|
103
|
+
* Kill all project tmux sessions
|
|
104
|
+
*/
|
|
105
|
+
killAllSessions(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Send keys to an agent session
|
|
108
|
+
*/
|
|
109
|
+
sendToAgent(agentId: string, keys: string): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Capture agent terminal output
|
|
112
|
+
*/
|
|
113
|
+
captureAgent(agentId: string): string | null;
|
|
114
|
+
/**
|
|
115
|
+
* List all agent sessions for this project
|
|
116
|
+
*/
|
|
117
|
+
listSessions(): string[];
|
|
118
|
+
}
|