@clsh/agent 0.0.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/dist/auth.d.ts +37 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +62 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +119 -0
- package/dist/config.js.map +1 -0
- package/dist/control-mode-parser.d.ts +68 -0
- package/dist/control-mode-parser.d.ts.map +1 -0
- package/dist/control-mode-parser.js +111 -0
- package/dist/control-mode-parser.js.map +1 -0
- package/dist/db.d.ts +44 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +63 -0
- package/dist/db.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/dist/power.d.ts +9 -0
- package/dist/power.d.ts.map +1 -0
- package/dist/power.js +29 -0
- package/dist/power.js.map +1 -0
- package/dist/pty-manager.d.ts +110 -0
- package/dist/pty-manager.d.ts.map +1 -0
- package/dist/pty-manager.js +468 -0
- package/dist/pty-manager.js.map +1 -0
- package/dist/server.d.ts +24 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +160 -0
- package/dist/server.js.map +1 -0
- package/dist/sse-handler.d.ts +13 -0
- package/dist/sse-handler.d.ts.map +1 -0
- package/dist/sse-handler.js +76 -0
- package/dist/sse-handler.js.map +1 -0
- package/dist/tmux.d.ts +34 -0
- package/dist/tmux.d.ts.map +1 -0
- package/dist/tmux.js +114 -0
- package/dist/tmux.js.map +1 -0
- package/dist/tunnel.d.ts +43 -0
- package/dist/tunnel.d.ts.map +1 -0
- package/dist/tunnel.js +294 -0
- package/dist/tunnel.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ws-handler.d.ts +13 -0
- package/dist/ws-handler.d.ts.map +1 -0
- package/dist/ws-handler.js +266 -0
- package/dist/ws-handler.js.map +1 -0
- package/package.json +47 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// @clsh/agent -- entry point
|
|
2
|
+
// Starts the local server, PTY sessions, tunnel, and prints QR code
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { loadConfig } from './config.js';
|
|
6
|
+
import { initDatabase } from './db.js';
|
|
7
|
+
import { generateBootstrapToken, hashToken } from './auth.js';
|
|
8
|
+
import { createAppServer, startServer } from './server.js';
|
|
9
|
+
import { setupWebSocketHandler } from './ws-handler.js';
|
|
10
|
+
import { PTYManager } from './pty-manager.js';
|
|
11
|
+
import { createTunnel, printAccessInfo, startTunnelMonitor, registerShutdownHandlers } from './tunnel.js';
|
|
12
|
+
import { isTmuxAvailable, ensureTmuxConfig } from './tmux.js';
|
|
13
|
+
import { checkNetworkPersistence } from './power.js';
|
|
14
|
+
/**
|
|
15
|
+
* Prevents macOS from sleeping while the agent is running.
|
|
16
|
+
* Flags: -d (display), -i (idle), -s (system/lid-close on AC power).
|
|
17
|
+
* The caffeinate process is killed automatically when the agent exits (-w).
|
|
18
|
+
*/
|
|
19
|
+
function preventSleep() {
|
|
20
|
+
if (process.platform !== 'darwin')
|
|
21
|
+
return null;
|
|
22
|
+
try {
|
|
23
|
+
const child = spawn('caffeinate', ['-dis', '-w', String(process.pid)], {
|
|
24
|
+
stdio: 'ignore',
|
|
25
|
+
detached: false,
|
|
26
|
+
});
|
|
27
|
+
child.unref();
|
|
28
|
+
console.log(' Sleep prevention active (caffeinate)');
|
|
29
|
+
return () => child.kill();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
console.log(' Warning: could not start caffeinate — machine may sleep');
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function main() {
|
|
37
|
+
// 0a. Check if macOS is configured for lid-close networking
|
|
38
|
+
checkNetworkPersistence();
|
|
39
|
+
// 0b. Prevent macOS from sleeping while the agent is running
|
|
40
|
+
const stopCaffeinate = preventSleep();
|
|
41
|
+
// 1. Load configuration
|
|
42
|
+
const config = loadConfig();
|
|
43
|
+
// 2. Initialize database
|
|
44
|
+
const { db, statements } = initDatabase(config.dbPath);
|
|
45
|
+
// 3. Generate bootstrap token and store its hash
|
|
46
|
+
const bootstrapToken = generateBootstrapToken();
|
|
47
|
+
const tokenId = randomUUID();
|
|
48
|
+
const tokenHash = hashToken(bootstrapToken);
|
|
49
|
+
statements.insertBootstrapToken.run(tokenId, tokenHash);
|
|
50
|
+
// 4. tmux session persistence (control mode -CC for scrollback support)
|
|
51
|
+
// Falls back to raw PTY if tmux is not installed or CLSH_NO_TMUX=1
|
|
52
|
+
let tmuxEnabled = false;
|
|
53
|
+
let tmuxConfPath = null;
|
|
54
|
+
if (config.tmuxDisabled) {
|
|
55
|
+
console.log(' Session persistence disabled (CLSH_NO_TMUX=1)');
|
|
56
|
+
}
|
|
57
|
+
else if (!isTmuxAvailable()) {
|
|
58
|
+
console.log(' Sessions are ephemeral (tmux not found — install tmux for session persistence)');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
tmuxConfPath = ensureTmuxConfig();
|
|
62
|
+
tmuxEnabled = true;
|
|
63
|
+
console.log(' Session persistence active (tmux control mode)');
|
|
64
|
+
}
|
|
65
|
+
// 5. Create HTTP + WebSocket server
|
|
66
|
+
const { httpServer, wss } = createAppServer(config, statements);
|
|
67
|
+
// 6. Set up PTY manager and WebSocket handler
|
|
68
|
+
const ptyManager = new PTYManager({
|
|
69
|
+
tmuxEnabled,
|
|
70
|
+
tmuxConfPath,
|
|
71
|
+
dbStatements: statements,
|
|
72
|
+
});
|
|
73
|
+
// 7. Recover sessions from previous server run (tmux sessions survive restarts)
|
|
74
|
+
if (tmuxEnabled) {
|
|
75
|
+
const recovered = ptyManager.rediscoverAll();
|
|
76
|
+
if (recovered.length > 0) {
|
|
77
|
+
console.log(` Recovered ${String(recovered.length)} session(s) from previous run`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
setupWebSocketHandler(wss, ptyManager, config.jwtSecret);
|
|
81
|
+
// 8. Start HTTP server (auto-finds open port if configured port is busy)
|
|
82
|
+
const actualPort = await startServer(httpServer, config.port);
|
|
83
|
+
if (actualPort !== config.port) {
|
|
84
|
+
console.log(` Agent running on port ${String(actualPort)} (${String(config.port)} was busy)`);
|
|
85
|
+
}
|
|
86
|
+
// 9. Create tunnel — tries ngrok → SSH (localhost.run) → local network IP
|
|
87
|
+
// If WEB_PORT was explicitly set (dev mode), tunnel to that; otherwise tunnel to the actual agent port
|
|
88
|
+
const tunnelPort = config.webPort !== config.port ? config.webPort : actualPort;
|
|
89
|
+
const tunnel = await createTunnel(tunnelPort, config.ngrokAuthtoken, config.ngrokStaticDomain, config.tunnelMethod);
|
|
90
|
+
// 10. Print clean startup info
|
|
91
|
+
printAccessInfo(tunnel.url, bootstrapToken, tunnel.method);
|
|
92
|
+
// 11. Monitor tunnel health — auto-recovers after sleep/wake or SSH death
|
|
93
|
+
const stopTunnelMonitor = startTunnelMonitor((newUrl, method) => {
|
|
94
|
+
// Tunnel was recreated with a (possibly new) URL — reprint access info
|
|
95
|
+
printAccessInfo(newUrl, bootstrapToken, method);
|
|
96
|
+
});
|
|
97
|
+
// 12. Register graceful shutdown handlers
|
|
98
|
+
registerShutdownHandlers(() => {
|
|
99
|
+
stopCaffeinate?.();
|
|
100
|
+
stopTunnelMonitor();
|
|
101
|
+
ptyManager.destroyAll(); // Kills control clients but leaves tmux sessions alive
|
|
102
|
+
db.close();
|
|
103
|
+
httpServer.close();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Auto-run when this file is the direct entry point (e.g. `tsx src/index.ts` or `node dist/index.js`).
|
|
107
|
+
// When imported by the CLI package, CLSH_CLI=1 is set so we skip auto-run.
|
|
108
|
+
if (!process.env['CLSH_CLI']) {
|
|
109
|
+
main().catch((err) => {
|
|
110
|
+
console.error('Fatal error starting clsh agent:', err);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/power.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if macOS is configured to keep network alive when the lid closes.
|
|
3
|
+
* Prints a one-time hint if not configured. Never modifies system settings.
|
|
4
|
+
*
|
|
5
|
+
* The key setting is `tcpkeepalive 1` which keeps TCP connections (like the
|
|
6
|
+
* ngrok tunnel) alive during display sleep / lid close.
|
|
7
|
+
*/
|
|
8
|
+
export declare function checkNetworkPersistence(): void;
|
|
9
|
+
//# sourceMappingURL=power.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power.d.ts","sourceRoot":"","sources":["../src/power.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAoB9C"}
|
package/dist/power.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Checks if macOS is configured to keep network alive when the lid closes.
|
|
4
|
+
* Prints a one-time hint if not configured. Never modifies system settings.
|
|
5
|
+
*
|
|
6
|
+
* The key setting is `tcpkeepalive 1` which keeps TCP connections (like the
|
|
7
|
+
* ngrok tunnel) alive during display sleep / lid close.
|
|
8
|
+
*/
|
|
9
|
+
export function checkNetworkPersistence() {
|
|
10
|
+
if (process.platform !== 'darwin')
|
|
11
|
+
return;
|
|
12
|
+
try {
|
|
13
|
+
const output = execSync('pmset -g', { encoding: 'utf-8' });
|
|
14
|
+
const tcpMatch = /tcpkeepalive\s+(\d+)/.exec(output);
|
|
15
|
+
if (tcpMatch?.[1] === '1') {
|
|
16
|
+
return; // Already configured, stay silent
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return; // Can't read pmset, skip silently
|
|
21
|
+
}
|
|
22
|
+
// ANSI colors matching the clsh startup style
|
|
23
|
+
const o = '\x1b[38;5;208m'; // orange
|
|
24
|
+
const dim = '\x1b[2m';
|
|
25
|
+
const r = '\x1b[0m';
|
|
26
|
+
console.log(`${o} Tip:${r} Wi-Fi may drop when you close the lid.`);
|
|
27
|
+
console.log(`${dim} Run once to fix:${r} sudo pmset -c tcpkeepalive 1`);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=power.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"power.js","sourceRoot":"","sources":["../src/power.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO;IAE1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YAC1B,OAAO,CAAC,kCAAkC;QAC5C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,kCAAkC;IAC5C,CAAC;IAED,8CAA8C;IAC9C,MAAM,CAAC,GAAG,gBAAgB,CAAC,CAAC,SAAS;IACrC,MAAM,GAAG,GAAG,SAAS,CAAC;IACtB,MAAM,CAAC,GAAG,SAAS,CAAC;IAEpB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,qBAAqB,CAAC,+BAA+B,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { type IPty } from 'node-pty';
|
|
2
|
+
import type { ShellType } from './types.js';
|
|
3
|
+
import type { DbStatements } from './db.js';
|
|
4
|
+
/** Session metadata passed to update listeners. */
|
|
5
|
+
export interface SessionMeta {
|
|
6
|
+
name: string;
|
|
7
|
+
cwd: string;
|
|
8
|
+
status: 'run' | 'idle';
|
|
9
|
+
}
|
|
10
|
+
export interface PTYSession {
|
|
11
|
+
id: string;
|
|
12
|
+
shell: ShellType;
|
|
13
|
+
pty: IPty;
|
|
14
|
+
buffer: string[];
|
|
15
|
+
name: string;
|
|
16
|
+
cwd: string;
|
|
17
|
+
status: 'run' | 'idle';
|
|
18
|
+
lastActivityAt: number;
|
|
19
|
+
/** tmux session name if wrapped, null if raw pty */
|
|
20
|
+
tmuxName: string | null;
|
|
21
|
+
/** Whether the user has explicitly renamed this session (suppresses OSC 7 name updates). */
|
|
22
|
+
userRenamed: boolean;
|
|
23
|
+
onData: (callback: (data: string) => void) => void;
|
|
24
|
+
onExit: (callback: (event: {
|
|
25
|
+
exitCode: number;
|
|
26
|
+
signal?: number;
|
|
27
|
+
}) => void) => void;
|
|
28
|
+
onUpdate: (callback: (meta: SessionMeta) => void) => void;
|
|
29
|
+
}
|
|
30
|
+
export interface PTYManagerOptions {
|
|
31
|
+
tmuxEnabled?: boolean;
|
|
32
|
+
tmuxConfPath?: string | null;
|
|
33
|
+
dbStatements?: DbStatements;
|
|
34
|
+
}
|
|
35
|
+
export declare class PTYManager {
|
|
36
|
+
private sessions;
|
|
37
|
+
private idleCheckInterval;
|
|
38
|
+
private updateListeners;
|
|
39
|
+
private tmuxEnabled;
|
|
40
|
+
private tmuxConfPath;
|
|
41
|
+
private db;
|
|
42
|
+
constructor(options?: PTYManagerOptions);
|
|
43
|
+
/** Checks all sessions and transitions them to idle if no recent activity. */
|
|
44
|
+
private checkIdleSessions;
|
|
45
|
+
/** Emits an update event to all update listeners for a session. */
|
|
46
|
+
private emitUpdate;
|
|
47
|
+
/** Whether a shell type should be wrapped in tmux. */
|
|
48
|
+
private shouldWrapInTmux;
|
|
49
|
+
/**
|
|
50
|
+
* Processes raw terminal data for a session: tracks CWD, updates buffer, notifies listeners.
|
|
51
|
+
* Used by both raw and control mode handlers to process actual terminal output.
|
|
52
|
+
*/
|
|
53
|
+
private processSessionOutput;
|
|
54
|
+
/** Wires up data/exit handlers for a raw PTY session (no tmux). */
|
|
55
|
+
private wireRawHandlers;
|
|
56
|
+
/**
|
|
57
|
+
* Wires up data/exit handlers for a tmux control mode session.
|
|
58
|
+
* Parses the control mode protocol and extracts raw %output data.
|
|
59
|
+
*/
|
|
60
|
+
private wireControlModeHandlers;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new PTY session with the specified shell type and dimensions.
|
|
63
|
+
* If tmux is enabled and the shell is wrappable, uses tmux control mode (-CC)
|
|
64
|
+
* for session persistence with proper scrollback support.
|
|
65
|
+
* Falls back to raw PTY if tmux is unavailable.
|
|
66
|
+
*/
|
|
67
|
+
create(shell: ShellType, cols?: number, rows?: number, name?: string): PTYSession;
|
|
68
|
+
/**
|
|
69
|
+
* Reattaches to a tmux session that survived a server restart.
|
|
70
|
+
* Uses control mode (-CC) for the attachment and bootstraps the buffer
|
|
71
|
+
* with capture-pane content so the client sees existing scrollback.
|
|
72
|
+
* Returns the restored PTYSession or null if the tmux session is gone.
|
|
73
|
+
*/
|
|
74
|
+
reattach(sessionId: string, tmuxName: string, shell: ShellType, savedName: string, savedCwd: string, cols?: number, rows?: number): PTYSession | null;
|
|
75
|
+
/**
|
|
76
|
+
* Rediscovers sessions from a previous server run.
|
|
77
|
+
* Reads the pty_sessions table, reattaches to any tmux sessions that still exist,
|
|
78
|
+
* and cleans up rows for dead sessions. Also kills zombie tmux sessions.
|
|
79
|
+
* Returns the list of successfully recovered sessions.
|
|
80
|
+
*/
|
|
81
|
+
rediscoverAll(): PTYSession[];
|
|
82
|
+
/**
|
|
83
|
+
* Writes data to the PTY stdin of the specified session.
|
|
84
|
+
* For control mode sessions, translates input to tmux send-keys -H commands.
|
|
85
|
+
*/
|
|
86
|
+
write(id: string, data: string): void;
|
|
87
|
+
/** Renames a session and marks it as user-renamed (suppresses OSC 7 name updates). */
|
|
88
|
+
rename(id: string, name: string): void;
|
|
89
|
+
/**
|
|
90
|
+
* Resizes the PTY of the specified session.
|
|
91
|
+
* For control mode sessions, sends refresh-client -C to tmux.
|
|
92
|
+
*/
|
|
93
|
+
resize(id: string, cols: number, rows: number): void;
|
|
94
|
+
/** Destroys a single session by ID, killing the underlying PTY and tmux session. */
|
|
95
|
+
destroy(id: string): void;
|
|
96
|
+
/** Retrieves a session by ID, or undefined if not found. */
|
|
97
|
+
get(id: string): PTYSession | undefined;
|
|
98
|
+
/** Returns all active sessions. */
|
|
99
|
+
list(): PTYSession[];
|
|
100
|
+
/**
|
|
101
|
+
* Graceful shutdown — kills node-pty client processes but leaves tmux sessions alive.
|
|
102
|
+
* tmux sessions and DB rows survive for rediscovery on next startup.
|
|
103
|
+
*/
|
|
104
|
+
destroyAll(): void;
|
|
105
|
+
/**
|
|
106
|
+
* Full cleanup — kills everything including tmux sessions and DB rows.
|
|
107
|
+
*/
|
|
108
|
+
destroyAllIncludingTmux(): void;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=pty-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pty-manager.d.ts","sourceRoot":"","sources":["../src/pty-manager.ts"],"names":[],"mappings":"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"}
|