agent-embassy 3.1.0 → 4.0.0

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 (112) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/CONTRIBUTING.md +92 -202
  3. package/README.md +157 -155
  4. package/SECURITY.md +191 -348
  5. package/dist/src/gateway/broker-check.d.ts +26 -0
  6. package/dist/src/gateway/broker-check.js +89 -0
  7. package/dist/src/gateway/broker-check.js.map +1 -0
  8. package/dist/src/gateway/broker-control.d.ts +72 -0
  9. package/dist/src/gateway/broker-control.js +164 -0
  10. package/dist/src/gateway/broker-control.js.map +1 -0
  11. package/dist/src/gateway/broker.d.ts +117 -0
  12. package/dist/src/gateway/broker.js +186 -0
  13. package/dist/src/gateway/broker.js.map +1 -0
  14. package/dist/src/gateway/claude-peer.d.ts +1 -124
  15. package/dist/src/gateway/claude-peer.js +61 -1052
  16. package/dist/src/gateway/claude-peer.js.map +1 -1
  17. package/dist/src/gateway/codex-stateless-transport.d.ts +0 -12
  18. package/dist/src/gateway/codex-stateless-transport.js +8 -142
  19. package/dist/src/gateway/codex-stateless-transport.js.map +1 -1
  20. package/dist/src/gateway/config.d.ts +2 -6
  21. package/dist/src/gateway/config.js +17 -27
  22. package/dist/src/gateway/config.js.map +1 -1
  23. package/dist/src/gateway/coordinator.d.ts +57 -0
  24. package/dist/src/gateway/coordinator.js +217 -0
  25. package/dist/src/gateway/coordinator.js.map +1 -0
  26. package/dist/src/gateway/core-cli.d.ts +15 -0
  27. package/dist/src/gateway/core-cli.js +282 -0
  28. package/dist/src/gateway/core-cli.js.map +1 -0
  29. package/dist/src/gateway/core-service-command.d.ts +16 -0
  30. package/dist/src/gateway/core-service-command.js +71 -0
  31. package/dist/src/gateway/core-service-command.js.map +1 -0
  32. package/dist/src/gateway/endpoint-directory.d.ts +33 -0
  33. package/dist/src/gateway/endpoint-directory.js +223 -0
  34. package/dist/src/gateway/endpoint-directory.js.map +1 -0
  35. package/dist/src/gateway/federation.d.ts +89 -0
  36. package/dist/src/gateway/federation.js +632 -0
  37. package/dist/src/gateway/federation.js.map +1 -0
  38. package/dist/src/gateway/ledger-codec.d.ts +3 -0
  39. package/dist/src/gateway/ledger-codec.js +159 -0
  40. package/dist/src/gateway/ledger-codec.js.map +1 -0
  41. package/dist/src/gateway/ledger.d.ts +138 -0
  42. package/dist/src/gateway/ledger.js +319 -0
  43. package/dist/src/gateway/ledger.js.map +1 -0
  44. package/dist/src/gateway/local-control.d.ts +23 -0
  45. package/dist/src/gateway/local-control.js +489 -0
  46. package/dist/src/gateway/local-control.js.map +1 -0
  47. package/dist/src/gateway/native-destinations.d.ts +34 -0
  48. package/dist/src/gateway/native-destinations.js +272 -0
  49. package/dist/src/gateway/native-destinations.js.map +1 -0
  50. package/dist/src/gateway/owned-state.d.ts +57 -0
  51. package/dist/src/gateway/owned-state.js +398 -0
  52. package/dist/src/gateway/owned-state.js.map +1 -0
  53. package/dist/src/gateway/provenance-envelope.d.ts +3 -3
  54. package/dist/src/gateway/provenance-envelope.js +3 -23
  55. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  56. package/dist/src/gateway/runtime.d.ts +41 -0
  57. package/dist/src/gateway/runtime.js +175 -0
  58. package/dist/src/gateway/runtime.js.map +1 -0
  59. package/docs/CONFIGURATION.md +178 -266
  60. package/docs/DELIVERY.md +133 -82
  61. package/docs/GATEWAY-ARCHITECTURE.md +276 -949
  62. package/package.json +5 -5
  63. package/skills/embassy-peer/SKILL.md +38 -196
  64. package/skills/embassy-peer/agents/openai.yaml +2 -2
  65. package/dist/src/gateway/claude-helper-protocol.d.ts +0 -117
  66. package/dist/src/gateway/claude-helper-protocol.js +0 -122
  67. package/dist/src/gateway/claude-helper-protocol.js.map +0 -1
  68. package/dist/src/gateway/claude-helper-supervisor.d.ts +0 -87
  69. package/dist/src/gateway/claude-helper-supervisor.js +0 -374
  70. package/dist/src/gateway/claude-helper-supervisor.js.map +0 -1
  71. package/dist/src/gateway/claude-helper.d.ts +0 -1
  72. package/dist/src/gateway/claude-helper.js +0 -252
  73. package/dist/src/gateway/claude-helper.js.map +0 -1
  74. package/dist/src/gateway/cli.d.ts +0 -56
  75. package/dist/src/gateway/cli.js +0 -1532
  76. package/dist/src/gateway/cli.js.map +0 -1
  77. package/dist/src/gateway/codex-socket-holder.d.ts +0 -26
  78. package/dist/src/gateway/codex-socket-holder.js +0 -76
  79. package/dist/src/gateway/codex-socket-holder.js.map +0 -1
  80. package/dist/src/gateway/control.d.ts +0 -279
  81. package/dist/src/gateway/control.js +0 -933
  82. package/dist/src/gateway/control.js.map +0 -1
  83. package/dist/src/gateway/peer-client.d.ts +0 -58
  84. package/dist/src/gateway/peer-client.js +0 -217
  85. package/dist/src/gateway/peer-client.js.map +0 -1
  86. package/dist/src/gateway/peer-mailbox.d.ts +0 -78
  87. package/dist/src/gateway/peer-mailbox.js +0 -168
  88. package/dist/src/gateway/peer-mailbox.js.map +0 -1
  89. package/dist/src/gateway/peer-protocol.d.ts +0 -110
  90. package/dist/src/gateway/peer-protocol.js +0 -79
  91. package/dist/src/gateway/peer-protocol.js.map +0 -1
  92. package/dist/src/gateway/peer-stdio.d.ts +0 -23
  93. package/dist/src/gateway/peer-stdio.js +0 -100
  94. package/dist/src/gateway/peer-stdio.js.map +0 -1
  95. package/dist/src/gateway/providers.d.ts +0 -164
  96. package/dist/src/gateway/providers.js +0 -975
  97. package/dist/src/gateway/providers.js.map +0 -1
  98. package/dist/src/gateway/server.d.ts +0 -46
  99. package/dist/src/gateway/server.js +0 -216
  100. package/dist/src/gateway/server.js.map +0 -1
  101. package/dist/src/gateway/service.d.ts +0 -371
  102. package/dist/src/gateway/service.js +0 -2335
  103. package/dist/src/gateway/service.js.map +0 -1
  104. package/dist/src/gateway/status-view.d.ts +0 -119
  105. package/dist/src/gateway/status-view.js +0 -484
  106. package/dist/src/gateway/status-view.js.map +0 -1
  107. package/dist/src/gateway/store.d.ts +0 -188
  108. package/dist/src/gateway/store.js +0 -2360
  109. package/dist/src/gateway/store.js.map +0 -1
  110. package/dist/src/gateway/types.d.ts +0 -541
  111. package/dist/src/gateway/types.js +0 -332
  112. package/dist/src/gateway/types.js.map +0 -1
