sessioncast-cli 1.1.4 → 2.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.
Files changed (38) hide show
  1. package/README.md +67 -66
  2. package/dist/agent/runner.js +26 -23
  3. package/dist/agent/session-handler.d.ts +30 -1
  4. package/dist/agent/session-handler.js +166 -36
  5. package/dist/agent/tmux-executor.d.ts +6 -0
  6. package/dist/agent/tmux-executor.js +61 -2
  7. package/dist/agent/tmux.d.ts +8 -0
  8. package/dist/agent/tmux.js +14 -0
  9. package/dist/agent/websocket.d.ts +16 -2
  10. package/dist/agent/websocket.js +54 -70
  11. package/dist/api.js +2 -5
  12. package/dist/commands/login.js +7 -29
  13. package/dist/index.js +4 -4
  14. package/package.json +2 -2
  15. package/dist/autopilot/index.d.ts +0 -94
  16. package/dist/autopilot/index.js +0 -322
  17. package/dist/autopilot/mission-analyzer.d.ts +0 -27
  18. package/dist/autopilot/mission-analyzer.js +0 -232
  19. package/dist/autopilot/project-detector.d.ts +0 -12
  20. package/dist/autopilot/project-detector.js +0 -326
  21. package/dist/autopilot/source-scanner.d.ts +0 -26
  22. package/dist/autopilot/source-scanner.js +0 -285
  23. package/dist/autopilot/speckit-generator.d.ts +0 -60
  24. package/dist/autopilot/speckit-generator.js +0 -511
  25. package/dist/autopilot/types.d.ts +0 -110
  26. package/dist/autopilot/types.js +0 -6
  27. package/dist/autopilot/workflow-generator.d.ts +0 -33
  28. package/dist/autopilot/workflow-generator.js +0 -278
  29. package/dist/project/executor.d.ts +0 -73
  30. package/dist/project/executor.js +0 -437
  31. package/dist/project/index.d.ts +0 -4
  32. package/dist/project/index.js +0 -20
  33. package/dist/project/manager.d.ts +0 -66
  34. package/dist/project/manager.js +0 -290
  35. package/dist/project/relay-client.d.ts +0 -37
  36. package/dist/project/relay-client.js +0 -204
  37. package/dist/project/types.d.ts +0 -48
  38. package/dist/project/types.js +0 -3
@@ -9,6 +9,8 @@ exports.createSession = createSession;
9
9
  exports.killSession = killSession;
10
10
  exports.isAvailable = isAvailable;
11
11
  exports.getVersion = getVersion;
12
+ exports.getActivePane = getActivePane;
13
+ exports.getPaneCwd = getPaneCwd;
12
14
  const tmux_executor_1 = require("./tmux-executor");
13
15
  // Lazy-initialized executor (created on first use)
14
16
  let executor = null;
@@ -131,3 +133,15 @@ function getVersion() {
131
133
  return null;
132
134
  }
133
135
  }
136
+ /**
137
+ * Get the active pane ID in a session
138
+ */
139
+ function getActivePane(sessionName) {
140
+ return getExecutor().getActivePane(sessionName);
141
+ }
142
+ /**
143
+ * Get the current working directory of a pane
144
+ */
145
+ function getPaneCwd(sessionName, paneId) {
146
+ return getExecutor().getPaneCwd(sessionName, paneId);
147
+ }
@@ -26,13 +26,27 @@ export declare class RelayWebSocketClient extends EventEmitter {
26
26
  connect(): void;
27
27
  private registerAsHost;
28
28
  private handleMessage;
29
- private handleFileUpload;
30
29
  private handleError;
31
30
  private scheduleReconnect;
32
31
  send(message: Message): boolean;
33
32
  sendScreen(data: Buffer): boolean;
34
33
  sendScreenCompressed(data: Buffer): boolean;
35
- sendFileView(filePath: string, content: string, language: string, error?: string): boolean;
34
+ /**
35
+ * Send file content to be displayed in the web FileViewer
36
+ * @param filename - The name of the file
37
+ * @param content - The file content (UTF-8 for text, base64 for images)
38
+ * @param contentType - MIME type (e.g., 'text/markdown', 'text/html', 'image/png')
39
+ * @param path - Optional file path
40
+ */
41
+ sendFileView(filename: string, content: string, contentType: string, path?: string): boolean;
42
+ /**
43
+ * Send upload complete notification to web viewer
44
+ */
45
+ sendUploadComplete(filename: string, path: string): boolean;
46
+ /**
47
+ * Send upload error notification to web viewer
48
+ */
49
+ sendUploadError(filename: string, error: string): boolean;
36
50
  getConnected(): boolean;
37
51
  destroy(): void;
38
52
  }
