clay-server 2.40.0-beta.3 → 2.40.0-beta.4
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/lib/claude-hook-installer.js +24 -76
- package/lib/cli-sessions.js +80 -45
- package/lib/project-connection.js +9 -1
- package/lib/project-sessions.js +132 -55
- package/lib/project.js +1 -0
- package/lib/public/css/filebrowser.css +2 -2
- package/lib/public/css/input.css +12 -0
- package/lib/public/css/menus.css +23 -0
- package/lib/public/css/sidebar.css +0 -85
- package/lib/public/css/tui-attention.css +41 -0
- package/lib/public/index.html +2 -1
- package/lib/public/modules/app-messages.js +4 -1
- package/lib/public/modules/input.js +43 -5
- package/lib/public/modules/session-tui-view.js +224 -10
- package/lib/public/modules/sidebar-mobile.js +2 -1
- package/lib/public/modules/sidebar-sessions.js +11 -83
- package/lib/public/modules/terminal-toolbar.js +129 -0
- package/lib/public/modules/terminal.js +15 -99
- package/lib/safe-bash-commands.js +171 -0
- package/lib/sdk-bridge.js +6 -51
- package/lib/sessions.js +1 -1
- package/lib/terminal-manager.js +44 -0
- package/lib/ws-schema.js +2 -0
- package/package.json +1 -1
package/lib/terminal-manager.js
CHANGED
|
@@ -3,6 +3,13 @@ var { createTerminal } = require("./terminal");
|
|
|
3
3
|
var MAX_TERMINALS = 10;
|
|
4
4
|
var SCROLLBACK_MAX = 50 * 1024; // 50 KB per terminal
|
|
5
5
|
|
|
6
|
+
// Idle reclaim: background `claude` TUI PTYs that nobody is viewing and that
|
|
7
|
+
// have produced no output / received no input for this long are killed to
|
|
8
|
+
// free system resources. Safe because TUI sessions resume on demand from
|
|
9
|
+
// their on-disk transcript (lazy resume), so the conversation isn't lost.
|
|
10
|
+
var TUI_IDLE_REAP_MS = 3 * 60 * 1000; // 3 minutes
|
|
11
|
+
var TUI_REAP_INTERVAL_MS = 60 * 1000; // sweep cadence
|
|
12
|
+
|
|
6
13
|
/**
|
|
7
14
|
* Create a terminal manager for a project.
|
|
8
15
|
* Manages persistent PTY sessions with scrollback buffering.
|
|
@@ -49,6 +56,7 @@ function createTerminalManager(opts) {
|
|
|
49
56
|
rows: rows || 24,
|
|
50
57
|
title: (opts && opts.title) || ("Terminal " + id),
|
|
51
58
|
kind: (opts && opts.kind) || "shell",
|
|
59
|
+
lastActivityAt: Date.now(),
|
|
52
60
|
exited: false,
|
|
53
61
|
exitCode: null,
|
|
54
62
|
subscribers: new Set(),
|
|
@@ -60,6 +68,7 @@ function createTerminalManager(opts) {
|
|
|
60
68
|
pty.onData(function (data) {
|
|
61
69
|
// Buffer scrollback with timestamps
|
|
62
70
|
var ts = Date.now();
|
|
71
|
+
session.lastActivityAt = ts; // output counts as activity (don't reap a working claude)
|
|
63
72
|
session.scrollback.push({ ts: ts, data: data });
|
|
64
73
|
session.scrollbackSize += data.length;
|
|
65
74
|
session.totalBytesWritten += data.length;
|
|
@@ -149,6 +158,7 @@ function createTerminalManager(opts) {
|
|
|
149
158
|
function write(id, data) {
|
|
150
159
|
var session = terminals.get(id);
|
|
151
160
|
if (session && session.pty) {
|
|
161
|
+
session.lastActivityAt = Date.now(); // user input counts as activity
|
|
152
162
|
session.pty.write(data);
|
|
153
163
|
}
|
|
154
164
|
}
|
|
@@ -225,7 +235,40 @@ function createTerminalManager(opts) {
|
|
|
225
235
|
};
|
|
226
236
|
}
|
|
227
237
|
|
|
238
|
+
// Periodic sweep: reclaim idle background TUI PTYs. A terminal is reaped
|
|
239
|
+
// only when it's a `tui-session`, has no live subscribers (nobody's viewing
|
|
240
|
+
// it), and has seen no input/output for TUI_IDLE_REAP_MS. The session is
|
|
241
|
+
// flagged reclaimed so its onExitHook keeps the Clay session record
|
|
242
|
+
// (lazy-resume re-spawns claude on demand) instead of deleting it.
|
|
243
|
+
function reapIdleTuiTerminals() {
|
|
244
|
+
var now = Date.now();
|
|
245
|
+
var toReap = [];
|
|
246
|
+
for (var session of terminals.values()) {
|
|
247
|
+
if (session.kind !== "tui-session" || session.exited || !session.pty) continue;
|
|
248
|
+
if (session.subscribers.size > 0) continue;
|
|
249
|
+
if (now - (session.lastActivityAt || 0) < TUI_IDLE_REAP_MS) continue;
|
|
250
|
+
toReap.push(session);
|
|
251
|
+
}
|
|
252
|
+
for (var i = 0; i < toReap.length; i++) {
|
|
253
|
+
toReap[i].reclaimed = true;
|
|
254
|
+
close(toReap[i].id); // pty.kill -> onExit -> onExitHook(session)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Flag a terminal as reclaimed (PTY closed but the owning Clay session
|
|
259
|
+
// should be kept, not deleted). Used by idle reap and by an explicit
|
|
260
|
+
// user "Close" before close() so the onExitHook can tell the difference
|
|
261
|
+
// from a real /exit.
|
|
262
|
+
function markReclaimed(id) {
|
|
263
|
+
var session = terminals.get(id);
|
|
264
|
+
if (session) session.reclaimed = true;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
var reapTimer = setInterval(reapIdleTuiTerminals, TUI_REAP_INTERVAL_MS);
|
|
268
|
+
if (reapTimer && typeof reapTimer.unref === "function") reapTimer.unref();
|
|
269
|
+
|
|
228
270
|
function destroyAll() {
|
|
271
|
+
if (reapTimer) { clearInterval(reapTimer); reapTimer = null; }
|
|
229
272
|
for (var session of terminals.values()) {
|
|
230
273
|
// Shutdown teardown: pty.kill triggers pty.onExit asynchronously, and
|
|
231
274
|
// that handler would normally invoke onExitHook (which for TUI
|
|
@@ -260,6 +303,7 @@ function createTerminalManager(opts) {
|
|
|
260
303
|
getScrollback: getScrollback,
|
|
261
304
|
destroyAll: destroyAll,
|
|
262
305
|
has: has,
|
|
306
|
+
markReclaimed: markReclaimed,
|
|
263
307
|
};
|
|
264
308
|
}
|
|
265
309
|
|
package/lib/ws-schema.js
CHANGED
|
@@ -17,6 +17,8 @@ var schema = {
|
|
|
17
17
|
// Session management
|
|
18
18
|
// -----------------------------------------------------------------------
|
|
19
19
|
"switch_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Switch the active session by local ID" },
|
|
20
|
+
"resume_tui_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Spawn the claude --resume PTY for a TUI session shown read-only (lazy resume)" },
|
|
21
|
+
"suspend_tui_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Close a live TUI session's PTY now but keep it resumable (explicit Close)" },
|
|
20
22
|
"new_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Create a new blank session" },
|
|
21
23
|
"delete_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Delete a session by ID" },
|
|
22
24
|
"rename_session": { direction: "c2s", handler: "lib/project-sessions.js", description: "Rename a session" },
|
package/package.json
CHANGED