sessioncast-cli 2.0.9 → 2.2.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/dist/agent/api-client.d.ts +7 -0
- package/dist/agent/api-client.js +56 -1
- package/dist/agent/debug.d.ts +3 -0
- package/dist/agent/debug.js +17 -0
- package/dist/agent/runner.js +4 -4
- package/dist/agent/session-handler.d.ts +7 -1
- package/dist/agent/session-handler.js +83 -0
- package/dist/agent/tmux.d.ts +13 -0
- package/dist/agent/tmux.js +30 -0
- package/dist/agent/types.d.ts +21 -0
- package/dist/agent/websocket.d.ts +1 -0
- package/dist/agent/websocket.js +18 -0
- package/dist/commands/agent.d.ts +1 -0
- package/dist/commands/agent.js +5 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -20,6 +20,13 @@ export declare class ApiWebSocketClient {
|
|
|
20
20
|
private handleLlmChat;
|
|
21
21
|
private handleSendKeys;
|
|
22
22
|
private handleListSessions;
|
|
23
|
+
/**
|
|
24
|
+
* Handle capability_request from relay — evaluate each requested capability
|
|
25
|
+
* against the agent's config and respond with capability_grant.
|
|
26
|
+
*
|
|
27
|
+
* Config values: true = auto-grant, false = auto-deny, 'ask' = deny + log notice
|
|
28
|
+
*/
|
|
29
|
+
private handleCapabilityRequest;
|
|
23
30
|
private sendApiResponse;
|
|
24
31
|
private send;
|
|
25
32
|
private scheduleReconnect;
|
package/dist/agent/api-client.js
CHANGED
|
@@ -138,6 +138,9 @@ class ApiWebSocketClient {
|
|
|
138
138
|
case 'list_sessions':
|
|
139
139
|
await this.handleListSessions(message);
|
|
140
140
|
break;
|
|
141
|
+
case 'capability_request':
|
|
142
|
+
this.handleCapabilityRequest(message);
|
|
143
|
+
break;
|
|
141
144
|
}
|
|
142
145
|
}
|
|
143
146
|
async handleExec(message) {
|
|
@@ -212,7 +215,18 @@ class ApiWebSocketClient {
|
|
|
212
215
|
try {
|
|
213
216
|
console.log('[API] list_sessions');
|
|
214
217
|
const sessions = tmux.listSessions();
|
|
215
|
-
|
|
218
|
+
const enriched = sessions.map(s => {
|
|
219
|
+
const cwd = tmux.getPaneCwd(s.name);
|
|
220
|
+
const git = cwd ? tmux.getGitInfo(cwd) : null;
|
|
221
|
+
return {
|
|
222
|
+
...s,
|
|
223
|
+
cwd: cwd || undefined,
|
|
224
|
+
gitBranch: git?.branch || undefined,
|
|
225
|
+
gitRemote: git?.remote || undefined,
|
|
226
|
+
gitRepo: git?.repo || undefined
|
|
227
|
+
};
|
|
228
|
+
});
|
|
229
|
+
this.sendApiResponse(meta.requestId, { sessions: enriched });
|
|
216
230
|
}
|
|
217
231
|
catch (error) {
|
|
218
232
|
this.sendApiResponse(meta.requestId, {
|
|
@@ -221,6 +235,47 @@ class ApiWebSocketClient {
|
|
|
221
235
|
});
|
|
222
236
|
}
|
|
223
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Handle capability_request from relay — evaluate each requested capability
|
|
240
|
+
* against the agent's config and respond with capability_grant.
|
|
241
|
+
*
|
|
242
|
+
* Config values: true = auto-grant, false = auto-deny, 'ask' = deny + log notice
|
|
243
|
+
*/
|
|
244
|
+
handleCapabilityRequest(message) {
|
|
245
|
+
const meta = message.meta;
|
|
246
|
+
if (!meta)
|
|
247
|
+
return;
|
|
248
|
+
const from = meta.from;
|
|
249
|
+
const requestedStr = meta.capabilities || '';
|
|
250
|
+
const requested = requestedStr.split(',').map(s => s.trim()).filter(Boolean);
|
|
251
|
+
const capConfig = this.apiConfig.capabilities || {};
|
|
252
|
+
const granted = [];
|
|
253
|
+
const denied = [];
|
|
254
|
+
for (const cap of requested) {
|
|
255
|
+
const setting = capConfig[cap];
|
|
256
|
+
if (setting === true) {
|
|
257
|
+
granted.push(cap);
|
|
258
|
+
}
|
|
259
|
+
else if (setting === 'ask') {
|
|
260
|
+
// Future: interactive prompt. For now, deny and log notice.
|
|
261
|
+
console.log(`[API] Capability '${cap}' requires user consent (configured as 'ask'). Denying by default.`);
|
|
262
|
+
denied.push(cap);
|
|
263
|
+
}
|
|
264
|
+
else if (setting === false || setting === undefined) {
|
|
265
|
+
// Explicitly denied or not configured → deny
|
|
266
|
+
denied.push(cap);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
console.log(`[API] Capability request from SDK: requested=[${requested}], granted=[${granted}], denied=[${denied}]`);
|
|
270
|
+
this.send({
|
|
271
|
+
type: 'capability_grant',
|
|
272
|
+
meta: {
|
|
273
|
+
from: from || '',
|
|
274
|
+
granted: granted.join(','),
|
|
275
|
+
denied: denied.join(',')
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
224
279
|
sendApiResponse(requestId, response) {
|
|
225
280
|
this.send({
|
|
226
281
|
type: 'api_response',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setDebug = setDebug;
|
|
4
|
+
exports.isDebug = isDebug;
|
|
5
|
+
exports.debugLog = debugLog;
|
|
6
|
+
let debugEnabled = false;
|
|
7
|
+
function setDebug(enabled) {
|
|
8
|
+
debugEnabled = enabled;
|
|
9
|
+
}
|
|
10
|
+
function isDebug() {
|
|
11
|
+
return debugEnabled;
|
|
12
|
+
}
|
|
13
|
+
function debugLog(tag, ...args) {
|
|
14
|
+
if (debugEnabled) {
|
|
15
|
+
console.log(`[DEBUG][${tag}]`, ...args);
|
|
16
|
+
}
|
|
17
|
+
}
|
package/dist/agent/runner.js
CHANGED
|
@@ -184,7 +184,7 @@ class AgentRunner {
|
|
|
184
184
|
const handler = new session_handler_1.TmuxSessionHandler({
|
|
185
185
|
config: this.config,
|
|
186
186
|
tmuxSession,
|
|
187
|
-
onCreateSession: (name) => this.createTmuxSession(name)
|
|
187
|
+
onCreateSession: (name, workingDir) => this.createTmuxSession(name, workingDir)
|
|
188
188
|
});
|
|
189
189
|
this.handlers.set(tmuxSession, handler);
|
|
190
190
|
handler.start();
|
|
@@ -199,7 +199,7 @@ class AgentRunner {
|
|
|
199
199
|
console.log(`Stopped handler for session: ${this.config.machineId}/${tmuxSession}`);
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
-
createTmuxSession(sessionName) {
|
|
202
|
+
createTmuxSession(sessionName, workingDir) {
|
|
203
203
|
// Sanitize session name
|
|
204
204
|
const sanitized = sessionName.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
205
205
|
if (!sanitized) {
|
|
@@ -210,8 +210,8 @@ class AgentRunner {
|
|
|
210
210
|
console.warn(`Session already exists: ${sanitized}`);
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
|
-
console.log(`Creating new tmux session: ${sanitized}`);
|
|
214
|
-
if (tmux.createSession(sanitized)) {
|
|
213
|
+
console.log(`Creating new tmux session: ${sanitized}${workingDir ? ` (cwd: ${workingDir})` : ''}`);
|
|
214
|
+
if (tmux.createSession(sanitized, workingDir)) {
|
|
215
215
|
console.log(`Successfully created tmux session: ${sanitized}`);
|
|
216
216
|
// Force immediate scan
|
|
217
217
|
this.scanAndUpdateSessions();
|
|
@@ -2,7 +2,7 @@ import { AgentConfig } from './types';
|
|
|
2
2
|
interface SessionHandlerOptions {
|
|
3
3
|
config: AgentConfig;
|
|
4
4
|
tmuxSession: string;
|
|
5
|
-
onCreateSession?: (name: string) => void;
|
|
5
|
+
onCreateSession?: (name: string, workingDir?: string) => void;
|
|
6
6
|
}
|
|
7
7
|
export declare class TmuxSessionHandler {
|
|
8
8
|
private config;
|
|
@@ -17,6 +17,8 @@ export declare class TmuxSessionHandler {
|
|
|
17
17
|
private captureTimer;
|
|
18
18
|
private lastPaneIds;
|
|
19
19
|
private lastPaneScreens;
|
|
20
|
+
private currentMetaJson;
|
|
21
|
+
private metaCheckTimer;
|
|
20
22
|
private pendingUploads;
|
|
21
23
|
private uploadDir;
|
|
22
24
|
constructor(options: SessionHandlerOptions);
|
|
@@ -50,6 +52,10 @@ export declare class TmuxSessionHandler {
|
|
|
50
52
|
* Get content type from file extension
|
|
51
53
|
*/
|
|
52
54
|
private getContentType;
|
|
55
|
+
private handleCreateWorktree;
|
|
56
|
+
private startMetaTracking;
|
|
57
|
+
private stopMetaTracking;
|
|
58
|
+
private checkAndSendMeta;
|
|
53
59
|
private handleKeys;
|
|
54
60
|
private startScreenCapture;
|
|
55
61
|
private stopScreenCapture;
|
|
@@ -38,7 +38,9 @@ const websocket_1 = require("./websocket");
|
|
|
38
38
|
const tmux = __importStar(require("./tmux"));
|
|
39
39
|
const fs = __importStar(require("fs"));
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
41
42
|
const sentry_1 = require("../sentry");
|
|
43
|
+
const debug_1 = require("./debug");
|
|
42
44
|
// Capture intervals
|
|
43
45
|
const CAPTURE_INTERVAL_ACTIVE_MS = 50;
|
|
44
46
|
const CAPTURE_INTERVAL_IDLE_MS = 200;
|
|
@@ -46,6 +48,7 @@ const ACTIVE_THRESHOLD_MS = 2000;
|
|
|
46
48
|
const FORCE_SEND_INTERVAL_MS = 10000;
|
|
47
49
|
const USE_COMPRESSION = true;
|
|
48
50
|
const MIN_COMPRESS_SIZE = 512;
|
|
51
|
+
const META_CHECK_INTERVAL_MS = 15000;
|
|
49
52
|
class TmuxSessionHandler {
|
|
50
53
|
constructor(options) {
|
|
51
54
|
this.wsClient = null;
|
|
@@ -57,6 +60,9 @@ class TmuxSessionHandler {
|
|
|
57
60
|
// Multi-pane tracking
|
|
58
61
|
this.lastPaneIds = '';
|
|
59
62
|
this.lastPaneScreens = new Map();
|
|
63
|
+
// Metadata tracking (cwd + git info)
|
|
64
|
+
this.currentMetaJson = '';
|
|
65
|
+
this.metaCheckTimer = null;
|
|
60
66
|
// File upload handling
|
|
61
67
|
this.pendingUploads = new Map();
|
|
62
68
|
this.uploadDir = process.cwd(); // Default to current working directory
|
|
@@ -88,6 +94,7 @@ class TmuxSessionHandler {
|
|
|
88
94
|
this.wsClient.on('connected', () => {
|
|
89
95
|
console.log(`[${this.tmuxSession}] Connected to relay`);
|
|
90
96
|
this.startScreenCapture();
|
|
97
|
+
this.startMetaTracking();
|
|
91
98
|
});
|
|
92
99
|
this.wsClient.on('disconnected', ({ code, reason }) => {
|
|
93
100
|
console.log(`[${this.tmuxSession}] Disconnected: code=${code}, reason=${reason}`);
|
|
@@ -127,6 +134,9 @@ class TmuxSessionHandler {
|
|
|
127
134
|
this.wsClient.on('uploadFile', (chunk) => {
|
|
128
135
|
this.handleUploadChunk(chunk);
|
|
129
136
|
});
|
|
137
|
+
this.wsClient.on('createWorktree', (branch) => {
|
|
138
|
+
this.handleCreateWorktree(branch);
|
|
139
|
+
});
|
|
130
140
|
this.wsClient.on('error', (error) => {
|
|
131
141
|
(0, sentry_1.captureException)(error);
|
|
132
142
|
console.error(`[${this.tmuxSession}] WebSocket error:`, error.message);
|
|
@@ -294,6 +304,78 @@ class TmuxSessionHandler {
|
|
|
294
304
|
};
|
|
295
305
|
return types[ext] || 'application/octet-stream';
|
|
296
306
|
}
|
|
307
|
+
handleCreateWorktree(branch) {
|
|
308
|
+
try {
|
|
309
|
+
const cwd = tmux.getPaneCwd(this.tmuxSession);
|
|
310
|
+
if (!cwd) {
|
|
311
|
+
console.error(`[${this.tmuxSession}] Cannot create worktree: no cwd`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
// Check if it's a git repo
|
|
315
|
+
try {
|
|
316
|
+
(0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', { cwd, stdio: 'pipe', timeout: 5000 });
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
console.error(`[${this.tmuxSession}] Cannot create worktree: not a git repo`);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
// Sanitize branch name
|
|
323
|
+
const safeBranch = branch.replace(/[^a-zA-Z0-9_\-/.]/g, '-');
|
|
324
|
+
const worktreeDir = path.join(cwd, '.worktrees', safeBranch.replace(/\//g, '-'));
|
|
325
|
+
console.log(`[${this.tmuxSession}] Creating worktree: branch=${safeBranch}, dir=${worktreeDir}`);
|
|
326
|
+
// git worktree add
|
|
327
|
+
(0, child_process_1.execSync)(`git worktree add -b "${safeBranch}" "${worktreeDir}"`, {
|
|
328
|
+
cwd, stdio: 'pipe', timeout: 10000
|
|
329
|
+
});
|
|
330
|
+
// Create new tmux session at worktree path
|
|
331
|
+
const sessionName = safeBranch.replace(/\//g, '-');
|
|
332
|
+
if (this.onCreateSession) {
|
|
333
|
+
this.onCreateSession(sessionName, worktreeDir);
|
|
334
|
+
}
|
|
335
|
+
console.log(`[${this.tmuxSession}] Worktree created: ${worktreeDir}`);
|
|
336
|
+
(0, debug_1.debugLog)(this.tmuxSession, 'Worktree created', { branch: safeBranch, dir: worktreeDir, session: sessionName });
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
console.error(`[${this.tmuxSession}] Worktree creation failed:`, error.message);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
startMetaTracking() {
|
|
343
|
+
this.checkAndSendMeta();
|
|
344
|
+
this.metaCheckTimer = setInterval(() => this.checkAndSendMeta(), META_CHECK_INTERVAL_MS);
|
|
345
|
+
}
|
|
346
|
+
stopMetaTracking() {
|
|
347
|
+
if (this.metaCheckTimer) {
|
|
348
|
+
clearInterval(this.metaCheckTimer);
|
|
349
|
+
this.metaCheckTimer = null;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
checkAndSendMeta() {
|
|
353
|
+
try {
|
|
354
|
+
const cwd = tmux.getPaneCwd(this.tmuxSession);
|
|
355
|
+
if (!cwd)
|
|
356
|
+
return;
|
|
357
|
+
const gitInfo = tmux.getGitInfo(cwd);
|
|
358
|
+
const meta = { cwd };
|
|
359
|
+
if (gitInfo?.branch)
|
|
360
|
+
meta.gitBranch = gitInfo.branch;
|
|
361
|
+
if (gitInfo?.remote)
|
|
362
|
+
meta.gitRemote = gitInfo.remote;
|
|
363
|
+
if (gitInfo?.repo)
|
|
364
|
+
meta.gitRepo = gitInfo.repo;
|
|
365
|
+
const json = JSON.stringify(meta);
|
|
366
|
+
(0, debug_1.debugLog)(this.tmuxSession, 'Meta check:', { cwd, gitInfo });
|
|
367
|
+
const changed = json !== this.currentMetaJson;
|
|
368
|
+
(0, debug_1.debugLog)(this.tmuxSession, changed ? 'Meta CHANGED, sending' : 'Meta unchanged, skip');
|
|
369
|
+
if (changed) {
|
|
370
|
+
this.currentMetaJson = json;
|
|
371
|
+
this.wsClient?.sendSessionMeta(meta);
|
|
372
|
+
console.log(`[${this.tmuxSession}] Session meta updated: ${json}`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
// Silently ignore meta check errors
|
|
377
|
+
}
|
|
378
|
+
}
|
|
297
379
|
handleKeys(keys, paneId) {
|
|
298
380
|
const target = paneId || this.tmuxSession;
|
|
299
381
|
tmux.sendKeys(target, keys, false);
|
|
@@ -405,6 +487,7 @@ class TmuxSessionHandler {
|
|
|
405
487
|
console.log(`[${this.tmuxSession}] Stopping`);
|
|
406
488
|
this.running = false;
|
|
407
489
|
this.stopScreenCapture();
|
|
490
|
+
this.stopMetaTracking();
|
|
408
491
|
if (this.wsClient) {
|
|
409
492
|
this.wsClient.destroy();
|
|
410
493
|
this.wsClient = null;
|
package/dist/agent/tmux.d.ts
CHANGED
|
@@ -56,4 +56,17 @@ export declare function listPanes(sessionName: string): PaneData[] | null;
|
|
|
56
56
|
* Capture a specific pane by its pane ID (e.g., %0, %1)
|
|
57
57
|
*/
|
|
58
58
|
export declare function capturePaneById(sessionName: string, paneId: string): string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Git info for a directory
|
|
61
|
+
*/
|
|
62
|
+
export interface GitInfo {
|
|
63
|
+
branch: string | null;
|
|
64
|
+
remote: string | null;
|
|
65
|
+
repo: string | null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Detect git info (branch, remote, repo) for a given directory.
|
|
69
|
+
* Returns null if the directory is not inside a git work tree.
|
|
70
|
+
*/
|
|
71
|
+
export declare function getGitInfo(cwd: string): GitInfo | null;
|
|
59
72
|
export type { PaneData } from './tmux-executor';
|
package/dist/agent/tmux.js
CHANGED
|
@@ -14,7 +14,10 @@ exports.getActivePane = getActivePane;
|
|
|
14
14
|
exports.getPaneCwd = getPaneCwd;
|
|
15
15
|
exports.listPanes = listPanes;
|
|
16
16
|
exports.capturePaneById = capturePaneById;
|
|
17
|
+
exports.getGitInfo = getGitInfo;
|
|
17
18
|
const tmux_executor_1 = require("./tmux-executor");
|
|
19
|
+
const child_process_1 = require("child_process");
|
|
20
|
+
const debug_1 = require("./debug");
|
|
18
21
|
// Lazy-initialized executor (created on first use)
|
|
19
22
|
let executor = null;
|
|
20
23
|
/**
|
|
@@ -171,3 +174,30 @@ function listPanes(sessionName) {
|
|
|
171
174
|
function capturePaneById(sessionName, paneId) {
|
|
172
175
|
return getExecutor().capturePaneById(sessionName, paneId);
|
|
173
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Detect git info (branch, remote, repo) for a given directory.
|
|
179
|
+
* Returns null if the directory is not inside a git work tree.
|
|
180
|
+
*/
|
|
181
|
+
function getGitInfo(cwd) {
|
|
182
|
+
try {
|
|
183
|
+
(0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', { cwd, stdio: 'pipe', timeout: 3000 });
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const run = (cmd) => {
|
|
189
|
+
try {
|
|
190
|
+
return (0, child_process_1.execSync)(cmd, { cwd, encoding: 'utf-8', stdio: 'pipe', timeout: 3000 }).trim();
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const branch = run('git rev-parse --abbrev-ref HEAD');
|
|
197
|
+
const remote = run('git config --get remote.origin.url');
|
|
198
|
+
const repo = remote
|
|
199
|
+
? remote.replace(/.*github\.com[:/]/, '').replace(/\.git$/, '')
|
|
200
|
+
: null;
|
|
201
|
+
(0, debug_1.debugLog)('git', `cwd=${cwd}, branch=${branch}, remote=${remote}, repo=${repo}`);
|
|
202
|
+
return { branch, remote, repo };
|
|
203
|
+
}
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -9,6 +9,21 @@ export interface ApiConfig {
|
|
|
9
9
|
agentId?: string;
|
|
10
10
|
exec?: ExecConfig;
|
|
11
11
|
llm?: LlmConfig;
|
|
12
|
+
capabilities?: CapabilitiesConfig;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Per-capability consent config for the CLI agent.
|
|
16
|
+
* Each capability can be:
|
|
17
|
+
* true — auto-grant when SDK requests it
|
|
18
|
+
* false — auto-deny
|
|
19
|
+
* 'ask' — deny with a log notice (future: interactive prompt)
|
|
20
|
+
*/
|
|
21
|
+
export interface CapabilitiesConfig {
|
|
22
|
+
exec?: boolean | 'ask';
|
|
23
|
+
exec_cwd?: boolean | 'ask';
|
|
24
|
+
llm_chat?: boolean | 'ask';
|
|
25
|
+
send_keys?: boolean | 'ask';
|
|
26
|
+
list_sessions?: boolean | 'ask';
|
|
12
27
|
}
|
|
13
28
|
export interface ExecConfig {
|
|
14
29
|
enabled: boolean;
|
|
@@ -37,6 +52,12 @@ export interface TmuxSession {
|
|
|
37
52
|
created?: string;
|
|
38
53
|
attached: boolean;
|
|
39
54
|
}
|
|
55
|
+
export interface SessionMetadata {
|
|
56
|
+
cwd: string | null;
|
|
57
|
+
gitBranch: string | null;
|
|
58
|
+
gitRemote: string | null;
|
|
59
|
+
gitRepo: string | null;
|
|
60
|
+
}
|
|
40
61
|
export interface ExecResult {
|
|
41
62
|
exitCode: number;
|
|
42
63
|
stdout: string;
|
|
@@ -33,6 +33,7 @@ export declare class RelayWebSocketClient extends EventEmitter {
|
|
|
33
33
|
sendScreenWithMeta(data: Buffer, meta: Record<string, string>): boolean;
|
|
34
34
|
sendScreenCompressed(data: Buffer): boolean;
|
|
35
35
|
sendScreenCompressedWithMeta(data: Buffer, meta: Record<string, string>): boolean;
|
|
36
|
+
sendSessionMeta(meta: Record<string, string>): boolean;
|
|
36
37
|
sendPaneLayout(panes: Array<{
|
|
37
38
|
id: string;
|
|
38
39
|
index: number;
|
package/dist/agent/websocket.js
CHANGED
|
@@ -40,6 +40,7 @@ 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 debug_1 = require("./debug");
|
|
43
44
|
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
44
45
|
const BASE_RECONNECT_DELAY_MS = 2000;
|
|
45
46
|
const MAX_RECONNECT_DELAY_MS = 60000;
|
|
@@ -116,6 +117,7 @@ class RelayWebSocketClient extends events_1.EventEmitter {
|
|
|
116
117
|
});
|
|
117
118
|
}
|
|
118
119
|
handleMessage(message) {
|
|
120
|
+
(0, debug_1.debugLog)('WS:IN', message.type, message.session);
|
|
119
121
|
switch (message.type) {
|
|
120
122
|
case 'keys':
|
|
121
123
|
if (message.session === this.sessionId && message.payload) {
|
|
@@ -141,6 +143,11 @@ class RelayWebSocketClient extends events_1.EventEmitter {
|
|
|
141
143
|
this.emit('killSession');
|
|
142
144
|
}
|
|
143
145
|
break;
|
|
146
|
+
case 'createWorktree':
|
|
147
|
+
if (message.session === this.sessionId && message.meta?.branch) {
|
|
148
|
+
this.emit('createWorktree', message.meta.branch);
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
144
151
|
case 'requestFileView':
|
|
145
152
|
if (message.session === this.sessionId && message.meta?.filePath) {
|
|
146
153
|
this.emit('requestFileView', message.meta.filePath);
|
|
@@ -232,6 +239,8 @@ class RelayWebSocketClient extends events_1.EventEmitter {
|
|
|
232
239
|
return false;
|
|
233
240
|
}
|
|
234
241
|
try {
|
|
242
|
+
(0, debug_1.debugLog)('WS:OUT', message.type, message.session, message.type === 'sessionMeta' ? JSON.stringify(message.meta) :
|
|
243
|
+
message.payload ? `payload=${message.payload.length}bytes` : '');
|
|
235
244
|
this.ws.send(JSON.stringify(message));
|
|
236
245
|
return true;
|
|
237
246
|
}
|
|
@@ -291,6 +300,15 @@ class RelayWebSocketClient extends events_1.EventEmitter {
|
|
|
291
300
|
return this.sendScreenWithMeta(data, meta);
|
|
292
301
|
}
|
|
293
302
|
}
|
|
303
|
+
sendSessionMeta(meta) {
|
|
304
|
+
if (!this.isConnected)
|
|
305
|
+
return false;
|
|
306
|
+
return this.send({
|
|
307
|
+
type: 'sessionMeta',
|
|
308
|
+
session: this.sessionId,
|
|
309
|
+
meta
|
|
310
|
+
});
|
|
311
|
+
}
|
|
294
312
|
sendPaneLayout(panes) {
|
|
295
313
|
if (!this.isConnected)
|
|
296
314
|
return false;
|
package/dist/commands/agent.d.ts
CHANGED
package/dist/commands/agent.js
CHANGED
|
@@ -7,8 +7,13 @@ exports.startAgent = startAgent;
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const runner_1 = require("../agent/runner");
|
|
9
9
|
const sentry_1 = require("../sentry");
|
|
10
|
+
const debug_1 = require("../agent/debug");
|
|
10
11
|
async function startAgent(options) {
|
|
11
12
|
try {
|
|
13
|
+
if (options.debug) {
|
|
14
|
+
(0, debug_1.setDebug)(true);
|
|
15
|
+
console.log(chalk_1.default.yellow('[DEBUG] Debug mode enabled'));
|
|
16
|
+
}
|
|
12
17
|
const config = runner_1.AgentRunner.loadConfig(options.config);
|
|
13
18
|
const runner = new runner_1.AgentRunner(config);
|
|
14
19
|
await runner.start();
|
package/dist/index.js
CHANGED
|
@@ -209,6 +209,7 @@ program
|
|
|
209
209
|
.command('agent')
|
|
210
210
|
.description('Start the SessionCast agent')
|
|
211
211
|
.option('-c, --config <path>', 'Path to config file')
|
|
212
|
+
.option('-d, --debug', 'Enable debug logging')
|
|
212
213
|
.action(agent_1.startAgent);
|
|
213
214
|
// Help examples
|
|
214
215
|
program.on('--help', () => {
|