@adhdev/mesh-shared 1.0.60-rc.69 → 1.0.60-rc.70

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
@@ -38,3 +38,5 @@ export * from './session-launch';
38
38
  export * from './turn-ipc';
39
39
  export * from './path-ownership';
40
40
  export * from './mission-brief';
41
+ export * from './keyed-status-delta';
42
+ export * from './keyed-doc-delta';
package/dist/index.js CHANGED
@@ -64,6 +64,7 @@ __export(index_exports, {
64
64
  MESH_P2P_SIGNAL_TYPES: () => MESH_P2P_SIGNAL_TYPES,
65
65
  MESH_RECORD_PAYLOAD_KEYS: () => MESH_RECORD_PAYLOAD_KEYS,
66
66
  MESH_SESSION_CLEANUP_MODES: () => MESH_SESSION_CLEANUP_MODES,
67
+ MESH_STATUS_DOC_SPEC: () => MESH_STATUS_DOC_SPEC,
67
68
  MESH_TASK_DIFFICULTIES: () => MESH_TASK_DIFFICULTIES,
68
69
  MESH_TASK_MODES: () => MESH_TASK_MODES,
69
70
  MESH_TASK_PRIORITIES: () => MESH_TASK_PRIORITIES,
@@ -214,10 +215,16 @@ __export(index_exports, {
214
215
  deriveProviderPriorityFromSlots: () => deriveProviderPriorityFromSlots,
215
216
  deriveSlotsFromLegacy: () => deriveSlotsFromLegacy,
216
217
  describeModelSelection: () => describeModelSelection,
218
+ diffKeyedDoc: () => diffKeyedDoc,
219
+ diffKeyedStatus: () => diffKeyedStatus,
220
+ digestKeyedDoc: () => digestKeyedDoc,
221
+ digestKeyedStatus: () => digestKeyedStatus,
217
222
  effectiveModelSelectionValue: () => effectiveModelSelectionValue,
218
223
  enumOf: () => enumOf,
219
224
  expandDaemonIdForms: () => expandDaemonIdForms,
220
225
  findOwnershipConflicts: () => findOwnershipConflicts,
226
+ foldKeyedDoc: () => foldKeyedDoc,
227
+ foldKeyedStatus: () => foldKeyedStatus,
221
228
  formatQuotaAccount: () => formatQuotaAccount,
222
229
  hasGitStatusEvidence: () => hasGitStatusEvidence,
223
230
  hasWorkerProtocolFooter: () => hasWorkerProtocolFooter,
@@ -1652,7 +1659,6 @@ var DAEMON_TO_DASHBOARD_P2P_TYPES = [
1652
1659
  "ping",
1653
1660
  "pong",
1654
1661
  "p2p_evicted",
1655
- "status_report",
1656
1662
  "status_event",
1657
1663
  "topic_update",
1658
1664
  "topic_update_chunk",
@@ -1661,7 +1667,8 @@ var DAEMON_TO_DASHBOARD_P2P_TYPES = [
1661
1667
  "session_io_error",
1662
1668
  "command_result",
1663
1669
  "command_result_chunk",
1664
- "response"
1670
+ "response",
1671
+ "transcript_topics_available"
1665
1672
  ];
1666
1673
  var isDaemonToDashboardP2PType = makeTypeGuard(DAEMON_TO_DASHBOARD_P2P_TYPES);
1667
1674
  function decodeDaemonToDashboardP2P(raw) {
@@ -1675,7 +1682,6 @@ function decodeDaemonToDashboardP2P(raw) {
1675
1682
  case "pong":
1676
1683
  case "p2p_evicted":
1677
1684
  return raw;
1678
- case "status_report":
1679
1685
  case "status_event":
1680
1686
  return isRecord(raw.payload) ? raw : null;
1681
1687
  case "topic_update":
@@ -1697,6 +1703,8 @@ function decodeDaemonToDashboardP2P(raw) {
1697
1703
  case "command_result":
1698
1704
  case "response":
1699
1705
  return isNonEmptyString(raw.id) ? raw : null;
1706
+ case "transcript_topics_available":
1707
+ return Array.isArray(raw.topics) && raw.topics.every((topic) => typeof topic === "string") ? { type: raw.type, topics: raw.topics } : null;
1700
1708
  }
1701
1709
  }
1702
1710
  var DASHBOARD_P2P_MESSAGE_KINDS = [
@@ -3591,6 +3599,393 @@ function touchedFilesOutsideOwnership(touched, owned) {
3591
3599
  const unusedDeclarations = owned.paths.map((p) => p.path).filter((p) => !usedDeclarations.has(p));
3592
3600
  return { undeclaredTouched, unusedDeclarations };
3593
3601
  }
3602
+
3603
+ // src/keyed-status-delta.ts
3604
+ function sig(value) {
3605
+ if (value === void 0) return void 0;
3606
+ try {
3607
+ return JSON.stringify(value);
3608
+ } catch {
3609
+ return void 0;
3610
+ }
3611
+ }
3612
+ function digestFields(source, ignore) {
3613
+ const sigs = /* @__PURE__ */ new Map();
3614
+ const values = {};
3615
+ for (const [key, value] of Object.entries(source)) {
3616
+ if (ignore.has(key)) continue;
3617
+ const s = sig(value);
3618
+ if (s === void 0) continue;
3619
+ sigs.set(key, s);
3620
+ values[key] = value;
3621
+ }
3622
+ return { sigs, values };
3623
+ }
3624
+ function sessionSignature(session, volatile) {
3625
+ if (volatile.size === 0) return sig(session) ?? "";
3626
+ const stable = {};
3627
+ for (const [key, value] of Object.entries(session)) {
3628
+ if (!volatile.has(key)) stable[key] = value;
3629
+ }
3630
+ return sig(stable) ?? "";
3631
+ }
3632
+ function fieldSigsOf(digest) {
3633
+ if (!digest.fieldSigs) {
3634
+ const sigs = /* @__PURE__ */ new Map();
3635
+ for (const [key, value] of Object.entries(digest.value)) {
3636
+ const s = sig(value);
3637
+ if (s !== void 0) sigs.set(key, s);
3638
+ }
3639
+ digest.fieldSigs = sigs;
3640
+ }
3641
+ return digest.fieldSigs;
3642
+ }
3643
+ function digestKeyedStatus(body, options = {}) {
3644
+ const volatile = new Set(options.volatileSessionFields ?? []);
3645
+ const top = digestFields(body, /* @__PURE__ */ new Set(["status", ...options.ignoreTopLevel ?? []]));
3646
+ const status = digestFields(body.status, /* @__PURE__ */ new Set(["sessions", ...options.ignoreStatus ?? []]));
3647
+ const sessions = /* @__PURE__ */ new Map();
3648
+ const order = [];
3649
+ for (const session of Array.isArray(body.status?.sessions) ? body.status.sessions : []) {
3650
+ if (!session || typeof session.id !== "string" || !session.id) continue;
3651
+ if (sessions.has(session.id)) continue;
3652
+ sessions.set(session.id, { value: session, sig: sessionSignature(session, volatile) });
3653
+ order.push(session.id);
3654
+ }
3655
+ return { top: top.sigs, topValues: top.values, status: status.sigs, statusValues: status.values, sessions, order, volatile };
3656
+ }
3657
+ function diffFieldMaps(prev, next, nextValues) {
3658
+ let set;
3659
+ let unset;
3660
+ for (const [key, s] of next) {
3661
+ if (prev.get(key) === s) continue;
3662
+ (set ??= {})[key] = nextValues[key];
3663
+ }
3664
+ for (const key of prev.keys()) {
3665
+ if (!next.has(key)) (unset ??= []).push(key);
3666
+ }
3667
+ return { ...set ? { set } : {}, ...unset ? { unset } : {} };
3668
+ }
3669
+ function sameOrder(a, b) {
3670
+ if (a.length !== b.length) return false;
3671
+ for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
3672
+ return true;
3673
+ }
3674
+ function diffKeyedStatus(prev, next) {
3675
+ const delta = {};
3676
+ const top = diffFieldMaps(prev.top, next.top, next.topValues);
3677
+ if (top.set) delta.set = top.set;
3678
+ if (top.unset) delta.unset = top.unset;
3679
+ const status = diffFieldMaps(prev.status, next.status, next.statusValues);
3680
+ if (status.set) delta.statusSet = status.set;
3681
+ if (status.unset) delta.statusUnset = status.unset;
3682
+ for (const [id2, nextSession] of next.sessions) {
3683
+ const prevSession = prev.sessions.get(id2);
3684
+ if (!prevSession) {
3685
+ ;
3686
+ (delta.sessions ??= []).push(nextSession.value);
3687
+ continue;
3688
+ }
3689
+ if (prevSession.sig === nextSession.sig) continue;
3690
+ const prevSigs = fieldSigsOf(prevSession);
3691
+ const nextSigs = fieldSigsOf(nextSession);
3692
+ const change = { id: id2 };
3693
+ let changed = false;
3694
+ for (const [key, s] of nextSigs) {
3695
+ if (key === "id" || prevSigs.get(key) === s) continue;
3696
+ change[key] = nextSession.value[key];
3697
+ changed = true;
3698
+ }
3699
+ const gone = [];
3700
+ for (const key of prevSigs.keys()) {
3701
+ if (!nextSigs.has(key)) gone.push(key);
3702
+ }
3703
+ if (changed) (delta.sessions ??= []).push(change);
3704
+ if (gone.length > 0) (delta.sessionUnset ??= {})[id2] = gone;
3705
+ }
3706
+ for (const id2 of prev.sessions.keys()) {
3707
+ if (!next.sessions.has(id2)) (delta.removedSessionIds ??= []).push(id2);
3708
+ }
3709
+ if (!sameOrder(prev.order, next.order)) delta.sessionOrder = [...next.order];
3710
+ return Object.keys(delta).length > 0 ? delta : null;
3711
+ }
3712
+ function foldKeyedStatus(held, delta) {
3713
+ const next = { ...held };
3714
+ for (const key of delta.unset ?? []) delete next[key];
3715
+ Object.assign(next, delta.set ?? {});
3716
+ const status = { ...held.status };
3717
+ for (const key of delta.statusUnset ?? []) delete status[key];
3718
+ Object.assign(status, delta.statusSet ?? {});
3719
+ const byId = /* @__PURE__ */ new Map();
3720
+ for (const session of held.status.sessions ?? []) byId.set(session.id, session);
3721
+ for (const id2 of delta.removedSessionIds ?? []) byId.delete(id2);
3722
+ for (const change of delta.sessions ?? []) {
3723
+ const base = byId.get(change.id);
3724
+ byId.set(change.id, base ? { ...base, ...change } : { ...change });
3725
+ }
3726
+ for (const [id2, keys] of Object.entries(delta.sessionUnset ?? {})) {
3727
+ const base = byId.get(id2);
3728
+ if (!base) continue;
3729
+ const trimmed = { ...base };
3730
+ for (const key of keys) delete trimmed[key];
3731
+ byId.set(id2, trimmed);
3732
+ }
3733
+ const order = delta.sessionOrder ?? (held.status.sessions ?? []).map((session) => session.id);
3734
+ const sessions = [];
3735
+ const placed = /* @__PURE__ */ new Set();
3736
+ for (const id2 of order) {
3737
+ const session = byId.get(id2);
3738
+ if (!session || placed.has(id2)) continue;
3739
+ sessions.push(session);
3740
+ placed.add(id2);
3741
+ }
3742
+ for (const [id2, session] of byId) {
3743
+ if (!placed.has(id2)) sessions.push(session);
3744
+ }
3745
+ status.sessions = sessions;
3746
+ next.status = status;
3747
+ return next;
3748
+ }
3749
+
3750
+ // src/keyed-doc-delta.ts
3751
+ function sig2(value) {
3752
+ if (value === void 0) return void 0;
3753
+ try {
3754
+ return JSON.stringify(value);
3755
+ } catch {
3756
+ return void 0;
3757
+ }
3758
+ }
3759
+ function isRecord3(value) {
3760
+ return !!value && typeof value === "object" && !Array.isArray(value);
3761
+ }
3762
+ function readPath(doc, path) {
3763
+ const [head, tail] = splitPath(path);
3764
+ if (!tail) return doc[head];
3765
+ const parent = doc[head];
3766
+ return isRecord3(parent) ? parent[tail] : void 0;
3767
+ }
3768
+ function splitPath(path) {
3769
+ const dot = path.indexOf(".");
3770
+ return dot < 0 ? [path, void 0] : [path.slice(0, dot), path.slice(dot + 1)];
3771
+ }
3772
+ function stripCollections(doc, spec) {
3773
+ const out = { ...doc };
3774
+ for (const path of Object.keys(spec.collections)) {
3775
+ const [head, tail] = splitPath(path);
3776
+ if (!tail) {
3777
+ delete out[head];
3778
+ continue;
3779
+ }
3780
+ const parent = out[head];
3781
+ if (!isRecord3(parent) || !(tail in parent)) continue;
3782
+ const copy = { ...parent };
3783
+ delete copy[tail];
3784
+ out[head] = copy;
3785
+ }
3786
+ return out;
3787
+ }
3788
+ function fieldSigsOf2(digest) {
3789
+ if (!digest.fieldSigs) {
3790
+ const sigs = /* @__PURE__ */ new Map();
3791
+ for (const [key, value] of Object.entries(digest.stable)) {
3792
+ const s = sig2(value);
3793
+ if (s !== void 0) sigs.set(key, s);
3794
+ }
3795
+ digest.fieldSigs = sigs;
3796
+ }
3797
+ return digest.fieldSigs;
3798
+ }
3799
+ function digestKeyedDoc(doc, spec) {
3800
+ const top = /* @__PURE__ */ new Map();
3801
+ const topValues = {};
3802
+ for (const [key, value] of Object.entries(stripCollections(doc, spec))) {
3803
+ const s = sig2(value);
3804
+ if (s === void 0) continue;
3805
+ top.set(key, s);
3806
+ topValues[key] = value;
3807
+ }
3808
+ const collections = /* @__PURE__ */ new Map();
3809
+ for (const [path, idField] of Object.entries(spec.collections)) {
3810
+ const list = readPath(doc, path);
3811
+ if (!Array.isArray(list)) continue;
3812
+ const rows = /* @__PURE__ */ new Map();
3813
+ const order = [];
3814
+ for (const row of list) {
3815
+ if (!isRecord3(row)) continue;
3816
+ const id2 = row[idField];
3817
+ if (typeof id2 !== "string" || !id2 || rows.has(id2)) continue;
3818
+ const stable = spec.stableRow ? spec.stableRow(path, row) : row;
3819
+ rows.set(id2, { value: row, stable, sig: sig2(stable) ?? "" });
3820
+ order.push(id2);
3821
+ }
3822
+ collections.set(path, { rows, order });
3823
+ }
3824
+ return { top, topValues, collections, volatile: new Set(spec.volatileTopLevel ?? []) };
3825
+ }
3826
+ function sameOrder2(a, b) {
3827
+ if (a.length !== b.length) return false;
3828
+ for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
3829
+ return true;
3830
+ }
3831
+ function diffCollection(prev, next, idField) {
3832
+ if (!next) return prev ? { absent: true } : null;
3833
+ const delta = {};
3834
+ const prevRows = prev?.rows ?? /* @__PURE__ */ new Map();
3835
+ const nextRows = next?.rows ?? /* @__PURE__ */ new Map();
3836
+ for (const [id2, nextRow] of nextRows) {
3837
+ const prevRow = prevRows.get(id2);
3838
+ if (!prevRow) {
3839
+ ;
3840
+ (delta.upsert ??= []).push(nextRow.value);
3841
+ continue;
3842
+ }
3843
+ if (prevRow.sig === nextRow.sig) continue;
3844
+ const prevSigs = fieldSigsOf2(prevRow);
3845
+ const nextSigs = fieldSigsOf2(nextRow);
3846
+ const change = { [idField]: id2 };
3847
+ let changed = false;
3848
+ for (const [key, s] of nextSigs) {
3849
+ if (key === idField || prevSigs.get(key) === s) continue;
3850
+ change[key] = nextRow.value[key];
3851
+ changed = true;
3852
+ }
3853
+ const gone = [];
3854
+ for (const key of prevSigs.keys()) if (!nextSigs.has(key) && !(key in nextRow.value)) gone.push(key);
3855
+ if (changed) (delta.upsert ??= []).push(change);
3856
+ if (gone.length > 0) (delta.unsetFields ??= {})[id2] = gone;
3857
+ }
3858
+ for (const id2 of prevRows.keys()) {
3859
+ if (!nextRows.has(id2)) (delta.removed ??= []).push(id2);
3860
+ }
3861
+ if (!sameOrder2(prev?.order ?? [], next?.order ?? [])) delta.order = [...next?.order ?? []];
3862
+ return Object.keys(delta).length > 0 ? delta : null;
3863
+ }
3864
+ function diffKeyedDoc(prev, next, spec) {
3865
+ const delta = {};
3866
+ let meaningful = false;
3867
+ let set;
3868
+ let unset;
3869
+ for (const [key, s] of next.top) {
3870
+ if (prev.top.get(key) === s) continue;
3871
+ (set ??= {})[key] = next.topValues[key];
3872
+ if (!next.volatile.has(key)) meaningful = true;
3873
+ }
3874
+ for (const key of prev.top.keys()) {
3875
+ if (next.top.has(key)) continue;
3876
+ (unset ??= []).push(key);
3877
+ if (!next.volatile.has(key)) meaningful = true;
3878
+ }
3879
+ for (const [path, idField] of Object.entries(spec.collections)) {
3880
+ const change = diffCollection(prev.collections.get(path), next.collections.get(path), idField);
3881
+ if (!change) continue;
3882
+ (delta.collections ??= {})[path] = change;
3883
+ meaningful = true;
3884
+ }
3885
+ if (!meaningful) return null;
3886
+ if (set) delta.set = set;
3887
+ if (unset) delta.unset = unset;
3888
+ return delta;
3889
+ }
3890
+ function foldCollection(held, change, idField) {
3891
+ const byId = /* @__PURE__ */ new Map();
3892
+ const heldOrder = [];
3893
+ for (const row of Array.isArray(held) ? held : []) {
3894
+ if (!isRecord3(row) || typeof row[idField] !== "string") continue;
3895
+ byId.set(row[idField], row);
3896
+ heldOrder.push(row[idField]);
3897
+ }
3898
+ for (const id2 of change.removed ?? []) byId.delete(id2);
3899
+ for (const row of change.upsert ?? []) {
3900
+ const id2 = row[idField];
3901
+ if (typeof id2 !== "string") continue;
3902
+ const base = byId.get(id2);
3903
+ byId.set(id2, base ? { ...base, ...row } : { ...row });
3904
+ }
3905
+ for (const [id2, keys] of Object.entries(change.unsetFields ?? {})) {
3906
+ const base = byId.get(id2);
3907
+ if (!base) continue;
3908
+ const trimmed = { ...base };
3909
+ for (const key of keys) delete trimmed[key];
3910
+ byId.set(id2, trimmed);
3911
+ }
3912
+ const order = change.order ?? heldOrder;
3913
+ const out = [];
3914
+ const placed = /* @__PURE__ */ new Set();
3915
+ for (const id2 of order) {
3916
+ const row = byId.get(id2);
3917
+ if (!row || placed.has(id2)) continue;
3918
+ out.push(row);
3919
+ placed.add(id2);
3920
+ }
3921
+ for (const [id2, row] of byId) if (!placed.has(id2)) out.push(row);
3922
+ return out;
3923
+ }
3924
+ function foldKeyedDoc(held, delta, spec) {
3925
+ const heldCollections = /* @__PURE__ */ new Map();
3926
+ for (const path of Object.keys(spec.collections)) heldCollections.set(path, readPath(held, path));
3927
+ const next = stripCollections(held, spec);
3928
+ for (const key of delta.unset ?? []) delete next[key];
3929
+ Object.assign(next, delta.set ?? {});
3930
+ for (const [path, idField] of Object.entries(spec.collections)) {
3931
+ const change = delta.collections?.[path];
3932
+ const heldList = heldCollections.get(path);
3933
+ if (change?.absent) {
3934
+ const [head2, tail2] = splitPath(path);
3935
+ if (!tail2) delete next[head2];
3936
+ continue;
3937
+ }
3938
+ if (!change && heldList === void 0) continue;
3939
+ const list = change ? foldCollection(heldList, change, idField) : heldList;
3940
+ const [head, tail] = splitPath(path);
3941
+ if (!tail) {
3942
+ next[head] = list;
3943
+ continue;
3944
+ }
3945
+ const parent = isRecord3(next[head]) ? { ...next[head] } : {};
3946
+ parent[tail] = list;
3947
+ next[head] = parent;
3948
+ }
3949
+ return next;
3950
+ }
3951
+ var MESH_STATUS_DOC_SPEC = {
3952
+ collections: { nodes: "nodeId", "queue.tasks": "id", missions: "id" },
3953
+ volatileTopLevel: [
3954
+ "refreshedAt",
3955
+ "sourceOfTruth",
3956
+ "turnPresentationCounters",
3957
+ "meshProtocolV2Counters",
3958
+ "pendingRetentionCounters",
3959
+ "meshProtocolMetrics"
3960
+ ],
3961
+ stableRow: (collection, row) => collection === "nodes" ? stableMeshNodeRow(row) : row
3962
+ };
3963
+ function without(value, keys) {
3964
+ if (!isRecord3(value)) return value;
3965
+ const out = { ...value };
3966
+ for (const key of keys) delete out[key];
3967
+ return out;
3968
+ }
3969
+ function stableMeshNodeRow(row) {
3970
+ const out = { ...row };
3971
+ delete out.lastSeenAt;
3972
+ delete out.updatedAt;
3973
+ delete out.last_seen_at;
3974
+ delete out.updated_at;
3975
+ if ("dataFreshness" in out) out.dataFreshness = without(out.dataFreshness, ["ageMs", "lastProbeAt", "staleness"]);
3976
+ if ("connection" in out) out.connection = without(out.connection, ["lastStateChangeAt"]);
3977
+ if ("git" in out) {
3978
+ const git = without(out.git, ["lastCheckedAt"]);
3979
+ if (isRecord3(git) && Array.isArray(git.submodules) && git.submodules.length === 0) delete git.submodules;
3980
+ out.git = git;
3981
+ }
3982
+ if ("nodeFacts" in out) out.nodeFacts = without(out.nodeFacts, ["reportedAt"]);
3983
+ const observation = out.gitObservation;
3984
+ if (isRecord3(observation) && (observation.source === "self" || observation.source === "local")) {
3985
+ out.gitObservation = without(observation, ["observedAt"]);
3986
+ }
3987
+ return out;
3988
+ }
3594
3989
  // Annotate the CommonJS export names for ESM import in node:
3595
3990
  0 && (module.exports = {
3596
3991
  CANCEL_REASONS,
@@ -3637,6 +4032,7 @@ function touchedFilesOutsideOwnership(touched, owned) {
3637
4032
  MESH_P2P_SIGNAL_TYPES,
3638
4033
  MESH_RECORD_PAYLOAD_KEYS,
3639
4034
  MESH_SESSION_CLEANUP_MODES,
4035
+ MESH_STATUS_DOC_SPEC,
3640
4036
  MESH_TASK_DIFFICULTIES,
3641
4037
  MESH_TASK_MODES,
3642
4038
  MESH_TASK_PRIORITIES,
@@ -3787,10 +4183,16 @@ function touchedFilesOutsideOwnership(touched, owned) {
3787
4183
  deriveProviderPriorityFromSlots,
3788
4184
  deriveSlotsFromLegacy,
3789
4185
  describeModelSelection,
4186
+ diffKeyedDoc,
4187
+ diffKeyedStatus,
4188
+ digestKeyedDoc,
4189
+ digestKeyedStatus,
3790
4190
  effectiveModelSelectionValue,
3791
4191
  enumOf,
3792
4192
  expandDaemonIdForms,
3793
4193
  findOwnershipConflicts,
4194
+ foldKeyedDoc,
4195
+ foldKeyedStatus,
3794
4196
  formatQuotaAccount,
3795
4197
  hasGitStatusEvidence,
3796
4198
  hasWorkerProtocolFooter,