@particle-academy/fancy-term-host 0.1.1 → 0.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/index.d.cts CHANGED
@@ -366,6 +366,23 @@ declare class HostClient extends EventEmitter implements PtyBackend {
366
366
  * the reattach (renderer remounts these specs, replaying host scrollback). */
367
367
  liveIds(): string[];
368
368
  isConnected(): boolean;
369
+ /**
370
+ * Gracefully shut the host DOWN — the deliberate counterpart to
371
+ * `disconnect()` (which leaves the host running). Asks the host to kill its
372
+ * ptys, remove its pidfile/socket, and exit cleanly, then drops the local
373
+ * socket. Use this when a consumer needs the host genuinely gone — e.g.
374
+ * before an Electron auto-update whose installer must overwrite the binary
375
+ * the host runs on — INSTEAD of SIGKILLing by pidfile pid, which skips the
376
+ * host's own cleanup.
377
+ *
378
+ * The client mirror already holds the live scrollback, so snapshot via the
379
+ * SnapshotStore BEFORE calling this if you want T1 history to survive.
380
+ *
381
+ * Resolves once the host acknowledges (`shutdown-ok`) or the connection
382
+ * closes (the host exited), whichever comes first; never rejects — a host
383
+ * that's already gone is a successful shutdown.
384
+ */
385
+ shutdownHost(timeoutMs?: number): Promise<void>;
369
386
  /** Disconnect WITHOUT killing host ptys (before-quit leave-running). */
370
387
  disconnect(): void;
371
388
  create(opts: CreateTerminalOpts): AttachResult;
@@ -450,6 +467,19 @@ declare function initTerminalBackend(): Promise<{
450
467
  * the host running so the next launch reattaches.
451
468
  */
452
469
  declare function disconnectHostLeaveRunning(): void;
470
+ /**
471
+ * Gracefully STOP the detached host (the opposite of leave-running): ask it to
472
+ * kill its ptys, clean up its pidfile/socket, and exit, then drop our client and
473
+ * revert to the in-process backend so any later create() still works.
474
+ *
475
+ * Intended for the case where a consumer needs the host genuinely gone — most
476
+ * notably before an Electron auto-update whose installer must overwrite the
477
+ * binary the detached host is running on. Snapshot first (the normal before-quit
478
+ * T1 path) if you want history to survive; this is a clean shutdown, NOT a
479
+ * SIGKILL-by-pidfile, so the host runs its own cleanup. No-op (resolves) when no
480
+ * host is active. NEVER throws.
481
+ */
482
+ declare function shutdownHost(timeoutMs?: number): Promise<void>;
453
483
 
454
484
  /**
455
485
  * Absolute path to the bundled detached pty-host script (Tier 3), so a
@@ -544,7 +574,7 @@ declare function resolveHostScript(dirname: string): string | null;
544
574
  * refuses to attach to a host whose pidfile reports a different version and
545
575
  * spawns a fresh host instead — see host-client.ts connect-or-spawn.
546
576
  */
547
- declare const PROTOCOL_VERSION = 1;
577
+ declare const PROTOCOL_VERSION = 2;
548
578
  /** Requests the client sends to the host. `seq` correlates a reply. */
549
579
  type ClientMessage = {
550
580
  kind: 'hello';
@@ -588,6 +618,9 @@ type ClientMessage = {
588
618
  } | {
589
619
  kind: 'ping';
590
620
  seq: number;
621
+ } | {
622
+ kind: 'shutdown';
623
+ seq: number;
591
624
  };
592
625
  /** Pushes + replies the host sends to the client. */
593
626
  type HostMessage = {
@@ -620,6 +653,9 @@ type HostMessage = {
620
653
  } | {
621
654
  kind: 'pong';
622
655
  seq: number;
656
+ } | {
657
+ kind: 'shutdown-ok';
658
+ seq: number;
623
659
  } | {
624
660
  kind: 'data';
625
661
  id: string;
@@ -808,4 +844,4 @@ declare function toNativeCwd(p: string): string;
808
844
  */
809
845
  declare function resolveSpawnCwd(requested: string | undefined | null): string;
810
846
 
811
- export { type AttachResult, type BackendDeps, type ClientMessage, type CreateTerminalOpts, type CwdHook, type Encryptor, type Frame, FrameDecoder, HostClient, type HostMessage, type HostSpawner, type HostStatus, PROTOCOL_VERSION, type Pidfile, type PtyBackend, type SettingsProvider, type ShellInfo, type ShellKind, type SnapshotRead, type SnapshotStore, type SnapshotStoreConfig, type TerminalInfo, type TerminalManager, configureHostLifecycle, configureInProcessBackend, createSnapshotStore, cwdHookEnv, cwdHookSpawn, defaultShell, defaultShellId, deletePidfile, detectShells, disconnectHostLeaveRunning, encodeFrame, getHostClient, inProcessBackend, initTerminalBackend, isHostBacked, isPidAlive, parseCommandLine, parseFileUrl, pidfilePath, pidfileUsable, ptyHostScriptPath, readPidfile, resolveDefaultShell, resolveHostScript, resolveSpawnCwd, scanOsc7Cwd, setActiveBackend, shellKind, socketPathFor, subscribeBackendEvents, terminalManager, toNativeCwd, userHash, writePidfile };
847
+ export { type AttachResult, type BackendDeps, type ClientMessage, type CreateTerminalOpts, type CwdHook, type Encryptor, type Frame, FrameDecoder, HostClient, type HostMessage, type HostSpawner, type HostStatus, PROTOCOL_VERSION, type Pidfile, type PtyBackend, type SettingsProvider, type ShellInfo, type ShellKind, type SnapshotRead, type SnapshotStore, type SnapshotStoreConfig, type TerminalInfo, type TerminalManager, configureHostLifecycle, configureInProcessBackend, createSnapshotStore, cwdHookEnv, cwdHookSpawn, defaultShell, defaultShellId, deletePidfile, detectShells, disconnectHostLeaveRunning, encodeFrame, getHostClient, inProcessBackend, initTerminalBackend, isHostBacked, isPidAlive, parseCommandLine, parseFileUrl, pidfilePath, pidfileUsable, ptyHostScriptPath, readPidfile, resolveDefaultShell, resolveHostScript, resolveSpawnCwd, scanOsc7Cwd, setActiveBackend, shellKind, shutdownHost, socketPathFor, subscribeBackendEvents, terminalManager, toNativeCwd, userHash, writePidfile };
package/dist/index.d.ts CHANGED
@@ -366,6 +366,23 @@ declare class HostClient extends EventEmitter implements PtyBackend {
366
366
  * the reattach (renderer remounts these specs, replaying host scrollback). */
367
367
  liveIds(): string[];
368
368
  isConnected(): boolean;
369
+ /**
370
+ * Gracefully shut the host DOWN — the deliberate counterpart to
371
+ * `disconnect()` (which leaves the host running). Asks the host to kill its
372
+ * ptys, remove its pidfile/socket, and exit cleanly, then drops the local
373
+ * socket. Use this when a consumer needs the host genuinely gone — e.g.
374
+ * before an Electron auto-update whose installer must overwrite the binary
375
+ * the host runs on — INSTEAD of SIGKILLing by pidfile pid, which skips the
376
+ * host's own cleanup.
377
+ *
378
+ * The client mirror already holds the live scrollback, so snapshot via the
379
+ * SnapshotStore BEFORE calling this if you want T1 history to survive.
380
+ *
381
+ * Resolves once the host acknowledges (`shutdown-ok`) or the connection
382
+ * closes (the host exited), whichever comes first; never rejects — a host
383
+ * that's already gone is a successful shutdown.
384
+ */
385
+ shutdownHost(timeoutMs?: number): Promise<void>;
369
386
  /** Disconnect WITHOUT killing host ptys (before-quit leave-running). */
370
387
  disconnect(): void;
371
388
  create(opts: CreateTerminalOpts): AttachResult;
@@ -450,6 +467,19 @@ declare function initTerminalBackend(): Promise<{
450
467
  * the host running so the next launch reattaches.
451
468
  */
452
469
  declare function disconnectHostLeaveRunning(): void;
470
+ /**
471
+ * Gracefully STOP the detached host (the opposite of leave-running): ask it to
472
+ * kill its ptys, clean up its pidfile/socket, and exit, then drop our client and
473
+ * revert to the in-process backend so any later create() still works.
474
+ *
475
+ * Intended for the case where a consumer needs the host genuinely gone — most
476
+ * notably before an Electron auto-update whose installer must overwrite the
477
+ * binary the detached host is running on. Snapshot first (the normal before-quit
478
+ * T1 path) if you want history to survive; this is a clean shutdown, NOT a
479
+ * SIGKILL-by-pidfile, so the host runs its own cleanup. No-op (resolves) when no
480
+ * host is active. NEVER throws.
481
+ */
482
+ declare function shutdownHost(timeoutMs?: number): Promise<void>;
453
483
 
454
484
  /**
455
485
  * Absolute path to the bundled detached pty-host script (Tier 3), so a
@@ -544,7 +574,7 @@ declare function resolveHostScript(dirname: string): string | null;
544
574
  * refuses to attach to a host whose pidfile reports a different version and
545
575
  * spawns a fresh host instead — see host-client.ts connect-or-spawn.
546
576
  */
547
- declare const PROTOCOL_VERSION = 1;
577
+ declare const PROTOCOL_VERSION = 2;
548
578
  /** Requests the client sends to the host. `seq` correlates a reply. */
549
579
  type ClientMessage = {
550
580
  kind: 'hello';
@@ -588,6 +618,9 @@ type ClientMessage = {
588
618
  } | {
589
619
  kind: 'ping';
590
620
  seq: number;
621
+ } | {
622
+ kind: 'shutdown';
623
+ seq: number;
591
624
  };
592
625
  /** Pushes + replies the host sends to the client. */
593
626
  type HostMessage = {
@@ -620,6 +653,9 @@ type HostMessage = {
620
653
  } | {
621
654
  kind: 'pong';
622
655
  seq: number;
656
+ } | {
657
+ kind: 'shutdown-ok';
658
+ seq: number;
623
659
  } | {
624
660
  kind: 'data';
625
661
  id: string;
@@ -808,4 +844,4 @@ declare function toNativeCwd(p: string): string;
808
844
  */
809
845
  declare function resolveSpawnCwd(requested: string | undefined | null): string;
810
846
 
811
- export { type AttachResult, type BackendDeps, type ClientMessage, type CreateTerminalOpts, type CwdHook, type Encryptor, type Frame, FrameDecoder, HostClient, type HostMessage, type HostSpawner, type HostStatus, PROTOCOL_VERSION, type Pidfile, type PtyBackend, type SettingsProvider, type ShellInfo, type ShellKind, type SnapshotRead, type SnapshotStore, type SnapshotStoreConfig, type TerminalInfo, type TerminalManager, configureHostLifecycle, configureInProcessBackend, createSnapshotStore, cwdHookEnv, cwdHookSpawn, defaultShell, defaultShellId, deletePidfile, detectShells, disconnectHostLeaveRunning, encodeFrame, getHostClient, inProcessBackend, initTerminalBackend, isHostBacked, isPidAlive, parseCommandLine, parseFileUrl, pidfilePath, pidfileUsable, ptyHostScriptPath, readPidfile, resolveDefaultShell, resolveHostScript, resolveSpawnCwd, scanOsc7Cwd, setActiveBackend, shellKind, socketPathFor, subscribeBackendEvents, terminalManager, toNativeCwd, userHash, writePidfile };
847
+ export { type AttachResult, type BackendDeps, type ClientMessage, type CreateTerminalOpts, type CwdHook, type Encryptor, type Frame, FrameDecoder, HostClient, type HostMessage, type HostSpawner, type HostStatus, PROTOCOL_VERSION, type Pidfile, type PtyBackend, type SettingsProvider, type ShellInfo, type ShellKind, type SnapshotRead, type SnapshotStore, type SnapshotStoreConfig, type TerminalInfo, type TerminalManager, configureHostLifecycle, configureInProcessBackend, createSnapshotStore, cwdHookEnv, cwdHookSpawn, defaultShell, defaultShellId, deletePidfile, detectShells, disconnectHostLeaveRunning, encodeFrame, getHostClient, inProcessBackend, initTerminalBackend, isHostBacked, isPidAlive, parseCommandLine, parseFileUrl, pidfilePath, pidfileUsable, ptyHostScriptPath, readPidfile, resolveDefaultShell, resolveHostScript, resolveSpawnCwd, scanOsc7Cwd, setActiveBackend, shellKind, shutdownHost, socketPathFor, subscribeBackendEvents, terminalManager, toNativeCwd, userHash, writePidfile };
package/dist/index.js CHANGED
@@ -1,5 +1,8 @@
1
- import { FrameDecoder, PROTOCOL_VERSION, encodeFrame, readPidfile, pidfileUsable, deletePidfile, resolveHostScript, resolveSpawnCwd, toNativeCwd } from './chunk-WMP4YLM5.js';
2
- export { FrameDecoder, PROTOCOL_VERSION, deletePidfile, encodeFrame, isPidAlive, pidfilePath, pidfileUsable, readPidfile, resolveHostScript, resolveSpawnCwd, socketPathFor, toNativeCwd, userHash, writePidfile } from './chunk-WMP4YLM5.js';
1
+ import { resolveSpawnCwd, toNativeCwd } from './chunk-V3MW5UTX.js';
2
+ export { resolveSpawnCwd, toNativeCwd } from './chunk-V3MW5UTX.js';
3
+ export { ptyHostScriptPath } from './chunk-DB3SIE53.js';
4
+ import { FrameDecoder, PROTOCOL_VERSION, encodeFrame, readPidfile, pidfileUsable, deletePidfile } from './chunk-7NXYRMNA.js';
5
+ export { FrameDecoder, PROTOCOL_VERSION, deletePidfile, encodeFrame, isPidAlive, pidfilePath, pidfileUsable, readPidfile, resolveHostScript, socketPathFor, userHash, writePidfile } from './chunk-7NXYRMNA.js';
3
6
  import { spawn } from 'node-pty';
4
7
  import { EventEmitter } from 'events';
5
8
  import fs2 from 'fs';
@@ -8,7 +11,6 @@ import os from 'os';
8
11
  import crypto from 'crypto';
9
12
  import zlib from 'zlib';
10
13
  import net from 'net';
11
- import { fileURLToPath } from 'url';
12
14
 
13
15
  // src/osc7.ts
14
16
  var OSC7_RE = /\x1b\]7;([^\x07\x1b]*)(?:\x07|\x1b\\)/g;
@@ -805,6 +807,42 @@ var HostClient = class _HostClient extends EventEmitter {
805
807
  isConnected() {
806
808
  return this.connected;
807
809
  }
810
+ /**
811
+ * Gracefully shut the host DOWN — the deliberate counterpart to
812
+ * `disconnect()` (which leaves the host running). Asks the host to kill its
813
+ * ptys, remove its pidfile/socket, and exit cleanly, then drops the local
814
+ * socket. Use this when a consumer needs the host genuinely gone — e.g.
815
+ * before an Electron auto-update whose installer must overwrite the binary
816
+ * the host runs on — INSTEAD of SIGKILLing by pidfile pid, which skips the
817
+ * host's own cleanup.
818
+ *
819
+ * The client mirror already holds the live scrollback, so snapshot via the
820
+ * SnapshotStore BEFORE calling this if you want T1 history to survive.
821
+ *
822
+ * Resolves once the host acknowledges (`shutdown-ok`) or the connection
823
+ * closes (the host exited), whichever comes first; never rejects — a host
824
+ * that's already gone is a successful shutdown.
825
+ */
826
+ shutdownHost(timeoutMs = 2e3) {
827
+ if (!this.socket || !this.connected) {
828
+ this.disconnect();
829
+ return Promise.resolve();
830
+ }
831
+ this.connected = false;
832
+ return new Promise((resolve) => {
833
+ let done = false;
834
+ const finish = () => {
835
+ if (done) return;
836
+ done = true;
837
+ clearTimeout(timer);
838
+ this.disconnect();
839
+ resolve();
840
+ };
841
+ const timer = setTimeout(finish, timeoutMs);
842
+ this.socket?.once("close", finish);
843
+ this.request({ kind: "shutdown", seq: this.nextSeq() }).then(finish).catch(finish);
844
+ });
845
+ }
808
846
  /** Disconnect WITHOUT killing host ptys (before-quit leave-running). */
809
847
  disconnect() {
810
848
  this.connected = false;
@@ -1009,11 +1047,18 @@ function disconnectHostLeaveRunning() {
1009
1047
  }
1010
1048
  }
1011
1049
  }
1012
- function ptyHostScriptPath() {
1013
- const here = typeof __dirname !== "undefined" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
1014
- return resolveHostScript(here) ?? path.join(here, "pty-host.js");
1050
+ async function shutdownHost(timeoutMs = 2e3) {
1051
+ const c = client;
1052
+ usingHost = false;
1053
+ client = null;
1054
+ setActiveBackend(inProcessBackend());
1055
+ if (!c) return;
1056
+ try {
1057
+ await c.shutdownHost(timeoutMs);
1058
+ } catch {
1059
+ }
1015
1060
  }
1016
1061
 
1017
- export { HostClient, configureHostLifecycle, configureInProcessBackend, createSnapshotStore, cwdHookEnv, cwdHookSpawn, defaultShell, defaultShellId, detectShells, disconnectHostLeaveRunning, getHostClient, inProcessBackend, initTerminalBackend, isHostBacked, parseCommandLine, parseFileUrl, ptyHostScriptPath, resolveDefaultShell, scanOsc7Cwd, setActiveBackend, shellKind, subscribeBackendEvents, terminalManager };
1062
+ export { HostClient, configureHostLifecycle, configureInProcessBackend, createSnapshotStore, cwdHookEnv, cwdHookSpawn, defaultShell, defaultShellId, detectShells, disconnectHostLeaveRunning, getHostClient, inProcessBackend, initTerminalBackend, isHostBacked, parseCommandLine, parseFileUrl, resolveDefaultShell, scanOsc7Cwd, setActiveBackend, shellKind, shutdownHost, subscribeBackendEvents, terminalManager };
1018
1063
  //# sourceMappingURL=index.js.map
1019
1064
  //# sourceMappingURL=index.js.map