@adhdev/session-host-core 1.0.58-rc.9 → 1.0.58-rc.90
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 +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +29 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +29 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/ipc.ts +88 -8
- package/src/spawn-env.ts +23 -0
package/dist/index.d.mts
CHANGED
|
@@ -533,7 +533,27 @@ interface SessionHostEndpointOptions {
|
|
|
533
533
|
platform?: NodeJS.Platform;
|
|
534
534
|
}
|
|
535
535
|
declare function getDefaultSessionHostEndpoint(appName?: string, options?: SessionHostEndpointOptions): SessionHostEndpoint;
|
|
536
|
-
|
|
536
|
+
/**
|
|
537
|
+
* UTF8-CHUNK-BOUNDARY: decode the socket stream, never the individual chunk.
|
|
538
|
+
*
|
|
539
|
+
* This used to call `chunk.toString()` on every Buffer independently. A socket
|
|
540
|
+
* hands us arbitrary byte slices — a multi-byte UTF-8 sequence straddling two
|
|
541
|
+
* chunks gets decoded as two truncated sequences, and each half becomes U+FFFD.
|
|
542
|
+
* The damage is silent by construction: the replacement character is valid JSON
|
|
543
|
+
* string content, so the envelope still parses and only the *value* is wrong.
|
|
544
|
+
* A pasted 11,994-char Korean prompt lost exactly one character that way — the
|
|
545
|
+
* `도` beginning at wire offset 8190, split across the 8192-byte chunk boundary,
|
|
546
|
+
* arrived as `�착`.
|
|
547
|
+
*
|
|
548
|
+
* StringDecoder holds an incomplete trailing sequence back until the bytes that
|
|
549
|
+
* finish it arrive, which is the only correct way to turn a byte stream into
|
|
550
|
+
* text. String chunks bypass it: they are already decoded, and feeding them
|
|
551
|
+
* through `Buffer.from` would re-encode text the caller never asked us to touch.
|
|
552
|
+
*/
|
|
553
|
+
declare function createLineParser(onEnvelope: (envelope: SessionHostWireEnvelope) => void): {
|
|
554
|
+
(chunk: Buffer | string): void;
|
|
555
|
+
end(): string;
|
|
556
|
+
};
|
|
537
557
|
interface SessionHostClientOptions {
|
|
538
558
|
endpoint?: SessionHostEndpoint;
|
|
539
559
|
appName?: string;
|
|
@@ -551,6 +571,16 @@ interface SessionHostDisconnectInfo {
|
|
|
551
571
|
/** In-flight requests abandoned by this disconnect (they were rejected). */
|
|
552
572
|
pendingRequests: number;
|
|
553
573
|
error?: Error;
|
|
574
|
+
/**
|
|
575
|
+
* Bytes discarded from a newline-unterminated frame at EOF (0 when the peer
|
|
576
|
+
* hung up on a clean frame boundary, which is the normal case).
|
|
577
|
+
*
|
|
578
|
+
* Non-zero means the peer was cut off MID-WRITE — diagnostic context that
|
|
579
|
+
* distinguishes "the host exited" from "the host died with a frame in
|
|
580
|
+
* flight". Before the parser's `end()` was reachable this was unknowable:
|
|
581
|
+
* the bytes were dropped with the decoder and no counter existed.
|
|
582
|
+
*/
|
|
583
|
+
droppedTailBytes: number;
|
|
554
584
|
}
|
|
555
585
|
declare class SessionHostClient {
|
|
556
586
|
readonly endpoint: SessionHostEndpoint;
|
package/dist/index.d.ts
CHANGED
|
@@ -533,7 +533,27 @@ interface SessionHostEndpointOptions {
|
|
|
533
533
|
platform?: NodeJS.Platform;
|
|
534
534
|
}
|
|
535
535
|
declare function getDefaultSessionHostEndpoint(appName?: string, options?: SessionHostEndpointOptions): SessionHostEndpoint;
|
|
536
|
-
|
|
536
|
+
/**
|
|
537
|
+
* UTF8-CHUNK-BOUNDARY: decode the socket stream, never the individual chunk.
|
|
538
|
+
*
|
|
539
|
+
* This used to call `chunk.toString()` on every Buffer independently. A socket
|
|
540
|
+
* hands us arbitrary byte slices — a multi-byte UTF-8 sequence straddling two
|
|
541
|
+
* chunks gets decoded as two truncated sequences, and each half becomes U+FFFD.
|
|
542
|
+
* The damage is silent by construction: the replacement character is valid JSON
|
|
543
|
+
* string content, so the envelope still parses and only the *value* is wrong.
|
|
544
|
+
* A pasted 11,994-char Korean prompt lost exactly one character that way — the
|
|
545
|
+
* `도` beginning at wire offset 8190, split across the 8192-byte chunk boundary,
|
|
546
|
+
* arrived as `�착`.
|
|
547
|
+
*
|
|
548
|
+
* StringDecoder holds an incomplete trailing sequence back until the bytes that
|
|
549
|
+
* finish it arrive, which is the only correct way to turn a byte stream into
|
|
550
|
+
* text. String chunks bypass it: they are already decoded, and feeding them
|
|
551
|
+
* through `Buffer.from` would re-encode text the caller never asked us to touch.
|
|
552
|
+
*/
|
|
553
|
+
declare function createLineParser(onEnvelope: (envelope: SessionHostWireEnvelope) => void): {
|
|
554
|
+
(chunk: Buffer | string): void;
|
|
555
|
+
end(): string;
|
|
556
|
+
};
|
|
537
557
|
interface SessionHostClientOptions {
|
|
538
558
|
endpoint?: SessionHostEndpoint;
|
|
539
559
|
appName?: string;
|
|
@@ -551,6 +571,16 @@ interface SessionHostDisconnectInfo {
|
|
|
551
571
|
/** In-flight requests abandoned by this disconnect (they were rejected). */
|
|
552
572
|
pendingRequests: number;
|
|
553
573
|
error?: Error;
|
|
574
|
+
/**
|
|
575
|
+
* Bytes discarded from a newline-unterminated frame at EOF (0 when the peer
|
|
576
|
+
* hung up on a clean frame boundary, which is the normal case).
|
|
577
|
+
*
|
|
578
|
+
* Non-zero means the peer was cut off MID-WRITE — diagnostic context that
|
|
579
|
+
* distinguishes "the host exited" from "the host died with a frame in
|
|
580
|
+
* flight". Before the parser's `end()` was reachable this was unknowable:
|
|
581
|
+
* the bytes were dropped with the decoder and no counter existed.
|
|
582
|
+
*/
|
|
583
|
+
droppedTailBytes: number;
|
|
554
584
|
}
|
|
555
585
|
declare class SessionHostClient {
|
|
556
586
|
readonly endpoint: SessionHostEndpoint;
|
package/dist/index.js
CHANGED
|
@@ -580,6 +580,7 @@ var SessionHostRegistry = class {
|
|
|
580
580
|
var os = __toESM(require("os"));
|
|
581
581
|
var path2 = __toESM(require("path"));
|
|
582
582
|
var net = __toESM(require("net"));
|
|
583
|
+
var import_string_decoder = require("string_decoder");
|
|
583
584
|
function generateUUID2() {
|
|
584
585
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
585
586
|
return crypto.randomUUID();
|
|
@@ -614,8 +615,9 @@ function serializeEnvelope(envelope) {
|
|
|
614
615
|
}
|
|
615
616
|
function createLineParser(onEnvelope) {
|
|
616
617
|
let buffer = "";
|
|
617
|
-
|
|
618
|
-
|
|
618
|
+
const decoder = new import_string_decoder.StringDecoder("utf8");
|
|
619
|
+
const parser = (chunk) => {
|
|
620
|
+
buffer += typeof chunk === "string" ? chunk : decoder.write(chunk);
|
|
619
621
|
let newlineIndex = buffer.indexOf("\n");
|
|
620
622
|
while (newlineIndex >= 0) {
|
|
621
623
|
const rawLine = buffer.slice(0, newlineIndex).trim();
|
|
@@ -626,6 +628,12 @@ function createLineParser(onEnvelope) {
|
|
|
626
628
|
newlineIndex = buffer.indexOf("\n");
|
|
627
629
|
}
|
|
628
630
|
};
|
|
631
|
+
parser.end = () => {
|
|
632
|
+
const remainder = buffer + decoder.end();
|
|
633
|
+
buffer = "";
|
|
634
|
+
return remainder;
|
|
635
|
+
};
|
|
636
|
+
return parser;
|
|
629
637
|
}
|
|
630
638
|
var establishedSockets = /* @__PURE__ */ new WeakSet();
|
|
631
639
|
var SessionHostClient = class {
|
|
@@ -657,7 +665,7 @@ var SessionHostClient = class {
|
|
|
657
665
|
this.disconnectListeners.delete(listener);
|
|
658
666
|
};
|
|
659
667
|
}
|
|
660
|
-
handleDisconnect(socket, reason, error) {
|
|
668
|
+
handleDisconnect(socket, reason, error, droppedTailBytes = 0) {
|
|
661
669
|
if (this.disconnectedSockets.has(socket)) return;
|
|
662
670
|
this.disconnectedSockets.add(socket);
|
|
663
671
|
const wasEstablished = establishedSockets.has(socket);
|
|
@@ -689,7 +697,8 @@ var SessionHostClient = class {
|
|
|
689
697
|
reason,
|
|
690
698
|
endpointPath: this.endpoint.path,
|
|
691
699
|
pendingRequests,
|
|
692
|
-
error
|
|
700
|
+
error,
|
|
701
|
+
droppedTailBytes
|
|
693
702
|
};
|
|
694
703
|
for (const listener of this.disconnectListeners) {
|
|
695
704
|
try {
|
|
@@ -709,7 +718,7 @@ var SessionHostClient = class {
|
|
|
709
718
|
}
|
|
710
719
|
const socket = net.createConnection(this.endpoint.path);
|
|
711
720
|
this.socket = socket;
|
|
712
|
-
|
|
721
|
+
const parser = createLineParser((envelope) => {
|
|
713
722
|
if (envelope.kind === "response") {
|
|
714
723
|
const waiter = this.requestWaiters.get(envelope.requestId);
|
|
715
724
|
if (waiter) {
|
|
@@ -721,15 +730,24 @@ var SessionHostClient = class {
|
|
|
721
730
|
if (envelope.kind === "event") {
|
|
722
731
|
for (const listener of this.eventListeners) listener(envelope.event);
|
|
723
732
|
}
|
|
724
|
-
})
|
|
733
|
+
});
|
|
734
|
+
socket.on("data", parser);
|
|
735
|
+
const flushParser = () => {
|
|
736
|
+
try {
|
|
737
|
+
return parser.end();
|
|
738
|
+
} catch {
|
|
739
|
+
return "";
|
|
740
|
+
}
|
|
741
|
+
};
|
|
725
742
|
socket.on("error", (error) => {
|
|
726
|
-
|
|
743
|
+
const remainder = flushParser();
|
|
744
|
+
this.handleDisconnect(socket, "error", error, remainder.length);
|
|
727
745
|
});
|
|
728
746
|
socket.on("close", () => {
|
|
729
|
-
this.handleDisconnect(socket, "closed");
|
|
747
|
+
this.handleDisconnect(socket, "closed", void 0, flushParser().length);
|
|
730
748
|
});
|
|
731
749
|
socket.on("end", () => {
|
|
732
|
-
this.handleDisconnect(socket, "ended");
|
|
750
|
+
this.handleDisconnect(socket, "ended", void 0, flushParser().length);
|
|
733
751
|
});
|
|
734
752
|
await new Promise((resolve3, reject) => {
|
|
735
753
|
socket.once("connect", () => {
|
|
@@ -867,6 +885,8 @@ function sanitizeSpawnEnv(baseEnv, overrides) {
|
|
|
867
885
|
delete env.CODEX_SANDBOX_NETWORK_DISABLED;
|
|
868
886
|
delete env.NO_COLOR;
|
|
869
887
|
delete env.COLOR;
|
|
888
|
+
delete env.COLUMNS;
|
|
889
|
+
delete env.LINES;
|
|
870
890
|
delete env.CLAUDECODE;
|
|
871
891
|
delete env.CLAUDE_CODE_CHILD_SESSION;
|
|
872
892
|
delete env.CLAUDE_CODE_ENTRYPOINT;
|