@capybara-hq/kernel 0.1.0-rc.12 → 0.1.0-rc.14

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 (267) hide show
  1. package/dist/admin/admin.schemas.d.ts +13 -0
  2. package/dist/agents/agent-lookup.d.ts +5 -0
  3. package/dist/agents/agent-lookup.js +15 -0
  4. package/dist/background/background.module.js +2 -2
  5. package/dist/background/launch-lock.d.ts +1 -1
  6. package/dist/background/launch-lock.js +1 -1
  7. package/dist/background/poll.job.d.ts +2 -2
  8. package/dist/background/poll.job.js +10 -10
  9. package/dist/background/stop.d.ts +1 -1
  10. package/dist/background/stop.js +3 -3
  11. package/dist/background/store.d.ts +5 -5
  12. package/dist/background/store.js +5 -5
  13. package/dist/background/tasks.service.d.ts +6 -6
  14. package/dist/background/tasks.service.js +13 -13
  15. package/dist/catalog/admin-catalog.controller.d.ts +13 -2
  16. package/dist/catalog/admin-catalog.controller.js +24 -3
  17. package/dist/catalog/admin-catalog.schemas.d.ts +10 -0
  18. package/dist/catalog/admin-catalog.schemas.js +7 -0
  19. package/dist/catalog/catalog-content.d.ts +9 -1
  20. package/dist/catalog/catalog-content.js +2 -1
  21. package/dist/catalog/catalog-files.d.ts +3 -2
  22. package/dist/catalog/catalog-files.js +8 -5
  23. package/dist/catalog/component-scope.service.d.ts +14 -1
  24. package/dist/catalog/component-scope.service.js +12 -2
  25. package/dist/catalog/marketplaces.service.d.ts +1 -1
  26. package/dist/catalog/org-catalog.controller.d.ts +5 -4
  27. package/dist/catalog/org-catalog.controller.js +5 -4
  28. package/dist/catalog/org-catalog.schemas.d.ts +18 -2
  29. package/dist/catalog/org-catalog.schemas.js +16 -2
  30. package/dist/catalog/org-catalog.service.js +8 -2
  31. package/dist/catalog/plugin-import.js +1 -1
  32. package/dist/catalog/plugin-package.js +37 -9
  33. package/dist/catalog/plugin-upgrade.d.ts +15 -1
  34. package/dist/catalog/plugin-upgrade.js +18 -5
  35. package/dist/channels/channels.module.js +2 -2
  36. package/dist/channels/connections.controller.d.ts +1 -1
  37. package/dist/channels/connections.controller.js +1 -1
  38. package/dist/channels/connections.service.d.ts +22 -5
  39. package/dist/channels/connections.service.js +56 -10
  40. package/dist/channels/inbound.d.ts +8 -8
  41. package/dist/channels/inbound.js +31 -31
  42. package/dist/channels/phrases.d.ts +27 -27
  43. package/dist/channels/phrases.js +27 -27
  44. package/dist/channels/webhook.d.ts +21 -1
  45. package/dist/channels/webhook.js +39 -4
  46. package/dist/config/docs.js +1 -1
  47. package/dist/config/schema.d.ts +2 -2
  48. package/dist/config/schema.js +21 -21
  49. package/dist/conversations/conversations.controller.d.ts +11 -11
  50. package/dist/conversations/conversations.controller.js +15 -15
  51. package/dist/conversations/conversations.module.d.ts +1 -1
  52. package/dist/conversations/conversations.module.js +7 -7
  53. package/dist/conversations/conversations.schemas.js +1 -1
  54. package/dist/conversations/conversations.service.d.ts +14 -14
  55. package/dist/conversations/conversations.service.js +19 -19
  56. package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
  57. package/dist/conversations/{environment-status.js → device-status.js} +18 -18
  58. package/dist/conversations/event-log.d.ts +1 -1
  59. package/dist/conversations/event-log.js +1 -1
  60. package/dist/conversations/events.d.ts +1 -1
  61. package/dist/conversations/events.js +2 -2
  62. package/dist/ctx/create-ctx.d.ts +26 -3
  63. package/dist/ctx/create-ctx.js +134 -26
  64. package/dist/db/kernel-schema.d.ts +37 -25
  65. package/dist/{environments → devices}/access.d.ts +19 -19
  66. package/dist/{environments → devices}/access.js +28 -28
  67. package/dist/devices/conversation-devices.d.ts +75 -0
  68. package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
  69. package/dist/devices/devices.controller.d.ts +36 -0
  70. package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
  71. package/dist/devices/devices.module.d.ts +5 -13
  72. package/dist/devices/devices.module.js +16 -29
  73. package/dist/devices/devices.schemas.d.ts +3 -0
  74. package/dist/devices/devices.schemas.js +14 -0
  75. package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
  76. package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
  77. package/dist/devices/dto.d.ts +13 -54
  78. package/dist/devices/dto.js +7 -39
  79. package/dist/devices/label.d.ts +11 -0
  80. package/dist/{environments → devices}/label.js +7 -7
  81. package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
  82. package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
  83. package/dist/errors.d.ts +29 -25
  84. package/dist/errors.js +29 -25
  85. package/dist/evals/recorded-tools.d.ts +2 -2
  86. package/dist/evals/recorded-tools.js +6 -6
  87. package/dist/extensions/admin-ops.js +1 -0
  88. package/dist/extensions/admin-view.js +2 -0
  89. package/dist/extensions/effective-config.d.ts +6 -0
  90. package/dist/extensions/effective-config.js +18 -7
  91. package/dist/extensions/guide-places.d.ts +66 -0
  92. package/dist/extensions/guide-places.js +152 -0
  93. package/dist/extensions/host.d.ts +13 -2
  94. package/dist/extensions/host.js +27 -6
  95. package/dist/extensions/instance.d.ts +17 -2
  96. package/dist/extensions/instance.js +21 -0
  97. package/dist/extensions/ledger.d.ts +1 -1
  98. package/dist/extensions/permission-set.d.ts +16 -2
  99. package/dist/extensions/permission-set.js +17 -3
  100. package/dist/extensions/permission-view.d.ts +10 -1
  101. package/dist/extensions/plugin-guides.d.ts +207 -54
  102. package/dist/extensions/plugin-guides.js +436 -165
  103. package/dist/files/previewers.d.ts +1 -1
  104. package/dist/files/previewers.js +1 -1
  105. package/dist/http/api.module.js +16 -6
  106. package/dist/http/gateway-routes.d.ts +1 -1
  107. package/dist/http/gateway-routes.js +1 -1
  108. package/dist/identity/settings.d.ts +32 -0
  109. package/dist/identity/settings.js +26 -2
  110. package/dist/infra/config/kernel-config.service.js +4 -4
  111. package/dist/infra/lock/lock.service.d.ts +8 -0
  112. package/dist/infra/lock/lock.service.js +27 -0
  113. package/dist/infra/throttler/named-throttlers.d.ts +4 -1
  114. package/dist/infra/throttler/named-throttlers.js +16 -1
  115. package/dist/infra/throttler/throttler.guard.js +1 -1
  116. package/dist/kernel.module.js +3 -3
  117. package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
  118. package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
  119. package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
  120. package/dist/{devices → local-devices}/device-auth.js +51 -53
  121. package/dist/local-devices/device-auth.module.d.ts +7 -0
  122. package/dist/{devices → local-devices}/device-auth.module.js +5 -5
  123. package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
  124. package/dist/{devices → local-devices}/device-routes.js +2 -2
  125. package/dist/local-devices/dto.d.ts +66 -0
  126. package/dist/local-devices/dto.js +44 -0
  127. package/dist/{devices → local-devices}/keys.d.ts +11 -11
  128. package/dist/{devices → local-devices}/keys.js +11 -11
  129. package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
  130. package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
  131. package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
  132. package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
  133. package/dist/local-devices/local-devices.module.d.ts +16 -0
  134. package/dist/local-devices/local-devices.module.js +44 -0
  135. package/dist/{devices → local-devices}/machines.d.ts +26 -26
  136. package/dist/{devices → local-devices}/machines.js +71 -71
  137. package/dist/{devices → local-devices}/relay.d.ts +15 -15
  138. package/dist/{devices → local-devices}/relay.js +55 -55
  139. package/dist/{devices → local-devices}/targets.d.ts +8 -8
  140. package/dist/{devices → local-devices}/targets.js +14 -14
  141. package/dist/orgs/offboarding.d.ts +6 -6
  142. package/dist/orgs/offboarding.js +12 -12
  143. package/dist/orgs/settings.service.d.ts +28 -0
  144. package/dist/orgs/settings.service.js +20 -1
  145. package/dist/overrides.d.ts +3 -1
  146. package/dist/overrides.js +2 -0
  147. package/dist/platform/exclusions.js +48 -8
  148. package/dist/platform/operation.js +10 -2
  149. package/dist/platform/ops/admin.ops.js +8 -2
  150. package/dist/platform/ops/connectors.ops.js +2 -0
  151. package/dist/platform/ops/conversations.ops.d.ts +3 -3
  152. package/dist/platform/ops/conversations.ops.js +9 -9
  153. package/dist/platform/ops/devices.ops.d.ts +26 -0
  154. package/dist/platform/ops/devices.ops.js +311 -0
  155. package/dist/platform/ops/org-settings.ops.js +2 -2
  156. package/dist/platform/ops/orgs.ops.js +1 -0
  157. package/dist/platform/ops/setup.ops.d.ts +24 -0
  158. package/dist/platform/ops/setup.ops.js +212 -0
  159. package/dist/platform/ops/ui.ops.d.ts +8 -0
  160. package/dist/platform/ops/ui.ops.js +41 -0
  161. package/dist/platform/platform-ops.module.d.ts +4 -2
  162. package/dist/platform/platform-ops.module.js +13 -5
  163. package/dist/platform/route-schemas.js +11 -3
  164. package/dist/roles/gateway-role.d.ts +3 -3
  165. package/dist/roles/gateway-role.js +4 -4
  166. package/dist/roles/gateway.module.d.ts +1 -1
  167. package/dist/roles/gateway.module.js +5 -5
  168. package/dist/roles/worker.module.js +1 -1
  169. package/dist/runtime/context/build.d.ts +1 -1
  170. package/dist/runtime/context/build.js +6 -6
  171. package/dist/runtime/context/compaction.js +1 -1
  172. package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
  173. package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
  174. package/dist/runtime/maintenance.d.ts +1 -1
  175. package/dist/sandbox/jobs.d.ts +13 -13
  176. package/dist/sandbox/jobs.js +20 -20
  177. package/dist/sandbox/leases.d.ts +9 -9
  178. package/dist/sandbox/leases.js +14 -14
  179. package/dist/sandbox/providers.d.ts +8 -8
  180. package/dist/sandbox/providers.js +8 -8
  181. package/dist/sandbox/sandbox.module.d.ts +1 -1
  182. package/dist/sandbox/sandbox.module.js +1 -1
  183. package/dist/sandbox/sandbox.service.d.ts +76 -76
  184. package/dist/sandbox/sandbox.service.js +230 -230
  185. package/dist/setup/kernel-checks.d.ts +91 -0
  186. package/dist/setup/kernel-checks.js +295 -0
  187. package/dist/setup/oauth-token-probe.d.ts +47 -0
  188. package/dist/setup/oauth-token-probe.js +108 -0
  189. package/dist/setup/redact-check.d.ts +18 -0
  190. package/dist/setup/redact-check.js +46 -0
  191. package/dist/setup/setup-check-registry.d.ts +86 -0
  192. package/dist/setup/setup-check-registry.js +75 -0
  193. package/dist/setup/setup-checks.controller.d.ts +28 -0
  194. package/dist/setup/setup-checks.controller.js +78 -0
  195. package/dist/setup/setup-checks.schemas.d.ts +38 -0
  196. package/dist/setup/setup-checks.schemas.js +43 -0
  197. package/dist/setup/setup-checks.service.d.ts +144 -0
  198. package/dist/setup/setup-checks.service.js +683 -0
  199. package/dist/setup/setup-guides.controller.d.ts +18 -0
  200. package/dist/setup/setup-guides.controller.js +48 -0
  201. package/dist/setup/setup-guides.schemas.d.ts +10 -0
  202. package/dist/setup/setup-guides.schemas.js +6 -0
  203. package/dist/setup/setup-guides.service.d.ts +126 -0
  204. package/dist/setup/setup-guides.service.js +315 -0
  205. package/dist/setup/setup.module.d.ts +8 -0
  206. package/dist/setup/setup.module.js +31 -0
  207. package/dist/tools/builtins/builtin-tools.d.ts +2 -2
  208. package/dist/tools/builtins/builtin-tools.js +5 -5
  209. package/dist/tools/builtins/platform.js +1 -1
  210. package/dist/tools/builtins/sandbox/bash.js +6 -6
  211. package/dist/tools/builtins/sandbox/common.d.ts +25 -25
  212. package/dist/tools/builtins/sandbox/common.js +51 -51
  213. package/dist/tools/builtins/sandbox/edit.js +2 -2
  214. package/dist/tools/builtins/sandbox/index.d.ts +1 -1
  215. package/dist/tools/builtins/sandbox/index.js +1 -1
  216. package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
  217. package/dist/tools/builtins/sandbox/task-output.js +10 -10
  218. package/dist/tools/builtins/sandbox/task-stop.js +2 -2
  219. package/dist/tools/builtins/sandbox/write.js +2 -2
  220. package/dist/tools/builtins/skill-load.d.ts +1 -1
  221. package/dist/tools/builtins/skill-load.js +2 -2
  222. package/dist/tools/connectors.controller.d.ts +28 -11
  223. package/dist/tools/connectors.controller.js +49 -14
  224. package/dist/tools/connectors.schemas.d.ts +4 -0
  225. package/dist/tools/connectors.schemas.js +4 -0
  226. package/dist/tools/connectors.service.d.ts +30 -2
  227. package/dist/tools/connectors.service.js +98 -3
  228. package/dist/tools/credentials.d.ts +20 -0
  229. package/dist/tools/credentials.js +90 -1
  230. package/dist/tools/oauth/tokens.d.ts +20 -0
  231. package/dist/tools/oauth/tokens.js +49 -24
  232. package/dist/tools/pipeline.js +4 -3
  233. package/dist/tools/registry.d.ts +2 -2
  234. package/dist/tools/tools.module.js +3 -3
  235. package/dist/ui/admin-ui.controller.d.ts +56 -0
  236. package/dist/ui/admin-ui.controller.js +192 -0
  237. package/dist/ui/arrangement.d.ts +74 -0
  238. package/dist/ui/arrangement.js +98 -0
  239. package/dist/ui/embed-token.d.ts +2 -2
  240. package/dist/ui/embed-token.js +30 -5
  241. package/dist/ui/registry.d.ts +29 -14
  242. package/dist/ui/registry.js +31 -10
  243. package/dist/ui/slots.controller.d.ts +11 -0
  244. package/dist/ui/slots.controller.js +25 -0
  245. package/dist/ui/ui-stream.d.ts +20 -3
  246. package/dist/ui/ui-stream.js +25 -7
  247. package/dist/ui/ui.schemas.d.ts +66 -0
  248. package/dist/ui/ui.schemas.js +65 -0
  249. package/dist/ui/views.controller.d.ts +35 -49
  250. package/dist/ui/views.controller.js +48 -70
  251. package/dist/ui/views.d.ts +84 -18
  252. package/dist/ui/views.js +201 -38
  253. package/package.json +3 -3
  254. package/src/migrations/0105_devices_rename.sql +136 -0
  255. package/src/migrations/0106_setup_guides_v2.sql +10 -0
  256. package/dist/devices/device-auth.module.d.ts +0 -7
  257. package/dist/environments/conversation-environments.d.ts +0 -75
  258. package/dist/environments/dto.d.ts +0 -25
  259. package/dist/environments/dto.js +0 -12
  260. package/dist/environments/environments.controller.d.ts +0 -36
  261. package/dist/environments/environments.module.d.ts +0 -8
  262. package/dist/environments/environments.module.js +0 -31
  263. package/dist/environments/environments.schemas.d.ts +0 -3
  264. package/dist/environments/environments.schemas.js +0 -14
  265. package/dist/environments/label.d.ts +0 -11
  266. package/dist/platform/ops/environments.ops.d.ts +0 -26
  267. package/dist/platform/ops/environments.ops.js +0 -311
