@adhdev/mesh-shared 1.0.55 → 1.0.56-rc.10

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.ts CHANGED
@@ -24,3 +24,4 @@ export * from './slot-proposal';
24
24
  export * from './interpolation';
25
25
  export * from './mesh-tool-names';
26
26
  export * from './mesh-status-probe';
27
+ export * from './rpc-chunking';
package/dist/index.js CHANGED
@@ -25,7 +25,14 @@ __export(index_exports, {
25
25
  CLI_SLOT_RECIPES: () => CLI_SLOT_RECIPES,
26
26
  DEFAULT_DIFFICULTY_BRAINS: () => DEFAULT_DIFFICULTY_BRAINS,
27
27
  MAGI_RAW_ANSWER_CAP: () => MAGI_RAW_ANSWER_CAP,
28
+ MESH_CHUNK_KIND: () => MESH_CHUNK_KIND,
29
+ MESH_CHUNK_PAYLOAD_CHARS: () => MESH_CHUNK_PAYLOAD_CHARS,
30
+ MESH_CHUNK_TTL_MS: () => MESH_CHUNK_TTL_MS,
31
+ MESH_MAX_CHUNKS: () => MESH_MAX_CHUNKS,
32
+ MESH_MAX_INLINE_FRAME_BYTES: () => MESH_MAX_INLINE_FRAME_BYTES,
33
+ MESH_MAX_REASSEMBLED_BYTES: () => MESH_MAX_REASSEMBLED_BYTES,
28
34
  MESH_TASK_DIFFICULTIES: () => MESH_TASK_DIFFICULTIES,
35
+ MeshChunkAssembler: () => MeshChunkAssembler,
29
36
  QUOTA_SUPPORTED_PROVIDERS: () => QUOTA_SUPPORTED_PROVIDERS,
30
37
  STATUS_PROBE_ARG_KEY: () => STATUS_PROBE_ARG_KEY,
31
38
  UNKNOWN_CLI_SLOT_RECIPE: () => UNKNOWN_CLI_SLOT_RECIPE,
@@ -46,7 +53,10 @@ __export(index_exports, {
46
53
  isRawDaemonDoId: () => isRawDaemonDoId,
47
54
  joinRepoPath: () => joinRepoPath,
48
55
  machineCoreFromDaemonId: () => machineCoreFromDaemonId,
56
+ measureWorstCaseChunkEnvelopeBytes: () => measureWorstCaseChunkEnvelopeBytes,
57
+ meshFrameNeedsChunking: () => meshFrameNeedsChunking,
49
58
  meshNodeIdMatches: () => meshNodeIdMatches,
59
+ meshUtf8ByteLength: () => meshUtf8ByteLength,
50
60
  meshWorkspacesEquivalent: () => meshWorkspacesEquivalent,
51
61
  normalizeBrainSlot: () => normalizeBrainSlot,
52
62
  normalizeDifficultyBrainMap: () => normalizeDifficultyBrainMap,
@@ -69,6 +79,7 @@ __export(index_exports, {
69
79
  scoreGitStatusCandidate: () => scoreGitStatusCandidate,
70
80
  scoreGitUpstreamFreshness: () => scoreGitUpstreamFreshness,
71
81
  sessionIdsEquivalent: () => sessionIdsEquivalent,
82
+ splitMeshFrame: () => splitMeshFrame,
72
83
  stripStatusProbeMarker: () => stripStatusProbeMarker,
73
84
  summarizeGitShape: () => summarizeGitShape,
74
85
  supportsQuota: () => supportsQuota,
@@ -732,9 +743,15 @@ function interpolateString(template, ctx) {
732
743
  var CANONICAL_MESH_TOOL_NAMES = [
733
744
  "mesh_status",
734
745
  "mesh_list_nodes",
735
- "mesh_enqueue_task",
746
+ // GRAPH-ORCHESTRATION Phase F — batch before task, mirroring ALL_MESH_TOOLS.
736
747
  "mesh_enqueue_batch",
748
+ "mesh_enqueue_task",
737
749
  "mesh_view_queue",
750
+ // GRAPH-ORCHESTRATION Phase E — the coordinator gate + graph view surface.
751
+ "mesh_graph_view",
752
+ "mesh_graph_gate_claim",
753
+ "mesh_graph_gate_release",
754
+ "mesh_graph_gate_abandon",
738
755
  "mesh_queue_cancel",
739
756
  "mesh_queue_requeue",
740
757
  "mesh_send_task",
@@ -801,6 +818,183 @@ function stripStatusProbeMarker(args) {
801
818
  const { [STATUS_PROBE_ARG_KEY]: _drop, ...rest } = args;
802
819
  return rest;
803
820
  }
821
+
822
+ // src/rpc-chunking.ts
823
+ var MESH_MAX_INLINE_FRAME_BYTES = 6e4;
824
+ var MESH_CHUNK_PAYLOAD_CHARS = 16e3;
825
+ var MESH_MAX_CHUNKS = 1024;
826
+ var MESH_MAX_REASSEMBLED_BYTES = 16e6;
827
+ var MESH_CHUNK_TTL_MS = 6e4;
828
+ var MESH_CHUNK_KIND = "rpc_chunk";
829
+ function meshUtf8ByteLength(value) {
830
+ if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(value).byteLength;
831
+ let bytes = 0;
832
+ for (let i = 0; i < value.length; i += 1) {
833
+ const code = value.charCodeAt(i);
834
+ if (code < 128) bytes += 1;
835
+ else if (code < 2048) bytes += 2;
836
+ else if (code >= 55296 && code <= 56319) {
837
+ bytes += 4;
838
+ i += 1;
839
+ } else bytes += 3;
840
+ }
841
+ return bytes;
842
+ }
843
+ function measureWorstCaseChunkEnvelopeBytes() {
844
+ const densest = "\uD55C".repeat(MESH_CHUNK_PAYLOAD_CHARS);
845
+ return meshUtf8ByteLength(JSON.stringify(
846
+ buildChunkEnvelope(Number.MAX_SAFE_INTEGER, "x".repeat(64), MESH_MAX_CHUNKS, MESH_MAX_CHUNKS, densest)
847
+ ));
848
+ }
849
+ function meshFrameNeedsChunking(json) {
850
+ return meshUtf8ByteLength(json) > MESH_MAX_INLINE_FRAME_BYTES;
851
+ }
852
+ function buildChunkEnvelope(version, chunkId, index, total, data) {
853
+ return { v: version, kind: MESH_CHUNK_KIND, chunkId, index, total, data };
854
+ }
855
+ function splitMeshFrame(json, chunkId, version) {
856
+ const slices = [];
857
+ let offset = 0;
858
+ while (offset < json.length) {
859
+ let end = Math.min(json.length, offset + MESH_CHUNK_PAYLOAD_CHARS);
860
+ while (end > offset) {
861
+ const candidate = json.slice(offset, end);
862
+ const probe = JSON.stringify(buildChunkEnvelope(version, chunkId, slices.length, MESH_MAX_CHUNKS, candidate));
863
+ if (meshUtf8ByteLength(probe) <= MESH_MAX_INLINE_FRAME_BYTES) break;
864
+ const shrunk = Math.max(1, Math.floor((end - offset) * 0.8));
865
+ if (offset + shrunk >= end) {
866
+ end -= 1;
867
+ continue;
868
+ }
869
+ end = offset + shrunk;
870
+ }
871
+ if (end <= offset) {
872
+ return { ok: false, reason: "chunk_too_large", detail: "a single character did not fit the chunk envelope budget" };
873
+ }
874
+ slices.push(json.slice(offset, end));
875
+ if (slices.length > MESH_MAX_CHUNKS) {
876
+ return {
877
+ ok: false,
878
+ reason: "too_many_chunks",
879
+ detail: `frame needs more than ${MESH_MAX_CHUNKS} chunks (${meshUtf8ByteLength(json)} bytes)`
880
+ };
881
+ }
882
+ offset = end;
883
+ }
884
+ if (slices.length === 0) {
885
+ return { ok: false, reason: "chunk_too_large", detail: "refusing to chunk an empty frame" };
886
+ }
887
+ const total = slices.length;
888
+ return { ok: true, chunks: slices.map((data, index) => buildChunkEnvelope(version, chunkId, index, total, data)) };
889
+ }
890
+ var MeshChunkAssembler = class {
891
+ constructor(now = () => Date.now()) {
892
+ this.now = now;
893
+ }
894
+ buffers = /* @__PURE__ */ new Map();
895
+ /** True when the frame is a chunk envelope this assembler should handle. */
896
+ static isChunkFrame(frame) {
897
+ return !!frame && typeof frame === "object" && frame.kind === MESH_CHUNK_KIND;
898
+ }
899
+ /** Drop partials older than the TTL so a dead sender cannot pin memory. */
900
+ sweep() {
901
+ const now = this.now();
902
+ for (const [key, entry] of Array.from(this.buffers.entries())) {
903
+ if (now - entry.createdAt > MESH_CHUNK_TTL_MS) this.buffers.delete(key);
904
+ }
905
+ }
906
+ /** Discard any partial state for a peer (call on disconnect). */
907
+ reset() {
908
+ this.buffers.clear();
909
+ }
910
+ /** Number of frames currently mid-reassembly — for tests and diagnostics. */
911
+ get pendingCount() {
912
+ return this.buffers.size;
913
+ }
914
+ /**
915
+ * Accept one chunk envelope.
916
+ *
917
+ * Never throws and never returns a partially-applied frame: the result is exactly one
918
+ * of partial / complete / failed, and `failed` carries a typed reason the transport
919
+ * turns into an explicit RPC error.
920
+ */
921
+ accept(frame) {
922
+ this.sweep();
923
+ const raw = frame;
924
+ const chunkId = typeof raw?.chunkId === "string" ? raw.chunkId : "";
925
+ const index = Number(raw?.index);
926
+ const total = Number(raw?.total);
927
+ const data = typeof raw?.data === "string" ? raw.data : "";
928
+ if (!chunkId || !Number.isInteger(index) || !Number.isInteger(total) || index < 0 || total <= 0 || index >= total || !data) {
929
+ return {
930
+ status: "failed",
931
+ reason: "malformed_chunk",
932
+ detail: `malformed chunk envelope (chunkId=${chunkId || "-"} index=${raw?.index} total=${raw?.total})`,
933
+ chunkId
934
+ };
935
+ }
936
+ if (total > MESH_MAX_CHUNKS) {
937
+ this.buffers.delete(chunkId);
938
+ return {
939
+ status: "failed",
940
+ reason: "too_many_chunks",
941
+ detail: `chunk total ${total} exceeds the ${MESH_MAX_CHUNKS} cap`,
942
+ chunkId
943
+ };
944
+ }
945
+ let entry = this.buffers.get(chunkId);
946
+ if (!entry) {
947
+ entry = { total, chunks: new Array(total).fill(""), received: 0, bytesReceived: 0, createdAt: this.now() };
948
+ this.buffers.set(chunkId, entry);
949
+ } else if (entry.total !== total) {
950
+ this.buffers.delete(chunkId);
951
+ return {
952
+ status: "failed",
953
+ reason: "inconsistent_total",
954
+ detail: `chunk ${index} declares total ${total} but the group was opened with ${entry.total}`,
955
+ chunkId
956
+ };
957
+ }
958
+ const existing = entry.chunks[index];
959
+ if (existing) {
960
+ if (existing === data) return { status: "partial", received: entry.received, total: entry.total };
961
+ this.buffers.delete(chunkId);
962
+ return {
963
+ status: "failed",
964
+ reason: "duplicate_chunk_mismatch",
965
+ detail: `chunk ${index} arrived twice with different content`,
966
+ chunkId
967
+ };
968
+ }
969
+ const chunkBytes = meshUtf8ByteLength(data);
970
+ if (entry.bytesReceived + chunkBytes > MESH_MAX_REASSEMBLED_BYTES) {
971
+ this.buffers.delete(chunkId);
972
+ return {
973
+ status: "failed",
974
+ reason: "budget_exceeded",
975
+ detail: `reassembled frame would exceed ${MESH_MAX_REASSEMBLED_BYTES} bytes`,
976
+ chunkId
977
+ };
978
+ }
979
+ entry.chunks[index] = data;
980
+ entry.received += 1;
981
+ entry.bytesReceived += chunkBytes;
982
+ if (entry.received < entry.total) {
983
+ return { status: "partial", received: entry.received, total: entry.total };
984
+ }
985
+ this.buffers.delete(chunkId);
986
+ try {
987
+ return { status: "complete", frame: JSON.parse(entry.chunks.join("")) };
988
+ } catch (error) {
989
+ return {
990
+ status: "failed",
991
+ reason: "reassembled_parse_failed",
992
+ detail: `reassembled frame is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
993
+ chunkId
994
+ };
995
+ }
996
+ }
997
+ };
804
998
  // Annotate the CommonJS export names for ESM import in node:
805
999
  0 && (module.exports = {
806
1000
  CANONICAL_MESH_TOOL_COUNT,
@@ -808,7 +1002,14 @@ function stripStatusProbeMarker(args) {
808
1002
  CLI_SLOT_RECIPES,
809
1003
  DEFAULT_DIFFICULTY_BRAINS,
810
1004
  MAGI_RAW_ANSWER_CAP,
1005
+ MESH_CHUNK_KIND,
1006
+ MESH_CHUNK_PAYLOAD_CHARS,
1007
+ MESH_CHUNK_TTL_MS,
1008
+ MESH_MAX_CHUNKS,
1009
+ MESH_MAX_INLINE_FRAME_BYTES,
1010
+ MESH_MAX_REASSEMBLED_BYTES,
811
1011
  MESH_TASK_DIFFICULTIES,
1012
+ MeshChunkAssembler,
812
1013
  QUOTA_SUPPORTED_PROVIDERS,
813
1014
  STATUS_PROBE_ARG_KEY,
814
1015
  UNKNOWN_CLI_SLOT_RECIPE,
@@ -829,7 +1030,10 @@ function stripStatusProbeMarker(args) {
829
1030
  isRawDaemonDoId,
830
1031
  joinRepoPath,
831
1032
  machineCoreFromDaemonId,
1033
+ measureWorstCaseChunkEnvelopeBytes,
1034
+ meshFrameNeedsChunking,
832
1035
  meshNodeIdMatches,
1036
+ meshUtf8ByteLength,
833
1037
  meshWorkspacesEquivalent,
834
1038
  normalizeBrainSlot,
835
1039
  normalizeDifficultyBrainMap,
@@ -852,6 +1056,7 @@ function stripStatusProbeMarker(args) {
852
1056
  scoreGitStatusCandidate,
853
1057
  scoreGitUpstreamFreshness,
854
1058
  sessionIdsEquivalent,
1059
+ splitMeshFrame,
855
1060
  stripStatusProbeMarker,
856
1061
  summarizeGitShape,
857
1062
  supportsQuota,