@adhdev/session-host-core 1.0.82-rc.25 → 1.0.82-rc.26
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 +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +137 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +136 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cli-child-priority.ts +1 -1
- package/src/index.ts +1 -0
- package/src/ipc.ts +138 -28
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,7 @@ declare function createLineParser<TEnvelope = SessionHostWireEnvelope>(onEnvelop
|
|
|
662
662
|
interface SessionHostClientOptions {
|
|
663
663
|
endpoint?: SessionHostEndpoint;
|
|
664
664
|
appName?: string;
|
|
665
|
+
requestTimeoutMs?: number;
|
|
665
666
|
}
|
|
666
667
|
/**
|
|
667
668
|
* Why an established session-host connection went away.
|
|
@@ -670,6 +671,7 @@ interface SessionHostClientOptions {
|
|
|
670
671
|
* - `closed` — socket fully closed ('close') without a preceding error/end
|
|
671
672
|
*/
|
|
672
673
|
type SessionHostDisconnectReason = 'error' | 'ended' | 'closed';
|
|
674
|
+
declare function disconnectSessionHostClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
673
675
|
interface SessionHostDisconnectInfo {
|
|
674
676
|
reason: SessionHostDisconnectReason;
|
|
675
677
|
endpointPath: string;
|
|
@@ -690,12 +692,17 @@ interface SessionHostDisconnectInfo {
|
|
|
690
692
|
declare class SessionHostClient {
|
|
691
693
|
readonly endpoint: SessionHostEndpoint;
|
|
692
694
|
private socket;
|
|
695
|
+
private connectPromise;
|
|
696
|
+
private requestTimeoutMs;
|
|
693
697
|
private requestWaiters;
|
|
694
698
|
private eventListeners;
|
|
695
699
|
private disconnectListeners;
|
|
696
700
|
/** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
|
|
697
701
|
private disconnectedSockets;
|
|
702
|
+
/** Session subscriptions established via create_session/attach_session, replayed automatically on reconnect. */
|
|
703
|
+
private attachedSessions;
|
|
698
704
|
constructor(options?: SessionHostClientOptions);
|
|
705
|
+
static disconnectClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
699
706
|
/**
|
|
700
707
|
* Fires when an established connection to the session host goes away.
|
|
701
708
|
*
|
|
@@ -710,9 +717,11 @@ declare class SessionHostClient {
|
|
|
710
717
|
*/
|
|
711
718
|
onDisconnect(listener: (info: SessionHostDisconnectInfo) => void): () => void;
|
|
712
719
|
private handleDisconnect;
|
|
720
|
+
private sendRawRequestOnSocket;
|
|
713
721
|
connect(): Promise<void>;
|
|
714
722
|
onEvent(listener: (event: SessionHostEvent) => void): () => void;
|
|
715
723
|
request<T = unknown>(request: SessionHostRequest): Promise<SessionHostResponse<T>>;
|
|
724
|
+
disconnect(error?: Error): void;
|
|
716
725
|
close(): Promise<void>;
|
|
717
726
|
}
|
|
718
727
|
declare function createResponseEnvelope(requestId: string, response: SessionHostResponse): SessionHostResponseEnvelope;
|
|
@@ -871,4 +880,4 @@ interface SessionHostControlTransport {
|
|
|
871
880
|
*/
|
|
872
881
|
declare function createSessionHostControlPlane(transport: SessionHostControlTransport): SessionHostControlPlane;
|
|
873
882
|
|
|
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 };
|
|
883
|
+
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, 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,7 @@ declare function createLineParser<TEnvelope = SessionHostWireEnvelope>(onEnvelop
|
|
|
662
662
|
interface SessionHostClientOptions {
|
|
663
663
|
endpoint?: SessionHostEndpoint;
|
|
664
664
|
appName?: string;
|
|
665
|
+
requestTimeoutMs?: number;
|
|
665
666
|
}
|
|
666
667
|
/**
|
|
667
668
|
* Why an established session-host connection went away.
|
|
@@ -670,6 +671,7 @@ interface SessionHostClientOptions {
|
|
|
670
671
|
* - `closed` — socket fully closed ('close') without a preceding error/end
|
|
671
672
|
*/
|
|
672
673
|
type SessionHostDisconnectReason = 'error' | 'ended' | 'closed';
|
|
674
|
+
declare function disconnectSessionHostClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
673
675
|
interface SessionHostDisconnectInfo {
|
|
674
676
|
reason: SessionHostDisconnectReason;
|
|
675
677
|
endpointPath: string;
|
|
@@ -690,12 +692,17 @@ interface SessionHostDisconnectInfo {
|
|
|
690
692
|
declare class SessionHostClient {
|
|
691
693
|
readonly endpoint: SessionHostEndpoint;
|
|
692
694
|
private socket;
|
|
695
|
+
private connectPromise;
|
|
696
|
+
private requestTimeoutMs;
|
|
693
697
|
private requestWaiters;
|
|
694
698
|
private eventListeners;
|
|
695
699
|
private disconnectListeners;
|
|
696
700
|
/** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
|
|
697
701
|
private disconnectedSockets;
|
|
702
|
+
/** Session subscriptions established via create_session/attach_session, replayed automatically on reconnect. */
|
|
703
|
+
private attachedSessions;
|
|
698
704
|
constructor(options?: SessionHostClientOptions);
|
|
705
|
+
static disconnectClients(endpoint?: SessionHostEndpoint, error?: Error): void;
|
|
699
706
|
/**
|
|
700
707
|
* Fires when an established connection to the session host goes away.
|
|
701
708
|
*
|
|
@@ -710,9 +717,11 @@ declare class SessionHostClient {
|
|
|
710
717
|
*/
|
|
711
718
|
onDisconnect(listener: (info: SessionHostDisconnectInfo) => void): () => void;
|
|
712
719
|
private handleDisconnect;
|
|
720
|
+
private sendRawRequestOnSocket;
|
|
713
721
|
connect(): Promise<void>;
|
|
714
722
|
onEvent(listener: (event: SessionHostEvent) => void): () => void;
|
|
715
723
|
request<T = unknown>(request: SessionHostRequest): Promise<SessionHostResponse<T>>;
|
|
724
|
+
disconnect(error?: Error): void;
|
|
716
725
|
close(): Promise<void>;
|
|
717
726
|
}
|
|
718
727
|
declare function createResponseEnvelope(requestId: string, response: SessionHostResponse): SessionHostResponseEnvelope;
|
|
@@ -871,4 +880,4 @@ interface SessionHostControlTransport {
|
|
|
871
880
|
*/
|
|
872
881
|
declare function createSessionHostControlPlane(transport: SessionHostControlTransport): SessionHostControlPlane;
|
|
873
882
|
|
|
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 };
|
|
883
|
+
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, 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,6 +50,7 @@ __export(index_exports, {
|
|
|
50
50
|
createLineParser: () => createLineParser,
|
|
51
51
|
createResponseEnvelope: () => createResponseEnvelope,
|
|
52
52
|
createSessionHostControlPlane: () => createSessionHostControlPlane,
|
|
53
|
+
disconnectSessionHostClients: () => disconnectSessionHostClients,
|
|
53
54
|
ensureNodePtySpawnHelperPermissions: () => ensureNodePtySpawnHelperPermissions,
|
|
54
55
|
formatRuntimeOwner: () => formatRuntimeOwner,
|
|
55
56
|
getDefaultSessionHostEndpoint: () => getDefaultSessionHostEndpoint,
|
|
@@ -804,16 +805,40 @@ function createLineParser(onEnvelope) {
|
|
|
804
805
|
return parser;
|
|
805
806
|
}
|
|
806
807
|
var establishedSockets = /* @__PURE__ */ new WeakSet();
|
|
808
|
+
var activeClientRefs = /* @__PURE__ */ new Set();
|
|
809
|
+
function disconnectSessionHostClients(endpoint, error) {
|
|
810
|
+
for (const ref of activeClientRefs) {
|
|
811
|
+
const client = ref.deref();
|
|
812
|
+
if (!client) {
|
|
813
|
+
activeClientRefs.delete(ref);
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
if (!endpoint || client.endpoint.path === endpoint.path) {
|
|
817
|
+
client.disconnect(error);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
807
821
|
var SessionHostClient = class {
|
|
808
822
|
endpoint;
|
|
809
823
|
socket = null;
|
|
824
|
+
connectPromise = null;
|
|
825
|
+
requestTimeoutMs = 3e4;
|
|
810
826
|
requestWaiters = /* @__PURE__ */ new Map();
|
|
811
827
|
eventListeners = /* @__PURE__ */ new Set();
|
|
812
828
|
disconnectListeners = /* @__PURE__ */ new Set();
|
|
813
829
|
/** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
|
|
814
830
|
disconnectedSockets = /* @__PURE__ */ new WeakSet();
|
|
831
|
+
/** Session subscriptions established via create_session/attach_session, replayed automatically on reconnect. */
|
|
832
|
+
attachedSessions = /* @__PURE__ */ new Map();
|
|
815
833
|
constructor(options = {}) {
|
|
816
834
|
this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
|
|
835
|
+
if (typeof options.requestTimeoutMs === "number" && options.requestTimeoutMs > 0) {
|
|
836
|
+
this.requestTimeoutMs = options.requestTimeoutMs;
|
|
837
|
+
}
|
|
838
|
+
activeClientRefs.add(new WeakRef(this));
|
|
839
|
+
}
|
|
840
|
+
static disconnectClients(endpoint, error) {
|
|
841
|
+
disconnectSessionHostClients(endpoint, error);
|
|
817
842
|
}
|
|
818
843
|
/**
|
|
819
844
|
* Fires when an established connection to the session host goes away.
|
|
@@ -856,6 +881,7 @@ var SessionHostClient = class {
|
|
|
856
881
|
this.requestWaiters.clear();
|
|
857
882
|
if (this.socket === socket) {
|
|
858
883
|
this.socket = null;
|
|
884
|
+
this.connectPromise = null;
|
|
859
885
|
}
|
|
860
886
|
try {
|
|
861
887
|
socket.destroy();
|
|
@@ -875,8 +901,48 @@ var SessionHostClient = class {
|
|
|
875
901
|
}
|
|
876
902
|
}
|
|
877
903
|
}
|
|
904
|
+
sendRawRequestOnSocket(socket, request) {
|
|
905
|
+
const requestId = generateUUID();
|
|
906
|
+
const envelope = {
|
|
907
|
+
kind: "request",
|
|
908
|
+
requestId,
|
|
909
|
+
request
|
|
910
|
+
};
|
|
911
|
+
const timeoutMs = this.requestTimeoutMs > 0 ? this.requestTimeoutMs : 3e4;
|
|
912
|
+
const timeoutLabel = timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3}s` : `${timeoutMs}ms`;
|
|
913
|
+
return new Promise((resolve3, reject) => {
|
|
914
|
+
const timeout = setTimeout(() => {
|
|
915
|
+
const timeoutError = new Error(`Session host request timed out after ${timeoutLabel} (${request.type})`);
|
|
916
|
+
if (this.socket === socket) {
|
|
917
|
+
this.disconnect(timeoutError);
|
|
918
|
+
} else {
|
|
919
|
+
this.requestWaiters.delete(requestId);
|
|
920
|
+
this.disconnectedSockets.add(socket);
|
|
921
|
+
try {
|
|
922
|
+
socket.destroy();
|
|
923
|
+
} catch {
|
|
924
|
+
}
|
|
925
|
+
reject(timeoutError);
|
|
926
|
+
}
|
|
927
|
+
}, timeoutMs);
|
|
928
|
+
this.requestWaiters.set(requestId, {
|
|
929
|
+
resolve: (value) => {
|
|
930
|
+
clearTimeout(timeout);
|
|
931
|
+
resolve3(value);
|
|
932
|
+
},
|
|
933
|
+
reject: (error) => {
|
|
934
|
+
clearTimeout(timeout);
|
|
935
|
+
reject(error);
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
socket.write(serializeEnvelope(envelope));
|
|
939
|
+
});
|
|
940
|
+
}
|
|
878
941
|
async connect() {
|
|
879
|
-
if (this.socket && !this.socket.destroyed)
|
|
942
|
+
if (this.socket && !this.socket.destroyed) {
|
|
943
|
+
if (this.connectPromise) await this.connectPromise;
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
880
946
|
if (this.socket) {
|
|
881
947
|
try {
|
|
882
948
|
this.socket.destroy();
|
|
@@ -884,6 +950,7 @@ var SessionHostClient = class {
|
|
|
884
950
|
}
|
|
885
951
|
this.socket = null;
|
|
886
952
|
}
|
|
953
|
+
this.connectPromise = null;
|
|
887
954
|
const socket = net.createConnection(this.endpoint.path);
|
|
888
955
|
this.socket = socket;
|
|
889
956
|
const parser = createLineParser((envelope) => {
|
|
@@ -917,13 +984,35 @@ var SessionHostClient = class {
|
|
|
917
984
|
socket.on("end", () => {
|
|
918
985
|
this.handleDisconnect(socket, "ended", void 0, flushParser().length);
|
|
919
986
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
987
|
+
const connectTask = (async () => {
|
|
988
|
+
await new Promise((resolve3, reject) => {
|
|
989
|
+
socket.once("connect", () => {
|
|
990
|
+
establishedSockets.add(socket);
|
|
991
|
+
resolve3();
|
|
992
|
+
});
|
|
993
|
+
socket.once("error", reject);
|
|
924
994
|
});
|
|
925
|
-
socket.
|
|
926
|
-
|
|
995
|
+
if (this.attachedSessions.size > 0 && this.socket === socket && !socket.destroyed) {
|
|
996
|
+
for (const [sessionId, sub] of [...this.attachedSessions.entries()]) {
|
|
997
|
+
if (this.socket !== socket || socket.destroyed) break;
|
|
998
|
+
const replayResponse = await this.sendRawRequestOnSocket(socket, {
|
|
999
|
+
type: "attach_session",
|
|
1000
|
+
payload: sub
|
|
1001
|
+
}).catch(() => null);
|
|
1002
|
+
if (replayResponse && !replayResponse.success) {
|
|
1003
|
+
this.attachedSessions.delete(sessionId);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
})();
|
|
1008
|
+
this.connectPromise = connectTask;
|
|
1009
|
+
try {
|
|
1010
|
+
await connectTask;
|
|
1011
|
+
} finally {
|
|
1012
|
+
if (this.connectPromise === connectTask) {
|
|
1013
|
+
this.connectPromise = null;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
927
1016
|
}
|
|
928
1017
|
onEvent(listener) {
|
|
929
1018
|
this.eventListeners.add(listener);
|
|
@@ -933,33 +1022,50 @@ var SessionHostClient = class {
|
|
|
933
1022
|
}
|
|
934
1023
|
async request(request) {
|
|
935
1024
|
await this.connect();
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
const
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1025
|
+
const requestSocket = this.socket;
|
|
1026
|
+
if (!requestSocket) throw new Error("Session host socket unavailable");
|
|
1027
|
+
const response = await this.sendRawRequestOnSocket(requestSocket, request);
|
|
1028
|
+
if (response.success) {
|
|
1029
|
+
if (request.type === "attach_session") {
|
|
1030
|
+
this.attachedSessions.set(request.payload.sessionId, {
|
|
1031
|
+
sessionId: request.payload.sessionId,
|
|
1032
|
+
clientId: request.payload.clientId,
|
|
1033
|
+
clientType: request.payload.clientType,
|
|
1034
|
+
readOnly: request.payload.readOnly === true
|
|
1035
|
+
});
|
|
1036
|
+
} else if (request.type === "create_session") {
|
|
1037
|
+
const createdId = response.result?.sessionId || request.payload.sessionId;
|
|
1038
|
+
const clientId = typeof request.payload.clientId === "string" ? request.payload.clientId.trim() : "";
|
|
1039
|
+
if (createdId && clientId) {
|
|
1040
|
+
this.attachedSessions.set(createdId, {
|
|
1041
|
+
sessionId: createdId,
|
|
1042
|
+
clientId,
|
|
1043
|
+
clientType: request.payload.clientType || "daemon",
|
|
1044
|
+
readOnly: false
|
|
1045
|
+
});
|
|
956
1046
|
}
|
|
957
|
-
})
|
|
958
|
-
|
|
959
|
-
|
|
1047
|
+
} else if (request.type === "detach_session" || request.type === "delete_session") {
|
|
1048
|
+
this.attachedSessions.delete(request.payload.sessionId);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
960
1051
|
return response;
|
|
961
1052
|
}
|
|
1053
|
+
disconnect(error) {
|
|
1054
|
+
const socket = this.socket;
|
|
1055
|
+
if (socket) {
|
|
1056
|
+
this.handleDisconnect(socket, error ? "error" : "closed", error, 0);
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
this.connectPromise = null;
|
|
1060
|
+
const failure = error || new Error(`Session host client disconnected (${this.endpoint.path})`);
|
|
1061
|
+
for (const waiter of this.requestWaiters.values()) {
|
|
1062
|
+
waiter.reject(failure);
|
|
1063
|
+
}
|
|
1064
|
+
this.requestWaiters.clear();
|
|
1065
|
+
}
|
|
962
1066
|
async close() {
|
|
1067
|
+
this.attachedSessions.clear();
|
|
1068
|
+
this.connectPromise = null;
|
|
963
1069
|
if (!this.socket) return;
|
|
964
1070
|
const socket = this.socket;
|
|
965
1071
|
this.socket = null;
|
|
@@ -1177,6 +1283,7 @@ function createSessionHostControlPlane(transport) {
|
|
|
1177
1283
|
createLineParser,
|
|
1178
1284
|
createResponseEnvelope,
|
|
1179
1285
|
createSessionHostControlPlane,
|
|
1286
|
+
disconnectSessionHostClients,
|
|
1180
1287
|
ensureNodePtySpawnHelperPermissions,
|
|
1181
1288
|
formatRuntimeOwner,
|
|
1182
1289
|
getDefaultSessionHostEndpoint,
|