dsh-ssh-tui 0.5.7 → 0.5.9

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.
@@ -3,13 +3,13 @@
3
3
  * Stale locks (dead pid) are stolen. A live lock with a reachable display
4
4
  * socket is an attach target, not a hard failure.
5
5
  */
6
- import { access, readdir } from 'node:fs/promises';
6
+ import { readdir } from 'node:fs/promises';
7
7
  import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
8
- import { constants as fsConstants, readFileSync } from 'node:fs';
9
- import { homedir } from 'node:os';
8
+ import { readFileSync } from 'node:fs';
9
+ import { execFile } from 'node:child_process';
10
10
  import { dirname, join } from 'node:path';
11
11
  import { t } from './i18n/index.js';
12
- import { sessionSockPath } from './display-sock.js';
12
+ import { displaySockExists, isPipePath, resolveDshHome, sessionSockPath } from './display-sock.js';
13
13
  export class SessionLockHeldError extends Error {
14
14
  lock;
15
15
  path;
@@ -20,7 +20,7 @@ export class SessionLockHeldError extends Error {
20
20
  this.path = path;
21
21
  }
22
22
  }
23
- export function sessionLockPath(sessionId, dshHome = process.env.DSH_HOME ?? join(homedir(), '.dsh')) {
23
+ export function sessionLockPath(sessionId, dshHome = resolveDshHome()) {
24
24
  const safe = sessionId.replaceAll(/[^A-Za-z0-9._-]/g, '_');
25
25
  return join(dshHome, 'tui-locks', `${safe}.json`);
26
26
  }
@@ -99,6 +99,152 @@ function readProcCmdline(pid) {
99
99
  return undefined;
100
100
  }
101
101
  }