@@ -68,20 +68,11 @@ const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
68
68
  /** RFC 6749 §5.2 形式的错误码(只有这种串才写进日志 / 错误,不回显对方任意文本)。 */
69
69
  const OAUTH_ERROR_RE = /^[a-z][a-z0-9_]{0,63}$/;
70
70
  /**
71
- * Calls the token endpoint (RFC 6749 §3.2), sending client_id / secret per the client's auth method
72
- * (Basic form-encodes them first, §2.3.1).
73
- * - 400 / 401 with a parsable RFC 6749 `error` code -> OAuthGrantError.
74
- * - 200 with `ok: false` (Slack reports every error this way), or with an `error` code and no
75
- * `access_token` -> OAuthGrantError with that code (`ok: false` wins over an `access_token`); a
76
- * transient code (`temporarily_unavailable`, `server_error`, Slack's `ratelimited`, ...) or no
77
- * parsable code -> OAuthUnavailable.
78
- * - Everything else (network error, timeout, 429, 408, 403 and other 4xx, a 4xx without a code,
79
- * 5xx, 3xx, a malformed body) -> OAuthUnavailable: a gateway's rate limit or a WAF block is not a
80
- * dead credential.
81
- * - A `token_type` other than Bearer / `user` / `opts.tokenTypes` -> OAuthGrantError
82
- * `unsupported_token_type`; an accepted one is stored as `Bearer`.
71
+ * The headers and form of a token request (RFC 6749 §3.2): client_id / secret per the client's
72
+ * auth method (Basic form-encodes them first, §2.3.1; otherwise `client_id`, plus
73
+ * `client_secret` for `client_secret_post`). Empty parameters are left out.
83
74
  */
