maka-agent 0.2.0-dev.3.20260830 → 0.2.0-dev.5.20260830

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.
Files changed (66) hide show
  1. package/dist/cli-core.js +1 -0
  2. package/dist/eval-bundle-path.js +1 -1
  3. package/dist/pi-tui-runner.js +3 -1
  4. package/dist/runtime-host-cli.js +37 -3
  5. package/dist/runtime-host-onboarding.js +10 -1
  6. package/dist/runtime-host-peer-mesh-management-command.js +17 -0
  7. package/dist/runtime-host-setup-command.js +33 -15
  8. package/dist/runtime-host-systemd-service.js +9 -3
  9. package/dist/runtime-host-tui-context.js +2 -6
  10. package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
  11. package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
  12. package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
  13. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  14. package/node_modules/@maka/eval/dist/external-subject.js +1 -1
  15. package/node_modules/@maka/eval/dist/harbor-external-subject.js +2 -2
  16. package/node_modules/@maka/runtime/dist/sandbox/macos-seatbelt.js +68 -9
  17. package/node_modules/@maka/runtime-host/dist/client/peer-client.js +22 -3
  18. package/node_modules/@maka/runtime-host/dist/operator/peer-mesh-management-frame.js +14 -0
  19. package/{packages/eval/dist/index.js → node_modules/@maka/runtime-host/dist/peer-mesh/display-name.js} +12 -10
  20. package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +32 -21
  21. package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +207 -47
  22. package/node_modules/@maka/runtime-host/dist/peer-mesh/owner.js +2 -0
  23. package/node_modules/@maka/runtime-host/dist/peer-mesh/store.js +18 -5
  24. package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
  25. package/node_modules/@maka/runtime-host/dist/protocol/peer-mesh.js +59 -2
  26. package/node_modules/@maka/runtime-host/dist/server/access-authority.js +11 -7
  27. package/node_modules/@maka/runtime-host/dist/server/connection-session.js +3 -0
  28. package/node_modules/@maka/runtime-host/dist/server/execution-service.js +1 -0
  29. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +1 -1
  30. package/node_modules/@maka/runtime-host/dist/server/peer-mesh-authority.js +19 -0
  31. package/package.json +1 -2
  32. package/packages/eval/dist/attempt-store.js +0 -138
  33. package/packages/eval/dist/cli.js +0 -119
  34. package/packages/eval/dist/experiment-directory.js +0 -59
  35. package/packages/eval/dist/experiment.js +0 -49
  36. package/packages/eval/dist/external-subject.js +0 -488
  37. package/packages/eval/dist/harbor-external-subject.js +0 -929
  38. package/packages/eval/dist/harbor-maka-subject.js +0 -83
  39. package/packages/eval/dist/harness-environment.js +0 -80
  40. package/packages/eval/dist/harness-executor.js +0 -1013
  41. package/packages/eval/dist/install-preflight.js +0 -201
  42. package/packages/eval/dist/maka-artifacts.js +0 -126
  43. package/packages/eval/dist/maka-runtime-policy.js +0 -42
  44. package/packages/eval/dist/maka-subject.js +0 -268
  45. package/packages/eval/dist/metering-checkpoint.js +0 -80
  46. package/packages/eval/dist/provider-admission.js +0 -39
  47. package/packages/eval/dist/provider-metering.js +0 -67
  48. package/packages/eval/dist/provider-web-tool-surface.js +0 -74
  49. package/packages/eval/dist/relay-result-frame.js +0 -38
  50. package/packages/eval/dist/result.js +0 -94
  51. package/packages/eval/dist/runner.js +0 -290
  52. package/packages/eval/dist/spec.js +0 -135
  53. package/packages/eval/dist/toolchain-verification.js +0 -130
  54. package/packages/eval/harbor/deepseek-codex-models.json +0 -69
  55. package/packages/eval/harbor/deepseek-harness-profile/cordis.patch.yml +0 -140
  56. package/packages/eval/harbor/deepseek-harness-profile/cordis.yml +0 -18
  57. package/packages/eval/harbor/deepseek-harness-profile/package.json +0 -10
  58. package/packages/eval/harbor/docker-compose-egress-proxy.yaml +0 -57
  59. package/packages/eval/harbor/egress-proxy/Dockerfile +0 -25
  60. package/packages/eval/harbor/egress-proxy/entrypoint.sh +0 -62
  61. package/packages/eval/harbor/egress-proxy/network-policy +0 -148
  62. package/packages/eval/harbor/egress_filter.py +0 -435
  63. package/packages/eval/harbor/eval_framework.py +0 -40
  64. package/packages/eval/harbor/relay_agent.py +0 -686
  65. package/packages/eval/harbor/run_trial.py +0 -223
  66. package/packages/eval/package.json +0 -20
@@ -19,6 +19,7 @@
19
19
  import { createHash, createPrivateKey, createPublicKey, generateKeyPairSync, randomBytes, sign, timingSafeEqual, verify, } from 'node:crypto';
20
20
  import { decodePeerMeshInvitation as decodePeerMeshInvitationWire, } from '../protocol/peer-mesh.js';
21
21
  import { PEER_MESH_MAX_MEMBERS, PEER_MESH_MAX_ROUTE_HINTS, PEER_MESH_ROUTE_RECORD_MAX_BYTES, } from './limits.js';