102
+ /** Clock/resolution slack when comparing a creation time with the lock write. */
103
+ export const PID_REUSE_SLACK_MS = 5_000;
104
+ /**
105
+ * Cache of Windows identities so one lock costs at most one probe per window.
106
+ *
107
+ * Keyed by pid *and* the lock instance that was inspected: scoping it to the
108
+ * lock (not just the pid) is what keeps a recycled pid from being judged by an
109
+ * identity it no longer has — a foreign cached identity applied to a fresh
110
+ * lock would declare a live Host stale and let a second Host write the same
111
+ * session. The short TTL bounds the same hazard for repeated inspections of
112
+ * one lock.
113
+ */
114
+ const WINDOWS_IDENTITY_TTL_MS = 10_000;
115
+ const windowsIdentityCache = new Map();
116
+ function lockInstanceKey(lock) {
117
+ return `${lock.pid}:${lock.startedAt}`;
118
+ }
119
+ /**
120
+ * Parse the probe's stdout. Everything after the last non-empty line is
121
+ * ignored (a stray warning banner must not masquerade as the image name), and
122
+ * an unexpected shape is reported as "unverifiable" rather than as a
123
+ * mismatch: mistaking noise for a foreign process would steal a live lock.
124
+ */
125
+ export function parseWindowsProcessIdentity(stdout) {
126
+ // Keep the raw line: the tab between name and timestamp is the shape being
127
+ // validated, and trimming whitespace off the end would delete it (a trailing
128
+ // tab means "name known, creation time unreadable", which is still useful).
129
+ const line = stdout.split('\n')
130
+ .map(entry => entry.replace(/\r$/u, ''))
131
+ .reverse()
132
+ .find(entry => entry.trim() !== '');
133
+ if (line === undefined || line.trim() === 'gone')
134
+ return undefined;
135
+ const trimmed = line.trimStart();
136
+ const tab = trimmed.indexOf('\t');
137
+ if (tab <= 0)
138
+ return undefined;
139
+ const name = trimmed.slice(0, tab).trim().toLowerCase();
140
+ if (!/^[a-z0-9_.-]+$/u.test(name))
141
+ return undefined;
142
+ const startedAt = Date.parse(trimmed.slice(tab + 1).trim());
143
+ return { name, ...Number.isFinite(startedAt) ? { startedAt } : {} };
144
+ }
145
+ /** Absolute Windows PowerShell, for hosts where the bare name is not on PATH. */
146
+ function systemPowerShell() {
147
+ const root = process.env.SystemRoot ?? process.env.windir ?? 'C:\\Windows';
148
+ return `${root}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
149
+ }
150
+ /**
151
+ * `Get-Process` beats WMI here: it is a single .NET call that reports both the
152
+ * image name (works across users) and the creation time. The script avoids
153
+ * double quotes so Node's CreateProcess quoting stays trivial, and formats the
154
+ * timestamp with the invariant culture so native-digit locales cannot turn it
155
+ * into NaN.
156
+ */
157
+ async function queryWindowsProcess(pid) {
158
+ const script = `$p = Get-Process -Id ${pid} -ErrorAction SilentlyContinue; `
159
+ + `if ($null -eq $p) { 'gone' } else { `
160
+ + `$st = ''; try { $st = $p.StartTime.ToUniversalTime().ToString('yyyy-MM-dd\\THH\\:mm\\:ss.fff\\Z', [System.Globalization.CultureInfo]::InvariantCulture) } catch {}; `
161
+ + `$p.ProcessName.ToLower() + [char]9 + $st }`;
162
+ for (const exe of ['powershell.exe', systemPowerShell()]) {
163
+ const stdout = await runPowerShell(exe, script);
164
+ // `undefined` means the interpreter could not run at all (missing,
165
+ // blocked, timed out); a readable answer — including `gone` — is final.
166
+ if (stdout === undefined)
167
+ continue;
168
+ return parseWindowsProcessIdentity(stdout);
169
+ }
170
+ return undefined;
171
+ }
172
+ /**
173
+ * Async on purpose: this runs on the TUI's render path (`/resume` lists every
174
+ * lock), where a synchronous spawn would freeze painting and keystrokes for
175
+ * the whole probe.
176
+ */
177
+ function runPowerShell(exe, script) {
178
+ return new Promise(resolve => {
179
+ execFile(exe, ['-NoProfile', '-NonInteractive', '-Command', script], {
180
+ encoding: 'utf8',
181
+ timeout: 5_000,
182
+ windowsHide: true,
183
+ maxBuffer: 64 * 1024,
184
+ }, (error, stdout) => {
185
+ if (error !== null) {
186
+ resolve(undefined);
187
+ return;
188
+ }
189
+ resolve(typeof stdout === 'string' ? stdout : '');
190
+ });
191
+ });
192
+ }
193
+ async function windowsProcessIdentity(lock) {
194
+ const key = lockInstanceKey(lock);
195
+ const cached = windowsIdentityCache.get(lock.pid);
196
+ if (cached !== undefined && cached.lockKey === key && Date.now() - cached.at < WINDOWS_IDENTITY_TTL_MS) {
197
+ return cached.identity;
198
+ }
199
+ const identity = await queryWindowsProcess(lock.pid);
200
+ // Only successful probes are cached: a transient failure must not make the
201
+ // pid look permanently dead for the rest of this process's life.
202
+ if (identity === undefined) {
203
+ windowsIdentityCache.delete(lock.pid);
204
+ return undefined;
205
+ }
206
+ if (windowsIdentityCache.size > 64)
207
+ windowsIdentityCache.clear();
208
+ windowsIdentityCache.set(lock.pid, { identity, at: Date.now(), lockKey: key });
209
+ return identity;
210
+ }
211
+ /** Image name this Host runs as (`node` / `dsh`), without `.exe`. */
212
+ export function hostImageName(execPath = process.execPath) {
213
+ // Split on both separators: the Windows probe's answer is compared on any
214
+ // platform, and tests may feed a Windows-style path from POSIX.
215
+ const file = execPath.split(/[\\/]/u).pop() ?? execPath;
216
+ return file.replace(/\.exe$/iu, '').toLowerCase();
217
+ }
218
+ /**
219
+ * Decide whether a live Windows pid can still be the lock's Host.
220
+ *
221
+ * Windows recycles pids aggressively, and without procfs an unrelated process
222
+ * inheriting the recorded pid used to look like a permanent live-but-silent
223
+ * Host ("zombie"), which blocked `--resume` until the lock was deleted by
224
+ * hand. Two facts rule reuse out:
225
+ * - the Host always runs this same executable, so a different image name is
226
+ * someone else's process;
227
+ * - the Host existed before it wrote the lock, so a process created after the
228
+ * lock was written cannot be its owner.
229
+ * An unverifiable process keeps the legacy best-effort answer (alive).
230
+ */
231
+ export function windowsProcessMatchesLock(lock, identity, expectedName = hostImageName(), slackMs = PID_REUSE_SLACK_MS) {
232
+ if (identity === undefined)
233
+ return true;
234
+ const lockStarted = Date.parse(lock.startedAt);
235
+ if (identity.startedAt !== undefined && Number.isFinite(lockStarted)) {
236
+ // The Host existed before it wrote the lock, so a process created after
237
+ // that cannot be its owner. The timeline answers on its own, which also
238
+ // covers a Host launched by a different runtime (bun vs node) or a renamed
239
+ // executable: only a pid the OS recycled can post-date the lock.
240
+ return identity.startedAt <= lockStarted + slackMs;
241
+ }
242
+ // No comparable timeline: the image name is the only signal left, and a
243
+ // mismatch there is weak enough that "unverifiable" is the safer answer.
244
+ if (identity.name !== '' && expectedName !== '' && identity.name !== expectedName)
245
+ return false;
246
+ return true;
247
+ }
102
248
  /**
103
249
  * True when `pid` is genuinely the Host process that wrote `lock`.
104
250
  *
@@ -113,21 +259,31 @@ function readProcCmdline(pid) {
113
259
  * boot, so a recycled or cross-namespace pid fails the check;
114
260
  * - older locks fall back to `/proc/<pid>/cmdline`: the detached Host is
115
261
  * always launched with `--resume=<sessionId>` in argv, so any other
116
- * process (kernel threads have an empty cmdline) is proven stale.
117
- * On platforms without procfs the legacy kill(pid, 0) behavior is kept.
262
+ * process (kernel threads have an empty cmdline) is proven stale;
263
+ * - Windows has neither: a `Get-Process` probe supplies the image name and
264
+ * creation time instead (see {@link windowsProcessMatchesLock}).
265
+ * On platforms where none of this is available the legacy kill(pid, 0)
266
+ * behavior is kept.
267
+ *
268
+ * Async because the Windows probe spawns PowerShell, and this runs on the
269
+ * render path (`/resume` inspects every lock); a synchronous spawn would
270
+ * freeze painting and keystrokes for the duration of the probe.
118
271
  */
119
- export function lockOwnerIsAlive(lock) {
272
+ export async function lockOwnerIsAlive(lock) {
120
273
  const pid = lock.pid;
121
274
  if (!Number.isInteger(pid) || pid <= 0)
122
275
  return false;
123
276
  if (!processIsAlive(pid))
124
277
  return false;
278
+ if (process.platform === 'win32') {
279
+ return windowsProcessMatchesLock(lock, await windowsProcessIdentity(lock));
280
+ }
125
281
  if (lock.bootId !== undefined && lock.pidStart !== undefined) {
126
282
  return readBootId() === lock.bootId && readProcStarttime(pid) === lock.pidStart;
127
283
  }
128
284
  const cmdline = readProcCmdline(pid);
129
285
  if (cmdline === undefined)
130
- return true; // no /proc (win32/darwin): legacy best-effort
286
+ return true; // no /proc (darwin): legacy best-effort
131
287
  return cmdline.includes(`--resume=${lock.sessionId}`);
132
288
  }
133
289
  export function formatLockHeldMessage(lock) {
@@ -137,7 +293,7 @@ export function formatLockHeldMessage(lock) {
137
293
  export function sessionLockDisabled(env = process.env) {
138
294
  return env.DSH_TUI_NO_SESSION_LOCK === '1' || env.DSH_TUI_NO_SESSION_LOCK === 'true';
139
295
  }
140
- export async function readSessionLock(sessionId, dshHome = process.env.DSH_HOME ?? join(homedir(), '.dsh')) {
296
+ export async function readSessionLock(sessionId, dshHome = resolveDshHome()) {
141
297
  const path = sessionLockPath(sessionId, dshHome);
142
298
  try {
143
299
  const info = parseSessionLock(await readFile(path, 'utf8'));
@@ -154,7 +310,7 @@ export async function writeSessionLock(path, info) {
154
310
  await writeFile(path, `${JSON.stringify(info, null, 2)}\n`, { mode: 0o600 });
155
311
  }
156
312
  export async function acquireSessionLock(sessionId, options = {}) {
157
- const dshHome = options.dshHome ?? process.env.DSH_HOME ?? join(homedir(), '.dsh');
313
+ const dshHome = options.dshHome ?? resolveDshHome();
158
314
  const path = sessionLockPath(sessionId, dshHome);
159
315
  await mkdir(dirname(path), { recursive: true, mode: 0o700 });
160
316
  const pid = options.pid ?? process.pid;
@@ -189,7 +345,7 @@ export async function acquireSessionLock(sessionId, options = {}) {
189
345
  existing = undefined;
190
346
  }
191
347
  const ours = options.pid ?? process.pid;
192
- if (existing !== undefined && existing.pid !== ours && lockOwnerIsAlive(existing)) {
348
+ if (existing !== undefined && existing.pid !== ours && await lockOwnerIsAlive(existing)) {
193
349
  throw new SessionLockHeldError(existing, path);
194
350
  }
195
351
  try {
@@ -213,7 +369,7 @@ export async function releaseSessionLock(path, pid = process.pid) {
213
369
  // Missing lock is fine.
214
370
  }
215
371
  }
216
- export async function inspectLiveHost(sessionId, dshHome = process.env.DSH_HOME ?? join(homedir(), '.dsh')) {
372
+ export async function inspectLiveHost(sessionId, dshHome = resolveDshHome()) {
217
373
  const held = await readSessionLock(sessionId, dshHome);
218
374
  if (held === undefined)
219
375
  return undefined;
@@ -221,19 +377,19 @@ export async function inspectLiveHost(sessionId, dshHome = process.env.DSH_HOME
221
377
  }
222
378
  async function inspectHeldLock(path, info, dshHome) {
223
379
  const sock = info.sock ?? sessionSockPath(info.sessionId, dshHome);
224
- const alive = lockOwnerIsAlive(info);
225
- let sockExists = false;
226
- try {
227
- await access(sock, fsConstants.F_OK);
228
- sockExists = true;
229
- }
230
- catch {
231
- sockExists = false;
232
- }
380
+ // A Windows named pipe is not a filesystem entry: fs.access() can never see
381
+ // it, so liveness must be probed with a connect (and it needs no unlink —
382
+ // Windows removes the pipe when the owning process exits). A reachable pipe
383
+ // also proves the owner is alive, so the pid identity probe can be skipped.
384
+ const sockExists = await displaySockExists(sock);
385
+ const alive = (isPipePath(sock) && sockExists) || await lockOwnerIsAlive(info);
233
386
  if (!alive) {
234
387
  // Host is gone. A leftover unix socket is not attachable — steal the
235
- // lock so --resume can reopen from the session log.
236
- if (sockExists) {
388
+ // lock so --resume can reopen from the session log, and remove the dead
389
+ // directory entry: the reachability probe cannot report it as ready, so
390
+ // it is cleaned by path (a Windows pipe is not a file entry and is
391
+ // already reclaimed by the OS).
392
+ if (!isPipePath(sock)) {
237
393
  try {
238
394
  await unlink(sock);
239
395
  }
@@ -254,7 +410,7 @@ async function inspectHeldLock(path, info, dshHome) {
254
410
  return { kind: 'attachable', lock: info, path, sock };
255
411
  }
256
412
  /** Every lock file under `$DSH_HOME/tui-locks` whose Host pid is still alive. */
257
- export async function listAttachableHosts(dshHome = process.env.DSH_HOME ?? join(homedir(), '.dsh')) {
413
+ export async function listAttachableHosts(dshHome = resolveDshHome()) {
258
414
  let names = [];
259
415
  try {
260
416
  names = await readdir(join(dshHome, 'tui-locks'));
@@ -1 +1 @@
1
- {"version":3,"file":"session-lock.js","sourceRoot":"","sources":["../src/session-lock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAqBnD,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,IAAI,CAAiB;IACrB,IAAI,CAAQ;IACrB,YAAY,IAAqB,EAAE,IAAY;QAC7C,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAA;QAClC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;QAClC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,SAAiB,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC;IAC1G,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAA;IAC1D,OAAO,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,OAAO,CAAC,CAAA;AACnD,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AACtE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAA;QACzD,MAAM,GAAG,GAAG,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;QACnG,MAAM,SAAS,GAAG,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;QACrF,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,IAAI,CAAC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE;YAAE,OAAO,SAAS,CAAA;QAClG,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;QAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAA;QACtC,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAA;QACtC,OAAO;YACL,GAAG;YACH,SAAS;YACT,SAAS,EAAE,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YACvE,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjG,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvG,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3F,GAAG,CAAC,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,kBAAkB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChG,GAAG,CAAC,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,GAAG,CAAC,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,YAAY;gBACrF,CAAC,CAAC,EAAE,WAAW,EAAE;gBACjB,CAAC,CAAC,EAAE,CAAC;SACR,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IACpD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAQ,KAA+B,CAAC,IAAI,KAAK,OAAO,CAAA;IAC1D,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,iCAAiC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAA;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,SAAS,iBAAiB,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,GAAG,OAAO,EAAE,MAAM,CAAC,CAAA;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,SAAS,CAAA;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC/C,OAAO,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,SAAS,GAAG,UAAU,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAqB;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IACpB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IACpD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC7D,OAAO,UAAU,EAAE,KAAK,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAA;IACjF,CAAC;IACD,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IACpC,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA,CAAC,8CAA8C;IACrF,OAAO,OAAO,CAAC,QAAQ,CAAC,YAAY,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAqB;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAA;IAC1D,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,OAAO,GAAG,CAAC,uBAAuB,KAAK,GAAG,IAAI,GAAG,CAAC,uBAAuB,KAAK,MAAM,CAAA;AACtF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAAiB,EACjB,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC;IAEzD,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAChD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QAC3D,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,SAAS,CAAA;QACxC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAqB;IACxE,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5D,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAiB,EACjB,UAQI,EAAE;IAEN,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;IAClF,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAChD,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAA;IACtC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1E,MAAM,IAAI,GAAoB;QAC5B,GAAG;QACH,SAAS;QACT,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC;QACzD,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,UAAU;QAClC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,OAAO;QACrD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,MAAM;KAC3C,CAAA;IACD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;IACpD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAC3D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAA;YACnE,IAAI,QAAqC,CAAA;YACzC,IAAI,CAAC;gBACH,QAAQ,GAAG,gBAAgB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;YAC3D,CAAC;YAAC,MAAM,CAAC;gBACP,QAAQ,GAAG,SAAS,CAAA;YACtB,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAA;YACvC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,GAAG,KAAK,IAAI,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClF,MAAM,IAAI,oBAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;YAChD,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,qDAAqD;YACvD,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG;IACtE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QAC9D,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,KAAK,GAAG;YAAE,OAAM;QACxD,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;AACH,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAAiB,EACjB,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC;IAEzD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACtD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACxC,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AACvD,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,IAAY,EACZ,IAAqB,EACrB,OAAe;IAEf,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAClE,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;IACpC,IAAI,UAAU,GAAG,KAAK,CAAA;IACtB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAA;QACpC,UAAU,GAAG,IAAI,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,UAAU,GAAG,KAAK,CAAA;IACpB,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,qEAAqE;QACrE,oDAAoD;QACpD,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,wDAAwD;YAC1D,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IAClE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AACvD,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC;IAEzD,IAAI,KAAK,GAAa,EAAE,CAAA;IACxB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAA;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;IACD,MAAM,KAAK,GAAsE,EAAE,CAAA;IACnF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAQ;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;QAC7C,IAAI,IAAiC,CAAA;QACrC,IAAI,CAAC;YACH,IAAI,GAAG,gBAAgB,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QACD,IAAI,IAAI,KAAK,SAAS;YAAE,SAAQ;QAChC,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QACvD,IAAI,IAAI,EAAE,IAAI,KAAK,YAAY;YAAE,SAAQ;QACzC,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IAClF,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
1
+ {"version":3,"file":"session-lock.js","sourceRoot":"","sources":["../src/session-lock.ts"],"names":[],"mappings":"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"}
package/lib/tui.js CHANGED
@@ -25,12 +25,12 @@ import { StringDecoder } from 'node:string_decoder';
25
25
  import { credentialRef } from '@deepseek-ai/dsh-credentials';
26
26
  import { createUserMessage, errorChain, ReasoningEffortId } from '@deepseek-ai/dsh-llm';
27
27
  import { SessionId } from '@deepseek-ai/dsh-session';
28
- import { commandAcceptsAttachments, forEachSessionEvent, isAssistantStreamEvent, listenHostEvent, sessionEventType, sessionEvents, settingsNamespace, streamChunkOf, } from './dsh-compat.js';
28
+ import { commandAcceptsAttachments, forEachSessionEventAsync, isAssistantStreamEvent, isTokenDeltaChunk, listenHostEvent, REPLAY_YIELD_EVERY, sessionEventType, sessionEvents, settingsNamespace, streamChunkOf, streamFirstTokenTime, streamFrameAttemptId, streamFrameOwner, } from './dsh-compat.js';
29
29
  import { classifyApprovalDetailed, commandForApprovalRequest, isApprovalStatusArg, parseAutoApprovalMode } from './auto-approval.js';
30
30
  import { buildReviewUserMessage, parseReviewOutput, reviewSystemPrompt } from './approval-reviewer.js';
31
31
  import { loadProviderCatalog, mergeProviderEntries } from './provider-catalog.js';
32
32
  import { formatFooterCwd, formatSessionTime, listResumableSessions } from './session-list.js';
33
- import { detachFromSshSession, DisplayHost, sessionSockPath } from './display-sock.js';
33
+ import { detachFromSshSession, DisplayHost, resolveDshHome, sessionSockPath } from './display-sock.js';
34
34
  import { applySavedLocale, getLocale, localeDisplayName, localeFromTag, setLocale, t, UI_LOCALE_NAMESPACE, } from './i18n/index.js';
35
35
  import { defaultReasoningEffort } from './reasoning.js';
36
36
  import { checkForPluginUpdate, installPluginLatest } from './update-check.js';
@@ -47,10 +47,10 @@ import { crossedQuotaThresholds, DEEPSEEK_PUBLIC_BASE_URL, formatAccountBalance,
47
47
  import { appendSubagentLog, applyTurnEndToPlan, cardCategoryLabel, cardCategoryOf, compactionHeaderText, formatCompactCommandError, isPromptInjectionMessage, matchTranscriptRows, parseFindQuery, parsePlanTodos, planCloseNudgeText, planMarkdownFromArgs, planDockNote, planIsLive, planTitleFromMarkdown, promptInjectionSources, promptInjectionTitle, subagentHeaderText, todoItemKind, todoProgressLabel, TODO_STATUS_MARK, } from './plan.js';
48
48
  import { buildToolHeader, canMergeToolCall, compactEditPath, compactToolBursts, countDiffAddDel, countDiffLines, countOutputLines, diffMetaDiffs, diffStatToken, formatModelList, HIDDEN_TOOL_NAMES, parseExitStatus, planReviewOf, presentToolCall, READ_TOOL_NAMES, SHELL_TOOL_NAMES, toolBodyFitsWorkspace, toolBodyLines, toolTitle, TOOL_FLIP_MS, wrappedToolBodyLineCount, } from './tool-present.js';
49
49
  export { clipAnsiToWidth, cursorVisualPosition, displayWidth, foldInputView, hrefAtColumn, osc52Clipboard, osc8Enabled, paintedLinkHits, fmtElapsedCompact, padAnsiToWidth, padToWidth, renderMarkdownLines, repeatToWidth, shimmerText, truncateToWidth, visibleWidth, waitCardCopy, waitSummaryFromReasoning, wrapWaitDetails, } from './term-text.js';
50
- export { captureHangupSignals, composePaintOutput, detectSshSession, formatLinkQualityChip, ignoreFurtherHangupSignals, isEscapePrefix, isHangupErrno, linkQualityOf, linkSignalPips, paintIntervalForRtt, paintLinkLabel, parseCursorPositionReply, pickerWindowStart, probeTerminalRttMs, releaseHangupSignals, resolvePaintIntervalMs, waitUntilIdleOrTimeout, writeBootSplash, } from './paint.js';
51
- export { CONTEXT_IDLE_COMPACT_RATIO, CONTEXT_PRESSURE_DANGER_RATIO, CONTEXT_PRESSURE_WARN_RATIO, CONTEXT_RING_EMPTY, CONTEXT_RING_SEGMENTS, contextPressureAlertText, contextPressureRingColor, contextPressureUsedTokens, contextPressureView, describeProviderRoute, dropFooterQuotaPlanName, fitFooterStatsLine, fitFooterStatusLine, footerActivity, footerIdentityParts, footerStatsGroups, formatContextPressureChip, formatContextPressureRing, formatContextPressureStatusLine, formatDuration, formatFooterQuota, formatQuotaBar, formatStatusReport, formatTokens, formatTokensPerSecond, parseContextPressure, promptPressureTokens, providerShortCode, providerUsesLocalOAuth, shouldIdleAutoCompact, } from './footer.js';
50
+ export { captureHangupSignals, composePaintOutput, detectSshSession, formatLinkQualityChip, ignoreFurtherHangupSignals, isEscapePrefix, findCursorPositionReply, isHangupErrno, linkQualityOf, linkSignalPips, paintIntervalForRtt, paintLinkLabel, parseCursorPositionReply, pickerWindowStart, probeTerminalRttMs, releaseHangupSignals, resolvePaintIntervalMs, waitUntilIdleOrTimeout, writeBootSplash, } from './paint.js';
51
+ export { CONTEXT_IDLE_COMPACT_RATIO, CONTEXT_PRESSURE_DANGER_RATIO, CONTEXT_PRESSURE_WARN_RATIO, CONTEXT_RING_EMPTY, CONTEXT_RING_SEGMENTS, contextPressureAlertText, contextPressureRingColor, contextPressureUsedTokens, contextPressureView, describeProviderRoute, dropFooterQuotaPlanName, fitFooterStatsLine, fitFooterStatusLine, footerActivity, footerIdentityParts, footerStatsGroups, formatContextPressureChip, formatContextPressureRing, formatContextPressureStatusLine, formatDuration, formatFooterQuota, formatQuotaBar, formatStatusReport, formatTokens, formatTokensPerSecond, parseContextPressure, promptPressureTokens, providerShortCode, providerUsesLocalOAuth, shouldIdleAutoCompact, subagentRouteLabel, } from './footer.js';
52
52
  export { crossedQuotaThresholds, formatAccountBalance, formatFooterBalance, formatOpenCodeGoUsage, formatQuotaSnapshot, formatQuotaStatusLine, joinUrl, openCodeSourceFor, parseDeepSeekBalance, parseOpenAiCompatibleBalance, parseOpenCodeGoQuota, parseSuperGrokBilling, quotaAlertText, quotaRefreshEverySteps, quotaRefreshEveryTurns, remainingPercentFromUsed, tightestQuotaWindow, } from './quota.js';
53
- export { commandAcceptsAttachments, forEachSessionEvent, isAssistantStreamEvent, listPersistenceHeaders, inspectPersistenceSession, sessionEventType, sessionEvents, settingsNamespace, streamChunkOf, } from './dsh-compat.js';
53
+ export { commandAcceptsAttachments, forEachSessionEvent, isAssistantStreamEvent, isTokenDeltaChunk, listPersistenceHeaders, inspectPersistenceSession, sessionEventType, sessionEvents, settingsNamespace, streamChunkOf, streamFirstTokenTime, streamFrameAttemptId, streamFrameOwner, } from './dsh-compat.js';
54
54
  export { applyTurnEndToPlan, askSummary, cardCategoryOf, compactionHeaderText, formatCompactCommandError, isPromptInjectionMessage, matchTranscriptRows, parseFindQuery, parsePlanTodos, planCloseNudgeText, planDockNote, planIsLive, planTitleFromMarkdown, planTurnLeftOpen, promptInjectionSources, promptInjectionTitle, subagentHeaderText, todoProgressLabel, todoSummary, } from './plan.js';
55
55
  export { buildToolHeader, canMergeToolCall, compactEditPath, compactToolBursts, compactToolGroups, countDiffAddDel, countDiffLines, countOutputLines, diffMetaDiffs, diffStatToken, friendlyJsonLines, parseExitStatus, presentToolCall, READ_TOOL_NAMES, renderToolDiff, toolBodyFitsWorkspace, toolBodyLines, toolStateColor, toolStateLabel, wrappedToolBodyLineCount, } from './tool-present.js';
56
56
  function discoverProviderModels(llm, request, signal) {
@@ -146,7 +146,7 @@ const RESERVED_BOTTOM_LINES = 3; // input line + stats line + status line
146
146
  const MAX_TRANSCRIPT_ROWS = 5000;
147
147
  const IS_WINDOWS = process.platform === 'win32';
148
148
  function dshHomeDir() {
149
- return process.env.DSH_HOME ?? join(homedir(), '.dsh');
149
+ return resolveDshHome();
150
150
  }
151
151
  function displayDshPath(file) {
152
152
  const home = dshHomeDir();
@@ -446,6 +446,12 @@ export class SshTui {
446
446
  usage: { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 },
447
447
  };
448
448
  openStepStats;
449
+ /** Attempt whose live `start` frame opened the current token stream. */
450
+ liveStreamOwner;
451
+ /** Live events parked while the (yielding) history replay holds the floor. */
452
+ replayQueue;
453
+ /** A relay claimed the display while a hangup was still cancelling/flushing. */
454
+ reattachedDuringHangup = false;
449
455
  pendingToolTimes = new Map();
450
456
  usageByStep = new Map();
451
457
  lastStatsTurn = null;
@@ -871,16 +877,29 @@ export class SshTui {
871
877
  this.paintIntervalMs = resolvePaintIntervalMs(undefined, {}, { ssh: true, rttMs: rtt });
872
878
  this.markDirty();
873
879
  }
874
- /** Replay the durable session log so a resumed session renders its history. */
875
- replayHistory() {
880
+ /**
881
+ * Replay the durable session log so a resumed session renders its history.
882
+ * Chunked on purpose: a synchronous walk of a long log froze the TUI on the
883
+ * pre-replay frame, so the relay's RTT frame could not be applied and the
884
+ * footer sat on `SSH ○○○○` for the whole load.
885
+ */
886
+ async replayHistory() {
887
+ const parked = [];
888
+ this.replayQueue = parked;
876
889
  this.replaying = true;
877
890
  try {
878
- forEachSessionEvent(this.agent.session, (event) => {
879
- this.handleSessionEvent(this.agent.session, event);
880
- });
891
+ await forEachSessionEventAsync(this.agent.session, (event) => {
892
+ this.applySessionEvent(this.agent.session, event);
893
+ }, REPLAY_YIELD_EVERY, () => this.disposed);
881
894
  }
882
895
  finally {
883
896
  this.replaying = false;
897
+ this.replayQueue = undefined;
898
+ }
899
+ for (const item of parked) {
900
+ if (this.disposed)
901
+ return;
902
+ this.applySessionEvent(item.session, item.event);
884
903
  }
885
904
  this.streaming = undefined;
886
905
  this.streamingReasoning = undefined;
@@ -1151,6 +1170,7 @@ export class SshTui {
1151
1170
  if (this.hangingUp || this.disposed)
1152
1171
  return;
1153
1172
  this.hangingUp = true;
1173
+ this.reattachedDuringHangup = false;
1154
1174
  ignoreFurtherHangupSignals();
1155
1175
  this.detachDisplay();
1156
1176
  const busy = this.isBusyForHangupKeepalive();
@@ -1165,6 +1185,17 @@ export class SshTui {
1165
1185
  await waitUntilIdleOrTimeout(() => this.agent.status !== 'running', HANGUP_CANCEL_TIMEOUT_MS);
1166
1186
  }
1167
1187
  await this.flushSession();
1188
+ // A relay can reattach while the cancel/flush above was in flight — the
1189
+ // common case is a user reconnecting the moment the link drops. Deciding
1190
+ // from the snapshot taken at the start would dispose (or exit) the Host
1191
+ // under the display the user just got back, and the launcher would report
1192
+ // `write EPIPE` for an attach that had already succeeded.
1193
+ if (this.reattachedDuringHangup) {
1194
+ this.reattachedDuringHangup = false;
1195
+ this.hangingUp = false;
1196
+ this.clearDetachedIdleTimer();
1197
+ return;
1198
+ }
1168
1199
  const keepHost = this.displayHost !== undefined && busy;
1169
1200
  if (keepHost) {
1170
1201
  this.hangingUp = false;
@@ -1327,6 +1358,12 @@ export class SshTui {
1327
1358
  }
1328
1359
  /** Re-open DECSET and start painting to an attached Display relay. */
1329
1360
  attachRelayDisplay() {
1361
+ // A relay that HELLOs while a hangup is still unwinding must be honored by
1362
+ // that hangup: the snapshot taken at the drop would otherwise dispose (or
1363
+ // exit) the Host under the display the user just got back, and the
1364
+ // launcher reports `write EPIPE` for an attach that had already succeeded.
1365
+ if (this.hangingUp)
1366
+ this.reattachedDuringHangup = true;
1330
1367
  this.displayDetached = false;
1331
1368
  this.hangingUp = false;
1332
1369
  this.clearDetachedIdleTimer();
@@ -2589,7 +2626,8 @@ export class SshTui {
2589
2626
  provider,
2590
2627
  parentModel,
2591
2628
  subModel: sub.model,
2592
- subDiffers: sub.model !== parentModel,
2629
+ ...(sub.provider === undefined ? {} : { subProvider: sub.provider }),
2630
+ ...(sub.reasoningEffort === undefined ? {} : { subEffort: String(sub.reasoningEffort) }),
2593
2631
  ...(quotaWindow === undefined || this.quotaSnapshot === undefined || this.quotaSnapshot.provider !== provider
2594
2632
  ? {}
2595
2633
  : { quotaCode: this.quotaSnapshot.plan, quotaPercent: quotaWindow.remainingPercent }),
@@ -2879,20 +2917,20 @@ export class SshTui {
2879
2917
  * row. 0.1.2 hosts append `assistant/chunk`; 0.1.5 emits the same chunk
2880
2918
  * on `agent/assistant-stream` and never writes it to the log.
2881
2919
  */
2882
- applyStreamChunk(streamed) {
2920
+ applyStreamChunk(streamed, statsOnly = false) {
2883
2921
  const { chunk } = streamed;
2884
2922
  const open = this.openStepStats;
2885
2923
  if (open !== null && open !== undefined
2886
2924
  && open.turn === streamed.turn && open.step === streamed.step) {
2887
- if (open.firstTokenTime === null
2888
- && chunk.type === 'text-delta'
2889
- && chunk.text !== '') {
2925
+ if (open.firstTokenTime === null && isTokenDeltaChunk(chunk)) {
2890
2926
  this.openStepStats = { ...open, firstTokenTime: streamed.time };
2891
2927
  }
2892
2928
  }
2893
- if (chunk.type === 'usage' && chunk.usage !== undefined) {
2929
+ if (chunk.type === 'usage' && chunk.usage !== undefined && streamed.stepKnown) {
2894
2930
  this.recordUsage(streamed.turn, streamed.step, chunk.usage);
2895
2931
  }
2932
+ if (statsOnly)
2933
+ return;
2896
2934
  if (chunk.type === 'text-delta') {
2897
2935
  this.streaming ??= { text: '', reasoning: '' };
2898
2936
  this.streaming.text += chunk.text ?? '';
@@ -2924,7 +2962,23 @@ export class SshTui {
2924
2962
  return;
2925
2963
  this.lastActivity = Date.now();
2926
2964
  this.refreshContextPressure();
2927
- const streamed = streamChunkOf(payload.frame);
2965
+ const owner = streamFrameOwner(payload.frame);
2966
+ if (owner !== undefined) {
2967
+ // Live chunk frames carry no turn/step: remember the attempt's step here
2968
+ // or every chunk is attributed to step 0 and the stats never match.
2969
+ this.liveStreamOwner = owner;
2970
+ return;
2971
+ }
2972
+ if (payload.frame?.type === 'end') {
2973
+ this.liveStreamOwner = undefined;
2974
+ return;
2975
+ }
2976
+ const attemptId = streamFrameAttemptId(payload.frame);
2977
+ const current = this.liveStreamOwner;
2978
+ const fallback = current !== undefined && (attemptId === undefined || attemptId === current.attemptId)
2979
+ ? current
2980
+ : this.openStepStats;
2981
+ const streamed = streamChunkOf(payload.frame, fallback);
2928
2982
  if (streamed !== undefined)
2929
2983
  this.applyStreamChunk(streamed);
2930
2984
  };
@@ -2953,14 +3007,30 @@ export class SshTui {
2953
3007
  };
2954
3008
  };
2955
3009
  handleSessionEvent = (session, event) => {
3010
+ if (this.replayQueue !== undefined) {
3011
+ // The replay yields between chunks, so live events can arrive mid-load.
3012
+ // Folding them now would interleave newer events under older history;
3013
+ // park them and drain in arrival order once the walk is done.
3014
+ this.replayQueue.push({ session, event });
3015
+ return;
3016
+ }
3017
+ this.applySessionEvent(session, event);
3018
+ };
3019
+ applySessionEvent(session, event) {
2956
3020
  if (session.id !== this.agent.id) {
2957
3021
  if (this.subagentSessions.has(session.id))
2958
3022
  this.handleSubagentSessionEvent(session.id, event);
2959
3023
  return;
2960
3024
  }
2961
3025
  this.lastActivity = Date.now();
2962
- if (this.replaying && isAssistantStreamEvent(event))
3026
+ if (this.replaying && isAssistantStreamEvent(event)) {
3027
+ // Replay skips the in-progress row, but durable chunks still carry the
3028
+ // timing the footer needs: a resumed session must keep TTFT and tok/s.
3029
+ const streamed = streamChunkOf(event);
3030
+ if (streamed !== undefined)
3031
+ this.applyStreamChunk(streamed, true);
2963
3032
  return;
3033
+ }
2964
3034
  if (!this.replaying)
2965
3035
  this.refreshContextPressure();
2966
3036
  const eventType = sessionEventType(event);
@@ -3021,12 +3091,19 @@ export class SshTui {
3021
3091
  const open = this.openStepStats;
3022
3092
  if (open !== undefined && open.turn === event.data.turn && open.step === event.data.step) {
3023
3093
  this.stats.llmMs += Math.max(0, event.time - open.startTime);
3024
- if (open.firstTokenTime !== null) {
3025
- this.stats.ttftMs += Math.max(0, open.firstTokenTime - open.startTime);
3094
+ // The settlement's own packed stream is authoritative: a retried
3095
+ // step keeps the failed attempt's first token in the live latch, and
3096
+ // spanning both attempts reported a rate ~20x off. 0.1.2 has no
3097
+ // `stream` and still relies on the replayed `assistant/chunk` events
3098
+ // (or the live latch) instead.
3099
+ const firstTokenTime = streamFirstTokenTime(event.data.stream)
3100
+ ?? open.firstTokenTime;
3101
+ if (firstTokenTime !== null && firstTokenTime !== undefined && Number.isFinite(firstTokenTime)) {
3102
+ this.stats.ttftMs += Math.max(0, firstTokenTime - open.startTime);
3026
3103
  this.stats.ttftSteps += 1;
3027
3104
  const outputTokens = event.data.usage?.outputTokens;
3028
3105
  if (typeof outputTokens === 'number' && Number.isFinite(outputTokens) && outputTokens >= 0) {
3029
- this.stats.decodeMs += Math.max(0, event.time - open.firstTokenTime);
3106
+ this.stats.decodeMs += Math.max(0, event.time - firstTokenTime);
3030
3107
  this.stats.decodeTokens += outputTokens;
3031
3108
  }
3032
3109
  }
@@ -3256,7 +3333,7 @@ export class SshTui {
3256
3333
  this.handleExtensionEvent(event);
3257
3334
  break;
3258
3335
  }
3259
- };
3336
+ }
3260
3337
  handleStatus = ({ agent, status }) => {
3261
3338
  if (agent !== this.agent)
3262
3339
  return;
@@ -7150,7 +7227,9 @@ export function mountTui(ctx, config) {
7150
7227
  stopWaiting();
7151
7228
  controller = new SshTui(ctx, agent, config);
7152
7229
  controller.start();
7153
- controller.replayHistory();
7230
+ // Not awaited: the first frames paint while the (chunked) replay fills the
7231
+ // transcript, and relay RTT/resize frames keep flowing during the load.
7232
+ void controller.replayHistory();
7154
7233
  };
7155
7234
  const fail = (failedSessionId, error) => {
7156
7235
  if (settled || failedSessionId !== sessionId)