@masons/agent-network 0.5.29 → 0.5.31

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 (49) hide show
  1. package/dist/broker/broker-daemon.d.ts +13 -3
  2. package/dist/broker/broker-daemon.d.ts.map +1 -1
  3. package/dist/broker/broker-daemon.js +294 -52
  4. package/dist/broker/closed-endpoint-lookup.d.ts +25 -0
  5. package/dist/broker/closed-endpoint-lookup.d.ts.map +1 -0
  6. package/dist/broker/closed-endpoint-lookup.js +59 -0
  7. package/dist/broker/control-event-dispatcher.d.ts +20 -0
  8. package/dist/broker/control-event-dispatcher.d.ts.map +1 -0
  9. package/dist/broker/control-event-dispatcher.js +45 -0
  10. package/dist/broker/control-event-types.d.ts +30 -0
  11. package/dist/broker/control-event-types.d.ts.map +1 -0
  12. package/dist/broker/control-event-types.js +1 -0
  13. package/dist/broker/endpoint-registry.d.ts +17 -1
  14. package/dist/broker/endpoint-registry.d.ts.map +1 -1
  15. package/dist/broker/endpoint-registry.js +39 -0
  16. package/dist/broker/endpoint-state-machine.d.ts +40 -0
  17. package/dist/broker/endpoint-state-machine.d.ts.map +1 -0
  18. package/dist/broker/endpoint-state-machine.js +92 -0
  19. package/dist/broker/entry.d.ts +11 -0
  20. package/dist/broker/entry.d.ts.map +1 -1
  21. package/dist/broker/entry.js +108 -5
  22. package/dist/broker/grace-timer.d.ts +9 -0
  23. package/dist/broker/grace-timer.d.ts.map +1 -0
  24. package/dist/broker/grace-timer.js +34 -0
  25. package/dist/broker/ipc-server.d.ts +8 -1
  26. package/dist/broker/ipc-server.d.ts.map +1 -1
  27. package/dist/broker/ipc-server.js +31 -0
  28. package/dist/broker/paths.d.ts +1 -0
  29. package/dist/broker/paths.d.ts.map +1 -1
  30. package/dist/broker/paths.js +2 -0
  31. package/dist/broker/plugin-liveness.d.ts +2 -0
  32. package/dist/broker/plugin-liveness.d.ts.map +1 -0
  33. package/dist/broker/plugin-liveness.js +15 -0
  34. package/dist/broker/reconnecting-buffer.d.ts +23 -0
  35. package/dist/broker/reconnecting-buffer.d.ts.map +1 -0
  36. package/dist/broker/reconnecting-buffer.js +107 -0
  37. package/dist/broker/routing-table.d.ts.map +1 -1
  38. package/dist/broker/routing-table.js +1 -1
  39. package/dist/broker/runtime-endpoint-port.d.ts +2 -1
  40. package/dist/broker/runtime-endpoint-port.d.ts.map +1 -1
  41. package/dist/broker/undispatched-inbox.d.ts +26 -0
  42. package/dist/broker/undispatched-inbox.d.ts.map +1 -0
  43. package/dist/broker/undispatched-inbox.js +53 -0
  44. package/dist/runtime-endpoint-client.d.ts +7 -0
  45. package/dist/runtime-endpoint-client.d.ts.map +1 -1
  46. package/dist/runtime-endpoint-client.js +11 -0
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-event-types.d.ts","sourceRoot":"","sources":["../../src/broker/control-event-types.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,YAAY,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,oBAAoB,CAAC;AAGzB,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAGD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,CAAC,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAGD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,CAAC,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -13,8 +13,9 @@ export interface BrokerEndpointEntry {
13
13
  agent_id: string;
14
14
  plugin_pid: number;
15
15
  ipc_ws: WebSocket;
16
- state: "active";
16
+ state: "active" | "reconnecting";
17
17
  state_since: Date;
18
+ grace_deadline?: Date;
18
19
  display_metadata: DisplayMetadata;
19
20
  correlation_ring: CorrelationRingBuffer;
20
21
  }
