@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.mjs
CHANGED
|
@@ -733,16 +733,40 @@ function createLineParser(onEnvelope) {
|
|
|
733
733
|
return parser;
|
|
734
734
|
}
|
|
735
735
|
var establishedSockets = /* @__PURE__ */ new WeakSet();
|
|
736
|
+
var activeClientRefs = /* @__PURE__ */ new Set();
|
|
737
|
+
function disconnectSessionHostClients(endpoint, error) {
|
|
738
|
+
for (const ref of activeClientRefs) {
|
|
739
|
+
const client = ref.deref();
|
|
740
|
+
if (!client) {
|
|
741
|
+
activeClientRefs.delete(ref);
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
if (!endpoint || client.endpoint.path === endpoint.path) {
|
|
745
|
+
client.disconnect(error);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
736
749
|
var SessionHostClient = class {
|
|
737
750
|
endpoint;
|
|
738
751
|
socket = null;
|
|
752
|
+
connectPromise = null;
|
|
753
|
+
requestTimeoutMs = 3e4;
|
|
739
754
|
requestWaiters = /* @__PURE__ */ new Map();
|
|
740
755
|
eventListeners = /* @__PURE__ */ new Set();
|
|
741
756
|
disconnectListeners = /* @__PURE__ */ new Set();
|
|
742
757
|
/** Guards against emitting both an 'error'-path and a 'close'-path disconnect for one socket. */
|
|
743
758
|
disconnectedSockets = /* @__PURE__ */ new WeakSet();
|
|
759
|
+
/** Session subscriptions established via create_session/attach_session, replayed automatically on reconnect. */
|
|
760
|
+
attachedSessions = /* @__PURE__ */ new Map();
|
|
744
761
|
constructor(options = {}) {
|
|
745
762
|
this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || "adhdev");
|
|
763
|
+
if (typeof options.requestTimeoutMs === "number" && options.requestTimeoutMs > 0) {
|
|
764
|
+
this.requestTimeoutMs = options.requestTimeoutMs;
|
|
765
|
+
}
|
|
766
|
+
activeClientRefs.add(new WeakRef(this));
|
|
767
|
+
}
|
|
768
|
+
static disconnectClients(endpoint, error) {
|
|
769
|
+
disconnectSessionHostClients(endpoint, error);
|
|
746
770
|
}
|
|
747
771
|
/**
|
|
748
772
|
* Fires when an established connection to the session host goes away.
|
|
@@ -785,6 +809,7 @@ var SessionHostClient = class {
|
|
|
785
809
|
this.requestWaiters.clear();
|
|
786
810
|
if (this.socket === socket) {
|
|
787
811
|
this.socket = null;
|
|
812
|
+
this.connectPromise = null;
|
|
788
813
|
}
|
|
789
814
|
try {
|
|
790
815
|
socket.destroy();
|
|
@@ -804,8 +829,48 @@ var SessionHostClient = class {
|
|
|
804
829
|
}
|
|
805
830
|
}
|
|
806
831
|
}
|
|
832
|
+
sendRawRequestOnSocket(socket, request) {
|
|
833
|
+
const requestId = generateUUID();
|
|
834
|
+
const envelope = {
|
|
835
|
+
kind: "request",
|
|
836
|
+
requestId,
|
|
837
|
+
request
|
|
838
|
+
};
|
|
839
|
+
const timeoutMs = this.requestTimeoutMs > 0 ? this.requestTimeoutMs : 3e4;
|
|
840
|
+
const timeoutLabel = timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3}s` : `${timeoutMs}ms`;
|
|
841
|
+
return new Promise((resolve3, reject) => {
|
|
842
|
+
const timeout = setTimeout(() => {
|
|
843
|
+
const timeoutError = new Error(`Session host request timed out after ${timeoutLabel} (${request.type})`);
|
|
844
|
+
if (this.socket === socket) {
|
|
845
|
+
this.disconnect(timeoutError);
|
|
846
|
+
} else {
|
|
847
|
+
this.requestWaiters.delete(requestId);
|
|
848
|
+
this.disconnectedSockets.add(socket);
|
|
849
|
+
try {
|
|
850
|
+
socket.destroy();
|
|
851
|
+
} catch {
|
|
852
|
+
}
|
|
853
|
+
reject(timeoutError);
|
|
854
|
+
}
|
|
855
|
+
}, timeoutMs);
|
|
856
|
+
this.requestWaiters.set(requestId, {
|
|
857
|
+
resolve: (value) => {
|
|
858
|
+
clearTimeout(timeout);
|
|
859
|
+
resolve3(value);
|
|
860
|
+
},
|
|
861
|
+
reject: (error) => {
|
|
862
|
+
clearTimeout(timeout);
|
|
863
|
+
reject(error);
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
socket.write(serializeEnvelope(envelope));
|
|
867
|
+
});
|
|
868
|
+
}
|
|
807
869
|
async connect() {
|
|
808
|
-
if (this.socket && !this.socket.destroyed)
|
|
870
|
+
if (this.socket && !this.socket.destroyed) {
|
|
871
|
+
if (this.connectPromise) await this.connectPromise;
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
809
874
|
if (this.socket) {
|
|
810
875
|
try {
|
|
811
876
|
this.socket.destroy();
|
|
@@ -813,6 +878,7 @@ var SessionHostClient = class {
|
|
|
813
878
|
}
|
|
814
879
|
this.socket = null;
|
|
815
880
|
}
|
|
881
|
+
this.connectPromise = null;
|
|
816
882
|
const socket = net.createConnection(this.endpoint.path);
|
|
817
883
|
this.socket = socket;
|
|
818
884
|
const parser = createLineParser((envelope) => {
|
|
@@ -846,13 +912,35 @@ var SessionHostClient = class {
|
|
|
846
912
|
socket.on("end", () => {
|
|
847
913
|
this.handleDisconnect(socket, "ended", void 0, flushParser().length);
|
|
848
914
|
});
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
915
|
+
const connectTask = (async () => {
|
|
916
|
+
await new Promise((resolve3, reject) => {
|
|
917
|
+
socket.once("connect", () => {
|
|
918
|
+
establishedSockets.add(socket);
|
|
919
|
+
resolve3();
|
|
920
|
+
});
|
|
921
|
+
socket.once("error", reject);
|
|
853
922
|
});
|
|
854
|
-
socket.
|
|
855
|
-
|
|
923
|
+
if (this.attachedSessions.size > 0 && this.socket === socket && !socket.destroyed) {
|
|
924
|
+
for (const [sessionId, sub] of [...this.attachedSessions.entries()]) {
|
|
925
|
+
if (this.socket !== socket || socket.destroyed) break;
|
|
926
|
+
const replayResponse = await this.sendRawRequestOnSocket(socket, {
|
|
927
|
+
type: "attach_session",
|
|
928
|
+
payload: sub
|
|
929
|
+
}).catch(() => null);
|
|
930
|
+
if (replayResponse && !replayResponse.success) {
|
|
931
|
+
this.attachedSessions.delete(sessionId);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
})();
|
|
936
|
+
this.connectPromise = connectTask;
|
|
937
|
+
try {
|
|
938
|
+
await connectTask;
|
|
939
|
+
} finally {
|
|
940
|
+
if (this.connectPromise === connectTask) {
|
|
941
|
+
this.connectPromise = null;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
856
944
|
}
|
|
857
945
|
onEvent(listener) {
|
|
858
946
|
this.eventListeners.add(listener);
|
|
@@ -862,33 +950,50 @@ var SessionHostClient = class {
|
|
|
862
950
|
}
|
|
863
951
|
async request(request) {
|
|
864
952
|
await this.connect();
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
953
|
+
const requestSocket = this.socket;
|
|
954
|
+
if (!requestSocket) throw new Error("Session host socket unavailable");
|
|
955
|
+
const response = await this.sendRawRequestOnSocket(requestSocket, request);
|
|
956
|
+
if (response.success) {
|
|
957
|
+
if (request.type === "attach_session") {
|
|
958
|
+
this.attachedSessions.set(request.payload.sessionId, {
|
|
959
|
+
sessionId: request.payload.sessionId,
|
|
960
|
+
clientId: request.payload.clientId,
|
|
961
|
+
clientType: request.payload.clientType,
|
|
962
|
+
readOnly: request.payload.readOnly === true
|
|
963
|
+
});
|
|
964
|
+
} else if (request.type === "create_session") {
|
|
965
|
+
const createdId = response.result?.sessionId || request.payload.sessionId;
|
|
966
|
+
const clientId = typeof request.payload.clientId === "string" ? request.payload.clientId.trim() : "";
|
|
967
|
+
if (createdId && clientId) {
|
|
968
|
+
this.attachedSessions.set(createdId, {
|
|
969
|
+
sessionId: createdId,
|
|
970
|
+
clientId,
|
|
971
|
+
clientType: request.payload.clientType || "daemon",
|
|
972
|
+
readOnly: false
|
|
973
|
+
});
|
|
885
974
|
}
|
|
886
|
-
})
|
|
887
|
-
|
|
888
|
-
|
|
975
|
+
} else if (request.type === "detach_session" || request.type === "delete_session") {
|
|
976
|
+
this.attachedSessions.delete(request.payload.sessionId);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
889
979
|
return response;
|
|
890
980
|
}
|
|
981
|
+
disconnect(error) {
|
|
982
|
+
const socket = this.socket;
|
|
983
|
+
if (socket) {
|
|
984
|
+
this.handleDisconnect(socket, error ? "error" : "closed", error, 0);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
this.connectPromise = null;
|
|
988
|
+
const failure = error || new Error(`Session host client disconnected (${this.endpoint.path})`);
|
|
989
|
+
for (const waiter of this.requestWaiters.values()) {
|
|
990
|
+
waiter.reject(failure);
|
|
991
|
+
}
|
|
992
|
+
this.requestWaiters.clear();
|
|
993
|
+
}
|
|
891
994
|
async close() {
|
|
995
|
+
this.attachedSessions.clear();
|
|
996
|
+
this.connectPromise = null;
|
|
892
997
|
if (!this.socket) return;
|
|
893
998
|
const socket = this.socket;
|
|
894
999
|
this.socket = null;
|
|
@@ -1105,6 +1210,7 @@ export {
|
|
|
1105
1210
|
createLineParser,
|
|
1106
1211
|
createResponseEnvelope,
|
|
1107
1212
|
createSessionHostControlPlane,
|
|
1213
|
+
disconnectSessionHostClients,
|
|
1108
1214
|
ensureNodePtySpawnHelperPermissions,
|
|
1109
1215
|
formatRuntimeOwner,
|
|
1110
1216
|
getDefaultSessionHostEndpoint,
|