@adhdev/session-host-core 1.0.82-rc.25 → 1.0.82-rc.27
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.mts +20 -4
- package/dist/index.d.ts +20 -4
- package/dist/index.js +200 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +198 -33
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cli-child-priority.ts +1 -1
- package/src/index.ts +2 -0
- package/src/ipc.ts +198 -31
package/dist/index.d.mts
CHANGED
|
@@ -478,7 +478,7 @@ declare function createCliChildPriorityPolicy(deps?: PriorityDependencies): <T e
|
|
|
478
478
|
* registering listeners/doing other work. There is a spawn-to-setPriority race:
|
|
479
479
|
* a child can run (and fork) before this call. Later descendants inherit nice
|
|
480
480
|
* on POSIX; early descendants are not retroactively changed. Windows creation
|
|
481
|
-
* and ConPTY inheritance require verification on the
|
|
481
|
+
* and ConPTY inheritance require verification on the DesktopA.
|
|
482
482
|
* Optional darwin-bg is applied asynchronously by taskpolicy after nice; the
|
|
483
483
|
* extra helper startup adds a further race before the background class takes
|
|
484
484
|
* effect. It also throttles I/O, so nice alone remains the default.
|
|
@@ -662,6 +662,9 @@ declare function createLineParser<TEnvelope = SessionHostWireEnvelope>(onEnvelop
|
|
|
662
662
|
interface SessionHostClientOptions {
|
|
663
663
|
endpoint?: SessionHostEndpoint;
|
|
664
664
|
appName?: string;
|
|
665
|
+
requestTimeoutMs?: number;
|
|
666
|
+
/** Join the shared client registry (default true). Disable for short-lived probes. */
|
|
667
|
+
registerAsShared?: boolean;
|
|
665
668
|
}
|
|
666
669
|
/**
|
|
667
670
|
* Why an established session-host connection went away.
|
|
@@ -670,6 +673,8 @@ interface SessionHostClientOptions {
|
|
|
670
673
|
* - `closed` — socket fully closed ('close') without a preceding error/end
|
|
671
674
|
*/
|
|
672
675
|
type SessionHostDisconnectReason = 'error' | 'ended' | 'closed';
|
|
676
|
+
declare function disconnectSessionHostClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
677
|
+
declare function findConnectedSessionHostClient(endpoint?: SessionHostEndpoint): SessionHostClient | null;
|
|
673
678
|
interface SessionHostDisconnectInfo {
|
|
674
679
|
reason: SessionHostDisconnectReason;
|
|
675
680
|
endpointPath: string;
|
|
@@ -690,12 +695,19 @@ interface SessionHostDisconnectInfo {
|
|
|
690
695
|
declare class SessionHostClient {
|
|
691
696
|
readonly endpoint: SessionHostEndpoint;
|
|
692
697
|
private socket;
|
|
698
|
+
private connectPromise;
|
|
699
|
+
private requestTimeoutMs;
|
|
693
700
|
private requestWaiters;
|
|
694
701
|
private eventListeners;
|
|
695
702
|
private disconnectListeners;
|
|
696
703
|
/** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
|
|
697
704
|
private disconnectedSockets;
|
|
705
|
+
/** Session subscriptions established via create_session/attach_session, replayed automatically on reconnect. */
|
|
706
|
+
private attachedSessions;
|
|
698
707
|
constructor(options?: SessionHostClientOptions);
|
|
708
|
+
static disconnectClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
709
|
+
static findConnectedClient(endpoint?: SessionHostEndpoint): SessionHostClient | null;
|
|
710
|
+
isConnected(): boolean;
|
|
699
711
|
/**
|
|
700
712
|
* Fires when an established connection to the session host goes away.
|
|
701
713
|
*
|
|
@@ -710,9 +722,13 @@ declare class SessionHostClient {
|
|
|
710
722
|
*/
|
|
711
723
|
onDisconnect(listener: (info: SessionHostDisconnectInfo) => void): () => void;
|
|
712
724
|
private handleDisconnect;
|
|
713
|
-
|
|
725
|
+
private sendRawRequestOnSocket;
|
|
726
|
+
connect(timeoutMs?: number): Promise<void>;
|
|
714
727
|
onEvent(listener: (event: SessionHostEvent) => void): () => void;
|
|
715
|
-
request<T = unknown>(request: SessionHostRequest
|
|
728
|
+
request<T = unknown>(request: SessionHostRequest, options?: {
|
|
729
|
+
timeoutMs?: number;
|
|
730
|
+
}): Promise<SessionHostResponse<T>>;
|
|
731
|
+
disconnect(error?: Error): void;
|
|
716
732
|
close(): Promise<void>;
|
|
717
733
|
}
|
|
718
734
|
declare function createResponseEnvelope(requestId: string, response: SessionHostResponse): SessionHostResponseEnvelope;
|
|
@@ -871,4 +887,4 @@ interface SessionHostControlTransport {
|
|
|
871
887
|
*/
|
|
872
888
|
declare function createSessionHostControlPlane(transport: SessionHostControlTransport): SessionHostControlPlane;
|
|
873
889
|
|
|
874
|
-
export { type AcquireWritePayload, type AttachSessionPayload, CLI_CHILD_NICE_ENV, CLI_CHILD_NICE_INCREMENT, CLI_CHILD_SCHEDULING_ENV, type ClearSessionBufferPayload, type CreateSessionPayload, DEFAULT_CONFIG_DIR_NAME, DEFAULT_SESSION_RING_BUFFER_MAX_BYTES, type DetachSessionPayload, type ForceDetachClientPayload, type GetHostDiagnosticsPayload, type GetSnapshotPayload, type GetTerminalSnapshotPayload, type HostUpgradeLeasePayload, type PruneDuplicateSessionsPayload, type ReleaseWritePayload, type ResizeSessionPayload, type RestartSessionPayload, type ResumeSessionPayload, SESSION_HOST_SUPPORTED_REQUEST_TYPES, type SendInputPayload, type SendSignalPayload, type SessionAttachedClient, type SessionBufferSnapshot, type SessionClientType, type SessionHostCategory, SessionHostClient, type SessionHostClientOptions, type SessionHostControlPlane, type SessionHostControlTransport, type SessionHostDiagnostics, type SessionHostDisconnectInfo, type SessionHostDisconnectReason, type SessionHostDuplicateSessionGroup, type SessionHostEndpoint, type SessionHostEndpointOptions, type SessionHostEvent, type SessionHostEventEnvelope, type SessionHostLogEntry, type SessionHostPruneDuplicatesResult, type SessionHostRecord, SessionHostRegistry, type SessionHostRequest, type SessionHostRequestEnvelope, type SessionHostRequestTrace, type SessionHostRequestType, type SessionHostResponse, type SessionHostResponseEnvelope, type SessionHostRuntimeTransition, type SessionHostSnapshot, type SessionHostSurfaceKind, type SessionHostSurfaceRecordLike, type SessionHostWireEnvelope, type SessionLaunchCommand, type SessionLifecycle, type SessionOwnerType, SessionRingBuffer, type SessionRingBufferOptions, type SessionTerminalSnapshot, type SessionTerminalState, type SessionTermination, type SessionTransport, type SessionWriteOwner, type StopSessionPayload, type UpdateSessionMetaPayload, applyTerminalColorEnv, buildRuntimeDisplayName, buildRuntimeKey, canonicalizeInstancePath, classifyTermination, createCliChildPriorityPolicy, createLineParser, createResponseEnvelope, createSessionHostControlPlane, ensureNodePtySpawnHelperPermissions, formatRuntimeOwner, getDefaultSessionHostEndpoint, getSessionHostRecoveryLabel, getSessionHostSurfaceKind, getWorkspaceLabel, hiddenSpawn as hiddenSpawnProcess, isDefaultInstanceConfigDir, isSessionHostLiveRuntime, isSessionHostRecoverySnapshot, isTerminalRecord, partitionSessionHostDiagnosticsSessions, partitionSessionHostRecords, replayLaunchEnv, resolveAttachableRuntimeRecord, resolveInstanceConfigDir, resolveRuntimeRecord, resolveSessionHostIpcKey, sanitizeSpawnEnv, spawnCliChild, writeEnvelope };
|
|
890
|
+
export { type AcquireWritePayload, type AttachSessionPayload, CLI_CHILD_NICE_ENV, CLI_CHILD_NICE_INCREMENT, CLI_CHILD_SCHEDULING_ENV, type ClearSessionBufferPayload, type CreateSessionPayload, DEFAULT_CONFIG_DIR_NAME, DEFAULT_SESSION_RING_BUFFER_MAX_BYTES, type DetachSessionPayload, type ForceDetachClientPayload, type GetHostDiagnosticsPayload, type GetSnapshotPayload, type GetTerminalSnapshotPayload, type HostUpgradeLeasePayload, type PruneDuplicateSessionsPayload, type ReleaseWritePayload, type ResizeSessionPayload, type RestartSessionPayload, type ResumeSessionPayload, SESSION_HOST_SUPPORTED_REQUEST_TYPES, type SendInputPayload, type SendSignalPayload, type SessionAttachedClient, type SessionBufferSnapshot, type SessionClientType, type SessionHostCategory, SessionHostClient, type SessionHostClientOptions, type SessionHostControlPlane, type SessionHostControlTransport, type SessionHostDiagnostics, type SessionHostDisconnectInfo, type SessionHostDisconnectReason, type SessionHostDuplicateSessionGroup, type SessionHostEndpoint, type SessionHostEndpointOptions, type SessionHostEvent, type SessionHostEventEnvelope, type SessionHostLogEntry, type SessionHostPruneDuplicatesResult, type SessionHostRecord, SessionHostRegistry, type SessionHostRequest, type SessionHostRequestEnvelope, type SessionHostRequestTrace, type SessionHostRequestType, type SessionHostResponse, type SessionHostResponseEnvelope, type SessionHostRuntimeTransition, type SessionHostSnapshot, type SessionHostSurfaceKind, type SessionHostSurfaceRecordLike, type SessionHostWireEnvelope, type SessionLaunchCommand, type SessionLifecycle, type SessionOwnerType, SessionRingBuffer, type SessionRingBufferOptions, type SessionTerminalSnapshot, type SessionTerminalState, type SessionTermination, type SessionTransport, type SessionWriteOwner, type StopSessionPayload, type UpdateSessionMetaPayload, applyTerminalColorEnv, buildRuntimeDisplayName, buildRuntimeKey, canonicalizeInstancePath, classifyTermination, createCliChildPriorityPolicy, createLineParser, createResponseEnvelope, createSessionHostControlPlane, disconnectSessionHostClients, ensureNodePtySpawnHelperPermissions, findConnectedSessionHostClient, formatRuntimeOwner, getDefaultSessionHostEndpoint, getSessionHostRecoveryLabel, getSessionHostSurfaceKind, getWorkspaceLabel, hiddenSpawn as hiddenSpawnProcess, isDefaultInstanceConfigDir, isSessionHostLiveRuntime, isSessionHostRecoverySnapshot, isTerminalRecord, partitionSessionHostDiagnosticsSessions, partitionSessionHostRecords, replayLaunchEnv, resolveAttachableRuntimeRecord, resolveInstanceConfigDir, resolveRuntimeRecord, resolveSessionHostIpcKey, sanitizeSpawnEnv, spawnCliChild, writeEnvelope };
|
package/dist/index.d.ts
CHANGED
|
@@ -478,7 +478,7 @@ declare function createCliChildPriorityPolicy(deps?: PriorityDependencies): <T e
|
|
|
478
478
|
* registering listeners/doing other work. There is a spawn-to-setPriority race:
|
|
479
479
|
* a child can run (and fork) before this call. Later descendants inherit nice
|
|
480
480
|
* on POSIX; early descendants are not retroactively changed. Windows creation
|
|
481
|
-
* and ConPTY inheritance require verification on the
|
|
481
|
+
* and ConPTY inheritance require verification on the DesktopA.
|
|
482
482
|
* Optional darwin-bg is applied asynchronously by taskpolicy after nice; the
|
|
483
483
|
* extra helper startup adds a further race before the background class takes
|
|
484
484
|
* effect. It also throttles I/O, so nice alone remains the default.
|
|
@@ -662,6 +662,9 @@ declare function createLineParser<TEnvelope = SessionHostWireEnvelope>(onEnvelop
|
|
|
662
662
|
interface SessionHostClientOptions {
|
|
663
663
|
endpoint?: SessionHostEndpoint;
|
|
664
664
|
appName?: string;
|
|
665
|
+
requestTimeoutMs?: number;
|
|
666
|
+
/** Join the shared client registry (default true). Disable for short-lived probes. */
|
|
667
|
+
registerAsShared?: boolean;
|
|
665
668
|
}
|
|
666
669
|
/**
|
|
667
670
|
* Why an established session-host connection went away.
|
|
@@ -670,6 +673,8 @@ interface SessionHostClientOptions {
|
|
|
670
673
|
* - `closed` — socket fully closed ('close') without a preceding error/end
|
|
671
674
|
*/
|
|
672
675
|
type SessionHostDisconnectReason = 'error' | 'ended' | 'closed';
|
|
676
|
+
declare function disconnectSessionHostClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
677
|
+
declare function findConnectedSessionHostClient(endpoint?: SessionHostEndpoint): SessionHostClient | null;
|
|
673
678
|
interface SessionHostDisconnectInfo {
|
|
674
679
|
reason: SessionHostDisconnectReason;
|
|
675
680
|
endpointPath: string;
|
|
@@ -690,12 +695,19 @@ interface SessionHostDisconnectInfo {
|
|
|
690
695
|
declare class SessionHostClient {
|
|
691
696
|
readonly endpoint: SessionHostEndpoint;
|
|
692
697
|
private socket;
|
|
698
|
+
private connectPromise;
|
|
699
|
+
private requestTimeoutMs;
|
|
693
700
|
private requestWaiters;
|
|
694
701
|
private eventListeners;
|
|
695
702
|
private disconnectListeners;
|
|
696
703
|
/** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
|
|
697
704
|
private disconnectedSockets;
|
|
705
|
+
/** Session subscriptions established via create_session/attach_session, replayed automatically on reconnect. */
|
|
706
|
+
private attachedSessions;
|
|
698
707
|
constructor(options?: SessionHostClientOptions);
|
|
708
|
+
static disconnectClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
709
|
+
static findConnectedClient(endpoint?: SessionHostEndpoint): SessionHostClient | null;
|
|
710
|
+
isConnected(): boolean;
|
|
699
711
|
/**
|
|
700
712
|
* Fires when an established connection to the session host goes away.
|
|
701
713
|
*
|
|
@@ -710,9 +722,13 @@ declare class SessionHostClient {
|
|
|
710
722
|
*/
|
|
711
723
|
onDisconnect(listener: (info: SessionHostDisconnectInfo) => void): () => void;
|
|
712
724
|
private handleDisconnect;
|
|
713
|
-
|
|
725
|
+
private sendRawRequestOnSocket;
|
|
726
|
+
connect(timeoutMs?: number): Promise<void>;
|
|
714
727
|
onEvent(listener: (event: SessionHostEvent) => void): () => void;
|
|
715
|
-
request<T = unknown>(request: SessionHostRequest
|
|
728
|
+
request<T = unknown>(request: SessionHostRequest, options?: {
|
|
729
|
+
timeoutMs?: number;
|
|
730
|
+
}): Promise<SessionHostResponse<T>>;
|
|
731
|
+
disconnect(error?: Error): void;
|
|
716
732
|
close(): Promise<void>;
|
|
717
733
|
}
|
|
718
734
|
declare function createResponseEnvelope(requestId: string, response: SessionHostResponse): SessionHostResponseEnvelope;
|
|
@@ -871,4 +887,4 @@ interface SessionHostControlTransport {
|
|
|
871
887
|
*/
|
|
872
888
|
declare function createSessionHostControlPlane(transport: SessionHostControlTransport): SessionHostControlPlane;
|
|
873
889
|
|
|
874
|
-
export { type AcquireWritePayload, type AttachSessionPayload, CLI_CHILD_NICE_ENV, CLI_CHILD_NICE_INCREMENT, CLI_CHILD_SCHEDULING_ENV, type ClearSessionBufferPayload, type CreateSessionPayload, DEFAULT_CONFIG_DIR_NAME, DEFAULT_SESSION_RING_BUFFER_MAX_BYTES, type DetachSessionPayload, type ForceDetachClientPayload, type GetHostDiagnosticsPayload, type GetSnapshotPayload, type GetTerminalSnapshotPayload, type HostUpgradeLeasePayload, type PruneDuplicateSessionsPayload, type ReleaseWritePayload, type ResizeSessionPayload, type RestartSessionPayload, type ResumeSessionPayload, SESSION_HOST_SUPPORTED_REQUEST_TYPES, type SendInputPayload, type SendSignalPayload, type SessionAttachedClient, type SessionBufferSnapshot, type SessionClientType, type SessionHostCategory, SessionHostClient, type SessionHostClientOptions, type SessionHostControlPlane, type SessionHostControlTransport, type SessionHostDiagnostics, type SessionHostDisconnectInfo, type SessionHostDisconnectReason, type SessionHostDuplicateSessionGroup, type SessionHostEndpoint, type SessionHostEndpointOptions, type SessionHostEvent, type SessionHostEventEnvelope, type SessionHostLogEntry, type SessionHostPruneDuplicatesResult, type SessionHostRecord, SessionHostRegistry, type SessionHostRequest, type SessionHostRequestEnvelope, type SessionHostRequestTrace, type SessionHostRequestType, type SessionHostResponse, type SessionHostResponseEnvelope, type SessionHostRuntimeTransition, type SessionHostSnapshot, type SessionHostSurfaceKind, type SessionHostSurfaceRecordLike, type SessionHostWireEnvelope, type SessionLaunchCommand, type SessionLifecycle, type SessionOwnerType, SessionRingBuffer, type SessionRingBufferOptions, type SessionTerminalSnapshot, type SessionTerminalState, type SessionTermination, type SessionTransport, type SessionWriteOwner, type StopSessionPayload, type UpdateSessionMetaPayload, applyTerminalColorEnv, buildRuntimeDisplayName, buildRuntimeKey, canonicalizeInstancePath, classifyTermination, createCliChildPriorityPolicy, createLineParser, createResponseEnvelope, createSessionHostControlPlane, ensureNodePtySpawnHelperPermissions, formatRuntimeOwner, getDefaultSessionHostEndpoint, getSessionHostRecoveryLabel, getSessionHostSurfaceKind, getWorkspaceLabel, hiddenSpawn as hiddenSpawnProcess, isDefaultInstanceConfigDir, isSessionHostLiveRuntime, isSessionHostRecoverySnapshot, isTerminalRecord, partitionSessionHostDiagnosticsSessions, partitionSessionHostRecords, replayLaunchEnv, resolveAttachableRuntimeRecord, resolveInstanceConfigDir, resolveRuntimeRecord, resolveSessionHostIpcKey, sanitizeSpawnEnv, spawnCliChild, writeEnvelope };
|
|
890
|
+
export { type AcquireWritePayload, type AttachSessionPayload, CLI_CHILD_NICE_ENV, CLI_CHILD_NICE_INCREMENT, CLI_CHILD_SCHEDULING_ENV, type ClearSessionBufferPayload, type CreateSessionPayload, DEFAULT_CONFIG_DIR_NAME, DEFAULT_SESSION_RING_BUFFER_MAX_BYTES, type DetachSessionPayload, type ForceDetachClientPayload, type GetHostDiagnosticsPayload, type GetSnapshotPayload, type GetTerminalSnapshotPayload, type HostUpgradeLeasePayload, type PruneDuplicateSessionsPayload, type ReleaseWritePayload, type ResizeSessionPayload, type RestartSessionPayload, type ResumeSessionPayload, SESSION_HOST_SUPPORTED_REQUEST_TYPES, type SendInputPayload, type SendSignalPayload, type SessionAttachedClient, type SessionBufferSnapshot, type SessionClientType, type SessionHostCategory, SessionHostClient, type SessionHostClientOptions, type SessionHostControlPlane, type SessionHostControlTransport, type SessionHostDiagnostics, type SessionHostDisconnectInfo, type SessionHostDisconnectReason, type SessionHostDuplicateSessionGroup, type SessionHostEndpoint, type SessionHostEndpointOptions, type SessionHostEvent, type SessionHostEventEnvelope, type SessionHostLogEntry, type SessionHostPruneDuplicatesResult, type SessionHostRecord, SessionHostRegistry, type SessionHostRequest, type SessionHostRequestEnvelope, type SessionHostRequestTrace, type SessionHostRequestType, type SessionHostResponse, type SessionHostResponseEnvelope, type SessionHostRuntimeTransition, type SessionHostSnapshot, type SessionHostSurfaceKind, type SessionHostSurfaceRecordLike, type SessionHostWireEnvelope, type SessionLaunchCommand, type SessionLifecycle, type SessionOwnerType, SessionRingBuffer, type SessionRingBufferOptions, type SessionTerminalSnapshot, type SessionTerminalState, type SessionTermination, type SessionTransport, type SessionWriteOwner, type StopSessionPayload, type UpdateSessionMetaPayload, applyTerminalColorEnv, buildRuntimeDisplayName, buildRuntimeKey, canonicalizeInstancePath, classifyTermination, createCliChildPriorityPolicy, createLineParser, createResponseEnvelope, createSessionHostControlPlane, disconnectSessionHostClients, ensureNodePtySpawnHelperPermissions, findConnectedSessionHostClient, formatRuntimeOwner, getDefaultSessionHostEndpoint, getSessionHostRecoveryLabel, getSessionHostSurfaceKind, getWorkspaceLabel, hiddenSpawn as hiddenSpawnProcess, isDefaultInstanceConfigDir, isSessionHostLiveRuntime, isSessionHostRecoverySnapshot, isTerminalRecord, partitionSessionHostDiagnosticsSessions, partitionSessionHostRecords, replayLaunchEnv, resolveAttachableRuntimeRecord, resolveInstanceConfigDir, resolveRuntimeRecord, resolveSessionHostIpcKey, sanitizeSpawnEnv, spawnCliChild, writeEnvelope };
|
package/dist/index.js
CHANGED
|
@@ -50,7 +50,9 @@ __export(index_exports, {
|
|
|
50
50
|
createLineParser: () => createLineParser,
|
|
51
51
|
createResponseEnvelope: () => createResponseEnvelope,
|
|
52
52
|
createSessionHostControlPlane: () => createSessionHostControlPlane,
|
|
53
|
+
disconnectSessionHostClients: () => disconnectSessionHostClients,
|
|
53
54
|
ensureNodePtySpawnHelperPermissions: () => ensureNodePtySpawnHelperPermissions,
|
|
55
|
+
findConnectedSessionHostClient: () => findConnectedSessionHostClient,
|
|
54
56
|
formatRuntimeOwner: () => formatRuntimeOwner,
|
|
55
57
|
getDefaultSessionHostEndpoint: () => getDefaultSessionHostEndpoint,
|
|
56
58
|
getSessionHostRecoveryLabel: () => getSessionHostRecoveryLabel,
|
|
@@ -804,16 +806,59 @@ function createLineParser(onEnvelope) {
|
|
|
804
806
|
return parser;
|
|
805
807
|
}
|
|
806
808
|
var establishedSockets = /* @__PURE__ */ new WeakSet();
|
|
809
|
+
var activeClientRefs = /* @__PURE__ */ new Set();
|
|
810
|
+
function disconnectSessionHostClients(endpoint, error) {
|
|
811
|
+
for (const ref of activeClientRefs) {
|
|
812
|
+
const client = ref.deref();
|
|
813
|
+
if (!client) {
|
|
814
|
+
activeClientRefs.delete(ref);
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
if (!endpoint || client.endpoint.path === endpoint.path) {
|
|
818
|
+
client.disconnect(error);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
function findConnectedSessionHostClient(endpoint) {
|
|
823
|
+
for (const ref of activeClientRefs) {
|
|
824
|
+
const client = ref.deref();
|
|
825
|
+
if (!client) {
|
|
826
|
+
activeClientRefs.delete(ref);
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
if ((!endpoint || client.endpoint.path === endpoint.path) && client.isConnected()) {
|
|
830
|
+
return client;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
return null;
|
|
834
|
+
}
|
|
807
835
|
var SessionHostClient = class {
|
|
808
836
|
endpoint;
|
|
809
837
|
socket = null;
|
|
838
|
+
connectPromise = null;
|
|
839
|
+
requestTimeoutMs = 3e4;
|
|
810
840
|
requestWaiters = /* @__PURE__ */ new Map();
|
|
811
841
|
eventListeners = /* @__PURE__ */ new Set();
|
|
812
842
|
disconnectListeners = /* @__PURE__ */ new Set();
|
|
813
843
|
/** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
|
|
814
844
|
disconnectedSockets = /* @__PURE__ */ new WeakSet();
|
|
845
|
+
/** Session subscriptions established via create_session/attach_session, replayed automatically on reconnect. */
|
|
846
|
+
attachedSessions = /* @__PURE__ */ new Map();
|
|
815
847
|
constructor(options = {}) {
|
|
816
848
|
this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
|
|
849
|
+
if (typeof options.requestTimeoutMs === "number" && options.requestTimeoutMs > 0) {
|
|
850
|
+
this.requestTimeoutMs = options.requestTimeoutMs;
|
|
851
|
+
}
|
|
852
|
+
if (options.registerAsShared !== false) activeClientRefs.add(new WeakRef(this));
|
|
853
|
+
}
|
|
854
|
+
static disconnectClients(endpoint, error) {
|
|
855
|
+
disconnectSessionHostClients(endpoint, error);
|
|
856
|
+
}
|
|
857
|
+
static findConnectedClient(endpoint) {
|
|
858
|
+
return findConnectedSessionHostClient(endpoint);
|
|
859
|
+
}
|
|
860
|
+
isConnected() {
|
|
861
|
+
return Boolean(this.socket && !this.socket.destroyed && establishedSockets.has(this.socket));
|
|
817
862
|
}
|
|
818
863
|
/**
|
|
819
864
|
* Fires when an established connection to the session host goes away.
|
|
@@ -856,6 +901,7 @@ var SessionHostClient = class {
|
|
|
856
901
|
this.requestWaiters.clear();
|
|
857
902
|
if (this.socket === socket) {
|
|
858
903
|
this.socket = null;
|
|
904
|
+
this.connectPromise = null;
|
|
859
905
|
}
|
|
860
906
|
try {
|
|
861
907
|
socket.destroy();
|
|
@@ -875,8 +921,47 @@ var SessionHostClient = class {
|
|
|
875
921
|
}
|
|
876
922
|
}
|
|
877
923
|
}
|
|
878
|
-
|
|
879
|
-
|
|
924
|
+
sendRawRequestOnSocket(socket, request, timeoutMs = this.requestTimeoutMs) {
|
|
925
|
+
const requestId = generateUUID();
|
|
926
|
+
const envelope = {
|
|
927
|
+
kind: "request",
|
|
928
|
+
requestId,
|
|
929
|
+
request
|
|
930
|
+
};
|
|
931
|
+
const timeoutLabel = timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3}s` : `${timeoutMs}ms`;
|
|
932
|
+
return new Promise((resolve3, reject) => {
|
|
933
|
+
const timeout = setTimeout(() => {
|
|
934
|
+
const timeoutError = Object.assign(new Error(`Session host request timed out after ${timeoutLabel} (${request.type})`), { code: "SESSION_HOST_REQUEST_TIMEOUT", requestType: request.type });
|
|
935
|
+
if (this.socket === socket) {
|
|
936
|
+
this.disconnect(timeoutError);
|
|
937
|
+
} else {
|
|
938
|
+
this.requestWaiters.delete(requestId);
|
|
939
|
+
this.disconnectedSockets.add(socket);
|
|
940
|
+
try {
|
|
941
|
+
socket.destroy();
|
|
942
|
+
} catch {
|
|
943
|
+
}
|
|
944
|
+
reject(timeoutError);
|
|
945
|
+
}
|
|
946
|
+
}, timeoutMs);
|
|
947
|
+
this.requestWaiters.set(requestId, {
|
|
948
|
+
resolve: (value) => {
|
|
949
|
+
clearTimeout(timeout);
|
|
950
|
+
resolve3(value);
|
|
951
|
+
},
|
|
952
|
+
reject: (error) => {
|
|
953
|
+
clearTimeout(timeout);
|
|
954
|
+
reject(error);
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
socket.write(serializeEnvelope(envelope));
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
async connect(timeoutMs = this.requestTimeoutMs) {
|
|
961
|
+
if (this.socket && !this.socket.destroyed) {
|
|
962
|
+
if (this.connectPromise) await this.connectPromise;
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
880
965
|
if (this.socket) {
|
|
881
966
|
try {
|
|
882
967
|
this.socket.destroy();
|
|
@@ -884,6 +969,7 @@ var SessionHostClient = class {
|
|
|
884
969
|
}
|
|
885
970
|
this.socket = null;
|
|
886
971
|
}
|
|
972
|
+
this.connectPromise = null;
|
|
887
973
|
const socket = net.createConnection(this.endpoint.path);
|
|
888
974
|
this.socket = socket;
|
|
889
975
|
const parser = createLineParser((envelope) => {
|
|
@@ -917,13 +1003,54 @@ var SessionHostClient = class {
|
|
|
917
1003
|
socket.on("end", () => {
|
|
918
1004
|
this.handleDisconnect(socket, "ended", void 0, flushParser().length);
|
|
919
1005
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1006
|
+
const connectTask = (async () => {
|
|
1007
|
+
await new Promise((resolve3, reject) => {
|
|
1008
|
+
const cleanup = () => {
|
|
1009
|
+
clearTimeout(timer);
|
|
1010
|
+
socket.off("connect", connected);
|
|
1011
|
+
socket.off("error", failed);
|
|
1012
|
+
socket.off("close", closed);
|
|
1013
|
+
};
|
|
1014
|
+
const connected = () => {
|
|
1015
|
+
cleanup();
|
|
1016
|
+
establishedSockets.add(socket);
|
|
1017
|
+
resolve3();
|
|
1018
|
+
};
|
|
1019
|
+
const failed = (error) => {
|
|
1020
|
+
cleanup();
|
|
1021
|
+
reject(error);
|
|
1022
|
+
};
|
|
1023
|
+
const closed = () => failed(new Error("Session host connection closed before connect"));
|
|
1024
|
+
const timer = setTimeout(() => {
|
|
1025
|
+
const error = Object.assign(new Error(`Session host connect timed out after ${timeoutMs}ms`), { code: "SESSION_HOST_CONNECT_TIMEOUT" });
|
|
1026
|
+
failed(error);
|
|
1027
|
+
if (this.socket === socket) this.disconnect(error);
|
|
1028
|
+
}, timeoutMs);
|
|
1029
|
+
socket.once("connect", connected);
|
|
1030
|
+
socket.once("error", failed);
|
|
1031
|
+
socket.once("close", closed);
|
|
924
1032
|
});
|
|
925
|
-
socket.
|
|
926
|
-
|
|
1033
|
+
if (this.attachedSessions.size > 0 && this.socket === socket && !socket.destroyed) {
|
|
1034
|
+
for (const [sessionId, sub] of [...this.attachedSessions.entries()]) {
|
|
1035
|
+
if (this.socket !== socket || socket.destroyed) break;
|
|
1036
|
+
const replayResponse = await this.sendRawRequestOnSocket(socket, {
|
|
1037
|
+
type: "attach_session",
|
|
1038
|
+
payload: sub
|
|
1039
|
+
}).catch(() => null);
|
|
1040
|
+
if (replayResponse && !replayResponse.success) {
|
|
1041
|
+
this.attachedSessions.delete(sessionId);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
})();
|
|
1046
|
+
this.connectPromise = connectTask;
|
|
1047
|
+
try {
|
|
1048
|
+
await connectTask;
|
|
1049
|
+
} finally {
|
|
1050
|
+
if (this.connectPromise === connectTask) {
|
|
1051
|
+
this.connectPromise = null;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
927
1054
|
}
|
|
928
1055
|
onEvent(listener) {
|
|
929
1056
|
this.eventListeners.add(listener);
|
|
@@ -931,35 +1058,73 @@ var SessionHostClient = class {
|
|
|
931
1058
|
this.eventListeners.delete(listener);
|
|
932
1059
|
};
|
|
933
1060
|
}
|
|
934
|
-
async request(request) {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1061
|
+
async request(request, options = {}) {
|
|
1062
|
+
const timeoutMs = Math.max(1, options.timeoutMs ?? this.requestTimeoutMs);
|
|
1063
|
+
const deadline = Date.now() + timeoutMs;
|
|
1064
|
+
const alreadyConnected = this.isConnected() && !this.connectPromise;
|
|
1065
|
+
if (options.timeoutMs !== void 0) {
|
|
1066
|
+
let timer;
|
|
1067
|
+
try {
|
|
1068
|
+
await Promise.race([
|
|
1069
|
+
this.connect(timeoutMs),
|
|
1070
|
+
new Promise((_resolve, reject) => {
|
|
1071
|
+
timer = setTimeout(() => {
|
|
1072
|
+
const error = Object.assign(new Error(`Session host connect timed out after ${timeoutMs}ms`), { code: "SESSION_HOST_CONNECT_TIMEOUT" });
|
|
1073
|
+
reject(error);
|
|
1074
|
+
this.disconnect(error);
|
|
1075
|
+
}, timeoutMs);
|
|
1076
|
+
})
|
|
1077
|
+
]);
|
|
1078
|
+
} finally {
|
|
1079
|
+
if (timer) clearTimeout(timer);
|
|
1080
|
+
}
|
|
1081
|
+
} else {
|
|
1082
|
+
await this.connect(timeoutMs);
|
|
1083
|
+
}
|
|
1084
|
+
const requestSocket = this.socket;
|
|
1085
|
+
if (!requestSocket) throw new Error("Session host socket unavailable");
|
|
1086
|
+
const response = await this.sendRawRequestOnSocket(requestSocket, request, options.timeoutMs === void 0 || alreadyConnected ? timeoutMs : Math.max(1, deadline - Date.now()));
|
|
1087
|
+
if (response.success) {
|
|
1088
|
+
if (request.type === "attach_session") {
|
|
1089
|
+
this.attachedSessions.set(request.payload.sessionId, {
|
|
1090
|
+
sessionId: request.payload.sessionId,
|
|
1091
|
+
clientId: request.payload.clientId,
|
|
1092
|
+
clientType: request.payload.clientType,
|
|
1093
|
+
readOnly: request.payload.readOnly === true
|
|
1094
|
+
});
|
|
1095
|
+
} else if (request.type === "create_session") {
|
|
1096
|
+
const createdId = response.result?.sessionId || request.payload.sessionId;
|
|
1097
|
+
const clientId = typeof request.payload.clientId === "string" ? request.payload.clientId.trim() : "";
|
|
1098
|
+
if (createdId && clientId) {
|
|
1099
|
+
this.attachedSessions.set(createdId, {
|
|
1100
|
+
sessionId: createdId,
|
|
1101
|
+
clientId,
|
|
1102
|
+
clientType: request.payload.clientType || "daemon",
|
|
1103
|
+
readOnly: false
|
|
1104
|
+
});
|
|
956
1105
|
}
|
|
957
|
-
})
|
|
958
|
-
|
|
959
|
-
|
|
1106
|
+
} else if (request.type === "detach_session" || request.type === "delete_session") {
|
|
1107
|
+
this.attachedSessions.delete(request.payload.sessionId);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
960
1110
|
return response;
|
|
961
1111
|
}
|
|
1112
|
+
disconnect(error) {
|
|
1113
|
+
const socket = this.socket;
|
|
1114
|
+
if (socket) {
|
|
1115
|
+
this.handleDisconnect(socket, error ? "error" : "closed", error, 0);
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
this.connectPromise = null;
|
|
1119
|
+
const failure = error || new Error(`Session host client disconnected (${this.endpoint.path})`);
|
|
1120
|
+
for (const waiter of this.requestWaiters.values()) {
|
|
1121
|
+
waiter.reject(failure);
|
|
1122
|
+
}
|
|
1123
|
+
this.requestWaiters.clear();
|
|
1124
|
+
}
|
|
962
1125
|
async close() {
|
|
1126
|
+
this.attachedSessions.clear();
|
|
1127
|
+
this.connectPromise = null;
|
|
963
1128
|
if (!this.socket) return;
|
|
964
1129
|
const socket = this.socket;
|
|
965
1130
|
this.socket = null;
|
|
@@ -1177,7 +1342,9 @@ function createSessionHostControlPlane(transport) {
|
|
|
1177
1342
|
createLineParser,
|
|
1178
1343
|
createResponseEnvelope,
|
|
1179
1344
|
createSessionHostControlPlane,
|
|
1345
|
+
disconnectSessionHostClients,
|
|
1180
1346
|
ensureNodePtySpawnHelperPermissions,
|
|
1347
|
+
findConnectedSessionHostClient,
|
|
1181
1348
|
formatRuntimeOwner,
|
|
1182
1349
|
getDefaultSessionHostEndpoint,
|
|
1183
1350
|
getSessionHostRecoveryLabel,
|