84
- export async function tokenRequest(client, params, http, opts = {}) {
75
+ export function tokenRequestInit(client, params) {
85
76
  const form = new URLSearchParams();
86
77
  for (const [k, v] of Object.entries(params))
87
78
  if (v !== undefined && v !== "")
@@ -91,8 +82,7 @@ export async function tokenRequest(client, params, http, opts = {}) {
91
82
  accept: "application/json",
92
83
  };
93
84
  if (client.authMethod === "client_secret_basic" && client.clientSecret !== undefined) {
94
- const enc = (s) => encodeURIComponent(s).replace(/%20/g, "+");
95
- headers.authorization = `Basic ${Buffer.from(`${enc(client.clientId)}:${enc(client.clientSecret)}`).toString("base64")}`;
85
+ headers.authorization = basicClientAuth(client.clientId, client.clientSecret);
96
86
  }
97
87
  else {
98
88
  form.set("client_id", client.clientId);
@@ -100,6 +90,46 @@ export async function tokenRequest(client, params, http, opts = {}) {
100
90
  form.set("client_secret", client.clientSecret);
101
91
  }
102
92
  }
93
+ return { headers, body: form };
94
+ }
95
+ /** The form encoding of a Basic client credential part (RFC 6749 §2.3.1). */
96
+ export const formEncode = (s) => encodeURIComponent(s).replace(/%20/g, "+");
97
+ /** The `Authorization` value of `client_secret_basic` (both parts form-encoded first). */
98
+ export const basicClientAuth = (clientId, clientSecret) => `Basic ${Buffer.from(`${formEncode(clientId)}:${formEncode(clientSecret)}`).toString("base64")}`;
99
+ /**
100
+ * The refusal code of a token endpoint answer, or null when it is not a refusal (the one parser of
101
+ * token refusals): a 400 / 401 whose JSON body has an RFC 6749-shaped `error`, or a 200 whose body
102
+ * carries `ok: false` (Slack) or an `error` and no `access_token`, with a code that is not
103
+ * transient. Only codes matching the RFC 6749 shape are returned, never other text of the body.
104
+ */
105
+ export function parseTokenRefusal(status, body) {
106
+ const code = isObj(body) ? body.error : undefined;
107
+ const shaped = typeof code === "string" && OAUTH_ERROR_RE.test(code) ? code : null;
108
+ if (status === 400 || status === 401)
109
+ return shaped;
110
+ if (status !== 200 || !isObj(body))
111
+ return null;
112
+ if (body.ok === false || (body.access_token === undefined && body.error !== undefined)) {
113
+ return shaped !== null && !TRANSIENT_ERRORS.has(shaped) ? shaped : null;
114
+ }
115
+ return null;
116
+ }
117
+ /**
118
+ * Calls the token endpoint (RFC 6749 §3.2), sending client_id / secret per the client's auth method
119
+ * (Basic form-encodes them first, §2.3.1).
120
+ * - 400 / 401 with a parsable RFC 6749 `error` code -> OAuthGrantError.
121
+ * - 200 with `ok: false` (Slack reports every error this way), or with an `error` code and no
122
+ * `access_token` -> OAuthGrantError with that code (`ok: false` wins over an `access_token`); a
123
+ * transient code (`temporarily_unavailable`, `server_error`, Slack's `ratelimited`, ...) or no
124
+ * parsable code -> OAuthUnavailable.
125
+ * - Everything else (network error, timeout, 429, 408, 403 and other 4xx, a 4xx without a code,
126
+ * 5xx, 3xx, a malformed body) -> OAuthUnavailable: a gateway's rate limit or a WAF block is not a
127
+ * dead credential.
128
+ * - A `token_type` other than Bearer / `user` / `opts.tokenTypes` -> OAuthGrantError
129
+ * `unsupported_token_type`; an accepted one is stored as `Bearer`.
130
+ */
131
+ export async function tokenRequest(client, params, http, opts = {}) {
132
+ const { headers, body: form } = tokenRequestInit(client, params);
103
133
  let res;
104
134
  try {
105
135
  res = await oauthFetch(client.tokenEndpoint, { method: "POST", headers, body: form }, http);
@@ -116,18 +146,13 @@ export async function tokenRequest(client, params, http, opts = {}) {
116
146
  catch {
117
147
  body = undefined;
118
148
  }
119
- if (res.status === 400 || res.status === 401) {
120
- const code = isObj(body) ? body.error : undefined;
121
- if (typeof code === "string" && OAUTH_ERROR_RE.test(code))
122
- throw new OAuthGrantError(code);
123
- }
149
+ const refusal = parseTokenRefusal(res.status, body);
150
+ if (refusal !== null)
151
+ throw new OAuthGrantError(refusal);
124
152
  if (res.status !== 200 || !isObj(body))
125
153
  throw new OAuthUnavailable();
154
+ // an error body without a usable code (or a transient one): unavailable, not a refusal
126
155
  if (body.ok === false || (body.access_token === undefined && body.error !== undefined)) {
127
- const code = body.error;
128
- if (typeof code === "string" && OAUTH_ERROR_RE.test(code) && !TRANSIENT_ERRORS.has(code)) {
129
- throw new OAuthGrantError(code);
130
- }
131
156
  throw new OAuthUnavailable();
132
157
  }
133
158
  const { access_token, refresh_token, expires_in, token_type, scope } = body;
@@ -207,9 +207,10 @@ let ToolPipeline = class ToolPipeline {
207
207
  },
208
208
  effective,
209
209
  switches,
210
- inlineViews: (plugin) => new Set((host?.current(plugin)?.manifest.ui ?? [])
211
- .filter((c) => c.place === "inline" && c.aliasOf === undefined)
212
- .map((c) => c.id)),
210
+ inlineViews: (plugin) => new Set((host?.current(plugin)?.ui ?? [])
211
+ .filter((r) => r.slot.id === "conversation.tool-result.card" &&
212
+ r.contribution.aliasOf === undefined)
213
+ .map((r) => r.contribution.id)),
213
214
  onToolsChanged: (orgId, connectorId) => {
214
215
  void drift?.onToolsChanged(orgId, connectorId);
215
216
  },
@@ -14,7 +14,7 @@ export { BUILTIN_TOOL_NAMES } from "./builtin-names.js";
14
14
  export { canonicalJson } from "./canonical-json.js";
15
15
  /**
16
16
  * What a tool's `unavailable` is asked with: the org, and for a run's listing the root
17
- * conversation (`conversationId`; the sandbox tools follow its environment, ruling R8), whether
17
+ * conversation (`conversationId`; the sandbox tools follow its device, ruling R8), whether
18
18
  * the run is an eval replay (`replay`: its tool calls are never executed), and a `memo` shared by
19
19
  * the tools of one listing (one answer per question per listing).
20
20
  */
@@ -346,7 +346,7 @@ export declare class ToolRegistry {
346
346
  forkChild?: boolean;
347
347
  /**
348
348
  * The root conversation of the run (a sub-agent's tree root): tools whose availability
349
- * depends on the conversation's environment (the sandbox tools) are listed by it.
349
+ * depends on the conversation's device (the sandbox tools) are listed by it.
350
350
  */
351
351
  sandboxConversationId?: string;
352
352
  /** An eval replay's listing: its calls are never executed (the sandbox tools are listed). */
@@ -9,7 +9,7 @@ import { BackgroundModule } from "../background/background.module.js";
9
9
  import { ConversationAccessModule } from "../conversations/access.js";
10
10
  import { AttachmentsModule } from "../conversations/attachments.module.js";
11
11
  import { EventLogModule } from "../conversations/event-log.js";
12
- import { EnvironmentsModule } from "../environments/environments.module.js";
12
+ import { DevicesModule } from "../devices/devices.module.js";
13
13
  import { ExtensionsModule } from "../extensions/extensions.module.js";
14
14
  import { QueueModule } from "../infra/queue/queue.module.js";
15
15
  import { ModelsModule } from "../models/models.module.js";
@@ -59,9 +59,9 @@ ToolsModule = __decorate([
59
59
  OrgLockModule,
60
60
  // the `Agent` tool's dispatch
61
61
  SubagentsModule,
62
- // the builtin sandbox and skill tools run in the conversation's environment
62
+ // the builtin sandbox and skill tools run in the conversation's device
63
63
  SandboxModule,
64
- EnvironmentsModule,
64
+ DevicesModule,
65
65
  // `Bash` with run_in_background records its task; TaskOutput / TaskStop finish and stop it
66
66
  BackgroundModule,
67
67
  // the conversation page's tool metadata reads only what the viewer may see
@@ -0,0 +1,56 @@
1
+ import type { UiActionResult, UiView } from "@capybara-hq/plugin-sdk";
2
+ import type { FastifyReply, FastifyRequest } from "fastify";
3
+ import type { z } from "zod";
4
+ import { ApiTokenService } from "../identity/api-tokens.js";
5
+ import { type Principal } from "../identity/principal.js";
6
+ import { SessionService } from "../identity/sessions.js";
7
+ import { EmbedTokens } from "./embed-token.js";
8
+ import { ContributionParams, PlatformActionBody, PlatformViewQuery } from "./ui.schemas.js";
9
+ import { OrgUiStreams } from "./ui-stream.js";
10
+ import { type UiArrangementSlot, type UiContributionItem, UiViews } from "./views.js";
11
+ /**
12
+ * Extension UI in the admin console (UI slots spec §7, platform scope): the `platform.page`
13
+ * contributions, for super admins only (`@SuperAdmin`, a person: service tokens are refused), with
14
+ * no org. A platform contribution needs its extension running (no org enablement applies) and is
15
+ * given the platform's deployment config; its render args carry `scope: "platform"`, `role:
16
+ * "superAdmin"` and no `orgId`.
17
+ * - `GET /api/v1/admin/ui/contributions` → `{ items }` (`platform.page` only, base order);
18
+ * - `GET /api/v1/admin/ui/arrangement` → `{ slots }` over every arrangeable slot, the platform's
19
+ * entries only, with every running extension's contributions (hidden ones marked);
20
+ * - `GET /api/v1/admin/ui/views/:plugin/:id?locale=` → `{ view }`;
21
+ * - `POST /api/v1/admin/ui/actions/:plugin/:id` (`{ actionId, payload?, answer?, locale? }`) →
22
+ * `{ toast }` | `{ view }`;
23
+ * - `POST /api/v1/admin/ui/embeds/:plugin/:id/token` → `{ token, src, expiresAt, expiresIn }`: a
24
+ * platform embed token (`scope: "platform"`, `role: "superAdmin"`, no `orgId`), which
25
+ * `ctx.ui.verifyEmbedToken` accepts only for a `platform.page` contribution while the account is
26
+ * still an active super admin;
27
+ * - `GET /api/v1/admin/ui/stream`: the platform refresh SSE (`event: ui`, topic `platform-ui`),
28
+ * super admin re-checked on the `runtime.sseRecheckMs` interval.
29
+ * A contribution in any other slot is 404 `ui.not_found`, the same as one that does not exist.
30
+ */
31
+ export declare class AdminUiController {
32
+ private readonly views;
33
+ private readonly streams;
34
+ private readonly sessions;
35
+ private readonly tokens;
36
+ private readonly embeds;
37
+ constructor(views: UiViews, streams: OrgUiStreams, sessions: SessionService, tokens: ApiTokenService, embeds: EmbedTokens);
38
+ contributions(principal: Principal): Promise<{
39
+ items: UiContributionItem[];
40
+ }>;
41
+ arrangement(principal: Principal): Promise<{
42
+ slots: UiArrangementSlot[];
43
+ }>;
44
+ view(principal: Principal, { plugin, id }: z.infer<typeof ContributionParams>, q: z.infer<typeof PlatformViewQuery>): Promise<{
45
+ view: UiView;
46
+ }>;
47
+ action(principal: Principal, { plugin, id }: z.infer<typeof ContributionParams>, body: z.infer<typeof PlatformActionBody>): Promise<UiActionResult>;
48
+ embedToken(principal: Principal, { plugin, id }: z.infer<typeof ContributionParams>): Promise<{
49
+ token: string;
50
+ src: string;
51
+ expiresAt: string;
52
+ expiresIn: number;
53
+ }>;
54
+ /** The platform refresh stream: written on the raw response (`reply.hijack()`) like the org one. */
55
+ stream(principal: Principal, req: FastifyRequest, reply: FastifyReply): Promise<void>;
56
+ }
@@ -0,0 +1,192 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { Controller, Get, HttpCode, Inject, Post, Req, Res } from "@nestjs/common";
11
+ import { ApiTokenService } from "../identity/api-tokens.js";
12
+ import { credentialCheck } from "../identity/credential-check.js";
13
+ import { CurrentPrincipal, requireUser, SuperAdmin, } from "../identity/principal.js";
14
+ import { SessionService } from "../identity/sessions.js";
15
+ import { createZodDto } from "../infra/validation/create-zod-dto.js";
16
+ import { ZBody, ZParam, ZQuery } from "../infra/validation/zod-params.js";
17
+ import { EMBED_TOKEN_TTL_SECONDS, EmbedTokens } from "./embed-token.js";
18
+ import { ContributionParams, PlatformActionBody, PlatformViewQuery } from "./ui.schemas.js";
19
+ import { OrgUiStreams } from "./ui-stream.js";
20
+ import { BEARER_RE, embedSrc } from "./views.controller.js";
21
+ import { UiViews } from "./views.js";
22
+ class AdminUiContributionParamsDto extends createZodDto(ContributionParams, "AdminUiContributionParams") {
23
+ }
24
+ class AdminUiViewQueryDto extends createZodDto(PlatformViewQuery, "AdminUiViewQuery") {
25
+ }
26
+ class AdminUiActionBodyDto extends createZodDto(PlatformActionBody, "AdminUiActionBody") {
27
+ }
28
+ /**
29
+ * Extension UI in the admin console (UI slots spec §7, platform scope): the `platform.page`
30
+ * contributions, for super admins only (`@SuperAdmin`, a person: service tokens are refused), with
31
+ * no org. A platform contribution needs its extension running (no org enablement applies) and is
32
+ * given the platform's deployment config; its render args carry `scope: "platform"`, `role:
33
+ * "superAdmin"` and no `orgId`.
34
+ * - `GET /api/v1/admin/ui/contributions` → `{ items }` (`platform.page` only, base order);
35
+ * - `GET /api/v1/admin/ui/arrangement` → `{ slots }` over every arrangeable slot, the platform's
36
+ * entries only, with every running extension's contributions (hidden ones marked);
37
+ * - `GET /api/v1/admin/ui/views/:plugin/:id?locale=` → `{ view }`;
38
+ * - `POST /api/v1/admin/ui/actions/:plugin/:id` (`{ actionId, payload?, answer?, locale? }`) →
39
+ * `{ toast }` | `{ view }`;
40
+ * - `POST /api/v1/admin/ui/embeds/:plugin/:id/token` → `{ token, src, expiresAt, expiresIn }`: a
41
+ * platform embed token (`scope: "platform"`, `role: "superAdmin"`, no `orgId`), which
42
+ * `ctx.ui.verifyEmbedToken` accepts only for a `platform.page` contribution while the account is
43
+ * still an active super admin;
44
+ * - `GET /api/v1/admin/ui/stream`: the platform refresh SSE (`event: ui`, topic `platform-ui`),
45
+ * super admin re-checked on the `runtime.sseRecheckMs` interval.
46
+ * A contribution in any other slot is 404 `ui.not_found`, the same as one that does not exist.
47
+ */
48
+ let AdminUiController = class AdminUiController {
49
+ views;
50
+ streams;
51
+ sessions;
52
+ tokens;
53
+ embeds;
54
+ constructor(views, streams, sessions, tokens, embeds) {
55
+ this.views = views;
56
+ this.streams = streams;
57
+ this.sessions = sessions;
58
+ this.tokens = tokens;
59
+ this.embeds = embeds;
60
+ }
61
+ async contributions(principal) {
62
+ requireUser(principal);
63
+ return { items: await this.views.platformContributions() };
64
+ }
65
+ async arrangement(principal) {
66
+ requireUser(principal);
67
+ return { slots: await this.views.platformArrangementView() };
68
+ }
69
+ async view(principal, { plugin, id }, q) {
70
+ const p = requireUser(principal);
71
+ const view = await this.views.render({
72
+ scope: "platform",
73
+ accountId: p.account.id,
74
+ plugin,
75
+ id,
76
+ locale: q.locale,
77
+ });
78
+ return { view };
79
+ }
80
+ async action(principal, { plugin, id }, body) {
81
+ const p = requireUser(principal);
82
+ return this.views.act({ scope: "platform", accountId: p.account.id, plugin, id, locale: body.locale }, {
83
+ actionId: body.actionId,
84
+ ...(body.payload !== undefined && { payload: body.payload }),
85
+ ...(body.answer !== undefined && { answer: body.answer }),
86
+ });
87
+ }
88
+ async embedToken(principal, { plugin, id }) {
89
+ const p = requireUser(principal);
90
+ const target = await this.views.embed({
91
+ scope: "platform",
92
+ accountId: p.account.id,
93
+ plugin,
94
+ id,
95
+ });
96
+ const { token, expiresAt } = this.embeds.issue({
97
+ plugin: target.plugin,
98
+ scope: "platform",
99
+ accountId: p.account.id,
100
+ role: "superAdmin",
101
+ contribution: target.contribution,
102
+ });
103
+ return {
104
+ token,
105
+ src: embedSrc(target.plugin, target.path),
106
+ expiresAt: expiresAt.toISOString(),
107
+ expiresIn: EMBED_TOKEN_TTL_SECONDS,
108
+ };
109
+ }
110
+ /** The platform refresh stream: written on the raw response (`reply.hijack()`) like the org one. */
111
+ async stream(principal, req, reply) {
112
+ const p = requireUser(principal);
113
+ const res = reply.raw;
114
+ const handle = await this.streams.open({
115
+ scope: "platform",
116
+ viewerAccountId: p.account.id,
117
+ credential: credentialCheck(p, BEARER_RE.exec(req.headers.authorization ?? "")?.[1], {
118
+ sessions: this.sessions,
119
+ tokens: this.tokens,
120
+ }),
121
+ }, {
122
+ write: (chunk) => {
123
+ res.write(chunk);
124
+ },
125
+ backlog: () => res.writableLength,
126
+ end: () => {
127
+ res.end();
128
+ },
129
+ abort: () => {
130
+ res.destroy();
131
+ },
132
+ });
133
+ reply.hijack();
134
+ res.on("close", () => handle.close());
135
+ if (res.destroyed || !res.socket || res.socket.destroyed) {
136
+ handle.close();
137
+ res.destroy();
138
+ return;
139
+ }
140
+ res.writeHead(200, {
141
+ "content-type": "text/event-stream; charset=utf-8",
142
+ "cache-control": "no-cache",
143
+ "x-accel-buffering": "no",
144
+ connection: "keep-alive",
145
+ });
146
+ res.flushHeaders();
147
+ handle.begin();
148
+ }
149
+ };
150
+ __decorate([
151
+ Get("contributions"),
152
+ __param(0, CurrentPrincipal())
153
+ ], AdminUiController.prototype, "contributions", null);
154
+ __decorate([
155
+ Get("arrangement"),
156
+ __param(0, CurrentPrincipal())
157
+ ], AdminUiController.prototype, "arrangement", null);
158
+ __decorate([
159
+ Get("views/:plugin/:id"),
160
+ __param(0, CurrentPrincipal()),
161
+ __param(1, ZParam(AdminUiContributionParamsDto)),
162
+ __param(2, ZQuery(AdminUiViewQueryDto))
163
+ ], AdminUiController.prototype, "view", null);
164
+ __decorate([
165
+ Post("actions/:plugin/:id"),
166
+ HttpCode(200),
167
+ __param(0, CurrentPrincipal()),
168
+ __param(1, ZParam(AdminUiContributionParamsDto)),
169
+ __param(2, ZBody(AdminUiActionBodyDto))
170
+ ], AdminUiController.prototype, "action", null);
171
+ __decorate([
172
+ Post("embeds/:plugin/:id/token"),
173
+ HttpCode(200),
174
+ __param(0, CurrentPrincipal()),
175
+ __param(1, ZParam(AdminUiContributionParamsDto))
176
+ ], AdminUiController.prototype, "embedToken", null);
177
+ __decorate([
178
+ Get("stream"),
179
+ __param(0, CurrentPrincipal()),
180
+ __param(1, Req()),
181
+ __param(2, Res())
182
+ ], AdminUiController.prototype, "stream", null);
183
+ AdminUiController = __decorate([
184
+ Controller("api/v1/admin/ui"),
185
+ SuperAdmin(),
186
+ __param(0, Inject(UiViews)),
187
+ __param(1, Inject(OrgUiStreams)),
188
+ __param(2, Inject(SessionService)),
189
+ __param(3, Inject(ApiTokenService)),
190
+ __param(4, Inject(EmbedTokens))
191
+ ], AdminUiController);
192
+ export { AdminUiController };
@@ -0,0 +1,74 @@
1
+ import { type UiSlotId } from "@capybara-hq/plugin-sdk";
2
+ import { z } from "zod";
3
+ import type { UiContributionItem } from "./views.js";
4
+ export declare const UiArrangementEntrySchema: z.ZodObject<{
5
+ hidden: z.ZodArray<z.ZodString>;
6
+ order: z.ZodArray<z.ZodString>;
7
+ }, z.core.$strict>;
8
+ export type UiArrangementEntry = z.infer<typeof UiArrangementEntrySchema>;
9
+ export declare const UiArrangementSchema: z.ZodRecord<z.ZodEnum<{
10
+ "agent.detail.section": "agent.detail.section";
11
+ "conversation.panel": "conversation.panel";
12
+ "conversation.properties.section": "conversation.properties.section";
13
+ "conversation.tool-result.card": "conversation.tool-result.card";
14
+ "file.preview": "file.preview";
15
+ "org.page": "org.page";
16
+ "org.settings.section": "org.settings.section";
17
+ "platform.page": "platform.page";
18
+ }> & z.core.$partial, z.ZodObject<{
19
+ hidden: z.ZodArray<z.ZodString>;
20
+ order: z.ZodArray<z.ZodString>;
21
+ }, z.core.$strict>>;
22
+ export type UiArrangement = z.infer<typeof UiArrangementSchema>;
23
+ /** The slots an org arranges: every arrangeable slot but the platform's own. */
24
+ export declare const ORG_ARRANGEABLE: readonly UiSlotId[];
25
+ /** An org's patch: a slot's entry replaces the stored one, null removes it. */
26
+ export declare const OrgUiArrangementPatchSchema: z.ZodRecord<z.ZodEnum<{
27
+ "agent.detail.section": "agent.detail.section";
28
+ "conversation.panel": "conversation.panel";
29
+ "conversation.properties.section": "conversation.properties.section";
30
+ "conversation.tool-result.card": "conversation.tool-result.card";
31
+ "file.preview": "file.preview";
32
+ "org.page": "org.page";
33
+ "org.settings.section": "org.settings.section";
34
+ "platform.page": "platform.page";
35
+ }> & z.core.$partial, z.ZodNullable<z.ZodObject<{
36
+ hidden: z.ZodArray<z.ZodString>;
37
+ order: z.ZodArray<z.ZodString>;
38
+ }, z.core.$strict>>>;
39
+ /** A deployment patch: like {@link OrgUiArrangementPatchSchema} over every arrangeable slot. */
40
+ export declare const UiArrangementPatchSchema: z.ZodRecord<z.ZodEnum<{
41
+ "agent.detail.section": "agent.detail.section";
42
+ "conversation.panel": "conversation.panel";
43
+ "conversation.properties.section": "conversation.properties.section";
44
+ "conversation.tool-result.card": "conversation.tool-result.card";
45
+ "file.preview": "file.preview";
46
+ "org.page": "org.page";
47
+ "org.settings.section": "org.settings.section";
48
+ "platform.page": "platform.page";
49
+ }> & z.core.$partial, z.ZodNullable<z.ZodObject<{
50
+ hidden: z.ZodArray<z.ZodString>;
51
+ order: z.ZodArray<z.ZodString>;
52
+ }, z.core.$strict>>>;
53
+ /** Merges a per-slot patch into the stored arrangement (null removes the slot's entry). */
54
+ export declare function mergeArrangement(current: UiArrangement | undefined, patch: Partial<Record<UiSlotId, UiArrangementEntry | null>>): UiArrangement;
55
+ /** The entry that applies to a slot: the org's if it arranged the slot, else the platform's. */
56
+ export declare function effectiveEntry(org: UiArrangement | undefined, platform: UiArrangement, slot: UiSlotId): {
57
+ entry: UiArrangementEntry;
58
+ source: "org" | "platform" | "none";
59
+ };
60
+ /**
61
+ * Orders the items of one slot (hidden ones stay in place): grouped by anchor in the slot's anchor
62
+ * order, also without an entry (the lists match what the page renders per anchor); within a group
63
+ * the keys of `entry.order` come first in that order, the rest in base order. Unknown keys are
64
+ * ignored, so an order never moves an item across anchors.
65
+ */
66
+ export declare function orderItems(items: UiContributionItem[], entry: UiArrangementEntry): UiContributionItem[];
67
+ /** {@link orderItems} without the hidden keys. */
68
+ export declare function arrange(items: UiContributionItem[], entry: UiArrangementEntry): UiContributionItem[];
69
+ /**
70
+ * Applies the per-slot entries to a mixed list: each slot's items are arranged and written back
71
+ * into the positions that slot occupied (a slot without an entry: its base order, grouped by
72
+ * anchor).
73
+ */
74
+ export declare function arrangeBySlot(items: UiContributionItem[], entryOf: (slot: UiSlotId) => UiArrangementEntry): UiContributionItem[];
@@ -0,0 +1,98 @@
1
+ import { UI_ARRANGEABLE_SLOTS, UI_CONTRIBUTION_KEY_RE, uiSlot, } from "@capybara-hq/plugin-sdk";
2
+ import { z } from "zod";
3
+ /**
4
+ * Arrangement of UI slots (UI slots spec §5): per slot, which contributions are hidden and in
5
+ * which order. "Hidden" means not listed: the access gate never reads an arrangement, so a hidden
6
+ * contribution's view, action and embed routes keep working for an allowed role.
7
+ */
8
+ const Key = z.string().regex(UI_CONTRIBUTION_KEY_RE);
9
+ const LIST_MAX = 200;
10
+ export const UiArrangementEntrySchema = z
11
+ .object({ hidden: z.array(Key).max(LIST_MAX), order: z.array(Key).max(LIST_MAX) })
12
+ .strict();
13
+ export const UiArrangementSchema = z.partialRecord(z.enum(UI_ARRANGEABLE_SLOTS), UiArrangementEntrySchema);
14
+ /** The slots an org arranges: every arrangeable slot but the platform's own. */
15
+ export const ORG_ARRANGEABLE = UI_ARRANGEABLE_SLOTS.filter((s) => s !== "platform.page");
16
+ /** An org's patch: a slot's entry replaces the stored one, null removes it. */
17
+ export const OrgUiArrangementPatchSchema = z.partialRecord(z.enum(ORG_ARRANGEABLE), UiArrangementEntrySchema.nullable());
18
+ /** A deployment patch: like {@link OrgUiArrangementPatchSchema} over every arrangeable slot. */
19
+ export const UiArrangementPatchSchema = z.partialRecord(z.enum(UI_ARRANGEABLE_SLOTS), UiArrangementEntrySchema.nullable());
20
+ /** Merges a per-slot patch into the stored arrangement (null removes the slot's entry). */
21
+ export function mergeArrangement(current, patch) {
22
+ const merged = { ...current };
23
+ for (const [slot, entry] of Object.entries(patch)) {
24
+ if (entry === null)
25
+ delete merged[slot];
26
+ else if (entry !== undefined)
27
+ merged[slot] = entry;
28
+ }
29
+ return merged;
30
+ }
31
+ const NONE = { hidden: [], order: [] };
32
+ /** The entry that applies to a slot: the org's if it arranged the slot, else the platform's. */
33
+ export function effectiveEntry(org, platform, slot) {
34
+ const o = org?.[slot];
35
+ if (o !== undefined)
36
+ return { entry: o, source: "org" };
37
+ const p = platform[slot];
38
+ if (p !== undefined)
39
+ return { entry: p, source: "platform" };
40
+ return { entry: NONE, source: "none" };
41
+ }
42
+ const keyOf = (i) => `${i.plugin}/${i.id}`;
43
+ /**
44
+ * Orders the items of one slot (hidden ones stay in place): grouped by anchor in the slot's anchor
45
+ * order, also without an entry (the lists match what the page renders per anchor); within a group
46
+ * the keys of `entry.order` come first in that order, the rest in base order. Unknown keys are
47
+ * ignored, so an order never moves an item across anchors.
48
+ */
49
+ export function orderItems(items, entry) {
50
+ const anchors = items[0] === undefined ? undefined : uiSlot(items[0].slot)?.anchors;
51
+ const groupOf = (i) => anchors === undefined ? 0 : Math.max(0, anchors.indexOf(i.after ?? anchors[0] ?? ""));
52
+ const rank = new Map(entry.order.map((k, n) => [k, n]));
53
+ return items
54
+ .map((item, base) => ({ item, base }))
55
+ .sort((a, b) => {
56
+ const g = groupOf(a.item) - groupOf(b.item);
57
+ if (g !== 0)
58
+ return g;
59
+ const ra = rank.get(keyOf(a.item));
60
+ const rb = rank.get(keyOf(b.item));
61
+ if (ra !== undefined && rb !== undefined)
62
+ return ra - rb;
63
+ if (ra !== undefined)
64
+ return -1;
65
+ if (rb !== undefined)
66
+ return 1;
67
+ return a.base - b.base;
68
+ })
69
+ .map((x) => x.item);
70
+ }
71
+ /** {@link orderItems} without the hidden keys. */
72
+ export function arrange(items, entry) {
73
+ const hidden = new Set(entry.hidden);
74
+ return orderItems(items, entry).filter((i) => !hidden.has(keyOf(i)));
75
+ }
76
+ /**
77
+ * Applies the per-slot entries to a mixed list: each slot's items are arranged and written back
78
+ * into the positions that slot occupied (a slot without an entry: its base order, grouped by
79
+ * anchor).
80
+ */
81
+ export function arrangeBySlot(items, entryOf) {
82
+ const bySlot = new Map();
83
+ items.forEach((i, n) => {
84
+ const at = bySlot.get(i.slot);
85
+ if (at)
86
+ at.push(n);
87
+ else
88
+ bySlot.set(i.slot, [n]);
89
+ });
90
+ const out = [...items];
91
+ for (const [slot, at] of bySlot) {
92
+ const arranged = arrange(at.map((n) => items[n]), entryOf(slot));
93
+ at.forEach((n, j) => {
94
+ out[n] = arranged[j];
95
+ });
96
+ }
97
+ return out.filter((i) => i !== undefined);
98
+ }
@@ -1,4 +1,4 @@
1
- import type { EmbedClaims } from "@capybara-hq/plugin-sdk";
1
+ import type { EmbedClaims, OrgEmbedClaims, PlatformEmbedClaims } from "@capybara-hq/plugin-sdk";
2
2
  import type { Keyring } from "../ctx/secrets.js";
3
3
  /** 嵌入令牌的有效期(秒)。网页在过期前 60 秒续期。 */
4
4
  export declare const EMBED_TOKEN_TTL_SECONDS = 300;
@@ -22,7 +22,7 @@ export declare class EmbedTokens {
22
22
  private readonly keys;
23
23
  constructor(keyring: Keyring, now?: () => number);
24
24
  /** 签发:`exp` = 现在 + {@link EMBED_TOKEN_TTL_SECONDS}。 */
25
- issue(c: Omit<EmbedClaims, "exp">): {
25
+ issue(c: Omit<OrgEmbedClaims, "exp"> | Omit<PlatformEmbedClaims, "exp">): {
26
26
  token: string;
27
27
  claims: EmbedClaims;
28
28
  expiresAt: Date;