@adhdev/mesh-shared 1.0.56-rc.8 → 1.0.56
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 +1 -0
- package/dist/index.js +200 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +189 -0
- package/dist/index.mjs.map +1 -1
- package/dist/mesh-tool-names.d.ts +2 -2
- package/dist/node-facts.d.ts +64 -5
- package/dist/rpc-chunking.d.ts +162 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/mesh-tool-names.ts +1 -0
- package/src/node-facts.ts +65 -5
- package/src/rpc-chunking.ts +336 -0
package/dist/index.d.ts
CHANGED
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,
|
|
@@ -740,6 +751,7 @@ var CANONICAL_MESH_TOOL_NAMES = [
|
|
|
740
751
|
"mesh_graph_view",
|
|
741
752
|
"mesh_graph_gate_claim",
|
|
742
753
|
"mesh_graph_gate_release",
|
|
754
|
+
"mesh_graph_gate_abandon",
|
|
743
755
|
"mesh_queue_cancel",
|
|
744
756
|
"mesh_queue_requeue",
|
|
745
757
|
"mesh_send_task",
|
|
@@ -806,6 +818,183 @@ function stripStatusProbeMarker(args) {
|
|
|
806
818
|
const { [STATUS_PROBE_ARG_KEY]: _drop, ...rest } = args;
|
|
807
819
|
return rest;
|
|
808
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
|
+
};
|
|
809
998
|
// Annotate the CommonJS export names for ESM import in node:
|
|
810
999
|
0 && (module.exports = {
|
|
811
1000
|
CANONICAL_MESH_TOOL_COUNT,
|
|
@@ -813,7 +1002,14 @@ function stripStatusProbeMarker(args) {
|
|
|
813
1002
|
CLI_SLOT_RECIPES,
|
|
814
1003
|
DEFAULT_DIFFICULTY_BRAINS,
|
|
815
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,
|
|
816
1011
|
MESH_TASK_DIFFICULTIES,
|
|
1012
|
+
MeshChunkAssembler,
|
|
817
1013
|
QUOTA_SUPPORTED_PROVIDERS,
|
|
818
1014
|
STATUS_PROBE_ARG_KEY,
|
|
819
1015
|
UNKNOWN_CLI_SLOT_RECIPE,
|
|
@@ -834,7 +1030,10 @@ function stripStatusProbeMarker(args) {
|
|
|
834
1030
|
isRawDaemonDoId,
|
|
835
1031
|
joinRepoPath,
|
|
836
1032
|
machineCoreFromDaemonId,
|
|
1033
|
+
measureWorstCaseChunkEnvelopeBytes,
|
|
1034
|
+
meshFrameNeedsChunking,
|
|
837
1035
|
meshNodeIdMatches,
|
|
1036
|
+
meshUtf8ByteLength,
|
|
838
1037
|
meshWorkspacesEquivalent,
|
|
839
1038
|
normalizeBrainSlot,
|
|
840
1039
|
normalizeDifficultyBrainMap,
|
|
@@ -857,6 +1056,7 @@ function stripStatusProbeMarker(args) {
|
|
|
857
1056
|
scoreGitStatusCandidate,
|
|
858
1057
|
scoreGitUpstreamFreshness,
|
|
859
1058
|
sessionIdsEquivalent,
|
|
1059
|
+
splitMeshFrame,
|
|
860
1060
|
stripStatusProbeMarker,
|
|
861
1061
|
summarizeGitShape,
|
|
862
1062
|
supportsQuota,
|