@@ -30,7 +31,22 @@ export declare class EndpointRegistry {
30
31
  register(args: RegisterArgs): BrokerEndpointEntry;
31
32
  get(endpoint_id: string): BrokerEndpointEntry | undefined;
32
33
  unregister(endpoint_id: string): BrokerEndpointEntry | undefined;
34
+ markReconnecting(endpoint_id: string, grace_deadline: Date): BrokerEndpointEntry;
35
+ markActive(endpoint_id: string, new_ws: WebSocket): BrokerEndpointEntry;
33
36
  preconditionForReattach(endpoint_id: string, plugin_pid: number): BrokerEndpointEntry | undefined;
37
+ getReattachStatus(endpoint_id: string, plugin_pid: number): {
38
+ ok: true;
39
+ entry: BrokerEndpointEntry;
40
+ } | {
41
+ ok: false;
42
+ reason: "endpoint_unknown";
43
+ } | {
44
+ ok: false;
45
+ reason: "reattach_pid_mismatch";
46
+ } | {
47
+ ok: false;
48
+ reason: "endpoint_not_reconnecting";
49
+ };
34
50
  list(): BrokerEndpointEntry[];
35
51
  size(): number;
36
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint-registry.d.ts","sourceRoot":"","sources":["../../src/broker/endpoint-registry.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,WAAW,EAAE,IAAI,CAAC;IAClB,gBAAgB,EAAE,eAAe,CAAC;IAClC,gBAAgB,EAAE,qBAAqB,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,gBAAgB,EAAE,eAAe,CAAC;CACnC;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0C;IAG/D,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,mBAAmB;IAkBjD,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAKzD,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAchE,uBAAuB,CACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,mBAAmB,GAAG,SAAS;IAQlC,IAAI,IAAI,mBAAmB,EAAE;IAK7B,IAAI,IAAI,MAAM;CAGf"}
1
+ {"version":3,"file":"endpoint-registry.d.ts","sourceRoot":"","sources":["../../src/broker/endpoint-registry.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,cAAc,CAAC;IACjC,WAAW,EAAE,IAAI,CAAC;IAElB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,gBAAgB,EAAE,eAAe,CAAC;IAClC,gBAAgB,EAAE,qBAAqB,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,gBAAgB,EAAE,eAAe,CAAC;CACnC;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0C;IAG/D,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,mBAAmB;IAkBjD,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAKzD,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAWhE,gBAAgB,CACd,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,IAAI,GACnB,mBAAmB;IAoBtB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,mBAAmB;IA8BvE,uBAAuB,CACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,mBAAmB,GAAG,SAAS;IAYlC,iBAAiB,CACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAEhB;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,mBAAmB,CAAA;KAAE,GACxC;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,kBAAkB,CAAA;KAAE,GACzC;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,uBAAuB,CAAA;KAAE,GAC9C;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,2BAA2B,CAAA;KAAE;IAWtD,IAAI,IAAI,mBAAmB,EAAE;IAK7B,IAAI,IAAI,MAAM;CAGf"}
@@ -27,14 +27,53 @@ export class EndpointRegistry {
27
27
  this.byId.delete(endpoint_id);
28
28
  return entry;
29
29
  }
30
+ markReconnecting(endpoint_id, grace_deadline) {
31
+ const entry = this.byId.get(endpoint_id);
32
+ if (!entry) {
33
+ throw new Error(`unknown endpoint_id: ${endpoint_id}`);
34
+ }
35
+ if (entry.state !== "active") {
36
+ throw new Error(`markReconnecting requires state=active, got state=${entry.state}`);
37
+ }
38
+ entry.state = "reconnecting";
39
+ entry.state_since = new Date();
40
+ entry.grace_deadline = grace_deadline;
41
+ return entry;
42
+ }
43
+ markActive(endpoint_id, new_ws) {
44
+ const entry = this.byId.get(endpoint_id);
45
+ if (!entry) {
46
+ throw new Error(`unknown endpoint_id: ${endpoint_id}`);
47
+ }
48
+ if (entry.state !== "reconnecting") {
49
+ throw new Error(`markActive requires state=reconnecting, got state=${entry.state}`);
50
+ }
51
+ entry.state = "active";
52
+ entry.state_since = new Date();
53
+ entry.grace_deadline = undefined;
54
+ entry.ipc_ws = new_ws;
55
+ return entry;
56
+ }
30
57
  preconditionForReattach(endpoint_id, plugin_pid) {
31
58
  const entry = this.byId.get(endpoint_id);
32
59
  if (!entry)
33
60
  return undefined;
34
61
  if (entry.plugin_pid !== plugin_pid)
35
62
  return undefined;
63
+ if (entry.state !== "reconnecting")
64
+ return undefined;
36
65
  return entry;
37
66
  }
67
+ getReattachStatus(endpoint_id, plugin_pid) {
68
+ const entry = this.byId.get(endpoint_id);
69
+ if (!entry)
70
+ return { ok: false, reason: "endpoint_unknown" };
71
+ if (entry.plugin_pid !== plugin_pid)
72
+ return { ok: false, reason: "reattach_pid_mismatch" };
73
+ if (entry.state !== "reconnecting")
74
+ return { ok: false, reason: "endpoint_not_reconnecting" };
75
+ return { ok: true, entry };
76
+ }
38
77
  list() {
39
78
  return Array.from(this.byId.values());
40
79
  }
@@ -0,0 +1,40 @@
1
+ export declare const DEFAULT_GRACE_MS: number;
2
+ export type EndpointState = "active" | "reconnecting" | "closed";
3
+ export type TransitionEvent = {
4
+ type: "register";
5
+ } | {
6
+ type: "ipc_close";
7
+ plugin_alive: boolean;
8
+ } | {
9
+ type: "reattach";
10
+ } | {
11
+ type: "grace_expired";
12
+ } | {
13
+ type: "explicit_unregister";
14
+ };
15
+ export type TransitionEffect = {
16
+ type: "start_grace_timer";
17
+ deadline_ms: number;
18
+ } | {
19
+ type: "cancel_grace_timer";
20
+ } | {
21
+ type: "emit_state";
22
+ state: EndpointState;
23
+ reason: string;
24
+ } | {
25
+ type: "drain_buffer";
26
+ } | {
27
+ type: "remove_from_registry";
28
+ } | {
29
+ type: "delete_buffer";
30
+ };
31
+ export interface TransitionResult {
32
+ next: EndpointState;
33
+ effects: readonly TransitionEffect[];
34
+ ignored?: boolean;
35
+ }
36
+ export interface TransitionOptions {
37
+ graceMs?: number;
38
+ }
39
+ export declare function transition(current: EndpointState, event: TransitionEvent, opts?: TransitionOptions): TransitionResult;
40
+ //# sourceMappingURL=endpoint-state-machine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-state-machine.d.ts","sourceRoot":"","sources":["../../src/broker/endpoint-state-machine.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,gBAAgB,QAAiB,CAAC;AAE/C,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,cAAc,GAAG,QAAQ,CAAC;AAEjE,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAOpB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,GAE5C;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAEpB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GAEzB;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEpC,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAMrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAEhC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,wBAAgB,UAAU,CACxB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,eAAe,EACtB,IAAI,GAAE,iBAAsB,GAC3B,gBAAgB,CAiGlB"}
@@ -0,0 +1,92 @@
1
+ export const DEFAULT_GRACE_MS = 10 * 60 * 1000;
2
+ export function transition(current, event, opts = {}) {
3
+ const graceMs = opts.graceMs ?? DEFAULT_GRACE_MS;
4
+ switch (current) {
5
+ case "active": {
6
+ switch (event.type) {
7
+ case "ipc_close":
8
+ if (event.plugin_alive) {
9
+ return {
10
+ next: "reconnecting",
11
+ effects: [
12
+ { type: "start_grace_timer", deadline_ms: graceMs },
13
+ {
14
+ type: "emit_state",
15
+ state: "reconnecting",
16
+ reason: "ipc_close",
17
+ },
18
+ ],
19
+ };
20
+ }
21
+ return {
22
+ next: "closed",
23
+ effects: [
24
+ { type: "emit_state", state: "closed", reason: "plugin_exit" },
25
+ { type: "delete_buffer" },
26
+ { type: "remove_from_registry" },
27
+ ],
28
+ };
29
+ case "explicit_unregister":
30
+ return {
31
+ next: "closed",
32
+ effects: [
33
+ {
34
+ type: "emit_state",
35
+ state: "closed",
36
+ reason: "explicit_unregister",
37
+ },
38
+ { type: "delete_buffer" },
39
+ { type: "remove_from_registry" },
40
+ ],
41
+ };
42
+ case "register":
43
+ case "reattach":
44
+ case "grace_expired":
45
+ return { next: "active", effects: [], ignored: true };
46
+ }
47
+ return { next: current, effects: [], ignored: true };
48
+ }
49
+ case "reconnecting": {
50
+ switch (event.type) {
51
+ case "reattach":
52
+ return {
53
+ next: "active",
54
+ effects: [
55
+ { type: "cancel_grace_timer" },
56
+ { type: "drain_buffer" },
57
+ { type: "emit_state", state: "active", reason: "reattach" },
58
+ ],
59
+ };
60
+ case "grace_expired":
61
+ return {
62
+ next: "closed",
63
+ effects: [
64
+ { type: "emit_state", state: "closed", reason: "grace_timeout" },
65
+ { type: "delete_buffer" },
66
+ { type: "remove_from_registry" },
67
+ ],
68
+ };
69
+ case "explicit_unregister":
70
+ return {
71
+ next: "closed",
72
+ effects: [
73
+ { type: "cancel_grace_timer" },
74
+ {
75
+ type: "emit_state",
76
+ state: "closed",
77
+ reason: "explicit_unregister",
78
+ },
79
+ { type: "delete_buffer" },
80
+ { type: "remove_from_registry" },
81
+ ],
82
+ };
83
+ case "ipc_close":
84
+ case "register":
85
+ return { next: "reconnecting", effects: [], ignored: true };
86
+ }
87
+ return { next: current, effects: [], ignored: true };
88
+ }
89
+ case "closed":
90
+ return { next: "closed", effects: [], ignored: true };
91
+ }
92
+ }
@@ -1,2 +1,13 @@
1
+ import { type BrokerLogger } from "./logger.js";
2
+ import type { RuntimeEndpointPort } from "./runtime-endpoint-port.js";
3
+ interface ResolvedCredentials {
4
+ accountId: string;
5
+ connectorUrl: string;
6
+ token: string;
7
+ apiHost: string;
8
+ }
9
+ export declare function resolveCredentialsFromFile(filePath: string, accountId: string, envApiHost: string | undefined): Promise<ResolvedCredentials>;
10
+ export declare function buildApiPort(apiHost: string, runtimeKey: string, logger: BrokerLogger): RuntimeEndpointPort;
1
11
  export declare function main(): Promise<void>;
12
+ export {};
2
13
  //# sourceMappingURL=entry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"AAmGA,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAgD1C"}
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"AA0EA,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,aAAa,CAAC;AAEpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAItE,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CA8F9B;AAyDD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,YAAY,GACnB,mBAAmB,CAkErB;AAYD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAgD1C"}
@@ -1,13 +1,70 @@
1
+ import { readFile } from "node:fs/promises";
1
2
  import { pathToFileURL } from "node:url";
2
3
  import { readConfig } from "../config-fs.js";
3
4
  import { DEFAULT_API_HOST } from "../platform-client.js";
4
- import { heartbeatRuntimeEndpoint, registerRuntimeEndpoint, unregisterRuntimeEndpoint, } from "../runtime-endpoint-client.js";
5
+ import { heartbeatRuntimeEndpoint, registerRuntimeEndpoint, transitionRuntimeEndpointState, unregisterRuntimeEndpoint, } from "../runtime-endpoint-client.js";
5
6
  import { startBrokerDaemon } from "./broker-daemon.js";
6
7
  import { ConnectorWS } from "./connector-ws.js";
7
8
  import { createBrokerLogger } from "./logger.js";
8
9
  import { resolveBrokerPaths } from "./paths.js";
9
10
  const DEFAULT_ACCOUNT_ID = "default";
10
- async function resolveCredentials(accountId, envApiHost) {
11
+ export async function resolveCredentialsFromFile(filePath, accountId, envApiHost) {
12
+ let raw;
13
+ try {
14
+ raw = await readFile(filePath, "utf8");
15
+ }
16
+ catch (err) {
17
+ const code = err.code;
18
+ if (code === "ENOENT") {
19
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE points to non-existent path: ${filePath}`);
20
+ }
21
+ throw new Error(`failed to read MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: ` +
22
+ (err instanceof Error ? err.message : String(err)));
23
+ }
24
+ let parsed;
25
+ try {
26
+ parsed = JSON.parse(raw);
27
+ }
28
+ catch (err) {
29
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath} is not valid JSON: ` +
30
+ (err instanceof Error ? err.message : String(err)));
31
+ }
32
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
33
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: top-level must be an object`);
34
+ }
35
+ const accounts = parsed.accounts;
36
+ if (typeof accounts !== "object" ||
37
+ accounts === null ||
38
+ Array.isArray(accounts)) {
39
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: missing or invalid "accounts" object`);
40
+ }
41
+ const accountRaw = accounts[accountId];
42
+ if (typeof accountRaw !== "object" ||
43
+ accountRaw === null ||
44
+ Array.isArray(accountRaw)) {
45
+ const available = Object.keys(accounts).join(", ") || "<none>";
46
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: account "${accountId}" not found (available: ${available})`);
47
+ }
48
+ const acct = accountRaw;
49
+ const connectorUrl = typeof acct.connectorUrl === "string" ? acct.connectorUrl : null;
50
+ const token = typeof acct.token === "string" ? acct.token : null;
51
+ if (!connectorUrl) {
52
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: account "${accountId}" missing required field "connectorUrl"`);
53
+ }
54
+ if (!token) {
55
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: account "${accountId}" missing required field "token"`);
56
+ }
57
+ if (acct.apiHost !== undefined && typeof acct.apiHost !== "string") {
58
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: account "${accountId}" optional field "apiHost" must be a string when present`);
59
+ }
60
+ if (acct.handle !== undefined && typeof acct.handle !== "string") {
61
+ throw new Error(`MASONS_BROKER_CREDENTIALS_FILE at ${filePath}: account "${accountId}" optional field "handle" must be a string when present`);
62
+ }
63
+ const apiHost = envApiHost ??
64
+ (typeof acct.apiHost === "string" ? acct.apiHost : DEFAULT_API_HOST);
65
+ return { accountId, connectorUrl, token, apiHost };
66
+ }
67
+ async function resolveCredentialsFromOpenClawConfig(accountId, envApiHost) {
11
68
  const config = await readConfig();
12
69
  const channels = config.channels;
13
70
  const network = channels?.["agent-network"];
@@ -19,11 +76,19 @@ async function resolveCredentials(accountId, envApiHost) {
19
76
  const token = typeof account?.token === "string" ? account.token : null;
20
77
  if (!connectorUrl || !token) {
21
78
  throw new Error(`agent-network credentials missing for account "${accountId}"; ` +
22
- "run setup before lazy-spawning the broker");
79
+ "run setup before lazy-spawning the broker " +
80
+ "(or set MASONS_BROKER_CREDENTIALS_FILE for Plugin hosts)");
23
81
  }
24
82
  return { accountId, connectorUrl, token, apiHost };
25
83
  }
