super-dsh 0.1.6 → 0.1.10-e

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 (260) hide show
  1. package/README.md +25 -3
  2. package/agent-agy/cordis.patch.yml +7 -4
  3. package/agent-agy/dist/agent.d.ts +12 -11
  4. package/agent-agy/dist/agy-auth-gateway.d.ts +124 -0
  5. package/agent-agy/dist/agy-auth-gateway.js +233 -0
  6. package/agent-agy/dist/agy-auth.d.ts +153 -0
  7. package/agent-agy/dist/agy-auth.js +179 -0
  8. package/agent-agy/dist/agy-cli-client.d.ts +39 -9
  9. package/agent-agy/dist/agy-cli-client.js +82 -18
  10. package/agent-agy/dist/agy-store.d.ts +8 -0
  11. package/agent-agy/dist/index.d.ts +46 -16
  12. package/agent-agy/dist/index.js +82 -56
  13. package/agent-agy/dist/models.d.ts +70 -0
  14. package/agent-agy/dist/models.js +102 -3
  15. package/agent-agy/package.json +7 -5
  16. package/agent-agy-sdk/cordis.patch.yml +58 -0
  17. package/agent-agy-sdk/dist/adapter.d.ts +15 -0
  18. package/agent-agy-sdk/dist/adapter.js +42 -0
  19. package/agent-agy-sdk/dist/agent-preset-agy.d.ts +27 -0
  20. package/agent-agy-sdk/dist/agent-preset-agy.js +32 -0
  21. package/agent-agy-sdk/dist/agent.d.ts +138 -0
  22. package/agent-agy-sdk/dist/agent.js +494 -0
  23. package/{agent-agy → agent-agy-sdk}/dist/agy-client.d.ts +26 -6
  24. package/{agent-agy → agent-agy-sdk}/dist/agy-client.js +43 -25
  25. package/agent-agy-sdk/dist/agy-sessions.d.ts +25 -0
  26. package/agent-agy-sdk/dist/agy-sessions.js +107 -0
  27. package/agent-agy-sdk/dist/agy-store.d.ts +39 -0
  28. package/agent-agy-sdk/dist/agy-store.js +83 -0
  29. package/agent-agy-sdk/dist/inbox.d.ts +26 -0
  30. package/agent-agy-sdk/dist/inbox.js +53 -0
  31. package/agent-agy-sdk/dist/index.d.ts +93 -0
  32. package/agent-agy-sdk/dist/index.js +476 -0
  33. package/agent-agy-sdk/dist/models.d.ts +41 -0
  34. package/agent-agy-sdk/dist/models.js +74 -0
  35. package/agent-agy-sdk/dist/sdk-venv.d.ts +76 -0
  36. package/agent-agy-sdk/dist/sdk-venv.js +173 -0
  37. package/agent-agy-sdk/dist/world-plugin.d.ts +10 -0
  38. package/agent-agy-sdk/dist/world-plugin.js +82 -0
  39. package/agent-agy-sdk/package.json +64 -0
  40. package/agent-claude/dist/adapter.js +106 -31
  41. package/agent-claude/dist/agent.js +154 -17
  42. package/agent-claude/dist/claude-client.js +84 -43
  43. package/agent-claude/dist/claude-launch.js +101 -0
  44. package/agent-claude/dist/claude-native-config.js +169 -0
  45. package/agent-claude/dist/claude-provider-gateway.js +340 -0
  46. package/agent-claude/dist/claude-providers.js +391 -0
  47. package/agent-claude/dist/claude-route.js +152 -0
  48. package/agent-claude/dist/index.js +214 -37
  49. package/agent-claude/dist/models.js +14 -0
  50. package/agent-claude/dist/sdk-runtime.js +320 -0
  51. package/agent-claude/package.json +6 -4
  52. package/agent-codex/README.md +141 -36
  53. package/agent-codex/cordis.patch.yml +14 -10
  54. package/agent-codex/dist/adapter.js +64 -28
  55. package/agent-codex/dist/agent.js +255 -81
  56. package/agent-codex/dist/app-server-approvals.js +165 -0
  57. package/agent-codex/dist/app-server-client.js +723 -0
  58. package/agent-codex/dist/app-server-events.js +432 -0
  59. package/agent-codex/dist/app-server-protocol.js +95 -0
  60. package/agent-codex/dist/app-server-wire.js +299 -0
  61. package/agent-codex/dist/codex-launch.js +78 -0
  62. package/agent-codex/dist/codex-native-config.js +392 -0
  63. package/agent-codex/dist/codex-provider-gateway.js +402 -0
  64. package/agent-codex/dist/codex-providers.js +376 -0
  65. package/agent-codex/dist/codex-route.js +86 -0
  66. package/agent-codex/dist/index.js +256 -115
  67. package/agent-codex/dist/permission.js +75 -1
  68. package/agent-codex/package.json +1 -2
  69. package/agent-codex-sdk/README.md +79 -0
  70. package/agent-codex-sdk/cordis.patch.yml +81 -0
  71. package/agent-codex-sdk/dist/adapter.js +91 -0
  72. package/agent-codex-sdk/dist/agent-preset-codex.js +32 -0
  73. package/agent-codex-sdk/dist/agent.js +1085 -0
  74. package/agent-codex-sdk/dist/codex-native-config.js +392 -0
  75. package/agent-codex-sdk/dist/codex-provider-gateway.js +402 -0
  76. package/agent-codex-sdk/dist/codex-providers.js +376 -0
  77. package/agent-codex-sdk/dist/codex-route.js +86 -0
  78. package/{agent-codex/dist/codex-client.js → agent-codex-sdk/dist/codex-sdk-client.js} +253 -32
  79. package/agent-codex-sdk/dist/codex-sdk-launch.js +92 -0
  80. package/agent-codex-sdk/dist/codex-store.js +180 -0
  81. package/agent-codex-sdk/dist/inbox.js +53 -0
  82. package/agent-codex-sdk/dist/index.js +739 -0
  83. package/agent-codex-sdk/dist/permission.js +71 -0
  84. package/agent-codex-sdk/dist/sdk-runtime.js +307 -0
  85. package/agent-codex-sdk/dist/session-map.js +167 -0
  86. package/agent-codex-sdk/dist/world-plugin.js +93 -0
  87. package/agent-codex-sdk/package.json +79 -0
  88. package/agent-codex-sdk/scripts/fetch-sdk-runtime.mjs +57 -0
  89. package/agent-omp/README.md +72 -55
  90. package/agent-omp/dist/agent.js +36 -11
  91. package/agent-omp/dist/index.js +92 -52
  92. package/agent-omp/dist/lazy-rpc.js +11 -4
  93. package/agent-omp/dist/omp-cli.js +114 -97
  94. package/agent-omp/dist/omp-store.js +12 -4
  95. package/agent-omp/dist/permission.js +70 -5
  96. package/agent-omp/dist/rpc-client.js +409 -0
  97. package/agent-omp/dist/world-plugin.js +36 -3
  98. package/agent-omp/package.json +2 -6
  99. package/agent-omp-sdk/README.md +103 -0
  100. package/agent-omp-sdk/cordis.patch.yml +108 -0
  101. package/agent-omp-sdk/dist/adapter.d.ts +21 -0
  102. package/agent-omp-sdk/dist/adapter.js +36 -0
  103. package/agent-omp-sdk/dist/agent-preset-omp.d.ts +31 -0
  104. package/agent-omp-sdk/dist/agent-preset-omp.js +32 -0
  105. package/agent-omp-sdk/dist/agent.d.ts +64 -0
  106. package/agent-omp-sdk/dist/agent.js +1178 -0
  107. package/agent-omp-sdk/dist/discovery.d.ts +57 -0
  108. package/agent-omp-sdk/dist/discovery.js +116 -0
  109. package/agent-omp-sdk/dist/inbox.d.ts +28 -0
  110. package/agent-omp-sdk/dist/inbox.js +53 -0
  111. package/agent-omp-sdk/dist/index.d.ts +60 -0
  112. package/agent-omp-sdk/dist/index.js +632 -0
  113. package/agent-omp-sdk/dist/knobs.d.ts +34 -0
  114. package/agent-omp-sdk/dist/knobs.js +50 -0
  115. package/agent-omp-sdk/dist/lazy-rpc.d.ts +98 -0
  116. package/agent-omp-sdk/dist/lazy-rpc.js +178 -0
  117. package/agent-omp-sdk/dist/mobile/zoom-guard.d.ts +187 -0
  118. package/agent-omp-sdk/dist/mobile/zoom-guard.js +294 -0
  119. package/agent-omp-sdk/dist/mobile-boot.d.ts +49 -0
  120. package/agent-omp-sdk/dist/mobile-boot.js +38 -0
  121. package/agent-omp-sdk/dist/models.d.ts +39 -0
  122. package/agent-omp-sdk/dist/models.js +299 -0
  123. package/agent-omp-sdk/dist/omp-cli.d.ts +67 -0
  124. package/agent-omp-sdk/dist/omp-cli.js +164 -0
  125. package/agent-omp-sdk/dist/omp-disk-discovery.d.ts +27 -0
  126. package/agent-omp-sdk/dist/omp-disk-discovery.js +178 -0
  127. package/agent-omp-sdk/dist/omp-executable.d.ts +2 -0
  128. package/agent-omp-sdk/dist/omp-executable.js +30 -0
  129. package/agent-omp-sdk/dist/omp-store.d.ts +134 -0
  130. package/agent-omp-sdk/dist/omp-store.js +526 -0
  131. package/agent-omp-sdk/dist/pairing.d.ts +7 -0
  132. package/agent-omp-sdk/dist/pairing.js +45 -0
  133. package/agent-omp-sdk/dist/permission.d.ts +138 -0
  134. package/agent-omp-sdk/dist/permission.js +161 -0
  135. package/agent-omp-sdk/dist/protocol.d.ts +189 -0
  136. package/agent-omp-sdk/dist/rpc-types.d.ts +77 -0
  137. package/agent-omp-sdk/dist/rpc-types.js +1 -0
  138. package/agent-omp-sdk/dist/sdk-client.d.ts +160 -0
  139. package/{agent-omp → agent-omp-sdk}/dist/sdk-client.js +108 -56
  140. package/agent-omp-sdk/dist/sdk-runtime.d.ts +211 -0
  141. package/agent-omp-sdk/dist/sdk-runtime.js +418 -0
  142. package/agent-omp-sdk/dist/sidecar-client.d.ts +87 -0
  143. package/agent-omp-sdk/dist/sidecar-client.js +197 -0
  144. package/agent-omp-sdk/dist/store/adapter.d.ts +17 -0
  145. package/agent-omp-sdk/dist/store/adapter.js +47 -0
  146. package/agent-omp-sdk/dist/store/db.d.ts +70 -0
  147. package/agent-omp-sdk/dist/store/db.js +210 -0
  148. package/agent-omp-sdk/dist/store/index.d.ts +23 -0
  149. package/agent-omp-sdk/dist/store/index.js +59 -0
  150. package/agent-omp-sdk/dist/store/reconcile.d.ts +15 -0
  151. package/agent-omp-sdk/dist/store/reconcile.js +51 -0
  152. package/agent-omp-sdk/dist/store/schema.d.ts +8 -0
  153. package/agent-omp-sdk/dist/store/schema.js +40 -0
  154. package/agent-omp-sdk/dist/transport.d.ts +49 -0
  155. package/agent-omp-sdk/dist/transport.js +35 -0
  156. package/agent-omp-sdk/dist/world-home.d.ts +4 -0
  157. package/agent-omp-sdk/dist/world-home.js +23 -0
  158. package/agent-omp-sdk/dist/world-plugin.d.ts +10 -0
  159. package/agent-omp-sdk/dist/world-plugin.js +137 -0
  160. package/agent-omp-sdk/package.json +87 -0
  161. package/client/index.js +1883 -287
  162. package/cordis.patch.yml +80 -0
  163. package/package.json +23 -9
  164. package/superd-hub/dist/a2a-delivery.d.ts +189 -0
  165. package/superd-hub/dist/a2a-delivery.js +240 -0
  166. package/superd-hub/dist/a2a-host.d.ts +76 -0
  167. package/superd-hub/dist/a2a-host.js +145 -0
  168. package/superd-hub/dist/a2a-ingest.d.ts +31 -0
  169. package/superd-hub/dist/a2a-ingest.js +636 -0
  170. package/superd-hub/dist/a2a-log.d.ts +17 -0
  171. package/superd-hub/dist/a2a-log.js +42 -0
  172. package/superd-hub/dist/a2a-row.d.ts +65 -0
  173. package/superd-hub/dist/a2a-row.js +162 -0
  174. package/superd-hub/dist/a2a-service.d.ts +357 -0
  175. package/superd-hub/dist/a2a-service.js +980 -0
  176. package/superd-hub/dist/a2a-wire.d.ts +220 -0
  177. package/superd-hub/dist/a2a-wire.js +305 -0
  178. package/superd-hub/dist/agent-ids.d.ts +10 -0
  179. package/superd-hub/dist/agent-ids.js +68 -0
  180. package/superd-hub/dist/agent-roster.d.ts +29 -18
  181. package/superd-hub/dist/agent-roster.js +54 -15
  182. package/superd-hub/dist/agent-status.d.ts +119 -0
  183. package/superd-hub/dist/agent-status.js +386 -0
  184. package/superd-hub/dist/client/agent-settings.d.ts +210 -0
  185. package/superd-hub/dist/client/agent-settings.js +300 -0
  186. package/superd-hub/dist/client/mesh-api.d.ts +134 -0
  187. package/superd-hub/dist/client/mesh-api.js +219 -0
  188. package/superd-hub/dist/client/mesh-groups.d.ts +63 -0
  189. package/superd-hub/dist/client/mesh-groups.js +66 -0
  190. package/superd-hub/dist/client/roster.d.ts +48 -0
  191. package/superd-hub/dist/client/roster.js +102 -0
  192. package/superd-hub/dist/client/runtime-settings-api.d.ts +76 -0
  193. package/superd-hub/dist/client/runtime-settings-api.js +137 -0
  194. package/superd-hub/dist/client/switch.d.ts +165 -0
  195. package/superd-hub/dist/client/switch.js +295 -0
  196. package/superd-hub/dist/exec-pty-channel.d.ts +58 -0
  197. package/superd-hub/dist/exec-pty-channel.js +162 -0
  198. package/superd-hub/dist/exec-pty-framing.d.ts +32 -0
  199. package/superd-hub/dist/exec-pty-framing.js +81 -0
  200. package/superd-hub/dist/exec-pty-rpc.d.ts +21 -0
  201. package/superd-hub/dist/exec-pty-rpc.js +128 -0
  202. package/superd-hub/dist/exec-pty-session.d.ts +76 -0
  203. package/superd-hub/dist/exec-pty-session.js +234 -0
  204. package/superd-hub/dist/exec.d.ts +56 -0
  205. package/superd-hub/dist/exec.js +225 -0
  206. package/superd-hub/dist/gateway.d.ts +39 -2
  207. package/superd-hub/dist/gateway.js +62 -3
  208. package/superd-hub/dist/hub-tool.d.ts +174 -0
  209. package/superd-hub/dist/hub-tool.js +464 -0
  210. package/superd-hub/dist/index.d.ts +15 -1
  211. package/superd-hub/dist/index.js +16 -0
  212. package/superd-hub/dist/machines.d.ts +45 -0
  213. package/superd-hub/dist/machines.js +125 -0
  214. package/superd-hub/dist/mesh-federate.d.ts +138 -0
  215. package/superd-hub/dist/mesh-federate.js +223 -0
  216. package/superd-hub/dist/mesh-gateway.d.ts +67 -0
  217. package/superd-hub/dist/mesh-gateway.js +408 -0
  218. package/superd-hub/dist/mesh-link.d.ts +274 -0
  219. package/superd-hub/dist/mesh-link.js +441 -0
  220. package/superd-hub/dist/mesh-rpc.d.ts +123 -0
  221. package/superd-hub/dist/mesh-rpc.js +250 -0
  222. package/superd-hub/dist/mux-client.d.ts +71 -0
  223. package/superd-hub/dist/mux-client.js +281 -0
  224. package/superd-hub/dist/pack-version.d.ts +2 -0
  225. package/superd-hub/dist/pack-version.js +30 -0
  226. package/superd-hub/dist/roster.d.ts +6 -0
  227. package/superd-hub/dist/rpc.d.ts +18 -2
  228. package/superd-hub/dist/rpc.js +34 -4
  229. package/superd-hub/dist/spawn-world.js +3 -1
  230. package/superd-hub/dist/switch-core.d.ts +62 -25
  231. package/superd-hub/dist/switch-core.js +53 -30
  232. package/superd-hub/dist/system-head.d.ts +22 -12
  233. package/superd-hub/dist/system-head.js +100 -84
  234. package/superd-hub/dist/wire-endpoints.d.ts +264 -0
  235. package/superd-hub/dist/wire-endpoints.js +180 -0
  236. package/superd-hub/lib/client/index.js +1883 -287
  237. package/superd-hub/package.json +11 -2
  238. package/agent-agy/dist/agent-preset-projection.d.ts +0 -31
  239. package/agent-agy/dist/agent-preset-projection.js +0 -33
  240. package/agent-claude/dist/agent-preset-projection.js +0 -30
  241. package/agent-codex/dist/agent-preset-projection.js +0 -37
  242. package/agent-codex/dist/app-home.js +0 -65
  243. package/agent-codex/dist/models.js +0 -152
  244. package/agent-codex/dist/spike.js +0 -46
  245. package/agent-hermes/dist/agent-preset-projection.js +0 -34
  246. package/agent-omp/dist/agent-preset-projection.js +0 -36
  247. package/agent-omp/dist/app-home.js +0 -86
  248. package/agent-omp/dist/sidecar-client.js +0 -195
  249. package/agent-pi/dist/agent-preset-projection.js +0 -29
  250. package/superd-hub/dist/client-shim.d.ts +0 -28
  251. package/superd-hub/dist/client-shim.js +0 -251
  252. package/superd-hub/dist/index-pass.d.ts +0 -22
  253. package/superd-hub/dist/index-pass.js +0 -47
  254. package/superd-hub/dist/labels.d.ts +0 -45
  255. package/superd-hub/dist/labels.js +0 -83
  256. /package/{agent-agy → agent-agy-sdk}/bridge/agy_bridge.py +0 -0
  257. /package/{agent-agy → agent-agy-sdk}/bridge/gemini_openai_server.mjs +0 -0
  258. /package/{agent-codex/dist/codex-events.js → agent-codex-sdk/dist/codex-sdk-events.js} +0 -0
  259. /package/{agent-omp → agent-omp-sdk}/dist/protocol.js +0 -0
  260. /package/{agent-omp → agent-omp-sdk}/sidecar/main.ts +0 -0
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Machine-mesh data access for the Hub machines panel (mesh P1, Task 5):
3
+ * the client half of `/api/superd/machines` (host side: mesh-rpc.ts) —
4
+ * same-origin fetch behind the standard browser-trust + cookie fence, the
5
+ * roster face's house style (`credentials: 'same-origin'`). The localStorage
6
+ * ledger era (machines-store.ts, retired with this module) ended: the hub's
7
+ * registry is the single source of truth, this file only fetches it and
8
+ * coerces the wire answer into row views.
9
+ *
10
+ * Node-safe by construction — no DOM, no react, no @deepseek-ai imports —
11
+ * so the host tsc emits it to `dist/client/mesh-api.js` and
12
+ * test/client-mesh-view.test.mjs runs the pure halves (coercion, token-URL
13
+ * pre-check) under `node --test` without jsdom: the switch-core/toast-core
14
+ * precedent in reverse (pure logic kept beside the fetch wrappers, all under
15
+ * src/client). No fetch happens at import time.
16
+ *
17
+ * @module superd-hub/client/mesh-api
18
+ */
19
+ /**
20
+ * Base path of the mesh machines API — the client-side spelling of the
21
+ * host's `MESH_API_BASE` (mesh-rpc.ts). Duplicated deliberately: importing
22
+ * the host module would drag its node:fs-backed dependencies into the
23
+ * browser bundle; a path literal cannot drift silently because the mesh-rpc
24
+ * route registration and this file are reviewed together.
25
+ */
26
+ const MESH_API_BASE = '/api/superd/machines';
27
+ /** The statuses the wire may carry; anything else coerces to `'pending'`. */
28
+ const STATUSES = ['pending', 'reachable', 'unreachable', 'auth-expired'];
29
+ /** Coerce the self block; a shape without a non-empty string id + string label is simply absent. */
30
+ function coerceSelf(raw) {
31
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
32
+ return undefined;
33
+ const { id, label } = raw;
34
+ if (typeof id !== 'string' || id === '' || typeof label !== 'string')
35
+ return undefined;
36
+ return { id, label };
37
+ }
38
+ /**
39
+ * Coerce a raw GET body into the panel's view list. Any bad shape degrades
40
+ * to the empty list (rows dropped individually, self dropped as a block) —
41
+ * the UI never crashes on a malformed answer.
42
+ *
43
+ * @param raw - the parsed JSON body (or anything else the wire produced).
44
+ * @returns self (when usable) + the coerced remote rows.
45
+ */
46
+ export function coerceMachineList(raw) {
47
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
48
+ return { machines: [] };
49
+ const record = raw;
50
+ const self = coerceSelf(record.self);
51
+ const machines = [];
52
+ if (Array.isArray(record.machines)) {
53
+ for (const entry of record.machines) {
54
+ if (typeof entry !== 'object' || entry === null || Array.isArray(entry))
55
+ continue;
56
+ const row = entry;
57
+ if (typeof row.id !== 'string' || row.id === '')
58
+ continue;
59
+ if (typeof row.name !== 'string' || row.name === '')
60
+ continue;
61
+ if (typeof row.origin !== 'string' || row.origin === '')
62
+ continue;
63
+ const status = typeof row.status === 'string' && STATUSES.includes(row.status)
64
+ ? row.status
65
+ : 'pending';
66
+ const base = {
67
+ id: row.id,
68
+ name: row.name,
69
+ label: typeof row.label === 'string' && row.label !== '' ? row.label : row.name,
70
+ origin: row.origin,
71
+ status,
72
+ self: self !== undefined && row.id === self.id,
73
+ };
74
+ const withProbe = typeof row.lastProbeAt === 'number' ? { ...base, lastProbeAt: row.lastProbeAt } : base;
75
+ machines.push(typeof row.versionWarning === 'string' && row.versionWarning !== ''
76
+ ? { ...withProbe, versionWarning: row.versionWarning }
77
+ : withProbe);
78
+ }
79
+ }
80
+ return self === undefined ? { machines } : { self, machines };
81
+ }
82
+ /**
83
+ * The version-warning chip for one machine row (I2): present EXACTLY when the
84
+ * coerced row carries a `versionWarning` — the Hub machines panel renders
85
+ * the chip iff this returns a value. Kept here beside the coercion so the
86
+ * presence contract stays unit-testable without jsdom (the HubPage seat is
87
+ * a one-line consumer following the existing chip patterns).
88
+ */
89
+ export function machineVersionChip(machine) {
90
+ return machine.versionWarning === undefined ? undefined : { text: machine.versionWarning };
91
+ }
92
+ /** Read a non-2xx body's `{error}` message; degrade to the bare status line. */
93
+ async function errorText(response) {
94
+ try {
95
+ const body = await response.json();
96
+ if (typeof body?.error === 'string' && body.error !== '')
97
+ return body.error;
98
+ }
99
+ catch {
100
+ /* not JSON — the status line below is the message */
101
+ }
102
+ return `HTTP ${response.status}`;
103
+ }
104
+ /**
105
+ * GET the machine list (self + remotes).
106
+ *
107
+ * @returns the coerced list — a malformed body degrades to the empty list, never a throw.
108
+ * @throws when the request fails or the face answers non-2xx.
109
+ */
110
+ export async function fetchMachines() {
111
+ const response = await fetch(MESH_API_BASE, { credentials: 'same-origin' });
112
+ if (!response.ok)
113
+ throw new Error(await errorText(response));
114
+ return coerceMachineList(await response.json().catch(() => undefined));
115
+ }
116
+ /**
117
+ * POST a pairing `{name, label?, tokenUrl}` (label omitted → the server
118
+ * collapses it to the name).
119
+ *
120
+ * @throws Error(body.error) when the face answers non-2xx — the message is
121
+ * mesh-link's own, already token-redacted.
122
+ */
123
+ export async function addMachine(input) {
124
+ const body = { name: input.name, tokenUrl: input.tokenUrl };
125
+ if (typeof input.label === 'string' && input.label !== '')
126
+ body.label = input.label;
127
+ const response = await fetch(MESH_API_BASE, {
128
+ credentials: 'same-origin',
129
+ method: 'POST',
130
+ headers: { 'content-type': 'application/json' },
131
+ body: JSON.stringify(body),
132
+ });
133
+ if (!response.ok)
134
+ throw new Error(await errorText(response));
135
+ }
136
+ /**
137
+ * DELETE one remote row by id (`{removed: boolean}` answers even for
138
+ * unknown ids — a false removal is a reload, not an error).
139
+ *
140
+ * @throws Error(body.error) on a non-2xx answer.
141
+ */
142
+ export async function removeMachine(id) {
143
+ const response = await fetch(`${MESH_API_BASE}?id=${encodeURIComponent(id)}`, {
144
+ credentials: 'same-origin',
145
+ method: 'DELETE',
146
+ });
147
+ if (!response.ok)
148
+ throw new Error(await errorText(response));
149
+ }
150
+ /**
151
+ * POST `{op: 'reprobe', id}` — a fresh probe of one remote; the outcome
152
+ * (even unreachable/auth-expired) lands in the status table server-side, so
153
+ * the caller reloads rather than interpreting the probe body.
154
+ *
155
+ * @throws Error(body.error) on a non-2xx answer (the op itself failed).
156
+ */
157
+ export async function reprobeMachine(id) {
158
+ const response = await fetch(MESH_API_BASE, {
159
+ credentials: 'same-origin',
160
+ method: 'POST',
161
+ headers: { 'content-type': 'application/json' },
162
+ body: JSON.stringify({ op: 'reprobe', id }),
163
+ });
164
+ if (!response.ok)
165
+ throw new Error(await errorText(response));
166
+ }
167
+ /**
168
+ * The standing cadence note (D18): machine status refresh rides the hub's
169
+ * 5-minute sweep — the panel renders this verbatim beside its live-fetch
170
+ * control. English copy to match the DSH UI.
171
+ */
172
+ export const AUTO_REFRESH_NOTE = 'auto-refreshes every 5 min';
173
+ /**
174
+ * The per-machine last-fetch line, shaped from the row's `lastProbeAt`
175
+ * (the hub's status table stamp — mesh-rpc joins it on every GET).
176
+ * Pure by design (the UI passes its own `now`): headless-testable without
177
+ * jsdom, same presence contract as {@link machineVersionChip} — absent or
178
+ * non-finite stamp means "never probed" and the panel omits the line.
179
+ *
180
+ * @param lastProbeAt - epoch ms of the machine's last recorded probe.
181
+ * @param now - epoch ms the panel renders at.
182
+ * @returns "Updated 2m ago" / "Updated just now" / … , or undefined.
183
+ */
184
+ export function lastFetchLabel(lastProbeAt, now) {
185
+ if (typeof lastProbeAt !== 'number' || !Number.isFinite(lastProbeAt))
186
+ return undefined;
187
+ const seconds = Math.max(0, Math.floor((now - lastProbeAt) / 1000));
188
+ if (seconds < 60)
189
+ return 'Updated just now';
190
+ if (seconds < 3600)
191
+ return `Updated ${Math.floor(seconds / 60)}m ago`;
192
+ if (seconds < 86_400)
193
+ return `Updated ${Math.floor(seconds / 3600)}h ago`;
194
+ return `Updated ${Math.floor(seconds / 86_400)}d ago`;
195
+ }
196
+ /**
197
+ * Client-side pre-check before a pairing submit: a parseable absolute
198
+ * http(s) URL carrying a non-empty `token` query param. The server re-parses
199
+ * authoritatively (mesh-link's parseTokenUrl); this only keeps obviously
200
+ * dead drafts off the wire.
201
+ *
202
+ * @param input - the raw token-URL draft (trim before calling).
203
+ * @returns whether the draft is submit-shaped.
204
+ */
205
+ export function validTokenUrl(input) {
206
+ if (typeof input !== 'string' || input === '')
207
+ return false;
208
+ let url;
209
+ try {
210
+ url = new URL(input);
211
+ }
212
+ catch {
213
+ return false;
214
+ }
215
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
216
+ return false;
217
+ const token = url.searchParams.get('token');
218
+ return token !== null && token !== '';
219
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Machine-section grouping for the Hub switch surfaces (mesh P2, Task 4):
3
+ * the pure core that turns a roster plus the machines API's label map into
4
+ * the menu/row sections — the LOCAL group first under the fixed
5
+ * {@link LOCAL_MACHINE_LABEL} heading, then one section per remote machine
6
+ * sorted by display label (key as the tiebreak). This is the client-half
7
+ * mirror of the host's wire ordering (agent-roster.ts sorts federated rows
8
+ * by machine label server-side); the client re-derives it so the sections
9
+ * stay correct even when the wire order changes or the roster is seeded
10
+ * from a stale baked global.
11
+ *
12
+ * The label map comes from `fetchMachines()` (mesh-api.ts): machine label,
13
+ * falling back to the name, falling back to the raw m4 —
14
+ * {@link machineLabelsFrom} builds it, and a machine the registry no longer
15
+ * knows simply keeps its raw m4 as the section label (never a crash).
16
+ *
17
+ * Node-safe by construction — no DOM, no react, no @deepseek-ai imports —
18
+ * so the host tsc emits it to `dist/client/mesh-groups.js` and
19
+ * test/client-mesh-groups.test.mjs runs the pure halves under `node --test`
20
+ * without jsdom: the mesh-api precedent. No fetch happens at import time.
21
+ *
22
+ * @module superd-hub/client/mesh-groups
23
+ */
24
+ import type { MeshList } from './mesh-api.js';
25
+ import type { AgentLink } from './roster.js';
26
+ /** The machine key every LOCAL roster row carries (older host shapes may omit the field — grouping treats absent as local). */
27
+ export declare const LOCAL_MACHINE_KEY = "local";
28
+ /** The LOCAL section's fixed display label — this machine needs no registry row to be named. */
29
+ export declare const LOCAL_MACHINE_LABEL = "This machine";
30
+ /** One machine's section: its grouping key, its display label, and its rows in roster order. */
31
+ export interface MachineAgentGroup {
32
+ /** The grouping key: {@link LOCAL_MACHINE_KEY} or the owning machine's m4. */
33
+ readonly key: string;
34
+ /** The section heading: the machine's display label ({@link LOCAL_MACHINE_LABEL} for local, the raw key when no label is known). */
35
+ readonly label: string;
36
+ /** This machine's roster rows, keeping the roster's own order. */
37
+ readonly agents: readonly AgentLink[];
38
+ }
39
+ /**
40
+ * Group a roster into machine sections for the switch menu and the Hub
41
+ * roster rows: the LOCAL group first (label {@link LOCAL_MACHINE_LABEL};
42
+ * rows whose `machine` is `'local'` or absent), then one group per remote
43
+ * machine sorted by display label (code-unit order) with the machine key as
44
+ * the tiebreak. Members keep the roster's given order inside their group;
45
+ * groups only exist for machines actually present in the roster (no empty
46
+ * local section when every row is federated). An unknown label map entry —
47
+ * missing, or an empty string — falls back to the raw machine key.
48
+ *
49
+ * @param links - the roster rows (any order; the section order is derived, not inherited).
50
+ * @param machineLabels - machine key (m4) → display label; the machines API answer via {@link machineLabelsFrom}.
51
+ * @returns the sections, local first.
52
+ */
53
+ export declare function groupByMachine(links: readonly AgentLink[], machineLabels: Readonly<Record<string, string>>): MachineAgentGroup[];
54
+ /**
55
+ * The machines API answer → the grouping label map: every remote row's
56
+ * `id → label` (mesh-api's coercion already collapsed an empty label to the
57
+ * machine name) plus the self block's own `m4 → label`. An absent list is
58
+ * the empty map — the caller's degrade-to-flat trigger, never a throw.
59
+ *
60
+ * @param list - the coerced `fetchMachines()` answer, when it succeeded.
61
+ * @returns machine key → display label (the raw key stays absent, not mapped).
62
+ */
63
+ export declare function machineLabelsFrom(list: MeshList | undefined): Record<string, string>;
@@ -0,0 +1,66 @@
1
+ /** The machine key every LOCAL roster row carries (older host shapes may omit the field — grouping treats absent as local). */
2
+ export const LOCAL_MACHINE_KEY = 'local';
3
+ /** The LOCAL section's fixed display label — this machine needs no registry row to be named. */
4
+ export const LOCAL_MACHINE_LABEL = 'This machine';
5
+ /** Whether a row's machine field parks it in the local section: `'local'` or absent (the coercion drops unknown values). */
6
+ function isLocalMachine(machine) {
7
+ return machine === undefined || machine === LOCAL_MACHINE_KEY;
8
+ }
9
+ /**
10
+ * Group a roster into machine sections for the switch menu and the Hub
11
+ * roster rows: the LOCAL group first (label {@link LOCAL_MACHINE_LABEL};
12
+ * rows whose `machine` is `'local'` or absent), then one group per remote
13
+ * machine sorted by display label (code-unit order) with the machine key as
14
+ * the tiebreak. Members keep the roster's given order inside their group;
15
+ * groups only exist for machines actually present in the roster (no empty
16
+ * local section when every row is federated). An unknown label map entry —
17
+ * missing, or an empty string — falls back to the raw machine key.
18
+ *
19
+ * @param links - the roster rows (any order; the section order is derived, not inherited).
20
+ * @param machineLabels - machine key (m4) → display label; the machines API answer via {@link machineLabelsFrom}.
21
+ * @returns the sections, local first.
22
+ */
23
+ export function groupByMachine(links, machineLabels) {
24
+ const local = [];
25
+ const byKey = new Map();
26
+ for (const link of links) {
27
+ if (isLocalMachine(link.machine)) {
28
+ local.push(link);
29
+ continue;
30
+ }
31
+ const machine = link.machine;
32
+ const bucket = byKey.get(machine);
33
+ if (bucket === undefined)
34
+ byKey.set(machine, [link]);
35
+ else
36
+ bucket.push(link);
37
+ }
38
+ const labelOf = (key) => {
39
+ const label = machineLabels[key];
40
+ return typeof label === 'string' && label !== '' ? label : key;
41
+ };
42
+ const remote = [...byKey.entries()]
43
+ .map(([key, agents]) => ({ key, label: labelOf(key), agents }))
44
+ .sort((a, b) => (a.label !== b.label ? (a.label < b.label ? -1 : 1) : (a.key < b.key ? -1 : a.key > b.key ? 1 : 0)));
45
+ return local.length > 0 ? [{ key: LOCAL_MACHINE_KEY, label: LOCAL_MACHINE_LABEL, agents: local }, ...remote] : remote;
46
+ }
47
+ /**
48
+ * The machines API answer → the grouping label map: every remote row's
49
+ * `id → label` (mesh-api's coercion already collapsed an empty label to the
50
+ * machine name) plus the self block's own `m4 → label`. An absent list is
51
+ * the empty map — the caller's degrade-to-flat trigger, never a throw.
52
+ *
53
+ * @param list - the coerced `fetchMachines()` answer, when it succeeded.
54
+ * @returns machine key → display label (the raw key stays absent, not mapped).
55
+ */
56
+ export function machineLabelsFrom(list) {
57
+ const labels = {};
58
+ if (list === undefined)
59
+ return labels;
60
+ for (const machine of list.machines) {
61
+ labels[machine.id] = machine.label !== '' ? machine.label : machine.name;
62
+ }
63
+ if (list.self !== undefined)
64
+ labels[list.self.id] = list.self.label;
65
+ return labels;
66
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Shared roster projection for the client half: the runtime list every Hub
3
+ * switch surface (the HubPanelIcon chevron menu, the HubPage Agent Runtimes
4
+ * rows — the sole agent-switch surface since the T-B RuntimeSeat retirement)
5
+ * renders. Source of truth = the hub's read-only `/api/agent-runtime` face;
6
+ * the baked `window.__DSH_AGENT_ROSTER__` global only seeds the first paint
7
+ * (a world page's baked copy can be stale, so the wire answer is
8
+ * authoritative).
9
+ *
10
+ * Node-safe by construction (no DOM globals, fetch only inside functions) —
11
+ * the host tsc dual-emits this file to `dist/client/roster.js` so
12
+ * test/client-mesh-groups.test.mjs can pin the coercion under `node --test`
13
+ * (the mesh-api/mesh-groups precedent).
14
+ *
15
+ * @module superd-hub/client/roster
16
+ */
17
+ /** One runtime as the roster hands it over: key, display label, mount path, machine. */
18
+ export interface AgentLink {
19
+ readonly key: string;
20
+ readonly label: string;
21
+ readonly path: string;
22
+ /**
23
+ * Machine the runtime comes from (mesh P2): `'local'` for this machine's
24
+ * rows, the owning machine's m4 id for federated rows. Optional and
25
+ * additive: the coercion drops unknown values to `undefined` and the
26
+ * grouping (mesh-groups.ts) treats absent as local — no parse-boundary
27
+ * default anymore, the wire's machine ids pass through verbatim.
28
+ */
29
+ readonly machine?: string;
30
+ /** Whether the world's data plane is up. Optional: older hosts omit it (parse boundary default). */
31
+ readonly ready?: boolean;
32
+ /** Whether the world's spawn REJECTED. Optional: older hosts omit it. */
33
+ readonly failed?: boolean;
34
+ }
35
+ /** The native runtime every composition can fall back to. */
36
+ export declare const NATIVE_LINK: AgentLink;
37
+ /** Seed from the index-baked roster global, when the page carries one. */
38
+ export declare function rosterFromGlobal(): AgentLink[] | undefined;
39
+ /** Normalize the current mount root: `/omp` and `/omp/` are the same page. */
40
+ export declare function currentMountPath(): string;
41
+ /**
42
+ * Ask the hub for the live roster (preferred `agents` shape with paths; the
43
+ * bare `available` key list falls back to `/<key>/` paths).
44
+ *
45
+ * @returns the runtime links, keyed by runtime.
46
+ * @throws when the face is unreachable or returns no usable roster.
47
+ */
48
+ export declare function fetchRoster(): Promise<AgentLink[]>;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Shared roster projection for the client half: the runtime list every Hub
3
+ * switch surface (the HubPanelIcon chevron menu, the HubPage Agent Runtimes
4
+ * rows — the sole agent-switch surface since the T-B RuntimeSeat retirement)
5
+ * renders. Source of truth = the hub's read-only `/api/agent-runtime` face;
6
+ * the baked `window.__DSH_AGENT_ROSTER__` global only seeds the first paint
7
+ * (a world page's baked copy can be stale, so the wire answer is
8
+ * authoritative).
9
+ *
10
+ * Node-safe by construction (no DOM globals, fetch only inside functions) —
11
+ * the host tsc dual-emits this file to `dist/client/roster.js` so
12
+ * test/client-mesh-groups.test.mjs can pin the coercion under `node --test`
13
+ * (the mesh-api/mesh-groups precedent).
14
+ *
15
+ * @module superd-hub/client/roster
16
+ */
17
+ /** The native runtime every composition can fall back to. */
18
+ export const NATIVE_LINK = { key: 'native', label: 'DSH', path: '/', machine: 'local', ready: true, failed: false };
19
+ /** Labels for the read-only face's bare keys (it reports keys, not labels). */
20
+ const FALLBACK_LABELS = {
21
+ native: 'DSH',
22
+ omp: 'OMP',
23
+ codex: 'Codex',
24
+ claude: 'Claude',
25
+ pi: 'Pi',
26
+ hermes: 'Hermes',
27
+ agy: 'Antigravity',
28
+ // The opt-in SDK halves carry their own keys so a host that reports only keys
29
+ // still renders a distinguishable label (the composite rows are `disabled: true`
30
+ // by default, so these appear only once an operator turns one on).
31
+ 'omp-sdk': 'OMP (SDK)',
32
+ 'agy-sdk': 'Antigravity (SDK)',
33
+ 'codex-sdk': 'Codex (SDK)',
34
+ };
35
+ /** Coerce a wire `agents` array into links; undefined when unusable/empty. */
36
+ function coerceAgents(raw) {
37
+ if (!Array.isArray(raw))
38
+ return undefined;
39
+ const links = [];
40
+ for (const entry of raw) {
41
+ if (typeof entry !== 'object' || entry === null)
42
+ continue;
43
+ const { key, label, path, machine } = entry;
44
+ if (typeof key !== 'string' || typeof path !== 'string')
45
+ continue;
46
+ links.push({
47
+ key,
48
+ label: typeof label === 'string' ? label : (FALLBACK_LABELS[key] ?? key),
49
+ path,
50
+ // Passthrough (mesh P2 Task 4): a string machine id rides verbatim
51
+ // ('local' for this machine's rows, the m4 for federated rows);
52
+ // anything else is dropped to undefined — the grouping treats absent
53
+ // as local, so an older host shape needs no default here.
54
+ machine: typeof machine === 'string' && machine !== '' ? machine : undefined,
55
+ ready: entry.ready === true,
56
+ failed: entry.failed === true,
57
+ });
58
+ }
59
+ return links.length > 0 ? links : undefined;
60
+ }
61
+ /** Seed from the index-baked roster global, when the page carries one. */
62
+ export function rosterFromGlobal() {
63
+ const raw = globalThis.__DSH_AGENT_ROSTER__;
64
+ return coerceAgents(raw?.agents);
65
+ }
66
+ /** Normalize the current mount root: `/omp` and `/omp/` are the same page. */
67
+ export function currentMountPath() {
68
+ const location = globalThis.location;
69
+ const pathname = location === undefined ? '/' : location.pathname;
70
+ if (pathname === '' || pathname === '/')
71
+ return '/';
72
+ return pathname.endsWith('/') ? pathname : `${pathname}/`;
73
+ }
74
+ /**
75
+ * Ask the hub for the live roster (preferred `agents` shape with paths; the
76
+ * bare `available` key list falls back to `/<key>/` paths).
77
+ *
78
+ * @returns the runtime links, keyed by runtime.
79
+ * @throws when the face is unreachable or returns no usable roster.
80
+ */
81
+ export async function fetchRoster() {
82
+ const response = await fetch('/api/agent-runtime', { credentials: 'same-origin' });
83
+ if (!response.ok)
84
+ throw new Error(`HTTP ${response.status}`);
85
+ const json = (await response.json());
86
+ const agents = coerceAgents(json.agents);
87
+ if (agents !== undefined)
88
+ return agents;
89
+ if (Array.isArray(json.available)) {
90
+ const links = [];
91
+ for (const key of json.available) {
92
+ if (typeof key !== 'string')
93
+ continue;
94
+ links.push(key === 'native'
95
+ ? NATIVE_LINK
96
+ : { key, label: FALLBACK_LABELS[key] ?? key, path: `/${key}/`, machine: 'local', ready: key === 'native' });
97
+ }
98
+ if (links.length > 0)
99
+ return links;
100
+ }
101
+ throw new Error('agent-runtime face returned no roster');
102
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * runtime-settings-api.ts — the browser half of a runtime's settings panel.
3
+ *
4
+ * The panel's config belongs to the ADAPTER, so nothing here knows what an auth
5
+ * method is: it posts a `client-request` envelope at the runtime's own world and
6
+ * hands the adapter's answer to `parseAuthView` (agent-settings.ts).
7
+ *
8
+ * POST /hub/api?agent=agy
9
+ * { type:'client-request', rpcId, method:'agyAuth/get'|'agyAuth/set',
10
+ * payload:{ args: {} | { request: { mode } } } }
11
+ *
12
+ * `/hub/api` is the hub family's prefix mount (`hub-route.ts`), which forwards
13
+ * `method` verbatim to the addressed world's `typertGateway`. The path needs no
14
+ * `CONTROL` exemption in fusion-transport.ts: the rewrite only touches same-origin
15
+ * `/api/...` paths, and `/hub/...` is never one of them.
16
+ *
17
+ * Node-safe: no DOM reach at module scope and `fetch` is injectable, so
18
+ * test/client-runtime-settings.test.mjs pins the envelope and every failure
19
+ * branch under `node --test` (the mesh-api.ts precedent).
20
+ *
21
+ * @module superd-hub/client/runtime-settings-api
22
+ */
23
+ import { type RuntimeAuthView, type RuntimeProvidersView } from './agent-settings.js';
24
+ /** Structural slice of `fetch` — the bundle uses the global, tests inject a stub. */
25
+ export type FetchLike = (input: string, init: RequestInit) => Promise<{
26
+ ok: boolean;
27
+ status: number;
28
+ text(): Promise<string>;
29
+ }>;
30
+ /** One rpcId for request/response correlation. `randomUUID` needs a secure context. */
31
+ export declare function mintRpcId(): string;
32
+ /** The wire body of one unary call. */
33
+ export interface ClientRequestEnvelope {
34
+ type: 'client-request';
35
+ rpcId: string;
36
+ method: string;
37
+ payload: {
38
+ args: Record<string, unknown>;
39
+ };
40
+ }
41
+ /** Build the envelope for one panel call (exported so tests pin the exact wire shape). */
42
+ /** The operation names the adapter Remotes accept (auth ladder + providers). */
43
+ export type RuntimeSettingsOp = 'get' | 'set' | 'save' | 'remove';
44
+ export declare function settingsEnvelope(namespace: string, op: RuntimeSettingsOp, args: Record<string, unknown>): ClientRequestEnvelope;
45
+ /** What a caller can do with a failed panel call — kept structural for the tests. */
46
+ declare function messageOf(error: unknown): string;
47
+ /**
48
+ * One unary call at a runtime's world, unwrapped to the RPC's value.
49
+ *
50
+ * Every failure mode is reported as a thrown `Error` carrying the adapter's own
51
+ * message where one exists: a transport failure, a malformed answer, and the
52
+ * gateway's business error (`{ok:false,error}`) must not look alike to the panel.
53
+ *
54
+ * @param agentKey - roster key addressing the world (`?agent=`).
55
+ * @param namespace - the adapter's Remote namespace (`agyAuth`).
56
+ * @param op - the Remote method.
57
+ * @param args - exact named wire arguments.
58
+ * @param doFetch - fetch implementation (tests inject).
59
+ * @returns the raw RPC value.
60
+ * @throws {Error} on transport, framing, or gateway failure.
61
+ */
62
+ export declare function callRuntimeSettings(agentKey: string, namespace: string, op: RuntimeSettingsOp, args: Record<string, unknown>, doFetch?: FetchLike): Promise<unknown>;
63
+ /** Read one runtime's panel state, parsed. */
64
+ export declare function fetchAuthView(agentKey: string, namespace: string, doFetch?: FetchLike): Promise<RuntimeAuthView>;
65
+ /** Adopt one auth form (`null` clears the explicit choice). */
66
+ export declare function setAuthMode(agentKey: string, namespace: string, mode: string | null, doFetch?: FetchLike): Promise<RuntimeAuthView>;
67
+ /** Read the multi-provider state of one runtime. */
68
+ export declare function fetchProvidersView(agentKey: string, namespace: string, doFetch?: FetchLike): Promise<RuntimeProvidersView>;
69
+ /**
70
+ * Add or edit one provider in the adapter's list. Which provider a session runs
71
+ * on is DSH's own per-session model selection, so this touches no active half.
72
+ */
73
+ export declare function saveProvider(agentKey: string, namespace: string, provider: unknown, doFetch?: FetchLike): Promise<RuntimeProvidersView>;
74
+ /** Drop one provider from the list. Does not rewrite the runtime's own config. */
75
+ export declare function removeProvider(agentKey: string, namespace: string, id: string, doFetch?: FetchLike): Promise<RuntimeProvidersView>;
76
+ export { messageOf as settingsErrorText };