claude-code-session-manager 0.40.1 → 0.40.2
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/index.html
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;0,6..72,700;1,6..72,400&family=Geist:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
10
|
-
<script type="module" crossorigin src="./assets/index-
|
|
10
|
+
<script type="module" crossorigin src="./assets/index-bdqOSyxG.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="./assets/monaco-editor-BW5C4Iv1.js">
|
|
12
12
|
<link rel="stylesheet" crossorigin href="./assets/monaco-editor-BTnBOi8r.css">
|
|
13
13
|
<link rel="stylesheet" crossorigin href="./assets/index-BxVBtmjA.css">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-session-manager",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.2",
|
|
4
4
|
"description": "Local cockpit for the Claude Code CLI — multi-tab terminal, full config surface, scheduler, voice dictation, and live observability.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main/index.cjs",
|
package/src/main/pty.cjs
CHANGED
|
@@ -25,6 +25,11 @@ const { sendIfAlive } = require('./lib/sendToRenderer.cjs');
|
|
|
25
25
|
// the remediation message so the user can cd there and rebuild.
|
|
26
26
|
const PKG_DIR = path.join(__dirname, '..', '..');
|
|
27
27
|
|
|
28
|
+
// Per-session replay buffer ceiling. Big enough that switching away from an
|
|
29
|
+
// Epic and back shows a meaningful working history, small enough that a dozen
|
|
30
|
+
// chatty sessions can't balloon main-process memory.
|
|
31
|
+
const REPLAY_BUFFER_MAX = 256 * 1024;
|
|
32
|
+
|
|
28
33
|
/**
|
|
29
34
|
* ANSI-formatted terminal text explaining a native-module / immediate-exit
|
|
30
35
|
* failure and exactly how to fix it. Written straight into the tab's output so
|
|
@@ -60,6 +65,13 @@ class PtyManager {
|
|
|
60
65
|
constructor() {
|
|
61
66
|
this.sessions = new Map(); // tabId -> { proc, cwd, created }
|
|
62
67
|
this.killed = new Set(); // tabIds explicitly killed — suppress their exit events
|
|
68
|
+
// tabId -> recent output, replayed verbatim on reattach. An Epic's
|
|
69
|
+
// Terminal pane unmounts whenever the user views a DIFFERENT Epic while
|
|
70
|
+
// its claude keeps running (Epic ⇄ claude-session is 1:1 and must survive
|
|
71
|
+
// browsing), so "pre-reattach output is lost" — tolerable for a dev
|
|
72
|
+
// reload — would read as the session having been wiped. Bounded ring so a
|
|
73
|
+
// long-lived session can't grow this without limit.
|
|
74
|
+
this.buffers = new Map();
|
|
63
75
|
this.window = null;
|
|
64
76
|
}
|
|
65
77
|
|
|
@@ -104,6 +116,15 @@ class PtyManager {
|
|
|
104
116
|
} catch {
|
|
105
117
|
/* pty may have exited between the check and the resize */
|
|
106
118
|
}
|
|
119
|
+
// Replay recent output so a reattached viewport isn't blank. The caller
|
|
120
|
+
// registers its pty:data listener BEFORE invoking spawn (see
|
|
121
|
+
// EpicTerminalPane / Terminal), and this fires on the next tick, so the
|
|
122
|
+
// listener is always in place by the time the replay lands. Sent as one
|
|
123
|
+
// chunk ahead of any live data, preserving ordering.
|
|
124
|
+
const replay = this.buffers.get(tabId);
|
|
125
|
+
if (replay) {
|
|
126
|
+
setImmediate(() => sendIfAlive(this.window, `pty:data:${tabId}`, replay));
|
|
127
|
+
}
|
|
107
128
|
// If the process has already exited but its session wasn't cleaned up,
|
|
108
129
|
// fire a synthetic exit after the renderer re-registers its onExit handler.
|
|
109
130
|
if (existing.proc.exitCode != null) {
|
|
@@ -154,6 +175,7 @@ class PtyManager {
|
|
|
154
175
|
|
|
155
176
|
proc.onData((data) => {
|
|
156
177
|
gotData = true;
|
|
178
|
+
this.#appendReplay(tabId, data);
|
|
157
179
|
sendIfAlive(this.window, `pty:data:${tabId}`, data);
|
|
158
180
|
});
|
|
159
181
|
|
|
@@ -164,6 +186,7 @@ class PtyManager {
|
|
|
164
186
|
if (this.killed.delete(tabId)) {
|
|
165
187
|
console.log('[pty] suppressed exit broadcast for killed tabId=', tabId);
|
|
166
188
|
this.sessions.delete(tabId);
|
|
189
|
+
this.buffers.delete(tabId);
|
|
167
190
|
return;
|
|
168
191
|
}
|
|
169
192
|
// Fast-exit detector: a shell that dies in <1.2s with a non-zero status
|
|
@@ -176,12 +199,22 @@ class PtyManager {
|
|
|
176
199
|
}
|
|
177
200
|
sendIfAlive(this.window, `pty:exit:${tabId}`, { exitCode, signal });
|
|
178
201
|
this.sessions.delete(tabId);
|
|
202
|
+
this.buffers.delete(tabId);
|
|
179
203
|
});
|
|
180
204
|
|
|
181
205
|
this.sessions.set(tabId, { proc, cwd, created: spawnedAt });
|
|
182
206
|
return { pid: proc.pid, cwd, reattached: false };
|
|
183
207
|
}
|
|
184
208
|
|
|
209
|
+
/** Append to a session's bounded replay buffer, trimming oldest output. */
|
|
210
|
+
#appendReplay(tabId, data) {
|
|
211
|
+
const next = (this.buffers.get(tabId) ?? '') + data;
|
|
212
|
+
this.buffers.set(
|
|
213
|
+
tabId,
|
|
214
|
+
next.length > REPLAY_BUFFER_MAX ? next.slice(next.length - REPLAY_BUFFER_MAX) : next,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
185
218
|
write({ tabId, data }) {
|
|
186
219
|
const s = this.sessions.get(tabId);
|
|
187
220
|
if (!s) {
|
|
@@ -225,6 +258,7 @@ class PtyManager {
|
|
|
225
258
|
/* already dead */
|
|
226
259
|
}
|
|
227
260
|
this.sessions.delete(tabId);
|
|
261
|
+
this.buffers.delete(tabId);
|
|
228
262
|
}
|
|
229
263
|
}
|
|
230
264
|
|