26
- function buildApiPort(apiHost, runtimeKey) {
84
+ async function resolveCredentials(accountId, envApiHost) {
85
+ const credentialsFile = process.env.MASONS_BROKER_CREDENTIALS_FILE;
86
+ if (credentialsFile) {
87
+ return resolveCredentialsFromFile(credentialsFile, accountId, envApiHost);
88
+ }
89
+ return resolveCredentialsFromOpenClawConfig(accountId, envApiHost);
90
+ }
91
+ export function buildApiPort(apiHost, runtimeKey, logger) {
27
92
  return {
28
93
  async register(params) {
29
94
  return registerRuntimeEndpoint({ apiHost }, runtimeKey, params);
@@ -34,8 +99,46 @@ function buildApiPort(apiHost, runtimeKey) {
34
99
  async unregister(endpointId, asNodeId) {
35
100
  await unregisterRuntimeEndpoint({ apiHost }, runtimeKey, endpointId, asNodeId);
36
101
  },
102
+ async transitionState(endpointId, params) {
103
+ try {
104
+ await transitionRuntimeEndpointState({ apiHost }, runtimeKey, endpointId, params);
105
+ }
106
+ catch (err) {
107
+ const status = errorStatus(err);
108
+ if (status === 404) {
109
+ logger.info("transitionState_404_degraded", {
110
+ endpoint_id: endpointId,
111
+ state: params.state,
112
+ reason: params.reason,
113
+ note: "apps/api state endpoint not yet shipped (PR-B1 in flight); state propagation skipped",
114
+ });
115
+ return;
116
+ }
117
+ await sleep(500);
118
+ try {
119
+ await transitionRuntimeEndpointState({ apiHost }, runtimeKey, endpointId, params);
120
+ }
121
+ catch (err2) {
122
+ logger.warn("transitionState_failed", {
123
+ endpoint_id: endpointId,
124
+ state: params.state,
125
+ reason: params.reason,
126
+ err: err2 instanceof Error ? err2.message : String(err2),
127
+ });
128
+ }
129
+ }
130
+ },
37
131
  };
38
132
  }
133
+ function errorStatus(err) {
134
+ if (typeof err !== "object" || err === null)
135
+ return null;
136
+ const status = err.status;
137
+ return typeof status === "number" ? status : null;
138
+ }
139
+ function sleep(ms) {
140
+ return new Promise((resolve) => setTimeout(resolve, ms));
141
+ }
39
142
  export async function main() {
40
143
  const accountId = process.env.MASONS_BROKER_ACCOUNT_ID ?? DEFAULT_ACCOUNT_ID;
41
144
  const envApiHost = process.env.MASONS_BROKER_API_HOST;
@@ -55,7 +158,7 @@ export async function main() {
55
158
  url: creds.connectorUrl,
56
159
  token: creds.token,
57
160
  });
58
- const apiPort = buildApiPort(creds.apiHost, creds.token);
161
+ const apiPort = buildApiPort(creds.apiHost, creds.token, logger);
59
162
  const broker = await startBrokerDaemon({
60
163
  paths,
61
164
  asNodeId,
@@ -0,0 +1,9 @@
1
+ export interface GraceTimerManager {
2
+ start(endpoint_id: string, ms: number, onExpire: () => void): void;
3
+ cancel(endpoint_id: string): void;
4
+ has(endpoint_id: string): boolean;
5
+ cancelAll(): void;
6
+ active(): readonly string[];
7
+ }
8
+ export declare function createGraceTimerManager(): GraceTimerManager;
9
+ //# sourceMappingURL=grace-timer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grace-timer.d.ts","sourceRoot":"","sources":["../../src/broker/grace-timer.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,iBAAiB;IAGhC,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAEnE,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAElC,SAAS,IAAI,IAAI,CAAC;IAElB,MAAM,IAAI,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAmC3D"}
@@ -0,0 +1,34 @@
1
+ export function createGraceTimerManager() {
2
+ const timers = new Map();
3
+ return {
4
+ start(endpoint_id, ms, onExpire) {
5
+ const existing = timers.get(endpoint_id);
6
+ if (existing)
7
+ clearTimeout(existing);
8
+ const handle = setTimeout(() => {
9
+ timers.delete(endpoint_id);
10
+ onExpire();
11
+ }, ms);
12
+ handle.unref?.();
13
+ timers.set(endpoint_id, handle);
14
+ },
15
+ cancel(endpoint_id) {
16
+ const handle = timers.get(endpoint_id);
17
+ if (handle) {
18
+ clearTimeout(handle);
19
+ timers.delete(endpoint_id);
20
+ }
21
+ },
22
+ has(endpoint_id) {
23
+ return timers.has(endpoint_id);
24
+ },
25
+ cancelAll() {
26
+ for (const [, handle] of timers)
27
+ clearTimeout(handle);
28
+ timers.clear();
29
+ },
30
+ active() {
31
+ return Array.from(timers.keys());
32
+ },
33
+ };
34
+ }
@@ -5,8 +5,15 @@ export interface IPCServerHandlers {
5
5
  heartbeatEndpoint(endpoint_id: string): Promise<void>;
6
6
  unregisterEndpoint(endpoint_id: string): Promise<void>;
7
7
  send(body: SendBody): Promise<SendResponse>;
8
- reattachEndpoint(endpoint_id: string, plugin_pid: number, ipcWs: WebSocket): Promise<boolean>;
8
+ reattachEndpoint(endpoint_id: string, plugin_pid: number, ipcWs: WebSocket): Promise<ReattachResponse>;
9
+ listUndispatched(): Promise<UndispatchedListResponse>;
10
+ dispatch(undispatched_id: string, target_endpoint_id: string): Promise<void>;
9
11
  }
12
+ export interface ReattachResponse {
13
+ restored: true;
14
+ reconnecting_buffer_count: number;
15
+ }
16
+ export type UndispatchedListResponse = import("./undispatched-inbox.js").UndispatchedMessage[];
10
17
  export interface RegisterEndpointBody {
11
18
  agent_id: string;
12
19
  plugin_pid: number;
@@ -1 +1 @@
1
- {"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../../src/broker/ipc-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../../src/broker/ipc-server.ts"],"names":[],"mappings":"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"}
@@ -94,6 +94,17 @@ async function routeHttp(req, res, bearerToken, handlers, logger) {
94
94
  sendJson(res, 200, { ok: true });
95
95
  return;
96
96
  }
97
+ const reattachMatch = /^\/v1\/endpoint\/([^/]+)\/reattach$/.exec(url);
98
+ if (method === "POST" && reattachMatch && reattachMatch[1]) {
99
+ const body = await readJson(req);
100
+ const pid = typeof body.plugin_pid === "number" ? body.plugin_pid : Number.NaN;
101
+ if (!Number.isFinite(pid) || pid <= 0) {
102
+ throw new BrokerHttpError(400, "plugin_pid_invalid", "plugin_pid is required and must be a positive number");
103
+ }
104
+ const out = await handlers.reattachEndpoint(decodeURIComponent(reattachMatch[1]), pid, null);
105
+ sendJson(res, 200, out);
106
+ return;
107
+ }
97
108
  const unregisterMatch = /^\/v1\/endpoint\/([^/]+)$/.exec(url);
98
109
  if (method === "DELETE" && unregisterMatch && unregisterMatch[1]) {
99
110
  await handlers.unregisterEndpoint(decodeURIComponent(unregisterMatch[1]));
@@ -106,6 +117,26 @@ async function routeHttp(req, res, bearerToken, handlers, logger) {
106
117
  sendJson(res, 200, out);
107
118
  return;
108
119
  }
120
+ if (method === "GET" && url === "/v1/undispatched") {
121
+ const items = await handlers.listUndispatched();
122
+ sendJson(res, 200, { items });
123
+ return;
124
+ }
125
+ if (method === "POST" && url === "/v1/dispatch") {
126
+ const body = await readJson(req);
127
+ const uid = typeof body.undispatched_id === "string"
128
+ ? body.undispatched_id
129
+ : undefined;
130
+ const tid = typeof body.target_endpoint_id === "string"
131
+ ? body.target_endpoint_id
132
+ : undefined;
133
+ if (!uid || !tid) {
134
+ throw new BrokerHttpError(400, "dispatch_body_invalid", "POST /v1/dispatch requires { undispatched_id, target_endpoint_id }");
135
+ }
136
+ await handlers.dispatch(uid, tid);
137
+ sendJson(res, 200, { ok: true });
138
+ return;
139
+ }
109
140
  sendJson(res, 404, { error: "not_found", path: url });
110
141
  }
111
142
  catch (err) {
@@ -5,6 +5,7 @@ export interface BrokerPaths {
5
5
  discoveryFile: string;
6
6
  discoveryDir: string;
7
7
  logDir: string;
8
+ buffersDir: string;
8
9
  }
9
10
  export declare function resolveBrokerPaths(principal: string, runtimeToken: string, opts?: BrokerPathOptions): BrokerPaths;
10
11
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/broker/paths.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,iBAAiB;IAEhC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAE1B,aAAa,EAAE,MAAM,CAAC;IAEtB,YAAY,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;CAChB;AASD,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE,iBAAsB,GAC3B,WAAW,CA8Bb"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/broker/paths.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,iBAAiB;IAEhC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAE1B,aAAa,EAAE,MAAM,CAAC;IAEtB,YAAY,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;IAQf,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE,iBAAsB,GAC3B,WAAW,CAgCb"}
@@ -17,10 +17,12 @@ export function resolveBrokerPaths(principal, runtimeToken, opts = {}) {
17
17
  .slice(0, AGENT_IDENTITY_HEX_LEN);
18
18
  const discoveryDir = join(userData, "runtime-broker", sanitizeSegment(principal), agentIdentity);
19
19
  const logDir = join(userData, "runtime-broker", "log");
20
+ const buffersDir = join(discoveryDir, "buffers");
20
21
  return {
21
22
  discoveryFile: join(discoveryDir, "discovery.json"),
22
23
  discoveryDir,
23
24
  logDir,
25
+ buffersDir,
24
26
  };
25
27
  }
26
28
  function sanitizeSegment(segment) {
@@ -0,0 +1,2 @@
1
+ export declare function isPluginAlive(plugin_pid: number): boolean;
2
+ //# sourceMappingURL=plugin-liveness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-liveness.d.ts","sourceRoot":"","sources":["../../src/broker/plugin-liveness.ts"],"names":[],"mappings":"AAyBA,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAiBzD"}
@@ -0,0 +1,15 @@
1
+ export function isPluginAlive(plugin_pid) {
2
+ if (!Number.isFinite(plugin_pid) || plugin_pid <= 0) {
3
+ return false;
4
+ }
5
+ try {
6
+ process.kill(plugin_pid, 0);
7
+ return true;
8
+ }
9
+ catch (err) {
10
+ const code = err.code;
11
+ if (code === "ESRCH")
12
+ return false;
13
+ return true;
14
+ }
15
+ }
@@ -0,0 +1,23 @@
1
+ export interface BufferedMessage {
2
+ id: string;
3
+ arrived_at: string;
4
+ envelope: {
5
+ from: string;
6
+ content: string;
7
+ contentType: string;
8
+ metadata?: Record<string, unknown>;
9
+ };
10
+ }
11
+ export interface ReconnectingBuffer {
12
+ append(msg: BufferedMessage): void;
13
+ read(): BufferedMessage[];
14
+ drain(): BufferedMessage[];
15
+ delete(): void;
16
+ size(): number;
17
+ }
18
+ export interface ReconnectingBufferManager {
19
+ forEndpoint(endpoint_id: string): ReconnectingBuffer;
20
+ cleanup(endpoint_id: string): void;
21
+ }
22
+ export declare function createReconnectingBufferManager(buffersDir: string): ReconnectingBufferManager;
23
+ //# sourceMappingURL=reconnecting-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconnecting-buffer.d.ts","sourceRoot":"","sources":["../../src/broker/reconnecting-buffer.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,eAAe;IAE9B,EAAE,EAAE,MAAM,CAAC;IAEX,UAAU,EAAE,MAAM,CAAC;IAEnB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IAEjC,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAAC;IAEnC,IAAI,IAAI,eAAe,EAAE,CAAC;IAE1B,KAAK,IAAI,eAAe,EAAE,CAAC;IAE3B,MAAM,IAAI,IAAI,CAAC;IAEf,IAAI,IAAI,MAAM,CAAC;CAChB;AA8ED,MAAM,WAAW,yBAAyB;IAExC,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAErD,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,MAAM,GACjB,yBAAyB,CAmB3B"}