22
+ import { canonicalPeerMeshDisplayName } from './display-name.js';
22
23
  export { PEER_MESH_MAX_INVITATION_RECORDS, PEER_MESH_MAX_MEMBERS, PEER_MESH_MAX_MESHES, PEER_MESH_MAX_PENDING_INVITATIONS, PEER_MESH_MAX_ROUTE_HINTS, PEER_MESH_MAX_TRANSIT_ADDRESSES_PER_RELAY, PEER_MESH_MAX_TRANSIT_RELAY_ADDRESSES, PEER_MESH_ROUTE_RECORD_MAX_BYTES, } from './limits.js';
23
24
  export function generatePeerMeshAuthorityKeyPair() {
24
25
  const { publicKey, privateKey } = generateKeyPairSync('ed25519');
@@ -114,13 +115,12 @@ export function validatePeerMeshInvitation(value) {
114
115
  });
115
116
  }
116
117
  export function canonicalPeerMeshRoster(value) {
117
- const record = exactObject(value, 'Peer Mesh roster', [
118
- 'version',
119
- 'meshId',
120
- 'revision',
121
- 'members',
122
- 'closed',
123
- ]);
118
+ const keys = ['version', 'meshId', 'revision', 'members', 'closed'];
119
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
120
+ if (Object.hasOwn(value, 'displayName'))
121
+ keys.push('displayName');
122
+ }
123
+ const record = exactObject(value, 'Peer Mesh roster', keys);
124
124
  if (record.version !== 1)
125
125
  throw new Error('Unsupported Peer Mesh roster version');
126
126
  const members = stringArray(record.members, 'members', PEER_MESH_MAX_MEMBERS, 256)
@@ -137,6 +137,9 @@ export function canonicalPeerMeshRoster(value) {
137
137
  revision: integer(record.revision, 'revision', 1),
138
138
  members: Object.freeze(members),
139
139
  closed: record.closed,
140
+ ...(record.displayName === undefined
141
+ ? {}
142
+ : { displayName: canonicalPeerMeshDisplayName(record.displayName) }),
140
143
  });
141
144
  }
142
145
  export function decodeAuthorityTarget(value) {
@@ -152,22 +155,23 @@ export function decodeAuthorityTarget(value) {
152
155
  });
153
156
  }
154
157
  export function canonicalPeerMeshRouteRecord(value) {
155
- const baseKeys = [
156
- 'version',
157
- 'peerId',
158
- 'sequence',
159
- 'expiresAt',
160
- 'routeHints',
161
- 'coordinationRelays',
162
- ];
163
- const record = exactObject(value, 'Peer Mesh route record', value &&
164
- typeof value === 'object' &&
165
- !Array.isArray(value) &&
166
- Object.hasOwn(value, 'transitMeshId')
167
- ? [...baseKeys, 'transitMeshId']
168
- : baseKeys);
158
+ const keys = ['version', 'peerId', 'sequence', 'expiresAt', 'routeHints', 'coordinationRelays'];
159
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
160
+ if (Object.hasOwn(value, 'endpointKind'))
161
+ keys.push('endpointKind');
162
+ if (Object.hasOwn(value, 'displayName'))
163
+ keys.push('displayName');
164
+ if (Object.hasOwn(value, 'transitMeshId'))
165
+ keys.push('transitMeshId');
166
+ }
167
+ const record = exactObject(value, 'Peer Mesh route record', keys);
169
168
  if (record.version !== 1)
170
169
  throw new Error('Unsupported Peer Mesh route record version');