@@ -1,371 +0,0 @@
1
- import type { GatewayConfig } from "./config.js";
2
- import { type GatewayControlHandlers, type GatewaySnapshotObservation } from "./control.js";
3
- import { spawnPeerClient } from "./peer-client.js";
4
- import { GatewayStore } from "./store.js";
5
- import { type GatewayPreparedWriteEvidence, type GatewayProvider, type GatewayPublicSnapshot, type LogicalRouteBinding } from "./types.js";
6
- export type GatewayAdapterRouteState = "idle" | "busy" | "awaiting_approval";
7
- export type GatewayAdapterRouteObservationState = GatewayAdapterRouteState | "unobserved";
8
- export type GatewayAdapterDiscovery = Readonly<{
9
- alias: string;
10
- routeHandle: string;
11
- kind: "interactive" | "bg";
12
- state: GatewayAdapterRouteState;
13
- }>;
14
- export type GatewayAdapterRegistryObservation = Readonly<{
15
- entriesScanned: number;
16
- parseableRecords: number;
17
- rejected: readonly Readonly<{
18
- safeErrorCode: string;
19
- count: number;
20
- }>[];
21
- }>;
22
- export type GatewayAdapterDiscoverySnapshot = Readonly<{
23
- peers: readonly GatewayAdapterDiscovery[];
24
- complete: boolean;
25
- registry?: GatewayAdapterRegistryObservation;
26
- }>;
27
- export type GatewayAdapterRouteObservation = Readonly<{
28
- route: LogicalRouteBinding;
29
- state: GatewayAdapterRouteObservationState;
30
- observedAt: string;
31
- safeErrorCode?: string;
32
- }>;
33
- export type GatewayAdapterNativeEndpoint = Readonly<{
34
- provider: GatewayProvider;
35
- hostId: string;
36
- routeHandle: string;
37
- }>;
38
- export type GatewayAdapterCallbacks = Readonly<{
39
- onRouteState: (event: GatewayAdapterRouteObservation) => void;
40
- onClaudeReply: (event: Readonly<{
41
- endpoint: GatewayAdapterNativeEndpoint;
42
- text: string;
43
- }>) => void;
44
- onClaudeMessage?: (event: Readonly<{
45
- endpoint: GatewayAdapterNativeEndpoint;
46
- sourceAlias: string;
47
- targetAlias: string;
48
- text: string;
49
- receiptHandle?: string;
50
- }>) => void;
51
- onProtocolNotice?: (event: Readonly<{
52
- code: string;
53
- }>) => void;
54
- }>;
55
- export type GatewayAdapterStart = Readonly<{
56
- health: "healthy" | "degraded";
57
- safeErrorCode?: string;
58
- }>;
59
- export type GatewayAdapterDispatchResult = Readonly<{
60
- state: "deferred";
61
- safeErrorCode?: string;
62
- }> | Readonly<{
63
- state: "delivered" | "unconfirmed" | "failed" | "ambiguous" | "expired" | "cancelled";
64
- safeErrorCode?: string;
65
- replyText?: string;
66
- }>;
67
- export type GatewayAdapterDispatchInput = Readonly<{
68
- attemptId: string;
69
- sourceAlias: string;
70
- sourceProvider: GatewayProvider;
71
- targetAlias: string;
72
- conversationId: string;
73
- binding: LogicalRouteBinding;
74
- authorization: "selected_route";
75
- messageId: string;
76
- text: string;
77
- expectsReply: boolean;
78
- deadlineAt: string;
79
- steer?: true;
80
- queuedAhead?: number;
81
- authorizeWrite: (evidence: GatewayPreparedWriteEvidence & Readonly<{
82
- attemptId: string;
83
- }>) => Promise<boolean>;
84
- onAccepted: (evidence: Readonly<{
85
- attemptId: string;
86
- }>) => Promise<void>;
87
- }>;
88
- export interface GatewayProviderAdapter {
89
- readonly identity: Readonly<{
90
- provider: GatewayProvider;
91
- hostId: string;
92
- }>;
93
- readonly protocol: string;
94
- readonly protocolVersion: string;
95
- latestRegistryObservation?(): GatewayAdapterRegistryObservation | undefined;
96
- initialize(callbacks: GatewayAdapterCallbacks): Promise<GatewayAdapterStart>;
97
- observeLogicalRoute?(input: Readonly<{
98
- alias: string;
99
- routeHandle: string;
100
- registrationId: string;
101
- }>): void;
102
- forgetLogicalRoute?(registrationId: string): void;
103
- discoverClaudePeers?(): Promise<GatewayAdapterDiscoverySnapshot>;
104
- selectRoute?(input: Readonly<{
105
- alias: string;
106
- routeHandle: string;
107
- }>): Promise<{
108
- routeHandle: string;
109
- state: GatewayAdapterRouteState;
110
- }>;
111
- assertWorkspaceDisjoint?(routeHandle: string, stateRoot: string): Promise<void>;
112
- resolveReplyAddress?(address: string): Promise<{
113
- routeHandle: string;
114
- }>;
115
- advertiseNativeSourcePeer?(input: Readonly<{
116
- alias: string;
117
- sourceProvider: GatewayProvider;
118
- cwd: string;
119
- }>): Promise<void>;
120
- unadvertiseNativeSourcePeer?(alias: string): Promise<void>;
121
- updateNativeSourcePeerStatus?(alias: string, status: "idle" | "busy" | "waiting"): Promise<void>;
122
- updateNativeInboundStatus?(receiptHandle: string, status: "held" | "delivered" | "denied" | "expired", diagnosticCode?: string): Promise<void>;
123
- notifyNativeInboundProgress?(receiptHandle: string, progress: Readonly<{
124
- kind: "stall";
125
- reason: "ROUTE_BUSY" | "ROUTE_UNAVAILABLE" | "AWAITING_EXTERNAL_APPROVAL";
126
- queuedForMs: number;
127
- }>): Promise<void>;
128
- releaseNativeInboundReceipt?(receiptHandle: string): Promise<boolean>;
129
- dispatch(input: GatewayAdapterDispatchInput): Promise<GatewayAdapterDispatchResult>;
130
- releaseRoute?(routeHandle: string): Promise<void>;
131
- close(): Promise<void>;
132
- }
133
- type GatewayServiceTimer = ReturnType<typeof setTimeout>;
134
- type GatewayServiceTimers = Readonly<{
135
- setTimeout: (callback: () => void, delayMs: number) => GatewayServiceTimer;
136
- clearTimeout: (timer: GatewayServiceTimer) => void;
137
- }>;
138
- export type GatewayServiceOptions = Readonly<{
139
- config: GatewayConfig;
140
- adapters?: readonly GatewayProviderAdapter[];
141
- store?: GatewayStore;
142
- now?: () => Date;
143
- nativePeerCwd?: string;
144
- timers?: GatewayServiceTimers;
145
- /** True when a process outside Embassy holds the managed Codex control socket while the managed layout is missing. */
146
- managedCodexSocketHeld?: () => Promise<boolean>;
147
- spawnPeer?: typeof spawnPeerClient;
148
- }>;
149
- export declare class GatewayService {
150
- readonly config: GatewayConfig;
151
- readonly store: GatewayStore;
152
- private readonly adapters;
153
- private readonly now;
154
- private readonly timers;
155
- private readonly nativePeerCwd;
156
- private readonly managedCodexSocketHeld;
157
- private readonly spawnPeer;
158
- private readonly peerClients;
159
- private readonly peerCatalogs;
160
- private readonly routeCleanupAliases;
161
- /** View-only freshness; never consulted by routing or write authorization. */
162
- private readonly peerRouteViews;
163
- private readonly connectors;
164
- private readonly routeObservations;
165
- private readonly candidates;
166
- private readonly collidingClaudeAliases;
167
- private readonly conversations;
168
- private readonly messageContexts;
169
- private readonly activeAttempts;
170
- private readonly reserveOperations;
171
- private readonly inboundOperations;
172
- private readonly peerRefreshOperations;
173
- private readonly pendingClaudeReplies;
174
- private readonly nativeReceipts;
175
- private readonly dispatchRunners;
176
- private readonly steerRunners;
177
- private readonly startingTargets;
178
- private readonly runtimeAlerts;
179
- /**
180
- * Ephemeral peer registrations and the wall-clock instant each one dies.
181
- * Nothing durable records them, so this map is the whole lifetime: it is
182
- * swept on the ordinary maintenance tick, and a restart simply never sees
183
- * the routes at all.
184
- */
185
- private readonly ephemeralPeerExpiries;
186
- /** Consecutive failed retirements per ephemeral alias; cleared on success or removal. */
187
- private readonly ephemeralExpiryFailures;
188
- private control;
189
- private wakeTimer;
190
- private nextDiscoveryAt;
191
- private nextManagedCodexCheckAt;
192
- private nextPeerRefreshAt;
193
- private managedCodexSocketHeldOutside;
194
- private revision;
195
- private snapshotRevision;
196
- private snapshotFingerprint;
197
- private running;
198
- private closing;
199
- private closeInFlight;
200
- constructor(options: GatewayServiceOptions);
201
- start(signal?: AbortSignal): Promise<void>;
202
- close(): Promise<void>;
203
- private closeOnce;
204
- handlers(): GatewayControlHandlers;
205
- private buildPeerCatalog;
206
- private receivePeerHandoff;
207
- snapshot(): Promise<GatewayPublicSnapshot>;
208
- observeSnapshot(): Promise<GatewaySnapshotObservation>;
209
- private health;
210
- private publicConnectors;
211
- private observeLoadedRoutes;
212
- private observeRoute;
213
- private forgetRoute;
214
- private adapterFor;
215
- private claudeAdapter;
216
- private advertise;
217
- private unadvertise;
218
- private reconcileAdvertisement;
219
- private reconcileUnadvertisement;
220
- private assertRouteNotCleaning;
221
- private retireRoute;
222
- private removeOwnedRoute;
223
- private recordActivity;
224
- private registerCodex;
225
- private registerPeer;
226
- private assertPeer;
227
- private unregisterPeer;
228
- /**
229
- * Retires every ephemeral peer registration whose lifetime has run out. It
230
- * is the same removal an explicit `unregister-peer` performs — queued work
231
- * is settled, not abandoned — minus the token check, because the authority
232
- * here is the clock the broker set itself.
233
- *
234
- * The clock is keyed by alias, and an alias can be re-registered durably
235
- * after its ephemeral holder left, so nothing is retired unless the route
236
- * behind the alias is still an ephemeral one. A retirement that throws
237
- * keeps its entry and is retried `EPHEMERAL_EXPIRY_RETRY_MS` later, with an
238
- * alert each time; after `EPHEMERAL_EXPIRY_MAX_ATTEMPTS` consecutive
239
- * failures the entry is dropped and the registration is left to the next
240
- * restart, which clears it by construction.
241
- */
242
- private expireEphemeralPeers;
243
- private awaitPeer;
244
- private peerReceipt;
245
- private unregisterCodex;
246
- /**
247
- * The name this session may take. A name belongs to one route at a time, so
248
- * when another Claude route already holds it and THAT route's session is
249
- * still live, this session takes a disambiguated name rather than displacing
250
- * a working session and cancelling its queued work. Twins that share a
251
- * display name therefore both keep routes and both stay reachable by UUID;
252
- * only a route whose session is actually gone is displaced.
253
- */
254
- private claimableAlias;
255
- /**
256
- * Installs (or brings up to date) the route of one discovered Claude
257
- * session. The adapter pins the session's route handle, the workspace
258
- * check keeps deliberately broad workspaces out, and the store reuses the
259
- * registration of a session already bound under the same (host, UUID) so a
260
- * re-anchored or renamed session keeps its identity and in-flight
261
- * conversations. Any Claude route the install displaced is forgotten and
262
- * released at the adapter; its work was settled `ENDPOINT_RETIRED` by the
263
- * store — and only a route whose own session is gone is ever displaced.
264
- */
265
- private installClaudeRoute;
266
- /**
267
- * Two first sends to the same never-installed session race: both read no
268
- * route and both mint a registration, and the loser's write is refused
269
- * because the identity is now bound. That is a race, not a conflict — the
270
- * session is exactly the one the loser resolved — so re-read once and adopt
271
- * the registration that won instead of failing an honest send.
272
- */
273
- private installWithConcurrentFirstSend;
274
- /**
275
- * Looks a Claude selector up without writing anything. Callers that may
276
- * still refuse — a `--from` alias that must match the sending session, a
277
- * native sender whose adapter-reported name must match discovery — resolve
278
- * here first, refuse on the read, and only then materialize.
279
- *
280
- * THE ALIAS-COLLISION FENCE lives here (emb-94, moved into the send path by
281
- * emb-104). Invariant: discovery is refreshed inside every send that
282
- * addresses a Claude session, never only on the timer; a NAME currently
283
- * shared by more than one live session is refused with a hard,
284
- * non-retryable `PEER_ALIAS_COLLISION` naming that alias, so the broker
285
- * never picks first and never installs a route under an ambiguous name;
286
- * collisions stay sticky while a scan is incomplete
287
- * (`collidingClaudeAliases` retention in refreshClaudeDiscovery); and
288
- * `availablePeers` keeps filtering colliders so `status` never lists an
289
- * unaddressable name.
290
- *
291
- * The fence is a fence on NAMES, not on sessions. A session UUID is
292
- * unambiguous by construction, so a UUID selector — an explicit
293
- * `send --to <uuid>`, an identity-pinned route addressed by its own handle,
294
- * or a sender resolved from its inherited socket — passes the fence even
295
- * while its display name collides. That is the emb-94 escape hatch: the
296
- * operator can always reach an ambiguously named session, and a collision on
297
- * a *sender's* name never silences that sender, whose identity was attested
298
- * rather than typed. In-flight conversations are likewise unaffected:
299
- * `reply` resolves by exact binding.
300
- */
301
- private lookUpClaudeRoute;
302
- /**
303
- * The name discovery currently shows for a looked-up session, which a caller
304
- * compares against the alias it claimed before anything is written.
305
- */
306
- private claimedAlias;
307
- /** Installs the looked-up session's route if it is not already current. */
308
- private materializeClaudeRoute;
309
- private assertThread;
310
- /**
311
- * Direction follows the inherited principal, not the route table: a Claude
312
- * session or its target may have no route yet, because routes install on
313
- * first send. A Codex task sends to Claude sessions and shell peers; a
314
- * Claude session sends to Codex tasks and shell peers (Claude-to-Claude is
315
- * native); a shell peer sends to either.
316
- */
317
- private send;
318
- private sendToClaude;
319
- private sendToCodex;
320
- /**
321
- * A send addressed by conversation token: the caller must own one end, the
322
- * other end is the binding the conversation recorded, and the caller's
323
- * principal is the same attested one every send carries.
324
- */
325
- private replyToConversation;
326
- private assertReplyCaller;
327
- private enqueueConversation;
328
- /**
329
- * A renamed Claude session is the same principal under a new display name,
330
- * so its open conversations follow it: the registration, not the alias, is
331
- * the identity, and a reply under the current name must still resolve.
332
- */
333
- private renameConversationCoordinates;
334
- private rememberConversation;
335
- private conversationIsActive;
336
- private deliveryStatus;
337
- private messageUpdatedAt;
338
- private kick;
339
- private kickExact;
340
- private kickSteer;
341
- private startRunner;
342
- private runTarget;
343
- private runPeerAttempt;
344
- private runProviderAttempt;
345
- private settleAttemptForShutdown;
346
- private resolvePrewrite;
347
- private applyDispatchResult;
348
- private callbacksFor;
349
- private onRouteState;
350
- private onClaudeMessage;
351
- private onClaudeReply;
352
- private enqueueCorrelatedReply;
353
- private installPendingClaudeReply;
354
- private pruneExpiredPendingClaudeReplies;
355
- private retirePendingClaudeReply;
356
- private activatePendingClaudeReply;
357
- private deliverPendingClaudeReply;
358
- private finishSettlements;
359
- private finishSettlement;
360
- private scheduleTargetRetry;
361
- private scheduleWake;
362
- private onWake;
363
- private refreshPeers;
364
- private refreshClaudeDiscovery;
365
- private refreshManagedCodexSocket;
366
- private assertWritable;
367
- private routeObservationStillCurrent;
368
- private alert;
369
- private recordPeerFailure;
370
- }
371
- export {};