@vibesdotdev/terminal-client 0.0.0-stage → 1.0.0-rc.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.
Files changed (195) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +102 -2
  3. package/dist/ansi/index.d.ts +11 -0
  4. package/dist/ansi/index.d.ts.map +1 -0
  5. package/dist/ansi/index.js +11 -0
  6. package/dist/ansi/index.js.map +1 -0
  7. package/dist/ansi/keymap.d.ts +77 -0
  8. package/dist/ansi/keymap.d.ts.map +1 -0
  9. package/dist/ansi/keymap.js +257 -0
  10. package/dist/ansi/keymap.js.map +1 -0
  11. package/dist/api-client-plugin.d.ts +4 -0
  12. package/dist/api-client-plugin.d.ts.map +1 -0
  13. package/dist/api-client-plugin.js +16 -0
  14. package/dist/api-client-plugin.js.map +1 -0
  15. package/dist/client/http-session.d.ts +44 -0
  16. package/dist/client/http-session.d.ts.map +1 -0
  17. package/dist/client/http-session.js +457 -0
  18. package/dist/client/http-session.js.map +1 -0
  19. package/dist/client/index.d.ts +8 -0
  20. package/dist/client/index.d.ts.map +1 -0
  21. package/dist/client/index.js +8 -0
  22. package/dist/client/index.js.map +1 -0
  23. package/dist/client.d.ts +56 -0
  24. package/dist/client.d.ts.map +1 -0
  25. package/dist/client.js +169 -0
  26. package/dist/client.js.map +1 -0
  27. package/dist/index.d.ts +14 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +14 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/pty-bridge/index.d.ts +15 -0
  32. package/dist/pty-bridge/index.d.ts.map +1 -0
  33. package/dist/pty-bridge/index.js +15 -0
  34. package/dist/pty-bridge/index.js.map +1 -0
  35. package/dist/pty-bridge/protocol.d.ts +6 -0
  36. package/dist/pty-bridge/protocol.d.ts.map +1 -0
  37. package/dist/pty-bridge/protocol.js +6 -0
  38. package/dist/pty-bridge/protocol.js.map +1 -0
  39. package/dist/pty-bridge/server.d.ts +7 -0
  40. package/dist/pty-bridge/server.d.ts.map +1 -0
  41. package/dist/pty-bridge/server.js +9 -0
  42. package/dist/pty-bridge/server.js.map +1 -0
  43. package/dist/remote-session.d.ts +51 -0
  44. package/dist/remote-session.d.ts.map +1 -0
  45. package/dist/remote-session.js +326 -0
  46. package/dist/remote-session.js.map +1 -0
  47. package/dist/schemas/http.d.ts +61 -0
  48. package/dist/schemas/http.d.ts.map +1 -0
  49. package/dist/schemas/http.js +45 -0
  50. package/dist/schemas/http.js.map +1 -0
  51. package/dist/schemas/remote.d.ts +25 -0
  52. package/dist/schemas/remote.d.ts.map +1 -0
  53. package/dist/schemas/remote.js +23 -0
  54. package/dist/schemas/remote.js.map +1 -0
  55. package/dist/schemas/session.d.ts +26 -0
  56. package/dist/schemas/session.d.ts.map +1 -0
  57. package/dist/schemas/session.js +17 -0
  58. package/dist/schemas/session.js.map +1 -0
  59. package/dist/schemas/store.d.ts +29 -0
  60. package/dist/schemas/store.d.ts.map +1 -0
  61. package/dist/schemas/store.js +22 -0
  62. package/dist/schemas/store.js.map +1 -0
  63. package/dist/schemas/terminal.d.ts +296 -0
  64. package/dist/schemas/terminal.d.ts.map +1 -0
  65. package/dist/schemas/terminal.js +243 -0
  66. package/dist/schemas/terminal.js.map +1 -0
  67. package/dist/server/index.d.ts +9 -0
  68. package/dist/server/index.d.ts.map +1 -0
  69. package/dist/server/index.js +9 -0
  70. package/dist/server/index.js.map +1 -0
  71. package/dist/server/session-store.d.ts +176 -0
  72. package/dist/server/session-store.d.ts.map +1 -0
  73. package/dist/server/session-store.js +462 -0
  74. package/dist/server/session-store.js.map +1 -0
  75. package/dist/server/sse-stream.d.ts +32 -0
  76. package/dist/server/sse-stream.d.ts.map +1 -0
  77. package/dist/server/sse-stream.js +87 -0
  78. package/dist/server/sse-stream.js.map +1 -0
  79. package/dist/svelte/HostPicker.svelte +256 -0
  80. package/dist/svelte/HostPicker.svelte.d.ts +30 -0
  81. package/dist/svelte/HostPicker.svelte.d.ts.map +1 -0
  82. package/dist/svelte/README.md +52 -0
  83. package/dist/svelte/ReconnectBanner.svelte +88 -0
  84. package/dist/svelte/ReconnectBanner.svelte.d.ts +16 -0
  85. package/dist/svelte/ReconnectBanner.svelte.d.ts.map +1 -0
  86. package/dist/svelte/SessionTabs.svelte +192 -0
  87. package/dist/svelte/SessionTabs.svelte.d.ts +17 -0
  88. package/dist/svelte/SessionTabs.svelte.d.ts.map +1 -0
  89. package/dist/svelte/Terminal.svelte +567 -0
  90. package/dist/svelte/Terminal.svelte.d.ts +25 -0
  91. package/dist/svelte/Terminal.svelte.d.ts.map +1 -0
  92. package/dist/svelte/TerminalMobileToolbar.svelte +56 -0
  93. package/dist/svelte/TerminalMobileToolbar.svelte.d.ts +14 -0
  94. package/dist/svelte/TerminalMobileToolbar.svelte.d.ts.map +1 -0
  95. package/dist/svelte/TerminalWorkspace.svelte +562 -0
  96. package/dist/svelte/TerminalWorkspace.svelte.d.ts +25 -0
  97. package/dist/svelte/TerminalWorkspace.svelte.d.ts.map +1 -0
  98. package/dist/svelte/ambient.d.ts +9 -0
  99. package/dist/svelte/docs/terminal-svelte.docs.descriptor.d.ts +4 -0
  100. package/dist/svelte/docs/terminal-svelte.docs.descriptor.d.ts.map +1 -0
  101. package/dist/svelte/docs/terminal-svelte.docs.descriptor.js +74 -0
  102. package/dist/svelte/index.d.ts +27 -0
  103. package/dist/svelte/index.d.ts.map +1 -0
  104. package/dist/svelte/index.js +26 -0
  105. package/dist/svelte/styles.css +8 -0
  106. package/dist/svelte/terminal-session-authority.d.ts +17 -0
  107. package/dist/svelte/terminal-session-authority.d.ts.map +1 -0
  108. package/dist/svelte/terminal-session-authority.js +25 -0
  109. package/dist/svelte/terminal-svelte.plugin.d.ts +19 -0
  110. package/dist/svelte/terminal-svelte.plugin.d.ts.map +1 -0
  111. package/dist/svelte/terminal-svelte.plugin.js +42 -0
  112. package/dist/svelte/terminal-theme.d.ts +11 -0
  113. package/dist/svelte/terminal-theme.d.ts.map +1 -0
  114. package/dist/svelte/terminal-theme.js +116 -0
  115. package/dist/svelte/tool-widgets/TerminalToolCard.svelte +65 -0
  116. package/dist/svelte/tool-widgets/TerminalToolCard.svelte.d.ts +5 -0
  117. package/dist/svelte/tool-widgets/TerminalToolCard.svelte.d.ts.map +1 -0
  118. package/dist/svelte/tool-widgets/terminal-tool-card.d.ts +25 -0
  119. package/dist/svelte/tool-widgets/terminal-tool-card.d.ts.map +1 -0
  120. package/dist/svelte/tool-widgets/terminal-tool-card.js +116 -0
  121. package/dist/svelte/types.d.ts +160 -0
  122. package/dist/svelte/types.d.ts.map +1 -0
  123. package/dist/svelte/types.js +51 -0
  124. package/dist/svelte/workspace.d.ts +3 -0
  125. package/dist/svelte/workspace.d.ts.map +1 -0
  126. package/dist/svelte/workspace.js +2 -0
  127. package/dist/terminal-client.plugin.d.ts +3 -0
  128. package/dist/terminal-client.plugin.d.ts.map +1 -0
  129. package/dist/terminal-client.plugin.js +3 -0
  130. package/dist/terminal-client.plugin.js.map +1 -0
  131. package/dist/terminal-runtime.d.ts +30 -0
  132. package/dist/terminal-runtime.d.ts.map +1 -0
  133. package/dist/terminal-runtime.js +673 -0
  134. package/dist/terminal-runtime.js.map +1 -0
  135. package/dist/terminal.consumer.plugin.d.ts +14 -0
  136. package/dist/terminal.consumer.plugin.d.ts.map +1 -0
  137. package/dist/terminal.consumer.plugin.js +31 -0
  138. package/dist/terminal.consumer.plugin.js.map +1 -0
  139. package/dist/tools/terminal.impl.consumer.d.ts +11 -0
  140. package/dist/tools/terminal.impl.consumer.d.ts.map +1 -0
  141. package/dist/tools/terminal.impl.consumer.js +20 -0
  142. package/dist/tools/terminal.impl.consumer.js.map +1 -0
  143. package/dist/tools/terminal.schemas.d.ts +3 -0
  144. package/dist/tools/terminal.schemas.d.ts.map +1 -0
  145. package/dist/tools/terminal.schemas.js +3 -0
  146. package/dist/tools/terminal.schemas.js.map +1 -0
  147. package/dist/tools/terminal.unified.descriptor.d.ts +218 -0
  148. package/dist/tools/terminal.unified.descriptor.d.ts.map +1 -0
  149. package/dist/tools/terminal.unified.descriptor.js +36 -0
  150. package/dist/tools/terminal.unified.descriptor.js.map +1 -0
  151. package/dist/tui/index.d.ts +9 -0
  152. package/dist/tui/index.d.ts.map +1 -0
  153. package/dist/tui/index.js +8 -0
  154. package/dist/tui/index.js.map +1 -0
  155. package/dist/tui/terminal-open.descriptor.d.ts +9 -0
  156. package/dist/tui/terminal-open.descriptor.d.ts.map +1 -0
  157. package/dist/tui/terminal-open.descriptor.js +18 -0
  158. package/dist/tui/terminal-open.descriptor.js.map +1 -0
  159. package/dist/tui/terminal-open.impl.consumer.d.ts +9 -0
  160. package/dist/tui/terminal-open.impl.consumer.d.ts.map +1 -0
  161. package/dist/tui/terminal-open.impl.consumer.js +13 -0
  162. package/dist/tui/terminal-open.impl.consumer.js.map +1 -0
  163. package/dist/tui/terminal-registry.descriptor.d.ts +11 -0
  164. package/dist/tui/terminal-registry.descriptor.d.ts.map +1 -0
  165. package/dist/tui/terminal-registry.descriptor.js +17 -0
  166. package/dist/tui/terminal-registry.descriptor.js.map +1 -0
  167. package/dist/tui/terminal-registry.impl.consumer.d.ts +71 -0
  168. package/dist/tui/terminal-registry.impl.consumer.d.ts.map +1 -0
  169. package/dist/tui/terminal-registry.impl.consumer.js +190 -0
  170. package/dist/tui/terminal-registry.impl.consumer.js.map +1 -0
  171. package/dist/tui/terminal-tui.plugin.d.ts +10 -0
  172. package/dist/tui/terminal-tui.plugin.d.ts.map +1 -0
  173. package/dist/tui/terminal-tui.plugin.js +32 -0
  174. package/dist/tui/terminal-tui.plugin.js.map +1 -0
  175. package/dist/tui/terminal.descriptor.d.ts +10 -0
  176. package/dist/tui/terminal.descriptor.d.ts.map +1 -0
  177. package/dist/tui/terminal.descriptor.js +25 -0
  178. package/dist/tui/terminal.descriptor.js.map +1 -0
  179. package/dist/tui/terminal.impl.consumer.d.ts +14 -0
  180. package/dist/tui/terminal.impl.consumer.d.ts.map +1 -0
  181. package/dist/tui/terminal.impl.consumer.js +189 -0
  182. package/dist/tui/terminal.impl.consumer.js.map +1 -0
  183. package/dist/tui/terminal.state-key.d.ts +30 -0
  184. package/dist/tui/terminal.state-key.d.ts.map +1 -0
  185. package/dist/tui/terminal.state-key.js +9 -0
  186. package/dist/tui/terminal.state-key.js.map +1 -0
  187. package/dist/tui/terminal.state.d.ts +152 -0
  188. package/dist/tui/terminal.state.d.ts.map +1 -0
  189. package/dist/tui/terminal.state.js +149 -0
  190. package/dist/tui/terminal.state.js.map +1 -0
  191. package/dist/workspace.d.ts +155 -0
  192. package/dist/workspace.d.ts.map +1 -0
  193. package/dist/workspace.js +292 -0
  194. package/dist/workspace.js.map +1 -0
  195. package/package.json +228 -4
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @vibesdotdev/terminal-client — shared server-side session store.
3
+ *
4
+ * An in-memory map of live PTY sessions paired with ownership metadata and a
5
+ * backlog ring (for SSE late-attach replay). The store is transport-agnostic: the
6
+ * caller supplies an `opener` function that resolves a real `ExecutionSession` from
7
+ * whatever source is appropriate for its surface:
8
+ *
9
+ * - hq-web passes `openRemoteSession(runtime, hostRef, opts)` — the session rides
10
+ * L4's `runtime/rpc` to a fleet host.
11
+ * - consumer-hq passes `openLocalSession(runtime, opts)` — the session is a direct
12
+ * Bun PTY on this machine.
13
+ *
14
+ * The rest of the store — ownership enforcement, backlog capture, eviction on exit,
15
+ * and the write verbs — is identical regardless of transport and lives here once.
16
+ *
17
+ * ### Detach vs. kill
18
+ *
19
+ * A browser tab close must NOT kill the PTY — the underlying shell keeps running
20
+ * so the user can re-attach. `detachSession()` records a last-active timestamp and
21
+ * removes the tab's SSE subscription without touching the PTY. The PTY is ONLY torn
22
+ * down by an explicit `killSession()` or when the idle timeout fires.
23
+ *
24
+ * ### Idle timeout
25
+ *
26
+ * When a stored session has no active SSE subscriber AND its `lastActiveMs` is
27
+ * older than `idleTimeoutMs` (default: 30 min), the reaper kills it and evicts it.
28
+ * The reaper runs every `reaperIntervalMs` (default: 60 s).
29
+ *
30
+ * ### maxSessions
31
+ *
32
+ * `openSession` rejects with `{ reason: 'MAX_SESSIONS' }` when the owner already
33
+ * has `maxSessions` (or more) active sessions, before opening a new PTY. The
34
+ * caller surfaces this as a user-readable error.
35
+ *
36
+ * SERVER-ONLY. Import only from `+server.ts` files or `$lib/server/**`.
37
+ */
38
+ import { CapabilityError, type RuntimeLifecycle, type RuntimeScope } from '@vibesdotdev/kernel';
39
+ /** The slice of the runtime the store needs: lifecycle-owned timers only. */
40
+ export type TerminalSessionStoreRuntime = {
41
+ lifecycle: Pick<RuntimeLifecycle, 'interval' | 'timeout' | 'now'>;
42
+ scope: Pick<RuntimeScope, 'lifecycle'>;
43
+ };
44
+ import type { ExecutionSession } from '../client.ts';
45
+ /**
46
+ * Options forwarded to the opener function. A superset of the session options
47
+ * both local and remote openers share.
48
+ */
49
+ export { SessionOpenOptionsSchema, type SessionOpenOptions } from '../schemas/session.ts';
50
+ import { type SessionOpenOptions } from '../schemas/session.ts';
51
+ import { type TerminalSessionStoreOptions } from '../schemas/store.ts';
52
+ export { TerminalSessionStoreOptionsSchema, type TerminalSessionStoreOptions } from '../schemas/store.ts';
53
+ /**
54
+ * A function that opens a real `ExecutionSession`. Supplied by each surface so
55
+ * the store never imports surface-specific deps (remote RPC for hq-web; local
56
+ * PTY for consumer-hq).
57
+ */
58
+ export type { SessionOpener } from '../schemas/store.ts';
59
+ import { type SessionOpener } from '../schemas/store.ts';
60
+ /**
61
+ * Typed rejection reason returned by `openSession` when the owner is at their
62
+ * session cap. This lets the API route surface a human-readable denial.
63
+ */
64
+ export type SessionOpenError = CapabilityError;
65
+ /**
66
+ * Session metadata exposed for the wave-2 tabs UI and the GET sessions list.
67
+ * Wire-format backward compatible (additive only).
68
+ */
69
+ export interface SessionMetadata {
70
+ id: string;
71
+ ownerId: string;
72
+ command: string;
73
+ startedAt: number;
74
+ /** true when no SSE subscriber is currently attached. */
75
+ detached: boolean;
76
+ exited: boolean;
77
+ }
78
+ export interface StoredSession {
79
+ session: ExecutionSession;
80
+ /** The user that opened this session — only its owner may drive/read it. */
81
+ ownerId: string;
82
+ /** Ring buffer of recent output so a late-attaching SSE stream sees scrollback. */
83
+ backlog: Uint8Array[];
84
+ exited: boolean;
85
+ /** Typed failure retained when the session ended abnormally. */
86
+ exitFailure?: CapabilityError;
87
+ /** Command used to open this session — for metadata / list display. */
88
+ command: string;
89
+ /** Unix ms when the session was opened. */
90
+ startedAt: number;
91
+ /**
92
+ * Unix ms of the last SSE subscriber detach (or session open if never detached).
93
+ * Used by the idle reaper.
94
+ */
95
+ lastActiveMs: number;
96
+ /**
97
+ * Count of currently attached SSE subscribers. The session is "detached" when
98
+ * this drops to zero — the PTY keeps running; only a kill or idle timeout ends it.
99
+ */
100
+ subscriberCount: number;
101
+ /** Stop capturing output after terminal cleanup. */
102
+ unsubscribeOutput: () => void;
103
+ }
104
+ export interface TerminalSessionStore {
105
+ /**
106
+ * Open a new session via the supplied opener and register it in the store,
107
+ * keyed by the resolved session id and tagged with the given ownerId.
108
+ *
109
+ * Ownership enforcement: only the user that opened a session may later
110
+ * drive or read it (`getOwnedSession` treats a mismatch as "not found").
111
+ *
112
+ * Throws `SessionOpenError` when `maxSessions` is exceeded.
113
+ */
114
+ openSession(ownerId: string, opts: SessionOpenOptions, opener?: SessionOpener): Promise<{
115
+ id: string;
116
+ }>;
117
+ /**
118
+ * Return the stored session only if it belongs to `ownerId`. A mismatch is
119
+ * treated as "not found" so the bridge never leaks another user's PTY.
120
+ */
121
+ getOwnedSession(id: string, ownerId: string): StoredSession | undefined;
122
+ writeToSession(id: string, ownerId: string, data: Uint8Array): boolean;
123
+ resizeSession(id: string, ownerId: string, cols: number, rows: number): boolean;
124
+ signalSession(id: string, ownerId: string, sig: string): boolean;
125
+ /**
126
+ * Refresh a session's idle clock to now. Called by the tool surface after a
127
+ * successful owned-session operation (write/read/resize) so an actively
128
+ * driven but SSE-unattached session is not reaped as idle. Returns false
129
+ * (no-op) when the session is missing, not owned, or already exited.
130
+ */
131
+ touchSession(id: string, ownerId: string): boolean;
132
+ /**
133
+ * Whether a session id is still tracked by the store (owner-agnostic).
134
+ * Lets consumers garbage-collect side tables keyed by session id once a
135
+ * session has been killed, exited, or idle-reaped.
136
+ */
137
+ hasSession(id: string): boolean;
138
+ /**
139
+ * Kill and evict the session. Explicit — the PTY is torn down immediately.
140
+ * This is what the "Kill session" UI button calls. NOT what browser tab close
141
+ * calls — use `detachSession` for that.
142
+ */
143
+ killSession(id: string, ownerId: string): boolean;
144
+ /**
145
+ * Detach an SSE subscriber without killing the PTY.
146
+ *
147
+ * Call when a browser tab closes or an SSE connection drops. The PTY keeps
148
+ * running. The session is eligible for idle eviction if no other subscriber
149
+ * re-attaches within `idleTimeoutMs`.
150
+ *
151
+ * Returns true when a session was found and detached; false when not found
152
+ * (already killed, wrong owner, etc.).
153
+ */
154
+ detachSession(id: string, ownerId: string): boolean;
155
+ /**
156
+ * Increment the subscriber count for a session (called when an SSE stream
157
+ * attaches). Clears the idle-eviction clock while a subscriber is present.
158
+ */
159
+ attachSession(id: string, ownerId: string): boolean;
160
+ /**
161
+ * List metadata for all sessions owned by `ownerId`. Used by the wave-2 tabs
162
+ * UI and the GET /api/sessions endpoint. Wire format: additive only.
163
+ */
164
+ listSessions(ownerId: string): SessionMetadata[];
165
+ /** Tear down the idle reaper (test teardown / graceful shutdown). */
166
+ dispose(): Promise<void>;
167
+ }
168
+ /**
169
+ * Create an isolated session store bound to the given opener.
170
+ *
171
+ * Call once at module scope (e.g. at the top of `$lib/server/terminal-store.ts`)
172
+ * so the store survives across requests within a single server process.
173
+ */
174
+ export declare function createTerminalSessionStore(runtime: TerminalSessionStoreRuntime, options?: TerminalSessionStoreOptions): TerminalSessionStore;
175
+ export declare function createTerminalSessionStore(runtime: TerminalSessionStoreRuntime, opener: SessionOpener, options?: TerminalSessionStoreOptions): TerminalSessionStore;
176
+ //# sourceMappingURL=session-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/server/session-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,462 @@
1
+ /**
2
+ * @vibesdotdev/terminal-client — shared server-side session store.
3
+ *
4
+ * An in-memory map of live PTY sessions paired with ownership metadata and a
5
+ * backlog ring (for SSE late-attach replay). The store is transport-agnostic: the
6
+ * caller supplies an `opener` function that resolves a real `ExecutionSession` from
7
+ * whatever source is appropriate for its surface:
8
+ *
9
+ * - hq-web passes `openRemoteSession(runtime, hostRef, opts)` — the session rides
10
+ * L4's `runtime/rpc` to a fleet host.
11
+ * - consumer-hq passes `openLocalSession(runtime, opts)` — the session is a direct
12
+ * Bun PTY on this machine.
13
+ *
14
+ * The rest of the store — ownership enforcement, backlog capture, eviction on exit,
15
+ * and the write verbs — is identical regardless of transport and lives here once.
16
+ *
17
+ * ### Detach vs. kill
18
+ *
19
+ * A browser tab close must NOT kill the PTY — the underlying shell keeps running
20
+ * so the user can re-attach. `detachSession()` records a last-active timestamp and
21
+ * removes the tab's SSE subscription without touching the PTY. The PTY is ONLY torn
22
+ * down by an explicit `killSession()` or when the idle timeout fires.
23
+ *
24
+ * ### Idle timeout
25
+ *
26
+ * When a stored session has no active SSE subscriber AND its `lastActiveMs` is
27
+ * older than `idleTimeoutMs` (default: 30 min), the reaper kills it and evicts it.
28
+ * The reaper runs every `reaperIntervalMs` (default: 60 s).
29
+ *
30
+ * ### maxSessions
31
+ *
32
+ * `openSession` rejects with `{ reason: 'MAX_SESSIONS' }` when the owner already
33
+ * has `maxSessions` (or more) active sessions, before opening a new PTY. The
34
+ * caller surfaces this as a user-readable error.
35
+ *
36
+ * SERVER-ONLY. Import only from `+server.ts` files or `$lib/server/**`.
37
+ */
38
+ import { CapabilityError, CaughtFailureSchema, isCapabilityError } from '@vibesdotdev/kernel';
39
+ import * as z from 'zod/v4';
40
+ // ---------------------------------------------------------------------------
41
+ // Public option types
42
+ // ---------------------------------------------------------------------------
43
+ /**
44
+ * Options forwarded to the opener function. A superset of the session options
45
+ * both local and remote openers share.
46
+ */
47
+ export { SessionOpenOptionsSchema } from "../schemas/session.js";
48
+ import { SessionOpenOptionsSchema } from "../schemas/session.js";
49
+ import { TerminalSessionStoreOptionsSchema } from "../schemas/store.js";
50
+ export { TerminalSessionStoreOptionsSchema } from "../schemas/store.js";
51
+ import { SessionOpenerSchema, ExecutionSessionSchema, SessionIdentitySchema, ResizeSchema, SignalSchema } from "../schemas/store.js";
52
+ function captureCleanupFailure(operation) {
53
+ try {
54
+ operation();
55
+ return null;
56
+ }
57
+ catch (cause) {
58
+ return CaughtFailureSchema.parse(cause);
59
+ }
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // Store factory options
63
+ // ---------------------------------------------------------------------------
64
+ // ---------------------------------------------------------------------------
65
+ // Store factory (one per surface module — no shared global across apps)
66
+ // ---------------------------------------------------------------------------
67
+ const MAX_BACKLOG = 256;
68
+ export function createTerminalSessionStore(runtime, openerOrOptions, providedOptions = {}) {
69
+ let openerCandidate;
70
+ try {
71
+ openerCandidate = SessionOpenerSchema.safeParse(openerOrOptions);
72
+ }
73
+ catch (cause) {
74
+ throw new CapabilityError('The terminal session store configuration is invalid.', 'INVALID_INPUT', {
75
+ reason: 'terminal-session-store-options-invalid',
76
+ retryable: false,
77
+ cause
78
+ });
79
+ }
80
+ const defaultOpener = openerCandidate.success ? openerCandidate.data : undefined;
81
+ const optionsInput = openerCandidate.success ? providedOptions : (openerOrOptions ?? {});
82
+ let options;
83
+ try {
84
+ options = TerminalSessionStoreOptionsSchema.parse(optionsInput);
85
+ }
86
+ catch (cause) {
87
+ throw new CapabilityError('The terminal session store configuration is invalid.', 'INVALID_INPUT', {
88
+ reason: 'terminal-session-store-options-invalid',
89
+ retryable: false,
90
+ cause
91
+ });
92
+ }
93
+ const maxSessions = options.maxSessions;
94
+ const idleTimeoutMs = options.idleTimeoutMs;
95
+ const reaperIntervalMs = options.reaperIntervalMs;
96
+ const sessions = new Map();
97
+ const pendingByOwner = new Map();
98
+ const evictionTimers = new Set();
99
+ let disposed = false;
100
+ let disposal;
101
+ // ---------------------------------------------------------------------------
102
+ // Idle reaper — runs every `reaperIntervalMs`, evicts sessions that have been
103
+ // detached (subscriberCount === 0) for longer than `idleTimeoutMs`.
104
+ // ---------------------------------------------------------------------------
105
+ const reap = () => {
106
+ const now = runtime.lifecycle.now();
107
+ const failures = [];
108
+ for (const [id, stored] of sessions) {
109
+ if (stored.exited)
110
+ continue;
111
+ if (stored.subscriberCount > 0)
112
+ continue;
113
+ if (now - stored.lastActiveMs >= idleTimeoutMs) {
114
+ const failure = captureCleanupFailure(() => stored.session.kill());
115
+ if (failure) {
116
+ failures.push(failure);
117
+ continue;
118
+ }
119
+ stored.exited = true;
120
+ stored.unsubscribeOutput();
121
+ sessions.delete(id);
122
+ }
123
+ }
124
+ if (failures.length === 1)
125
+ throw failures[0];
126
+ if (failures.length > 1)
127
+ throw new AggregateError(failures, 'Idle terminal cleanup failed.');
128
+ };
129
+ // A finite host (one CLI invocation) starts no autonomous background work:
130
+ // the lifecycle refuses the interval, and its sessions end with the
131
+ // invocation, so there is nothing to reap. Any other refusal propagates.
132
+ const disposeReaper = runtime.scope.lifecycle === 'finite'
133
+ ? () => { }
134
+ : runtime.lifecycle.interval(reap, reaperIntervalMs);
135
+ // ---------------------------------------------------------------------------
136
+ // Internal helpers
137
+ // ---------------------------------------------------------------------------
138
+ function countActiveSessions(ownerId) {
139
+ let count = 0;
140
+ for (const stored of sessions.values()) {
141
+ if (stored.ownerId === ownerId && !stored.exited)
142
+ count++;
143
+ }
144
+ return count;
145
+ }
146
+ function scheduleEviction(id) {
147
+ let cancel = () => { };
148
+ cancel = runtime.lifecycle.timeout(() => {
149
+ evictionTimers.delete(cancel);
150
+ const stored = sessions.get(id);
151
+ stored?.unsubscribeOutput();
152
+ sessions.delete(id);
153
+ }, 5_000);
154
+ evictionTimers.add(cancel);
155
+ }
156
+ function admitIdentity(input) {
157
+ try {
158
+ return SessionIdentitySchema.parse(input);
159
+ }
160
+ catch (cause) {
161
+ throw new CapabilityError('The terminal session identity is invalid.', 'INVALID_INPUT', {
162
+ reason: 'terminal-session-identity-invalid',
163
+ retryable: false,
164
+ cause
165
+ });
166
+ }
167
+ }
168
+ // ---------------------------------------------------------------------------
169
+ // Public methods
170
+ // ---------------------------------------------------------------------------
171
+ async function openSession(ownerIdInput, optsInput, requestOpener) {
172
+ if (disposed) {
173
+ throw new CapabilityError('The terminal session store is disposed.', 'CONFLICT', {
174
+ reason: 'terminal-session-store-disposed',
175
+ retryable: false
176
+ });
177
+ }
178
+ let ownerId;
179
+ let opts;
180
+ try {
181
+ ownerId = SessionIdentitySchema.parse(ownerIdInput);
182
+ opts = SessionOpenOptionsSchema.parse(optsInput);
183
+ }
184
+ catch (cause) {
185
+ throw new CapabilityError('The terminal session request is invalid.', 'INVALID_INPUT', {
186
+ reason: 'terminal-session-request-invalid',
187
+ retryable: false,
188
+ cause
189
+ });
190
+ }
191
+ const opener = requestOpener ?? defaultOpener;
192
+ if (!opener) {
193
+ throw new CapabilityError('The terminal session opener is unavailable.', 'UNAVAILABLE', {
194
+ reason: 'terminal-session-opener-missing',
195
+ retryable: false
196
+ });
197
+ }
198
+ let admittedOpener;
199
+ try {
200
+ admittedOpener = SessionOpenerSchema.parse(opener);
201
+ }
202
+ catch (cause) {
203
+ throw new CapabilityError('The terminal session opener is invalid.', 'INVALID_INPUT', {
204
+ reason: 'terminal-session-opener-invalid',
205
+ retryable: false,
206
+ cause
207
+ });
208
+ }
209
+ // maxSessions enforcement: reject before opening the PTY.
210
+ let reserved = false;
211
+ if (maxSessions > 0) {
212
+ const current = countActiveSessions(ownerId) + (pendingByOwner.get(ownerId) ?? 0);
213
+ if (current >= maxSessions) {
214
+ throw new CapabilityError('The terminal session limit has been reached.', 'RATE_LIMITED', {
215
+ reason: 'MAX_SESSIONS',
216
+ retryable: true,
217
+ details: { current, max: maxSessions }
218
+ });
219
+ }
220
+ pendingByOwner.set(ownerId, (pendingByOwner.get(ownerId) ?? 0) + 1);
221
+ reserved = true;
222
+ }
223
+ let session;
224
+ try {
225
+ session = ExecutionSessionSchema.parse(await admittedOpener(opts));
226
+ }
227
+ catch (cause) {
228
+ const failure = CaughtFailureSchema.parse(cause);
229
+ if (isCapabilityError(failure))
230
+ throw failure;
231
+ throw new CapabilityError('The terminal session could not be opened.', 'UNAVAILABLE', {
232
+ reason: 'terminal-session-open-failed',
233
+ retryable: true,
234
+ cause: failure
235
+ });
236
+ }
237
+ finally {
238
+ if (reserved) {
239
+ const pending = (pendingByOwner.get(ownerId) ?? 1) - 1;
240
+ if (pending > 0)
241
+ pendingByOwner.set(ownerId, pending);
242
+ else
243
+ pendingByOwner.delete(ownerId);
244
+ }
245
+ }
246
+ if (disposed) {
247
+ session.kill();
248
+ await session.exited();
249
+ throw new CapabilityError('The terminal session store was disposed while opening.', 'CANCELLED', {
250
+ reason: 'terminal-session-open-cancelled',
251
+ retryable: false
252
+ });
253
+ }
254
+ if (sessions.has(session.id)) {
255
+ session.kill();
256
+ await session.exited();
257
+ throw new CapabilityError('The terminal session id is already active.', 'CONFLICT', {
258
+ reason: 'terminal-session-id-conflict',
259
+ retryable: false
260
+ });
261
+ }
262
+ const now = runtime.lifecycle.now();
263
+ const stored = {
264
+ session,
265
+ ownerId,
266
+ backlog: [],
267
+ exited: false,
268
+ command: opts.command,
269
+ startedAt: now,
270
+ lastActiveMs: now,
271
+ subscriberCount: 0,
272
+ unsubscribeOutput: () => { }
273
+ };
274
+ sessions.set(session.id, stored);
275
+ // Capture output into the backlog ring so a slightly-late SSE attach
276
+ // replays what already happened (e.g. the shell prompt). Cap to bound memory.
277
+ stored.unsubscribeOutput = session.onOutput((bytes) => {
278
+ stored.backlog.push(new Uint8Array(bytes));
279
+ if (stored.backlog.length > MAX_BACKLOG)
280
+ stored.backlog.shift();
281
+ });
282
+ void session.exited()
283
+ .then(() => ({ kind: 'exit' }), (cause) => ({
284
+ kind: 'failure',
285
+ failure: CapabilityError.from(CaughtFailureSchema.parse(cause))
286
+ }))
287
+ .then((outcome) => {
288
+ stored.exited = true;
289
+ if (outcome.kind === 'failure')
290
+ stored.exitFailure = outcome.failure;
291
+ stored.unsubscribeOutput();
292
+ if (disposed)
293
+ sessions.delete(session.id);
294
+ else
295
+ scheduleEviction(session.id);
296
+ });
297
+ return { id: session.id };
298
+ }
299
+ function getOwnedSession(idInput, ownerIdInput) {
300
+ const id = admitIdentity(idInput);
301
+ const ownerId = admitIdentity(ownerIdInput);
302
+ const stored = sessions.get(id);
303
+ if (!stored || stored.ownerId !== ownerId)
304
+ return undefined;
305
+ return stored;
306
+ }
307
+ function writeToSession(id, ownerId, data) {
308
+ const stored = getOwnedSession(id, ownerId);
309
+ if (!stored || stored.exited)
310
+ return false;
311
+ let copied;
312
+ try {
313
+ copied = new Uint8Array(data);
314
+ }
315
+ catch (cause) {
316
+ throw new CapabilityError('The terminal input bytes are invalid.', 'INVALID_INPUT', {
317
+ reason: 'terminal-input-invalid',
318
+ retryable: false,
319
+ cause
320
+ });
321
+ }
322
+ stored.session.write(copied);
323
+ return true;
324
+ }
325
+ function resizeSession(id, ownerId, cols, rows) {
326
+ const stored = getOwnedSession(id, ownerId);
327
+ if (!stored || stored.exited)
328
+ return false;
329
+ let size;
330
+ try {
331
+ size = ResizeSchema.parse({ cols, rows });
332
+ }
333
+ catch (cause) {
334
+ throw new CapabilityError('The terminal size is invalid.', 'INVALID_INPUT', {
335
+ reason: 'terminal-size-invalid',
336
+ retryable: false,
337
+ cause
338
+ });
339
+ }
340
+ stored.session.resize(size.cols, size.rows);
341
+ return true;
342
+ }
343
+ function signalSession(id, ownerId, sig) {
344
+ const stored = getOwnedSession(id, ownerId);
345
+ if (!stored || stored.exited)
346
+ return false;
347
+ let signal;
348
+ try {
349
+ signal = SignalSchema.parse(sig);
350
+ }
351
+ catch (cause) {
352
+ throw new CapabilityError('The terminal signal is invalid.', 'INVALID_INPUT', {
353
+ reason: 'terminal-signal-invalid',
354
+ retryable: false,
355
+ cause
356
+ });
357
+ }
358
+ stored.session.signal(signal);
359
+ return true;
360
+ }
361
+ function touchSession(id, ownerId) {
362
+ const stored = getOwnedSession(id, ownerId);
363
+ if (!stored || stored.exited)
364
+ return false;
365
+ stored.lastActiveMs = runtime.lifecycle.now();
366
+ return true;
367
+ }
368
+ function hasSession(id) {
369
+ return sessions.has(admitIdentity(id));
370
+ }
371
+ function killSession(id, ownerId) {
372
+ const stored = getOwnedSession(id, ownerId);
373
+ if (!stored)
374
+ return false;
375
+ stored.session.kill();
376
+ stored.exited = true;
377
+ scheduleEviction(id);
378
+ return true;
379
+ }
380
+ function detachSession(id, ownerId) {
381
+ const stored = getOwnedSession(id, ownerId);
382
+ if (!stored || stored.exited)
383
+ return false;
384
+ if (stored.subscriberCount > 0) {
385
+ stored.subscriberCount = Math.max(0, stored.subscriberCount - 1);
386
+ }
387
+ stored.lastActiveMs = runtime.lifecycle.now();
388
+ return true;
389
+ }
390
+ function attachSession(id, ownerId) {
391
+ const stored = getOwnedSession(id, ownerId);
392
+ if (!stored || stored.exited)
393
+ return false;
394
+ stored.subscriberCount++;
395
+ stored.lastActiveMs = runtime.lifecycle.now();
396
+ return true;
397
+ }
398
+ function listSessions(ownerId) {
399
+ const admittedOwner = admitIdentity(ownerId);
400
+ const result = [];
401
+ for (const stored of sessions.values()) {
402
+ if (stored.ownerId !== admittedOwner)
403
+ continue;
404
+ result.push({
405
+ id: stored.session.id,
406
+ ownerId: admittedOwner,
407
+ command: stored.command,
408
+ startedAt: stored.startedAt,
409
+ detached: stored.subscriberCount === 0 && !stored.exited,
410
+ exited: stored.exited
411
+ });
412
+ }
413
+ return result;
414
+ }
415
+ function dispose() {
416
+ disposal ??= (async () => {
417
+ disposed = true;
418
+ disposeReaper();
419
+ for (const cancel of evictionTimers)
420
+ cancel();
421
+ evictionTimers.clear();
422
+ const failures = [];
423
+ const active = [...sessions.values()];
424
+ for (const stored of active) {
425
+ stored.unsubscribeOutput();
426
+ const failure = captureCleanupFailure(() => stored.session.kill());
427
+ if (failure)
428
+ failures.push(failure);
429
+ }
430
+ for (const stored of active) {
431
+ const outcome = await stored.session.exited().then(() => ({ kind: 'exit' }), (cause) => ({
432
+ kind: 'failure',
433
+ failure: CaughtFailureSchema.parse(cause)
434
+ }));
435
+ if (outcome.kind === 'failure')
436
+ failures.push(outcome.failure);
437
+ }
438
+ sessions.clear();
439
+ pendingByOwner.clear();
440
+ if (failures.length === 1)
441
+ throw failures[0];
442
+ if (failures.length > 1)
443
+ throw new AggregateError(failures, 'Terminal session store cleanup failed.');
444
+ })();
445
+ return disposal;
446
+ }
447
+ return {
448
+ openSession,
449
+ getOwnedSession,
450
+ writeToSession,
451
+ resizeSession,
452
+ signalSession,
453
+ killSession,
454
+ detachSession,
455
+ attachSession,
456
+ listSessions,
457
+ touchSession,
458
+ hasSession,
459
+ dispose
460
+ };
461
+ }
462
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/server/session-store.ts"],"names":[],"mappings":"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"}