170
+ if (record.endpointKind !== undefined &&
171
+ record.endpointKind !== 'client' &&
172
+ record.endpointKind !== 'host') {
173
+ throw new Error('Invalid Peer Mesh endpoint kind');
174
+ }
171
175
  const route = Object.freeze({
172
176
  version: 1,
173
177
  peerId: token(record.peerId, 'peerId', 256),
@@ -175,6 +179,10 @@ export function canonicalPeerMeshRouteRecord(value) {
175
179
  expiresAt: integer(record.expiresAt, 'route expiry', 1),
176
180
  routeHints: Object.freeze(addressArray(record.routeHints, 'routeHints')),
177
181
  coordinationRelays: Object.freeze(addressArray(record.coordinationRelays, 'coordinationRelays')),
182
+ ...(record.endpointKind === undefined ? {} : { endpointKind: record.endpointKind }),
183
+ ...(record.displayName === undefined
184
+ ? {}
185
+ : { displayName: canonicalPeerMeshDisplayName(record.displayName) }),
178
186
  ...(record.transitMeshId === undefined
179
187
  ? {}
180
188
  : { transitMeshId: string(record.transitMeshId, 'transitMeshId', 128) }),
@@ -201,6 +209,8 @@ export function decodeSignedPeerMeshRouteRecord(value) {
201
209
  export function peerMeshRouteRecordSigningBytes(route) {
202
210
  return Buffer.from(`maka.peer-mesh.route.v1\n${JSON.stringify({
203
211
  coordinationRelays: route.coordinationRelays,
212
+ ...(route.displayName ? { displayName: route.displayName } : {}),
213
+ ...(route.endpointKind ? { endpointKind: route.endpointKind } : {}),
204
214
  expiresAt: route.expiresAt,
205
215
  peerId: route.peerId,
206
216
  routeHints: route.routeHints,
@@ -212,6 +222,7 @@ export function peerMeshRouteRecordSigningBytes(route) {
212
222
  function encodeRoster(roster) {
213
223
  return Buffer.from(`maka.peer-mesh.roster.v1\n${JSON.stringify({
214
224
  closed: roster.closed,
225
+ ...(roster.displayName ? { displayName: roster.displayName } : {}),
215
226
  members: roster.members,
216
227
  meshId: roster.meshId,
217
228
  revision: roster.revision,
@@ -18,6 +18,7 @@
18
18
  */
19
19
  import { setTimeout as delay } from 'node:timers/promises';
20
20
  import { canonicalPeerMeshRoster, canonicalPeerMeshRouteRecord, createPeerMeshInvitationSecret, validatePeerMeshInvitation, decodeSignedPeerMeshRoster, decodeSignedPeerMeshRouteRecord, generatePeerMeshAuthorityKeyPair, matchesPeerMeshInvitationSecret, PEER_MESH_MAX_MEMBERS, PEER_MESH_MAX_MESHES, PEER_MESH_MAX_INVITATION_RECORDS, PEER_MESH_MAX_PENDING_INVITATIONS, PEER_MESH_MAX_TRANSIT_ADDRESSES_PER_RELAY, PEER_MESH_MAX_TRANSIT_RELAY_ADDRESSES, peerMeshRouteRecordSigningBytes, peerMeshId, peerMeshInvitationSecretDigest, signPeerMeshRoster, } from './model.js';
21
+ import { canonicalPeerMeshDisplayName } from './display-name.js';
21
22
  import { authorityKeys, openPeerMeshStateStore, } from './store.js';
22
23
  const CONTROL_FRAME_MAX_BYTES = 64 * 1024;
23
24
  const DEFAULT_INVITATION_TTL_MS = 15 * 60 * 1_000;
@@ -47,6 +48,7 @@ export async function openPeerMeshNode(input) {
47
48
  class PeerMeshNodeImpl {
48
49
  #store;
49
50
  #peer;
51
+ #endpointKind;
50
52
  #now;
51
53
  #activeControlStreams = new Set();
52
54
  #lifetime = new AbortController();
@@ -60,6 +62,7 @@ class PeerMeshNodeImpl {
60
62
  constructor(input) {
61
63
  this.#store = input.store;
62
64
  this.#peer = input.peer;
65
+ this.#endpointKind = input.endpointKind;
63
66
  this.#now = input.now ?? Date.now;
64
67
  }
65
68
  async initialize() {
@@ -71,13 +74,64 @@ class PeerMeshNodeImpl {
71
74
  this.#assertOpen();
72
75
  return this.#peer.identity().peerId;
73
76
  }
77
+ displayName() {
78
+ this.#assertOpen();
79
+ return this.#store.read().displayName ?? undefined;
80
+ }
81
+ setDisplayName(displayName) {
82
+ return this.#admitMesh(async () => {
83
+ const canonical = displayName === null ? null : canonicalPeerMeshDisplayName(displayName);
84
+ await this.#store.mutate(async (current) => {
85
+ if (current.displayName === canonical)
86
+ return { state: current, result: undefined };
87
+ const state = { ...current, displayName: canonical };
88
+ const localPeerId = this.#peer.identity().peerId;
89
+ if (!state.meshes.some((mesh) => isActiveMembership(mesh, localPeerId))) {
90
+ return { state, result: undefined };
91
+ }
92
+ const route = await this.#signLocalRoute(state);
93
+ return {
94
+ state: {
95
+ ...state,
96
+ routes: mergeRoutes(state.routes, [route], this.#now()),
97
+ },
98
+ result: undefined,
99
+ };
100
+ });
101
+ void this.reconcile().catch(() => undefined);
102
+ });
103
+ }
104
+ setMeshDisplayName(meshId, displayName) {
105
+ return this.#admitMesh(async () => {
106
+ const canonical = displayName === null ? undefined : canonicalPeerMeshDisplayName(displayName);
107
+ await this.#store.mutate((current) => {
108
+ const state = requireAuthority(current.meshes, meshId);
109
+ if (state.roster.roster.closed)
110
+ throw new Error('Peer Mesh is closed');
111
+ if (state.roster.roster.displayName === canonical)
112
+ return { state: current, result: undefined };
113
+ const { displayName: _currentDisplayName, ...currentRoster } = state.roster.roster;
114
+ const roster = signPeerMeshRoster(canonicalPeerMeshRoster({
115
+ ...currentRoster,
116
+ revision: state.roster.roster.revision + 1,
117
+ ...(canonical ? { displayName: canonical } : {}),
118
+ }), authorityKeys(state));
119
+ return {
120
+ state: { ...current, meshes: replaceMesh(current.meshes, { ...state, roster }) },
121
+ result: undefined,
122
+ };
123
+ });
124
+ const stored = this.#store.read();
125
+ return peerMeshStatus(requireAuthority(stored.meshes, meshId), this.#peer.identity(), this.#endpointKind, stored.routes, this.#now());
126
+ });
127
+ }
74
128
  status() {
75
129
  this.#assertOpen();
76
130
  const identity = this.#peer.identity();
77
131
  const stored = this.#store.read();
78
132
  return Object.freeze(stored.meshes
79
133
  .filter((state) => isActiveMembership(state, identity.peerId))
80
- .map((state) => peerMeshStatus(state, identity, stored.routes, this.#now())));
134
+ .map((state) => peerMeshStatus(state, identity, this.#endpointKind, stored.routes, this.#now())));
81
135
  }
82
136
  create() {
83
137
  return this.#admitMesh(async () => {
@@ -116,7 +170,7 @@ class PeerMeshNodeImpl {
116
170
  };
117
171
  });
118
172
  const stored = this.#store.read();
119
- return peerMeshStatus(findMesh(stored.meshes, state.roster.roster.meshId), identity, stored.routes, now);
173
+ return peerMeshStatus(findMesh(stored.meshes, state.roster.roster.meshId), identity, this.#endpointKind, stored.routes, now);
120
174
  });
121
175
  }
122
176
  invite(meshId, input = {}) {
@@ -211,6 +265,7 @@ class PeerMeshNodeImpl {
211
265
  throw new Error('Peer Mesh authority returned an unrelated roster');
212
266
  }
213
267
  const routes = await this.#validateRoutes(response.routes, roster, this.#now());
268
+ operationSignal.throwIfAborted();
214
269
  await this.#store.mutate((current) => {
215
270
  const existing = findMesh(current.meshes, invitation.meshId);
216
271
  if (existing?.role === 'authority') {
@@ -246,7 +301,7 @@ class PeerMeshNodeImpl {
246
301
  await this.#refreshLocalRoute();
247
302
  await this.#reconcileTransit();
248
303
  const stored = this.#store.read();
249
- return peerMeshStatus(findMesh(stored.meshes, invitation.meshId), identity, stored.routes);
304
+ return peerMeshStatus(findMesh(stored.meshes, invitation.meshId), identity, this.#endpointKind, stored.routes);
250
305
  }
251
306
  finally {
252
307
  await stream.close().catch(() => undefined);
@@ -366,12 +421,31 @@ class PeerMeshNodeImpl {
366
421
  transitRelayPeerIds: Object.freeze(transitRelayPeerIds),
367
422
  });
368
423
  }
424
+ async prepareRoutes(peerId, signal) {
425
+ this.#assertOpen();
426
+ signal.throwIfAborted();
427
+ const localPeerId = this.#peer.identity().peerId;
428
+ const stored = this.#store.read();
429
+ const visible = stored.meshes.some((mesh) => isActiveMembership(mesh, localPeerId) && mesh.roster.roster.members.includes(peerId));
430
+ if (!visible)
431
+ return;
432
+ if (stored.routes.some(({ route }) => route.peerId === peerId && route.expiresAt > this.#now())) {
433
+ return;
434
+ }
435
+ await this.reconcile(signal);
436
+ }
369
437
  reconcile(signal) {
370
438
  if (this.#lifetime.signal.aborted)
371
439
  return Promise.reject(new Error('Peer Mesh node is closed'));
372
- const task = this.#reconcileTail.then(() => this.#reconcile(signal));
373
- this.#reconcileTail = task.then(() => undefined, () => undefined);
374
- return task;
440
+ const previous = this.#reconcileTail;
441
+ let release;
442
+ const turn = new Promise((resolve) => {
443
+ release = resolve;
444
+ });
445
+ this.#reconcileTail = previous.then(() => turn);
446
+ return waitForTurn(previous, signal)
447
+ .then(() => this.#reconcile(signal))
448
+ .finally(release);
375
449
  }
376
450
  async serve() {
377
451
  if (this.#lifetime.signal.aborted)
@@ -435,7 +509,9 @@ class PeerMeshNodeImpl {
435
509
  const pending = [];
436
510
  const gossipCursor = this.#gossipCursor;
437
511
  this.#gossipCursor = (this.#gossipCursor + 1) % PEER_MESH_MAX_MEMBERS;
512
+ const now = this.#now();
438
513
  for (const [index, state] of memberships.entries()) {
514
+ const authorityRoute = stored.routes.find(({ route }) => route.peerId === state.authority.peerId);
439
515
  const targets = [currentAuthorityTarget(state, stored.routes)];
440
516
  const gossipRoutes = state.roster.roster.members
441
517
  .filter((peerId) => peerId !== identity.peerId && peerId !== state.authority.peerId)
@@ -446,13 +522,18 @@ class PeerMeshNodeImpl {
446
522
  if (gossipRoutes.length > 0) {
447
523
  targets.push(gossipRoutes[(gossipCursor + index) % gossipRoutes.length]);
448
524
  }
449
- pending.push({ meshId: state.roster.roster.meshId, targets });
525
+ pending.push({
526
+ meshId: state.roster.roster.meshId,
527
+ targets,
528
+ authorityRouteExpired: authorityRoute !== undefined && authorityRoute.route.expiresAt <= now,
529
+ });
450
530
  }
451
531
  if (pending.length === 0)
452
532
  return;
453
533
  const start = this.#reconcileCursor % pending.length;
454
534
  const deadline = AbortSignal.timeout(RECONCILE_DEADLINE_MS);
455
535
  const operationSignal = AbortSignal.any([lifetimeSignal, deadline]);
536
+ const failures = [];
456
537
  let next = 0;
457
538
  const worker = async () => {
458
539
  while (!operationSignal.aborted) {
@@ -460,17 +541,14 @@ class PeerMeshNodeImpl {
460
541
  next += 1;
461
542
  if (offset >= pending.length)
462
543
  return;
463
- const { meshId, targets } = pending[(start + offset) % pending.length];
544
+ const { meshId, targets, authorityRouteExpired } = pending[(start + offset) % pending.length];
464
545
  try {
465
- const outcomes = await Promise.allSettled(targets.map((target) => this.#syncPeer(meshId, target, operationSignal)));
466
- if (!outcomes.some(({ status }) => status === 'fulfilled')) {
467
- const failure = outcomes.find((outcome) => outcome.status === 'rejected');
468
- throw failure?.reason ?? new Error('Peer Mesh synchronization failed');
469
- }
546
+ await this.#syncTargets(meshId, targets, authorityRouteExpired, operationSignal);
470
547
  }
471
- catch {
548
+ catch (error) {
472
549
  if (lifetimeSignal.aborted)
473
550
  lifetimeSignal.throwIfAborted();
551
+ failures.push(error);
474
552
  if (deadline.aborted)
475
553
  return;
476
554
  }
@@ -480,6 +558,46 @@ class PeerMeshNodeImpl {
480
558
  this.#reconcileCursor = (start + Math.min(next, pending.length)) % pending.length;
481
559
  await this.#reconcileTransit();
482
560
  lifetimeSignal.throwIfAborted();
561
+ if (failures.length > 0) {
562
+ throw new AggregateError(failures, 'Peer Mesh synchronization did not reach every membership');
563
+ }
564
+ }
565
+ async #syncTargets(meshId, targets, authorityRouteExpired, signal) {
566
+ if (!authorityRouteExpired || targets.length === 1) {
567
+ try {
568
+ await this.#syncPeer(meshId, targets[0], signal);
569
+ }
570
+ catch (authorityFailure) {
571
+ const fallbackTargets = targets.slice(1);
572
+ if (fallbackTargets.length === 0)
573
+ throw authorityFailure;
574
+ await Promise.any(fallbackTargets.map((target) => this.#syncPeer(meshId, target, signal)));
575
+ }
576
+ return;
577
+ }
578
+ const controllers = targets.map(() => new AbortController());
579
+ const authorityPeerId = targets[0].peerId;
580
+ const attempts = targets.map(async (target, index) => {
581
+ await this.#syncPeer(meshId, target, AbortSignal.any([signal, controllers[index].signal]));
582
+ if (index > 0 && !this.#hasFreshRoute(meshId, authorityPeerId)) {
583
+ throw new Error('Peer Mesh gossip did not recover the authority route');
584
+ }
585
+ });
586
+ try {
587
+ await Promise.any(attempts);
588
+ }
589
+ finally {
590
+ for (const controller of controllers)
591
+ controller.abort();
592
+ await Promise.allSettled(attempts);
593
+ }
594
+ }
595
+ #hasFreshRoute(meshId, peerId) {
596
+ const stored = this.#store.read();
597
+ const mesh = findMesh(stored.meshes, meshId);
598
+ return Boolean(mesh &&
599
+ isActiveMembership(mesh, this.#peer.identity().peerId) &&
600
+ stored.routes.some(({ route }) => route.peerId === peerId && route.expiresAt > this.#now()));
483
601
  }
484
602
  async #syncPeer(meshId, target, signal) {
485
603
  for (let page = 0; page <= Math.ceil(PEER_MESH_MAX_MEMBERS / ROUTE_PAGE_SIZE); page += 1) {
@@ -492,10 +610,12 @@ class PeerMeshNodeImpl {
492
610
  const route = stored.routes.find((candidate) => candidate.route.peerId === localPeerId);
493
611
  if (!route)
494
612
  throw new Error('Peer Mesh local route is unavailable');
613
+ const discovered = this.resolveRoutes(target.peerId);
495
614
  const stream = await this.#peer.connectMeshControl({
496
615
  peerId: target.peerId,
497
- routeHints: target.routeHints,
498
- coordinationRelays: target.coordinationRelays,
616
+ routeHints: mergeAddresses(discovered?.routeHints ?? [], target.routeHints),
617
+ coordinationRelays: mergeAddresses(discovered?.coordinationRelays ?? [], target.coordinationRelays),
618
+ transitRelayPeerIds: discovered?.transitRelayPeerIds,
499
619
  directDeadlineMs: CONNECT_DEADLINE_MS,
500
620
  }, signal);
501
621
  try {
@@ -527,31 +647,32 @@ class PeerMeshNodeImpl {
527
647
  }
528
648
  async #refreshLocalRouteOnce() {
529
649
  const identity = this.#peer.identity();
530
- const current = this.#store.read();
531
- const active = current.meshes.filter((state) => isActiveMembership(state, identity.peerId));
532
- if (active.length === 0)
533
- return undefined;
534
- const existing = current.routes
535
- .filter(({ route }) => route.peerId === identity.peerId)
536
- .sort((left, right) => right.route.sequence - left.route.sequence)[0];
537
650
  const now = this.#now();
538
- if (existing &&
539
- existing.route.expiresAt > now + ROUTE_REFRESH_LEAD_MS &&
540
- sameAddresses(existing.route.routeHints, identity.listenAddresses) &&
541
- sameAddresses(existing.route.coordinationRelays, identity.coordinationRelays) &&
542
- existing.route.transitMeshId === current.transitMeshId) {
543
- return existing;
544
- }
545
- const route = await this.#signLocalRoute();
546
- await this.#store.mutate((states) => ({
547
- state: { ...states, routes: mergeRoutes(states.routes, [route], now) },
548
- result: undefined,
549
- }));
550
- return route;
651
+ return this.#store.mutate(async (current) => {
652
+ if (!current.meshes.some((state) => isActiveMembership(state, identity.peerId))) {
653
+ return { state: current, result: undefined };
654
+ }
655
+ const existing = current.routes
656
+ .filter(({ route }) => route.peerId === identity.peerId)
657
+ .sort((left, right) => right.route.sequence - left.route.sequence)[0];
658
+ if (existing &&
659
+ existing.route.expiresAt > now + ROUTE_REFRESH_LEAD_MS &&
660
+ sameAddresses(existing.route.routeHints, identity.listenAddresses) &&
661
+ sameAddresses(existing.route.coordinationRelays, identity.coordinationRelays) &&
662
+ existing.route.endpointKind === this.#endpointKind &&
663
+ existing.route.displayName === (current.displayName ?? undefined) &&
664
+ existing.route.transitMeshId === current.transitMeshId) {
665
+ return { state: current, result: existing };
666
+ }
667
+ const route = await this.#signLocalRoute(current);
668
+ return {
669
+ state: { ...current, routes: mergeRoutes(current.routes, [route], now) },
670
+ result: route,
671
+ };
672
+ });
551
673
  }
552
- async #signLocalRoute() {
674
+ async #signLocalRoute(stored = this.#store.read()) {
553
675
  const identity = this.#peer.identity();
554
- const stored = this.#store.read();
555
676
  const maxSequence = stored.routes
556
677
  .filter(({ route }) => route.peerId === identity.peerId)
557
678
  .reduce((maximum, { route }) => Math.max(maximum, route.sequence), 0);
@@ -562,6 +683,8 @@ class PeerMeshNodeImpl {
562
683
  expiresAt: this.#now() + ROUTE_TTL_MS,
563
684
  routeHints: identity.listenAddresses,
564
685
  coordinationRelays: identity.coordinationRelays,
686
+ ...(this.#endpointKind ? { endpointKind: this.#endpointKind } : {}),
687
+ ...(stored.displayName ? { displayName: stored.displayName } : {}),
565
688
  ...(stored.transitMeshId ? { transitMeshId: stored.transitMeshId } : {}),
566
689
  });
567
690
  const proof = await this.#peer.signIdentity(peerMeshRouteRecordSigningBytes(route));
@@ -660,6 +783,9 @@ class PeerMeshNodeImpl {
660
783
  revision: state.roster.roster.revision + 1,
661
784
  members: next.members,
662
785
  closed: next.closed,
786
+ ...(state.roster.roster.displayName
787
+ ? { displayName: state.roster.roster.displayName }
788
+ : {}),
663
789
  }, authorityKeys(state));
664
790
  const updated = {
665
791
  ...state,
@@ -676,7 +802,7 @@ class PeerMeshNodeImpl {
676
802
  await this.#refreshLocalRoute();
677
803
  await this.#reconcileTransit();
678
804
  const stored = this.#store.read();
679
- return peerMeshStatus(findMesh(stored.meshes, meshId), this.#peer.identity(), stored.routes);
805
+ return peerMeshStatus(findMesh(stored.meshes, meshId), this.#peer.identity(), this.#endpointKind, stored.routes);
680
806
  }
681
807
  #acceptIncoming(stream) {
682
808
  let peerStreams = 0;
@@ -932,7 +1058,7 @@ class PeerMeshNodeImpl {
932
1058
  if (route.peerId === localPeerId ||
933
1059
  route.expiresAt <= now ||
934
1060
  route.transitMeshId === undefined ||
935
- route.routeHints.length === 0) {
1061
+ route.routeHints.length + route.coordinationRelays.length === 0) {
936
1062
  return false;
937
1063
  }
938
1064
  return isActiveMeshMember(stored.meshes, route.transitMeshId, localPeerId, route.peerId);
@@ -953,13 +1079,18 @@ function transitRelayCandidates(routes) {
953
1079
  for (const { route } of routes) {
954
1080
  if (remaining === 0)
955
1081
  break;
956
- const addresses = [
1082
+ const routeHints = [
957
1083
  ...new Set(route.routeHints.filter((address) => isBaseRelayFor(address, route.peerId))),
958
1084
  ].slice(0, Math.min(PEER_MESH_MAX_TRANSIT_ADDRESSES_PER_RELAY, remaining));
959
- if (addresses.length === 0)
1085
+ const coordinationRelays = [...new Set(route.coordinationRelays)].slice(0, Math.min(PEER_MESH_MAX_TRANSIT_ADDRESSES_PER_RELAY - routeHints.length, remaining - routeHints.length));
1086
+ if (routeHints.length + coordinationRelays.length === 0)
960
1087
  continue;
961
- candidates.push(Object.freeze({ peerId: route.peerId, addresses: Object.freeze(addresses) }));
962
- remaining -= addresses.length;
1088
+ candidates.push(Object.freeze({
1089
+ peerId: route.peerId,
1090
+ addresses: Object.freeze(routeHints),
1091
+ coordinationRelays: Object.freeze(coordinationRelays),
1092
+ }));
1093
+ remaining -= routeHints.length + coordinationRelays.length;
963
1094
  }
964
1095
  return Object.freeze(candidates);
965
1096
  }
@@ -976,7 +1107,9 @@ function isActiveMeshMember(meshes, meshId, localPeerId, peerId) {
976
1107
  isActiveMembership(mesh, localPeerId) &&
977
1108
  mesh.roster.roster.members.includes(peerId));
978
1109
  }
979
- function peerMeshStatus(state, identity, routes = [], now = Date.now()) {
1110
+ function peerMeshStatus(state, identity, endpointKind, routes = [], now = Date.now()) {
1111
+ const localDisplayName = routes.find(({ route }) => route.peerId === identity.peerId)?.route
1112
+ .displayName;
980
1113
  return Object.freeze({
981
1114
  role: state.role === 'authority' ? 'authority' : 'member',
982
1115
  authority: state.role === 'authority' ? authorityTarget(identity) : state.authority,
@@ -985,20 +1118,30 @@ function peerMeshStatus(state, identity, routes = [], now = Date.now()) {
985
1118
  ? state.invitations.filter((invitation) => invitation.status === 'pending' && invitation.expiresAt > now).length
986
1119
  : 0,
987
1120
  memberRoutes: Object.freeze(state.roster.roster.members.map((peerId) => {
988
- if (peerId === identity.peerId)
989
- return Object.freeze({ peerId, state: 'local' });
1121
+ if (peerId === identity.peerId) {
1122
+ return Object.freeze({
1123
+ peerId,
1124
+ ...(endpointKind ? { endpointKind } : {}),
1125
+ ...(localDisplayName ? { displayName: localDisplayName } : {}),
1126
+ state: 'local',
1127
+ });
1128
+ }
990
1129
  const route = routes.find((candidate) => candidate.route.peerId === peerId)?.route;
991
1130
  if (!route)
992
1131
  return Object.freeze({ peerId, state: 'unknown' });
993
1132
  if (route.expiresAt <= now) {
994
1133
  return Object.freeze({
995
1134
  peerId,
1135
+ ...(route.endpointKind ? { endpointKind: route.endpointKind } : {}),
1136
+ ...(route.displayName ? { displayName: route.displayName } : {}),
996
1137
  state: 'stale',
997
1138
  expiresAt: route.expiresAt,
998
1139
  });
999
1140
  }
1000
1141
  return Object.freeze({
1001
1142
  peerId,
1143
+ ...(route.endpointKind ? { endpointKind: route.endpointKind } : {}),
1144
+ ...(route.displayName ? { displayName: route.displayName } : {}),
1002
1145
  state: route.routeHints.length > 0
1003
1146
  ? 'route_available'
1004
1147
  : 'coordination_only',
@@ -1118,6 +1261,23 @@ function responseRoutes(state, routes, knownRoutes, now) {
1118
1261
  function sameAddresses(left, right) {
1119
1262
  return left.length === right.length && left.every((address, index) => address === right[index]);
1120
1263
  }
1264
+ function mergeAddresses(primary, fallback) {
1265
+ return Object.freeze([...new Set([...primary, ...fallback])].slice(0, 32));
1266
+ }
1267
+ function waitForTurn(previous, signal) {
1268
+ if (!signal)
1269
+ return previous;
1270
+ if (signal.aborted)
1271
+ return Promise.reject(signal.reason);
1272
+ return new Promise((resolve, reject) => {
1273
+ const onAbort = () => reject(signal.reason);
1274
+ signal.addEventListener('abort', onAbort, { once: true });
1275
+ void previous.then(() => {
1276
+ signal.removeEventListener('abort', onAbort);
1277
+ resolve();
1278
+ });
1279
+ });
1280
+ }
1121
1281
  function mergeTargets(primary, fallback) {
1122
1282
  return Object.freeze({
1123
1283
  peerId: primary.peerId,
@@ -42,6 +42,7 @@ export async function openRuntimeHostPeerMeshOwner(input) {
42
42
  : { automaticRelayDiscovery: input.automaticRelayDiscovery }),
43
43
  routeResolver: {
44
44
  resolveRoutes: (peerId) => resolverMesh?.resolveRoutes(peerId),
45
+ prepareRoutes: async (peerId, signal) => resolverMesh?.prepareRoutes(peerId, signal),
45
46
  },
46
47
  });
47
48
  }
@@ -54,6 +55,7 @@ export async function openRuntimeHostPeerMeshOwner(input) {
54
55
  mesh = await openPeerMeshNode({
55
56
  dataRoot: join(input.dataRoot, client.identity().peerId),
56
57
  peer: client,
58
+ endpointKind: input.endpointKind,
57
59
  });
58
60
  resolverMesh = mesh;
59
61
  }
@@ -20,6 +20,7 @@ import { chmod, lstat, mkdir, open, readFile, rename, unlink } from 'node:fs/pro
20
20
  import { dirname, join } from 'node:path';
21
21
  import { acquireFileLifetimeOwner, } from '@maka/storage/file-lifetime-owner';
22
22
  import { decodeAuthorityTarget, decodeSignedPeerMeshRoster, decodeSignedPeerMeshRouteRecord, PEER_MESH_MAX_INVITATION_RECORDS, PEER_MESH_MAX_MEMBERS, PEER_MESH_MAX_MESHES, PEER_MESH_MAX_PENDING_INVITATIONS, validatePeerMeshAuthorityKeyPair, } from './model.js';
23
+ import { canonicalPeerMeshDisplayName } from './display-name.js';
23
24
  const STATE_FILE = 'peer-mesh.json';
24
25
  const LOCK_FILE = 'peer-mesh.owner';
25
26
  const MAX_STATE_BYTES = 1024 * 1024;
@@ -94,7 +95,7 @@ class PeerMeshStateStoreImpl {
94
95
  const task = this.#tail.then(async () => {
95
96
  if (this.#failure)
96
97
  throw this.#failure;
97
- const updated = operation(this.#state);
98
+ const updated = await operation(this.#state);
98
99
  if (updated.state === this.#state)
99
100
  return updated.result;
100
101
  const candidate = pruneUnreferencedRoutes(updated.state, this.localPeerId);
@@ -251,21 +252,30 @@ async function readState(path, expectedLocalPeerId) {
251
252
  Object.hasOwn(record, 'meshes') &&
252
253
  Object.hasOwn(record, 'routes') &&
253
254
  Object.hasOwn(record, 'transitMeshId');
254
- if (!versionOne && !versionTwo && !versionThree) {
255
+ const versionFour = record.version === 4 &&
256
+ Object.keys(record).length === 6 &&
257
+ Object.hasOwn(record, 'localPeerId') &&
258
+ Object.hasOwn(record, 'displayName') &&
259
+ Object.hasOwn(record, 'meshes') &&
260
+ Object.hasOwn(record, 'routes') &&
261
+ Object.hasOwn(record, 'transitMeshId');
262
+ if (!versionOne && !versionTwo && !versionThree && !versionFour) {
255
263
  throw new Error('Unsupported Peer Mesh state document');
256
264
  }
257
265
  if (boundedString(record.localPeerId, 'localPeerId', 256) !== expectedLocalPeerId) {
258
266
  throw new Error('Peer Mesh state belongs to a different peer identity');
259
267
  }
260
268
  return decodePeerMeshStoredState({
269
+ displayName: versionFour ? record.displayName : null,
261
270
  meshes: record.meshes,
262
271
  routes: versionOne ? [] : record.routes,
263
- transitMeshId: versionThree ? record.transitMeshId : null,
272
+ transitMeshId: versionThree || versionFour ? record.transitMeshId : null,
264
273
  }, expectedLocalPeerId);
265
274
  }
266
275
  catch (error) {
267
276
  if (isNodeError(error, 'ENOENT')) {
268
277
  return Object.freeze({
278
+ displayName: null,
269
279
  meshes: Object.freeze([]),
270
280
  routes: Object.freeze([]),
271
281
  transitMeshId: null,
@@ -286,7 +296,7 @@ async function pathExists(path) {
286
296
  }
287
297
  }
288
298
  async function writeState(path, localPeerId, state) {
289
- const document = `${JSON.stringify({ version: 3, localPeerId, ...state }, null, 2)}\n`;
299
+ const document = `${JSON.stringify({ version: 4, localPeerId, ...state }, null, 2)}\n`;
290
300
  if (Buffer.byteLength(document) > MAX_STATE_BYTES)
291
301
  throw new Error('Peer Mesh state is too large');
292
302
  const temporary = `${path}.tmp`;
@@ -395,13 +405,15 @@ function decodePeerMeshStoredState(value, localPeerId) {
395
405
  throw new Error('Invalid Peer Mesh state document');
396
406
  }
397
407
  const record = value;
398
- if (Object.keys(record).length !== 3 ||
408
+ if (Object.keys(record).length !== 4 ||
409
+ !Object.hasOwn(record, 'displayName') ||
399
410
  !Object.hasOwn(record, 'meshes') ||
400
411
  !Object.hasOwn(record, 'routes') ||
401
412
  !Object.hasOwn(record, 'transitMeshId')) {
402
413
  throw new Error('Invalid Peer Mesh state document');
403
414
  }
404
415
  const meshes = decodePeerMeshStates(record.meshes, localPeerId);
416
+ const displayName = record.displayName === null ? null : canonicalPeerMeshDisplayName(record.displayName);
405
417
  const transitMeshId = record.transitMeshId === null
406
418
  ? null
407
419
  : boundedString(record.transitMeshId, 'transitMeshId', 128);
@@ -410,6 +422,7 @@ function decodePeerMeshStoredState(value, localPeerId) {
410
422
  throw new Error('Peer Mesh transit selection is not an active membership');
411
423
  }
412
424
  return Object.freeze({
425
+ displayName,
413
426
  meshes,
414
427
  routes: decodeRoutes(record.routes, meshes),
415
428
  transitMeshId,
@@ -59,7 +59,11 @@ export const RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION = 1;
59
59
  export const RUNTIME_HOST_PROTOCOL_VERSION = 0;
60
60
  // Increment when the same protocol version no longer guarantees safe Client-Host
61
61
  // interoperability. Mismatches are rejected before domain commands are admitted.
62
- export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 74;
62
+ export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 76;
63
+ // 76: Peer Mesh endpoint and Mesh display names are signed, persisted facts
64
+ // managed through Host operations rather than local-only Client labels.
65
+ // 75: Peer Mesh routes identify whether a peer is a Client or Runtime Host so
66
+ // management surfaces can present the endpoint authority boundary accurately.
63
67
  // 74: Capability-provider credentials may carry one Host-authenticated owner
64
68
  // identity. Older peers cannot preserve the association and could select an
65
69
  // unrelated provider for an interactive Session.