sessioncast-cli 1.0.0 → 1.1.1
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/README.md +65 -40
- package/dist/agent/session-handler.d.ts +1 -0
- package/dist/agent/session-handler.js +42 -0
- package/dist/agent/tmux-executor.d.ts +66 -0
- package/dist/agent/tmux-executor.js +368 -0
- package/dist/agent/tmux.d.ts +9 -1
- package/dist/agent/tmux.js +52 -76
- package/dist/agent/websocket.d.ts +2 -8
- package/dist/agent/websocket.js +78 -14
- package/dist/autopilot/index.d.ts +94 -0
- package/dist/autopilot/index.js +322 -0
- package/dist/autopilot/mission-analyzer.d.ts +27 -0
- package/dist/autopilot/mission-analyzer.js +232 -0
- package/dist/autopilot/project-detector.d.ts +12 -0
- package/dist/autopilot/project-detector.js +326 -0
- package/dist/autopilot/source-scanner.d.ts +26 -0
- package/dist/autopilot/source-scanner.js +285 -0
- package/dist/autopilot/speckit-generator.d.ts +60 -0
- package/dist/autopilot/speckit-generator.js +511 -0
- package/dist/autopilot/types.d.ts +110 -0
- package/dist/autopilot/types.js +6 -0
- package/dist/autopilot/workflow-generator.d.ts +33 -0
- package/dist/autopilot/workflow-generator.js +278 -0
- package/dist/commands/autopilot.d.ts +30 -0
- package/dist/commands/autopilot.js +262 -0
- package/dist/commands/login.d.ts +2 -1
- package/dist/commands/login.js +199 -8
- package/dist/commands/project.d.ts +1 -1
- package/dist/commands/project.js +4 -13
- package/dist/config.d.ts +20 -0
- package/dist/config.js +69 -2
- package/dist/index.js +7 -47
- package/dist/project/executor.d.ts +8 -53
- package/dist/project/executor.js +64 -520
- package/dist/project/manager.d.ts +0 -13
- package/dist/project/manager.js +0 -107
- package/dist/project/relay-client.d.ts +18 -68
- package/dist/project/relay-client.js +134 -130
- package/dist/project/types.d.ts +5 -0
- package/dist/utils/fileUtils.d.ts +28 -0
- package/dist/utils/fileUtils.js +159 -0
- package/dist/utils/oauthServer.d.ts +18 -0
- package/dist/utils/oauthServer.js +244 -0
- package/dist/utils/pkce.d.ts +16 -0
- package/dist/utils/pkce.js +73 -0
- package/package.json +7 -14
- package/scripts/postinstall.js +75 -0
- package/LICENSE +0 -21
package/dist/commands/login.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -7,35 +40,193 @@ exports.login = login;
|
|
|
7
40
|
exports.logout = logout;
|
|
8
41
|
exports.status = status;
|
|
9
42
|
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const ora_1 = __importDefault(require("ora"));
|
|
44
|
+
const open_1 = __importDefault(require("open"));
|
|
45
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
10
46
|
const config_1 = require("../config");
|
|
11
|
-
|
|
47
|
+
const pkce_1 = require("../utils/pkce");
|
|
48
|
+
const oauthServer_1 = require("../utils/oauthServer");
|
|
49
|
+
const os = __importStar(require("os"));
|
|
50
|
+
const CLIENT_ID = 'sessioncast-cli';
|
|
51
|
+
const DEFAULT_SCOPES = 'openid profile email';
|
|
52
|
+
async function login(apiKey, options = {}) {
|
|
53
|
+
// If API key provided, use manual login
|
|
54
|
+
if (apiKey) {
|
|
55
|
+
return manualLogin(apiKey, options);
|
|
56
|
+
}
|
|
57
|
+
// Otherwise, use browser-based OAuth login
|
|
58
|
+
return browserLogin(options);
|
|
59
|
+
}
|
|
60
|
+
async function manualLogin(apiKey, options) {
|
|
12
61
|
if (options.url) {
|
|
13
62
|
(0, config_1.setApiUrl)(options.url);
|
|
14
63
|
console.log(chalk_1.default.gray(`API URL set to: ${options.url}`));
|
|
15
64
|
}
|
|
16
65
|
// Validate API key format
|
|
17
|
-
if (!apiKey.startsWith('sk-')) {
|
|
18
|
-
console.log(chalk_1.default.red('Invalid
|
|
66
|
+
if (!apiKey.startsWith('sk-') && !apiKey.startsWith('agt_')) {
|
|
67
|
+
console.log(chalk_1.default.red('Invalid key format. Key should start with "sk-" or "agt_"'));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
if (apiKey.startsWith('agt_')) {
|
|
71
|
+
(0, config_1.setAgentToken)(apiKey);
|
|
72
|
+
console.log(chalk_1.default.green('✓ Agent token saved!'));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
(0, config_1.setApiKey)(apiKey);
|
|
76
|
+
console.log(chalk_1.default.green('✓ API key saved!'));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function browserLogin(options = {}) {
|
|
80
|
+
console.log(chalk_1.default.bold('\n SessionCast Login\n'));
|
|
81
|
+
// Set custom URLs if provided
|
|
82
|
+
if (options.url) {
|
|
83
|
+
(0, config_1.setApiUrl)(options.url);
|
|
84
|
+
}
|
|
85
|
+
if (options.auth) {
|
|
86
|
+
(0, config_1.setAuthUrl)(options.auth);
|
|
87
|
+
}
|
|
88
|
+
const authUrl = (0, config_1.getAuthUrl)();
|
|
89
|
+
const apiUrl = (0, config_1.getApiUrl)();
|
|
90
|
+
// Find available port for callback
|
|
91
|
+
const spinner = (0, ora_1.default)('Preparing login...').start();
|
|
92
|
+
let port;
|
|
93
|
+
try {
|
|
94
|
+
port = await (0, oauthServer_1.findAvailablePort)(9876);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
spinner.fail('Could not find an available port');
|
|
98
|
+
console.log(chalk_1.default.yellow('\nFallback: Manual token entry'));
|
|
99
|
+
console.log(chalk_1.default.gray(`Visit ${authUrl} and copy your token`));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
104
|
+
// Generate PKCE values
|
|
105
|
+
const codeVerifier = (0, pkce_1.generateCodeVerifier)();
|
|
106
|
+
const codeChallenge = (0, pkce_1.generateCodeChallenge)(codeVerifier);
|
|
107
|
+
const state = (0, pkce_1.generateState)();
|
|
108
|
+
// Build authorization URL
|
|
109
|
+
const authorizationUrl = new URL(`${authUrl}/oauth/authorize`);
|
|
110
|
+
authorizationUrl.searchParams.set('client_id', CLIENT_ID);
|
|
111
|
+
authorizationUrl.searchParams.set('redirect_uri', redirectUri);
|
|
112
|
+
authorizationUrl.searchParams.set('response_type', 'code');
|
|
113
|
+
authorizationUrl.searchParams.set('scope', DEFAULT_SCOPES);
|
|
114
|
+
authorizationUrl.searchParams.set('state', state);
|
|
115
|
+
authorizationUrl.searchParams.set('code_challenge', codeChallenge);
|
|
116
|
+
authorizationUrl.searchParams.set('code_challenge_method', 'S256');
|
|
117
|
+
spinner.text = 'Opening browser...';
|
|
118
|
+
// Start callback server and open browser
|
|
119
|
+
const serverPromise = (0, oauthServer_1.startCallbackServer)(port, 300000); // 5 minute timeout
|
|
120
|
+
try {
|
|
121
|
+
await (0, open_1.default)(authorizationUrl.toString());
|
|
122
|
+
spinner.text = 'Waiting for authentication...';
|
|
123
|
+
console.log(chalk_1.default.gray(`\n If browser didn't open, visit:\n ${authorizationUrl.toString()}\n`));
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
spinner.warn('Could not open browser automatically');
|
|
127
|
+
console.log(chalk_1.default.yellow(`\nPlease open this URL in your browser:\n${authorizationUrl.toString()}\n`));
|
|
128
|
+
}
|
|
129
|
+
// Wait for callback
|
|
130
|
+
let result;
|
|
131
|
+
try {
|
|
132
|
+
result = await serverPromise;
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
spinner.fail(err.message || 'Login failed');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Check for errors
|
|
140
|
+
if (result.error) {
|
|
141
|
+
spinner.fail(`Authentication failed: ${result.errorDescription || result.error}`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Verify state
|
|
146
|
+
if (result.state !== state) {
|
|
147
|
+
spinner.fail('Security error: State mismatch');
|
|
148
|
+
process.exit(1);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (!result.code) {
|
|
152
|
+
spinner.fail('No authorization code received');
|
|
153
|
+
process.exit(1);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Exchange code for token
|
|
157
|
+
spinner.text = 'Exchanging code for token...';
|
|
158
|
+
try {
|
|
159
|
+
const tokenResponse = await (0, node_fetch_1.default)(`${authUrl}/oauth/token`, {
|
|
160
|
+
method: 'POST',
|
|
161
|
+
headers: {
|
|
162
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
163
|
+
},
|
|
164
|
+
body: new URLSearchParams({
|
|
165
|
+
grant_type: 'authorization_code',
|
|
166
|
+
client_id: CLIENT_ID,
|
|
167
|
+
code: result.code,
|
|
168
|
+
redirect_uri: redirectUri,
|
|
169
|
+
code_verifier: codeVerifier,
|
|
170
|
+
}).toString(),
|
|
171
|
+
});
|
|
172
|
+
if (!tokenResponse.ok) {
|
|
173
|
+
const errorText = await tokenResponse.text();
|
|
174
|
+
throw new Error(`Token exchange failed: ${errorText}`);
|
|
175
|
+
}
|
|
176
|
+
const tokenData = await tokenResponse.json();
|
|
177
|
+
// Save tokens
|
|
178
|
+
(0, config_1.setAccessToken)(tokenData.access_token, tokenData.expires_in);
|
|
179
|
+
if (tokenData.refresh_token) {
|
|
180
|
+
(0, config_1.setRefreshToken)(tokenData.refresh_token);
|
|
181
|
+
}
|
|
182
|
+
spinner.text = 'Generating agent token...';
|
|
183
|
+
// Generate agent token
|
|
184
|
+
const agentTokenResponse = await (0, node_fetch_1.default)(`${apiUrl}/api/tokens/generate`, {
|
|
185
|
+
method: 'POST',
|
|
186
|
+
headers: {
|
|
187
|
+
'Authorization': `Bearer ${tokenData.access_token}`,
|
|
188
|
+
'Content-Type': 'application/json',
|
|
189
|
+
},
|
|
190
|
+
body: JSON.stringify({
|
|
191
|
+
machineId: os.hostname(),
|
|
192
|
+
}),
|
|
193
|
+
});
|
|
194
|
+
if (agentTokenResponse.ok) {
|
|
195
|
+
const agentData = await agentTokenResponse.json();
|
|
196
|
+
(0, config_1.setAgentToken)(agentData.token);
|
|
197
|
+
(0, config_1.setMachineId)(agentData.machineId || os.hostname());
|
|
198
|
+
}
|
|
199
|
+
spinner.succeed('Login successful!');
|
|
200
|
+
console.log(chalk_1.default.green('\n✓ You are now logged in to SessionCast\n'));
|
|
201
|
+
console.log(chalk_1.default.gray(' Run `sessioncast agent` to start the agent'));
|
|
202
|
+
console.log(chalk_1.default.gray(' Run `sessioncast status` to check your login status\n'));
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
spinner.fail(`Login failed: ${err.message}`);
|
|
19
206
|
process.exit(1);
|
|
20
207
|
}
|
|
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
208
|
}
|
|
25
209
|
async function logout() {
|
|
26
210
|
if (!(0, config_1.isLoggedIn)()) {
|
|
27
211
|
console.log(chalk_1.default.yellow('Not logged in.'));
|
|
28
212
|
return;
|
|
29
213
|
}
|
|
30
|
-
(0, config_1.
|
|
214
|
+
(0, config_1.clearAuth)();
|
|
31
215
|
console.log(chalk_1.default.green('✓ Logged out successfully!'));
|
|
32
216
|
}
|
|
33
217
|
function status() {
|
|
218
|
+
const accessToken = (0, config_1.getAccessToken)();
|
|
34
219
|
if ((0, config_1.isLoggedIn)()) {
|
|
35
220
|
console.log(chalk_1.default.green('✓ Logged in'));
|
|
221
|
+
if (accessToken) {
|
|
222
|
+
console.log(chalk_1.default.gray(' Auth method: OAuth'));
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
console.log(chalk_1.default.gray(' Auth method: API Key / Agent Token'));
|
|
226
|
+
}
|
|
36
227
|
}
|
|
37
228
|
else {
|
|
38
229
|
console.log(chalk_1.default.yellow('Not logged in'));
|
|
39
|
-
console.log(chalk_1.default.gray('Run: sessioncast login
|
|
230
|
+
console.log(chalk_1.default.gray('Run: sessioncast login'));
|
|
40
231
|
}
|
|
41
232
|
}
|
|
@@ -10,7 +10,7 @@ export declare function projectInit(projectPath: string, options: {
|
|
|
10
10
|
export declare function projectRun(projectPath: string, options: {
|
|
11
11
|
watch?: boolean;
|
|
12
12
|
noClaude?: boolean;
|
|
13
|
-
|
|
13
|
+
relay?: string;
|
|
14
14
|
relayToken?: string;
|
|
15
15
|
}): Promise<void>;
|
|
16
16
|
/**
|
package/dist/commands/project.js
CHANGED
|
@@ -91,28 +91,19 @@ async function projectRun(projectPath, options) {
|
|
|
91
91
|
console.error(chalk_1.default.red('Error: No workflow.yml found. Define your workflow first.'));
|
|
92
92
|
process.exit(1);
|
|
93
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
94
|
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
104
95
|
console.log(` Workflow: ${chalk_1.default.bold(workflow.name)}`);
|
|
105
96
|
console.log(` Mission: ${workflow.mission}`);
|
|
106
97
|
console.log(` Agents: ${workflow.agents.map(a => a.id).join(', ')}`);
|
|
107
98
|
console.log(` Auto-launch Claude: ${options.noClaude ? 'No' : 'Yes'}`);
|
|
108
|
-
if (options.
|
|
109
|
-
console.log(` Relay: ${options.
|
|
99
|
+
if (options.relay) {
|
|
100
|
+
console.log(` Relay: ${options.relay}`);
|
|
110
101
|
}
|
|
111
102
|
console.log(chalk_1.default.gray('─'.repeat(50)));
|
|
112
103
|
const executor = new project_1.WorkflowExecutor(manager, {
|
|
113
104
|
autoLaunchClaude: !options.noClaude,
|
|
114
|
-
relayUrl: options.
|
|
115
|
-
relayToken: relayToken
|
|
105
|
+
relayUrl: options.relay,
|
|
106
|
+
relayToken: options.relayToken
|
|
116
107
|
});
|
|
117
108
|
executor.on('agent-started', ({ agentId, sessionName }) => {
|
|
118
109
|
console.log(chalk_1.default.cyan(`[${agentId}] Started - tmux session: ${sessionName}`));
|
package/dist/config.d.ts
CHANGED
|
@@ -2,6 +2,13 @@ import Conf from 'conf';
|
|
|
2
2
|
interface ConfigSchema {
|
|
3
3
|
apiKey?: string;
|
|
4
4
|
apiUrl: string;
|
|
5
|
+
authUrl: string;
|
|
6
|
+
relayUrl: string;
|
|
7
|
+
accessToken?: string;
|
|
8
|
+
refreshToken?: string;
|
|
9
|
+
tokenExpiresAt?: number;
|
|
10
|
+
agentToken?: string;
|
|
11
|
+
machineId?: string;
|
|
5
12
|
}
|
|
6
13
|
declare const config: Conf<ConfigSchema>;
|
|
7
14
|
export declare function getApiKey(): string | undefined;
|
|
@@ -9,5 +16,18 @@ export declare function setApiKey(key: string): void;
|
|
|
9
16
|
export declare function clearApiKey(): void;
|
|
10
17
|
export declare function getApiUrl(): string;
|
|
11
18
|
export declare function setApiUrl(url: string): void;
|
|
19
|
+
export declare function getAuthUrl(): string;
|
|
20
|
+
export declare function setAuthUrl(url: string): void;
|
|
21
|
+
export declare function getRelayUrl(): string;
|
|
22
|
+
export declare function setRelayUrl(url: string): void;
|
|
23
|
+
export declare function getAccessToken(): string | undefined;
|
|
24
|
+
export declare function setAccessToken(token: string, expiresIn: number): void;
|
|
25
|
+
export declare function getRefreshToken(): string | undefined;
|
|
26
|
+
export declare function setRefreshToken(token: string): void;
|
|
27
|
+
export declare function getAgentToken(): string | undefined;
|
|
28
|
+
export declare function setAgentToken(token: string): void;
|
|
29
|
+
export declare function getMachineId(): string | undefined;
|
|
30
|
+
export declare function setMachineId(id: string): void;
|
|
31
|
+
export declare function clearAuth(): void;
|
|
12
32
|
export declare function isLoggedIn(): boolean;
|
|
13
33
|
export default config;
|
package/dist/config.js
CHANGED
|
@@ -8,12 +8,27 @@ exports.setApiKey = setApiKey;
|
|
|
8
8
|
exports.clearApiKey = clearApiKey;
|
|
9
9
|
exports.getApiUrl = getApiUrl;
|
|
10
10
|
exports.setApiUrl = setApiUrl;
|
|
11
|
+
exports.getAuthUrl = getAuthUrl;
|
|
12
|
+
exports.setAuthUrl = setAuthUrl;
|
|
13
|
+
exports.getRelayUrl = getRelayUrl;
|
|
14
|
+
exports.setRelayUrl = setRelayUrl;
|
|
15
|
+
exports.getAccessToken = getAccessToken;
|
|
16
|
+
exports.setAccessToken = setAccessToken;
|
|
17
|
+
exports.getRefreshToken = getRefreshToken;
|
|
18
|
+
exports.setRefreshToken = setRefreshToken;
|
|
19
|
+
exports.getAgentToken = getAgentToken;
|
|
20
|
+
exports.setAgentToken = setAgentToken;
|
|
21
|
+
exports.getMachineId = getMachineId;
|
|
22
|
+
exports.setMachineId = setMachineId;
|
|
23
|
+
exports.clearAuth = clearAuth;
|
|
11
24
|
exports.isLoggedIn = isLoggedIn;
|
|
12
25
|
const conf_1 = __importDefault(require("conf"));
|
|
13
26
|
const config = new conf_1.default({
|
|
14
27
|
projectName: 'sessioncast',
|
|
15
28
|
defaults: {
|
|
16
|
-
apiUrl: 'https://api.sessioncast.io'
|
|
29
|
+
apiUrl: 'https://api.sessioncast.io',
|
|
30
|
+
authUrl: 'https://auth.sessioncast.io',
|
|
31
|
+
relayUrl: 'wss://relay.sessioncast.io/ws',
|
|
17
32
|
}
|
|
18
33
|
});
|
|
19
34
|
function getApiKey() {
|
|
@@ -31,7 +46,59 @@ function getApiUrl() {
|
|
|
31
46
|
function setApiUrl(url) {
|
|
32
47
|
config.set('apiUrl', url);
|
|
33
48
|
}
|
|
49
|
+
function getAuthUrl() {
|
|
50
|
+
return config.get('authUrl');
|
|
51
|
+
}
|
|
52
|
+
function setAuthUrl(url) {
|
|
53
|
+
config.set('authUrl', url);
|
|
54
|
+
}
|
|
55
|
+
function getRelayUrl() {
|
|
56
|
+
return config.get('relayUrl');
|
|
57
|
+
}
|
|
58
|
+
function setRelayUrl(url) {
|
|
59
|
+
config.set('relayUrl', url);
|
|
60
|
+
}
|
|
61
|
+
// OAuth token management
|
|
62
|
+
function getAccessToken() {
|
|
63
|
+
const token = config.get('accessToken');
|
|
64
|
+
const expiresAt = config.get('tokenExpiresAt');
|
|
65
|
+
// Check if token is expired
|
|
66
|
+
if (token && expiresAt && Date.now() > expiresAt) {
|
|
67
|
+
return undefined; // Token expired
|
|
68
|
+
}
|
|
69
|
+
return token;
|
|
70
|
+
}
|
|
71
|
+
function setAccessToken(token, expiresIn) {
|
|
72
|
+
config.set('accessToken', token);
|
|
73
|
+
config.set('tokenExpiresAt', Date.now() + (expiresIn * 1000));
|
|
74
|
+
}
|
|
75
|
+
function getRefreshToken() {
|
|
76
|
+
return config.get('refreshToken');
|
|
77
|
+
}
|
|
78
|
+
function setRefreshToken(token) {
|
|
79
|
+
config.set('refreshToken', token);
|
|
80
|
+
}
|
|
81
|
+
// Agent token (for relay connection)
|
|
82
|
+
function getAgentToken() {
|
|
83
|
+
return config.get('agentToken');
|
|
84
|
+
}
|
|
85
|
+
function setAgentToken(token) {
|
|
86
|
+
config.set('agentToken', token);
|
|
87
|
+
}
|
|
88
|
+
function getMachineId() {
|
|
89
|
+
return config.get('machineId');
|
|
90
|
+
}
|
|
91
|
+
function setMachineId(id) {
|
|
92
|
+
config.set('machineId', id);
|
|
93
|
+
}
|
|
94
|
+
function clearAuth() {
|
|
95
|
+
config.delete('apiKey');
|
|
96
|
+
config.delete('accessToken');
|
|
97
|
+
config.delete('refreshToken');
|
|
98
|
+
config.delete('tokenExpiresAt');
|
|
99
|
+
config.delete('agentToken');
|
|
100
|
+
}
|
|
34
101
|
function isLoggedIn() {
|
|
35
|
-
return !!getApiKey();
|
|
102
|
+
return !!(getApiKey() || getAccessToken() || getAgentToken());
|
|
36
103
|
}
|
|
37
104
|
exports.default = config;
|
package/dist/index.js
CHANGED
|
@@ -11,17 +11,17 @@ const agents_1 = require("./commands/agents");
|
|
|
11
11
|
const sessions_1 = require("./commands/sessions");
|
|
12
12
|
const sendkeys_1 = require("./commands/sendkeys");
|
|
13
13
|
const agent_1 = require("./commands/agent");
|
|
14
|
-
const project_1 = require("./commands/project");
|
|
15
14
|
const program = new commander_1.Command();
|
|
16
15
|
program
|
|
17
16
|
.name('sessioncast')
|
|
18
17
|
.description('SessionCast CLI - Control your agents from anywhere')
|
|
19
|
-
.version('1.0
|
|
18
|
+
.version('0.1.0');
|
|
20
19
|
// Login command
|
|
21
20
|
program
|
|
22
|
-
.command('login
|
|
23
|
-
.description('Login
|
|
21
|
+
.command('login [api-key]')
|
|
22
|
+
.description('Login to SessionCast (opens browser if no API key provided)')
|
|
24
23
|
.option('-u, --url <url>', 'Custom API URL')
|
|
24
|
+
.option('-a, --auth <url>', 'Custom Auth URL')
|
|
25
25
|
.action(login_1.login);
|
|
26
26
|
// Logout command
|
|
27
27
|
program
|
|
@@ -57,60 +57,20 @@ program
|
|
|
57
57
|
.description('Start the SessionCast agent')
|
|
58
58
|
.option('-c, --config <path>', 'Path to config file')
|
|
59
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
60
|
// Help examples
|
|
95
61
|
program.on('--help', () => {
|
|
96
62
|
console.log('');
|
|
97
63
|
console.log('Examples:');
|
|
98
|
-
console.log(' $ sessioncast login
|
|
64
|
+
console.log(' $ sessioncast login # Browser-based login (recommended)');
|
|
65
|
+
console.log(' $ sessioncast login agt_xxx # Login with agent token');
|
|
99
66
|
console.log(' $ sessioncast agents');
|
|
100
67
|
console.log(' $ sessioncast list');
|
|
101
68
|
console.log(' $ sessioncast list macbook');
|
|
102
69
|
console.log(' $ sessioncast send macbook:dev "ls -la"');
|
|
103
70
|
console.log(' $ sessioncast send server:main:0 "npm run build"');
|
|
104
|
-
console.log(' $ sessioncast agent # Start agent
|
|
71
|
+
console.log(' $ sessioncast agent # Start agent');
|
|
105
72
|
console.log(' $ sessioncast agent -c ~/.sessioncast.yml # Start with custom config');
|
|
106
73
|
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
74
|
console.log('Target format:');
|
|
115
75
|
console.log(' <agent>:<session> - Send to session');
|
|
116
76
|
console.log(' <agent>:<session>:<window> - Send to specific window');
|
|
@@ -5,7 +5,6 @@ export interface ExecutorOptions {
|
|
|
5
5
|
claudeCommand?: string;
|
|
6
6
|
relayUrl?: string;
|
|
7
7
|
relayToken?: string;
|
|
8
|
-
machineId?: string;
|
|
9
8
|
}
|
|
10
9
|
export declare class WorkflowExecutor extends EventEmitter {
|
|
11
10
|
private manager;
|
|
@@ -19,6 +18,14 @@ export declare class WorkflowExecutor extends EventEmitter {
|
|
|
19
18
|
* Start workflow execution
|
|
20
19
|
*/
|
|
21
20
|
start(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Connect to relay server and register project
|
|
23
|
+
*/
|
|
24
|
+
private connectToRelay;
|
|
25
|
+
/**
|
|
26
|
+
* Update relay with current agents list
|
|
27
|
+
*/
|
|
28
|
+
private updateRelayAgents;
|
|
22
29
|
/**
|
|
23
30
|
* Start PM Agent tmux session
|
|
24
31
|
*/
|
|
@@ -43,58 +50,6 @@ export declare class WorkflowExecutor extends EventEmitter {
|
|
|
43
50
|
* Main execution loop
|
|
44
51
|
*/
|
|
45
52
|
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
53
|
/**
|
|
99
54
|
* Stop workflow execution
|
|
100
55
|
*/
|