@@ -40,7 +40,6 @@ exports.RelayWebSocketClient = void 0;
40
40
  const ws_1 = __importDefault(require("ws"));
41
41
  const events_1 = require("events");
42
42
  const zlib = __importStar(require("zlib"));
43
- const fileUtils_1 = require("../utils/fileUtils");
44
43
  const MAX_RECONNECT_ATTEMPTS = 5;
45
44
  const BASE_RECONNECT_DELAY_MS = 2000;
46
45
  const MAX_RECONNECT_DELAY_MS = 60000;
@@ -117,10 +116,6 @@ class RelayWebSocketClient extends events_1.EventEmitter {
117
116
  });
118
117
  }
119
118
  handleMessage(message) {
120
- // Debug: log all incoming message types (except frequent ones)
121
- if (message.type !== 'pong' && message.type !== 'keys') {
122
- console.log(`[WS] Message received: type=${message.type}, session=${message.session}`);
123
- }
124
119
  switch (message.type) {
125
120
  case 'keys':
126
121
  if (message.session === this.sessionId && message.payload) {
@@ -147,17 +142,20 @@ class RelayWebSocketClient extends events_1.EventEmitter {
147
142
  }
148
143
  break;
149
144
  case 'requestFileView':
150
- console.log(`[WS] requestFileView received: session=${message.session}, mySession=${this.sessionId}, filePath=${message.meta?.filePath}`);
151
145
  if (message.session === this.sessionId && message.meta?.filePath) {
152
146
  this.emit('requestFileView', message.meta.filePath);
153
147
  }
154
- else {
155
- console.log(`[WS] requestFileView ignored: sessionMatch=${message.session === this.sessionId}, hasFilePath=${!!message.meta?.filePath}`);
156
- }
157
148
  break;
158
149
  case 'uploadFile':
159
- if (message.session === this.sessionId && message.meta && message.payload) {
160
- this.handleFileUpload(message);
150
+ if (message.session === this.sessionId && message.payload && message.meta) {
151
+ this.emit('uploadFile', {
152
+ filename: message.meta.filename,
153
+ size: parseInt(message.meta.size || '0', 10),
154
+ mimeType: message.meta.mimeType,
155
+ chunkIndex: parseInt(message.meta.chunkIndex || '0', 10),
156
+ totalChunks: parseInt(message.meta.totalChunks || '1', 10),
157
+ payload: message.payload
158
+ });
161
159
  }
162
160
  break;
163
161
  case 'error':
@@ -167,55 +165,6 @@ class RelayWebSocketClient extends events_1.EventEmitter {
167
165
  this.emit('message', message);
168
166
  }
169
167
  }
170
- async handleFileUpload(message) {
171
- const meta = message.meta;
172
- if (!meta || !message.payload)
173
- return;
174
- try {
175
- const result = await (0, fileUtils_1.handleUploadChunk)(this.sessionId, {
176
- filename: meta.filename || 'unknown',
177
- size: meta.size || '0',
178
- mimeType: meta.mimeType || 'application/octet-stream',
179
- chunkIndex: meta.chunkIndex || '0',
180
- totalChunks: meta.totalChunks || '1',
181
- }, message.payload);
182
- // Only send response when upload is complete (result is not null)
183
- if (result) {
184
- if (result.success) {
185
- this.send({
186
- type: 'uploadComplete',
187
- session: this.sessionId,
188
- meta: {
189
- filename: meta.filename || 'unknown',
190
- path: result.path || '',
191
- success: 'true',
192
- },
193
- });
194
- }
195
- else {
196
- this.send({
197
- type: 'uploadError',
198
- session: this.sessionId,
199
- meta: {
200
- filename: meta.filename || 'unknown',
201
- error: result.error || 'Upload failed',
202
- },
203
- });
204
- }
205
- }
206
- }
207
- catch (e) {
208
- console.error('[WS] File upload error:', e);
209
- this.send({
210
- type: 'uploadError',
211
- session: this.sessionId,
212
- meta: {
213
- filename: meta.filename || 'unknown',
214
- error: e instanceof Error ? e.message : 'Upload failed',
215
- },
216
- });
217
- }
218
- }
219
168
  handleError(message) {
220
169
  const meta = message.meta;
221
170
  if (!meta)
@@ -316,21 +265,56 @@ class RelayWebSocketClient extends events_1.EventEmitter {
316
265
  return this.sendScreen(data);
317
266
  }
318
267
  }
319
- sendFileView(filePath, content, language, error) {
268
+ /**
269
+ * Send file content to be displayed in the web FileViewer
270
+ * @param filename - The name of the file
271
+ * @param content - The file content (UTF-8 for text, base64 for images)
272
+ * @param contentType - MIME type (e.g., 'text/markdown', 'text/html', 'image/png')
273
+ * @param path - Optional file path
274
+ */
275
+ sendFileView(filename, content, contentType, path) {
320
276
  if (!this.isConnected)
321
277
  return false;
322
- const meta = {
323
- filePath: filePath,
324
- language: language
325
- };
326
- if (error) {
327
- meta.error = error;
328
- }
329
278
  return this.send({
330
279
  type: 'file_view',
331
280
  session: this.sessionId,
332
- meta: meta,
333
- payload: Buffer.from(content).toString('base64')
281
+ meta: {
282
+ filename,
283
+ contentType,
284
+ path: path || ''
285
+ },
286
+ payload: content
287
+ });
288
+ }
289
+ /**
290
+ * Send upload complete notification to web viewer
291
+ */
292
+ sendUploadComplete(filename, path) {
293
+ if (!this.isConnected)
294
+ return false;
295
+ return this.send({
296
+ type: 'uploadComplete',
297
+ session: this.sessionId,
298
+ meta: {
299
+ filename,
300
+ path,
301
+ success: 'true'
302
+ }
303
+ });
304
+ }
305
+ /**
306
+ * Send upload error notification to web viewer
307
+ */
308
+ sendUploadError(filename, error) {
309
+ if (!this.isConnected)
310
+ return false;
311
+ return this.send({
312
+ type: 'uploadError',
313
+ session: this.sessionId,
314
+ meta: {
315
+ filename,
316
+ error
317
+ }
334
318
  });
335
319
  }
336
320
  getConnected() {
package/dist/api.js CHANGED
@@ -9,14 +9,11 @@ const config_1 = require("./config");
9
9
  class ApiClient {
10
10
  getHeaders() {
11
11
  const apiKey = (0, config_1.getApiKey)();
12
- const accessToken = (0, config_1.getAccessToken)();
13
- const agentToken = (0, config_1.getAgentToken)();
14
- const token = accessToken || apiKey || agentToken;
15
- if (!token) {
12
+ if (!apiKey) {
16
13
  throw new Error('Not logged in. Run: sessioncast login');
17
14
  }
18
15
  return {
19
- 'Authorization': `Bearer ${token}`,
16
+ 'Authorization': `Bearer ${apiKey}`,
20
17
  'Content-Type': 'application/json'
21
18
  };
22
19
  }
@@ -69,11 +69,11 @@ async function manualLogin(apiKey, options) {
69
69
  }
70
70
  if (apiKey.startsWith('agt_')) {
71
71
  (0, config_1.setAgentToken)(apiKey);
72
- console.log(chalk_1.default.green(' Agent token saved!'));
72
+ console.log(chalk_1.default.green('\u2713 Agent token saved!'));
73
73
  }
74
74
  else {
75
75
  (0, config_1.setApiKey)(apiKey);
76
- console.log(chalk_1.default.green(' API key saved!'));
76
+ console.log(chalk_1.default.green('\u2713 API key saved!'));
77
77
  }
78
78
  }
79
79
  async function browserLogin(options = {}) {
@@ -197,15 +197,9 @@ async function browserLogin(options = {}) {
197
197
  (0, config_1.setMachineId)(agentData.machineId || os.hostname());
198
198
  }
199
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(' Start the agent:'));
202
- console.log(chalk_1.default.white(' sessioncast agent\n'));
203
- console.log(chalk_1.default.gray(' Run in background:'));
204
- console.log(chalk_1.default.white(' nohup sessioncast agent > agent.log 2>&1 &\n'));
205
- console.log(chalk_1.default.gray(' Check logs:'));
206
- console.log(chalk_1.default.white(' tail -f agent.log\n'));
207
- await checkForUpdates();
208
- process.exit(0);
200
+ console.log(chalk_1.default.green('\n\u2713 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'));
209
203
  }
210
204
  catch (err) {
211
205
  spinner.fail(`Login failed: ${err.message}`);
@@ -218,12 +212,12 @@ async function logout() {
218
212
  return;
219
213
  }
220
214
  (0, config_1.clearAuth)();
221
- console.log(chalk_1.default.green(' Logged out successfully!'));
215
+ console.log(chalk_1.default.green('\u2713 Logged out successfully!'));
222
216
  }
223
217
  function status() {
224
218
  const accessToken = (0, config_1.getAccessToken)();
225
219
  if ((0, config_1.isLoggedIn)()) {
226
- console.log(chalk_1.default.green(' Logged in'));
220
+ console.log(chalk_1.default.green('\u2713 Logged in'));
227
221
  if (accessToken) {
228
222
  console.log(chalk_1.default.gray(' Auth method: OAuth'));
229
223
  }
@@ -236,19 +230,3 @@ function status() {
236
230
  console.log(chalk_1.default.gray('Run: sessioncast login'));
237
231
  }
238
232
  }
239
- const CURRENT_VERSION = '1.1.4';
240
- async function checkForUpdates() {
241
- try {
242
- const res = await (0, node_fetch_1.default)('https://registry.npmjs.org/sessioncast-cli/latest', { timeout: 3000 });
243
- if (!res.ok) return;
244
- const data = await res.json();
245
- const latest = data.version;
246
- if (latest && latest !== CURRENT_VERSION) {
247
- console.log(chalk_1.default.yellow(` ⬆ Update available: ${CURRENT_VERSION} → ${latest}`));
248
- console.log(chalk_1.default.white(` npm install -g sessioncast-cli@latest\n`));
249
- }
250
- }
251
- catch (_e) {
252
- // silently ignore - network errors shouldn't block login
253
- }
254
- }
package/dist/index.js CHANGED
@@ -85,12 +85,12 @@ function showWelcome() {
85
85
  return;
86
86
  const { available, isWindows } = checkTmux();
87
87
  console.log('');
88
- console.log(chalk_1.default.green.bold(' SessionCast CLI installed'));
88
+ console.log(chalk_1.default.green.bold('\u2713 SessionCast CLI installed'));
89
89
  console.log('');
90
90
  if (!available) {
91
- console.log(chalk_1.default.yellow(' tmux not found'));
91
+ console.log(chalk_1.default.yellow('\u26a0 tmux not found'));
92
92
  if (isWindows) {
93
- console.log(chalk_1.default.gray(' Install itmux: https://github.com/phayte/itmux'));
93
+ console.log(chalk_1.default.gray(' Install itmux: https://github.com/itefixnet/itmux'));
94
94
  console.log(chalk_1.default.gray(' Or: choco install itmux'));
95
95
  }
96
96
  else if (os.platform() === 'darwin') {
@@ -113,7 +113,7 @@ const program = new commander_1.Command();
113
113
  program
114
114
  .name('sessioncast')
115
115
  .description('SessionCast CLI - Control your agents from anywhere')
116
- .version('1.1.2');
116
+ .version(require('../package.json').version);
117
117
  // Login command
118
118
  program
119
119
  .command('login [api-key]')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sessioncast-cli",
3
- "version": "1.1.4",
3
+ "version": "2.0.0",
4
4
  "description": "SessionCast CLI - Control your agents from anywhere",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -10,7 +10,7 @@
10
10
  "build": "tsc",
11
11
  "dev": "ts-node src/index.ts",
12
12
  "start": "node dist/index.js",
13
- "prepublishOnly": "echo 'skip build'"
13
+ "prepublishOnly": "npm run build"
14
14
  },
15
15
  "keywords": [
16
16
  "sessioncast",
@@ -1,94 +0,0 @@
1
- /**
2
- * AutoPilot - Single-prompt execution layer for SessionCast
3
- *
4
- * Enables opencode-style experience: one prompt → auto-detect → auto-analyze → auto-execute
5
- */
6
- import { EventEmitter } from 'events';
7
- import { AutoPilotContext, AutoPilotOptions, GeneratedWorkflow } from './types';
8
- import { toExecutableWorkflow } from './workflow-generator';
9
- import { generateSpeckit } from './speckit-generator';
10
- export * from './types';
11
- export { generateSpeckit, generateQuickSpeckit, saveSpeckit } from './speckit-generator';
12
- export type { SpeckitOutput } from './speckit-generator';
13
- export declare class AutoPilot extends EventEmitter {
14
- private options;
15
- private context;
16
- private llmClient?;
17
- constructor(options: AutoPilotOptions);
18
- /**
19
- * Create initial context
20
- */
21
- private createInitialContext;
22
- /**
23
- * Set LLM client for mission analysis
24
- */
25
- setLlmClient(client: {
26
- chat: (messages: {
27
- role: string;
28
- content: string;
29
- }[]) => Promise<string>;
30
- }): void;
31
- /**
32
- * Get current context
33
- */
34
- getContext(): AutoPilotContext;
35
- /**
36
- * Main entry point: execute a single prompt
37
- */
38
- execute(prompt: string): Promise<GeneratedWorkflow>;
39
- /**
40
- * Quick execute without LLM analysis
41
- */
42
- quickExecute(prompt: string): Promise<GeneratedWorkflow>;
43
- /**
44
- * Phase 1: Detect project type
45
- */
46
- private detectProject;
47
- /**
48
- * Phase 2: Scan sources
49
- */
50
- private scanProject;
51
- /**
52
- * Phase 3: Analyze mission
53
- */
54
- private analyzeMission;
55
- /**
56
- * Phase 4: Generate workflow
57
- */
58
- private generateWorkflow;
59
- /**
60
- * Convert to executable workflow format (compatible with existing ProjectManager)
61
- */
62
- toExecutableFormat(): ReturnType<typeof toExecutableWorkflow> | null;
63
- /**
64
- * Convert to Speckit format (plan.md + tasks.md)
65
- */
66
- toSpeckit(): ReturnType<typeof generateSpeckit>;
67
- /**
68
- * Generate and save Speckit files
69
- */
70
- saveSpeckit(outputDir?: string): {
71
- planPath: string;
72
- tasksPath: string;
73
- };
74
- /**
75
- * Update status and emit event
76
- */
77
- private updateStatus;
78
- /**
79
- * Get a summary of the analysis for display
80
- */
81
- getSummary(): string;
82
- /**
83
- * Save workflow to file
84
- */
85
- saveWorkflow(outputPath?: string): Promise<string>;
86
- }
87
- /**
88
- * Convenience function for one-shot execution
89
- */
90
- export declare function autoPilot(prompt: string, options: AutoPilotOptions): Promise<GeneratedWorkflow>;
91
- /**
92
- * Quick version without LLM
93
- */
94
- export declare function autoPilotQuick(prompt: string, options: AutoPilotOptions): Promise<GeneratedWorkflow>;