@capybara-hq/kernel 0.1.0-rc.11 → 0.1.0-rc.13

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 (220) 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/agents/agents.schemas.d.ts +3 -0
  5. package/dist/agents/agents.service.js +11 -1
  6. package/dist/agents/definition.d.ts +1 -0
  7. package/dist/agents/definition.js +7 -3
  8. package/dist/agents/org-templates.js +4 -0
  9. package/dist/agents/pending-connectors.service.js +1 -1
  10. package/dist/background/background.module.js +2 -2
  11. package/dist/background/launch-lock.d.ts +1 -1
  12. package/dist/background/launch-lock.js +1 -1
  13. package/dist/background/poll.job.d.ts +2 -2
  14. package/dist/background/poll.job.js +10 -10
  15. package/dist/background/stop.d.ts +1 -1
  16. package/dist/background/stop.js +3 -3
  17. package/dist/background/store.d.ts +5 -5
  18. package/dist/background/store.js +5 -5
  19. package/dist/background/tasks.service.d.ts +6 -6
  20. package/dist/background/tasks.service.js +13 -13
  21. package/dist/catalog/component-scope.controller.d.ts +18 -6
  22. package/dist/catalog/component-scope.controller.js +36 -13
  23. package/dist/catalog/component-scope.service.d.ts +11 -0
  24. package/dist/catalog/component-scope.service.js +4 -0
  25. package/dist/catalog/component-state.d.ts +8 -0
  26. package/dist/catalog/component-state.js +19 -11
  27. package/dist/catalog/marketplaces.service.d.ts +1 -1
  28. package/dist/catalog/plugin-import.js +4 -1
  29. package/dist/channels/channels.module.js +2 -2
  30. package/dist/channels/inbound.d.ts +8 -8
  31. package/dist/channels/inbound.js +31 -31
  32. package/dist/channels/phrases.d.ts +27 -27
  33. package/dist/channels/phrases.js +27 -27
  34. package/dist/config/docs.js +1 -1
  35. package/dist/config/schema.d.ts +2 -2
  36. package/dist/config/schema.js +21 -21
  37. package/dist/conversations/conversations.controller.d.ts +11 -11
  38. package/dist/conversations/conversations.controller.js +15 -15
  39. package/dist/conversations/conversations.module.d.ts +1 -1
  40. package/dist/conversations/conversations.module.js +7 -7
  41. package/dist/conversations/conversations.schemas.js +1 -1
  42. package/dist/conversations/conversations.service.d.ts +23 -14
  43. package/dist/conversations/conversations.service.js +28 -21
  44. package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
  45. package/dist/conversations/{environment-status.js → device-status.js} +18 -18
  46. package/dist/conversations/event-log.d.ts +1 -1
  47. package/dist/conversations/event-log.js +1 -1
  48. package/dist/conversations/events.d.ts +2 -1
  49. package/dist/conversations/events.js +2 -2
  50. package/dist/ctx/create-ctx.d.ts +10 -1
  51. package/dist/ctx/create-ctx.js +86 -25
  52. package/dist/db/kernel-schema.d.ts +39 -23
  53. package/dist/{environments → devices}/access.d.ts +19 -19
  54. package/dist/{environments → devices}/access.js +28 -28
  55. package/dist/devices/conversation-devices.d.ts +75 -0
  56. package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
  57. package/dist/devices/devices.controller.d.ts +36 -0
  58. package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
  59. package/dist/devices/devices.module.d.ts +5 -13
  60. package/dist/devices/devices.module.js +16 -29
  61. package/dist/devices/devices.schemas.d.ts +3 -0
  62. package/dist/devices/devices.schemas.js +14 -0
  63. package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
  64. package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
  65. package/dist/devices/dto.d.ts +13 -54
  66. package/dist/devices/dto.js +7 -39
  67. package/dist/devices/label.d.ts +11 -0
  68. package/dist/{environments → devices}/label.js +7 -7
  69. package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
  70. package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
  71. package/dist/errors.d.ts +27 -25
  72. package/dist/errors.js +27 -25
  73. package/dist/evals/recorded-tools.d.ts +2 -2
  74. package/dist/evals/recorded-tools.js +6 -6
  75. package/dist/extensions/admin-ops.js +1 -0
  76. package/dist/extensions/admin-view.js +2 -0
  77. package/dist/extensions/effective-config.d.ts +6 -0
  78. package/dist/extensions/effective-config.js +18 -7
  79. package/dist/extensions/host.d.ts +13 -2
  80. package/dist/extensions/host.js +24 -3
  81. package/dist/extensions/instance.d.ts +12 -1
  82. package/dist/extensions/instance.js +13 -0
  83. package/dist/extensions/permission-view.d.ts +10 -1
  84. package/dist/files/previewers.d.ts +1 -1
  85. package/dist/files/previewers.js +1 -1
  86. package/dist/http/api.module.js +10 -6
  87. package/dist/http/gateway-routes.d.ts +1 -1
  88. package/dist/http/gateway-routes.js +1 -1
  89. package/dist/identity/settings.d.ts +32 -0
  90. package/dist/identity/settings.js +26 -2
  91. package/dist/infra/config/kernel-config.service.js +4 -4
  92. package/dist/kernel.module.js +3 -3
  93. package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
  94. package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
  95. package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
  96. package/dist/{devices → local-devices}/device-auth.js +51 -53
  97. package/dist/local-devices/device-auth.module.d.ts +7 -0
  98. package/dist/{devices → local-devices}/device-auth.module.js +5 -5
  99. package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
  100. package/dist/{devices → local-devices}/device-routes.js +2 -2
  101. package/dist/local-devices/dto.d.ts +66 -0
  102. package/dist/local-devices/dto.js +44 -0
  103. package/dist/{devices → local-devices}/keys.d.ts +11 -11
  104. package/dist/{devices → local-devices}/keys.js +11 -11
  105. package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
  106. package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
  107. package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
  108. package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
  109. package/dist/local-devices/local-devices.module.d.ts +16 -0
  110. package/dist/local-devices/local-devices.module.js +44 -0
  111. package/dist/{devices → local-devices}/machines.d.ts +26 -26
  112. package/dist/{devices → local-devices}/machines.js +71 -71
  113. package/dist/{devices → local-devices}/relay.d.ts +15 -15
  114. package/dist/{devices → local-devices}/relay.js +55 -55
  115. package/dist/{devices → local-devices}/targets.d.ts +8 -8
  116. package/dist/{devices → local-devices}/targets.js +14 -14
  117. package/dist/orgs/offboarding.d.ts +6 -6
  118. package/dist/orgs/offboarding.js +12 -12
  119. package/dist/orgs/settings.service.d.ts +28 -0
  120. package/dist/orgs/settings.service.js +20 -1
  121. package/dist/platform/exclusions.js +48 -3
  122. package/dist/platform/operation.js +6 -2
  123. package/dist/platform/ops/admin.ops.js +8 -2
  124. package/dist/platform/ops/agents.ops.js +19 -6
  125. package/dist/platform/ops/conversations.ops.d.ts +3 -3
  126. package/dist/platform/ops/conversations.ops.js +9 -9
  127. package/dist/platform/ops/devices.ops.d.ts +26 -0
  128. package/dist/platform/ops/devices.ops.js +311 -0
  129. package/dist/platform/ops/org-settings.ops.js +2 -2
  130. package/dist/platform/ops/orgs.ops.js +1 -0
  131. package/dist/platform/ops/ui.ops.d.ts +8 -0
  132. package/dist/platform/ops/ui.ops.js +41 -0
  133. package/dist/platform/platform-ops.module.d.ts +3 -2
  134. package/dist/platform/platform-ops.module.js +8 -5
  135. package/dist/platform/route-schemas.js +6 -3
  136. package/dist/roles/gateway-role.d.ts +3 -3
  137. package/dist/roles/gateway-role.js +4 -4
  138. package/dist/roles/gateway.module.d.ts +1 -1
  139. package/dist/roles/gateway.module.js +5 -5
  140. package/dist/roles/worker.module.js +1 -1
  141. package/dist/runtime/context/build.d.ts +1 -1
  142. package/dist/runtime/context/build.js +6 -6
  143. package/dist/runtime/context/compaction.js +1 -1
  144. package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
  145. package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
  146. package/dist/runtime/maintenance.d.ts +1 -1
  147. package/dist/runtime/subagents/definition.d.ts +3 -2
  148. package/dist/runtime/subagents/definition.js +2 -1
  149. package/dist/sandbox/jobs.d.ts +13 -13
  150. package/dist/sandbox/jobs.js +20 -20
  151. package/dist/sandbox/leases.d.ts +9 -9
  152. package/dist/sandbox/leases.js +14 -14
  153. package/dist/sandbox/providers.d.ts +8 -8
  154. package/dist/sandbox/providers.js +8 -8
  155. package/dist/sandbox/sandbox.module.d.ts +1 -1
  156. package/dist/sandbox/sandbox.module.js +1 -1
  157. package/dist/sandbox/sandbox.service.d.ts +76 -76
  158. package/dist/sandbox/sandbox.service.js +230 -230
  159. package/dist/tools/builtins/builtin-tools.d.ts +2 -2
  160. package/dist/tools/builtins/builtin-tools.js +5 -5
  161. package/dist/tools/builtins/platform.js +1 -1
  162. package/dist/tools/builtins/sandbox/bash.js +6 -6
  163. package/dist/tools/builtins/sandbox/common.d.ts +25 -25
  164. package/dist/tools/builtins/sandbox/common.js +51 -51
  165. package/dist/tools/builtins/sandbox/edit.js +2 -2
  166. package/dist/tools/builtins/sandbox/index.d.ts +1 -1
  167. package/dist/tools/builtins/sandbox/index.js +1 -1
  168. package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
  169. package/dist/tools/builtins/sandbox/task-output.js +10 -10
  170. package/dist/tools/builtins/sandbox/task-stop.js +2 -2
  171. package/dist/tools/builtins/sandbox/write.js +2 -2
  172. package/dist/tools/builtins/skill-load.d.ts +1 -1
  173. package/dist/tools/builtins/skill-load.js +2 -2
  174. package/dist/tools/connector-account-policies.d.ts +51 -0
  175. package/dist/tools/connector-account-policies.js +165 -0
  176. package/dist/tools/connectors.controller.d.ts +35 -4
  177. package/dist/tools/connectors.controller.js +66 -7
  178. package/dist/tools/connectors.schemas.d.ts +11 -0
  179. package/dist/tools/connectors.schemas.js +11 -0
  180. package/dist/tools/connectors.service.d.ts +2 -0
  181. package/dist/tools/connectors.service.js +1 -0
  182. package/dist/tools/pipeline.d.ts +1 -1
  183. package/dist/tools/pipeline.js +4 -3
  184. package/dist/tools/policy.d.ts +23 -1
  185. package/dist/tools/policy.js +99 -24
  186. package/dist/tools/registry.d.ts +2 -2
  187. package/dist/tools/tools.module.js +6 -3
  188. package/dist/ui/admin-ui.controller.d.ts +56 -0
  189. package/dist/ui/admin-ui.controller.js +192 -0
  190. package/dist/ui/arrangement.d.ts +74 -0
  191. package/dist/ui/arrangement.js +98 -0
  192. package/dist/ui/embed-token.d.ts +2 -2
  193. package/dist/ui/embed-token.js +30 -5
  194. package/dist/ui/registry.d.ts +29 -14
  195. package/dist/ui/registry.js +31 -10
  196. package/dist/ui/slots.controller.d.ts +11 -0
  197. package/dist/ui/slots.controller.js +25 -0
  198. package/dist/ui/ui-stream.d.ts +20 -3
  199. package/dist/ui/ui-stream.js +25 -7
  200. package/dist/ui/ui.schemas.d.ts +66 -0
  201. package/dist/ui/ui.schemas.js +65 -0
  202. package/dist/ui/views.controller.d.ts +35 -49
  203. package/dist/ui/views.controller.js +48 -70
  204. package/dist/ui/views.d.ts +84 -18
  205. package/dist/ui/views.js +201 -38
  206. package/package.json +3 -3
  207. package/src/migrations/0104_connector_tool_account_policies.sql +16 -0
  208. package/src/migrations/0105_devices_rename.sql +136 -0
  209. package/dist/devices/device-auth.module.d.ts +0 -7
  210. package/dist/environments/conversation-environments.d.ts +0 -75
  211. package/dist/environments/dto.d.ts +0 -25
  212. package/dist/environments/dto.js +0 -12
  213. package/dist/environments/environments.controller.d.ts +0 -36
  214. package/dist/environments/environments.module.d.ts +0 -8
  215. package/dist/environments/environments.module.js +0 -31
  216. package/dist/environments/environments.schemas.d.ts +0 -3
  217. package/dist/environments/environments.schemas.js +0 -14
  218. package/dist/environments/label.d.ts +0 -11
  219. package/dist/platform/ops/environments.ops.d.ts +0 -26
  220. package/dist/platform/ops/environments.ops.js +0 -311
@@ -13,7 +13,7 @@ import { sql } from "kysely";
13
13
  import { AgentLookup, visibleTo } from "../agents/agent-lookup.js";
14
14
  import { BackgroundTaskStopper } from "../background/stop.js";
15
15
  import { unbindConversation } from "../channels/threads.js";
16
- import { ConversationEnvironments, } from "../environments/conversation-environments.js";
16
+ import { ConversationDevices, } from "../devices/conversation-devices.js";
17
17
  import { ApiError } from "../errors.js";
18
18
  import { KernelDb } from "../infra/database/kernel-db.js";
19
19
  import { TransactionHost } from "../infra/database/transaction-host.js";
@@ -69,7 +69,7 @@ const COLUMNS = [
69
69
  "parent_conversation_id",
70
70
  "subagent_type",
71
71
  "archived_at",
72
- "environment_id",
72
+ "device_id",
73
73
  ];
74
74
  function toView(r) {
75
75
  return {
@@ -86,7 +86,7 @@ function toView(r) {
86
86
  parentConversationId: r.parent_conversation_id,
87
87
  subagentType: r.subagent_type,
88
88
  archivedAt: r.archived_at,
89
- environmentId: r.environment_id,
89
+ deviceId: r.device_id,
90
90
  activity: r.activity ?? null,
91
91
  };
92
92
  }
@@ -129,7 +129,7 @@ let ConversationsService = class ConversationsService {
129
129
  attachments;
130
130
  invoker;
131
131
  background;
132
- environments;
132
+ devices;
133
133
  txHost;
134
134
  constructor(db, eventLog, agents, access,
135
135
  /** Starts and stops the conversation's runs. */
@@ -144,8 +144,8 @@ let ConversationsService = class ConversationsService {
144
144
  invoker,
145
145
  /** Stops a deleted conversation's background tasks. */
146
146
  background,
147
- /** The environment a new conversation is bound to (environments spec §4.1 item 1). */
148
- environments, txHost) {
147
+ /** The device a new conversation is bound to (environments spec §4.1 item 1). */
148
+ devices, txHost) {
149
149
  this.db = db;
150
150
  this.eventLog = eventLog;
151
151
  this.agents = agents;
@@ -157,7 +157,7 @@ let ConversationsService = class ConversationsService {
157
157
  this.attachments = attachments;
158
158
  this.invoker = invoker;
159
159
  this.background = background;
160
- this.environments = environments;
160
+ this.devices = devices;
161
161
  this.txHost = txHost;
162
162
  }
163
163
  /**
@@ -170,14 +170,14 @@ let ConversationsService = class ConversationsService {
170
170
  .catch((err) => this.log.warn("ensureRun on conversation open failed", { conversationId, err }));
171
171
  }
172
172
  /**
173
- * Creates an empty conversation bound to its environment (`pick`, see
174
- * {@link ConversationEnvironments.forNew}); an agent the account cannot use →
175
- * `agent.not_found`, an environment it may not use → `environment.not_found` /
176
- * `environment.unavailable`, and nothing is created.
173
+ * Creates an empty conversation bound to its device (`pick`, see
174
+ * {@link ConversationDevices.forNew}); an agent the account cannot use →
175
+ * `agent.not_found`, a device it may not use → `device.not_found` /
176
+ * `device.unavailable`, and nothing is created.
177
177
  */
178
178
  async create(orgId, accountId, agentId, pick = {}) {
179
179
  await this.agents.get(orgId, agentId, accountId);
180
- const environmentId = await this.environments.forNew(orgId, accountId, pick);
180
+ const deviceId = await this.devices.forNew(orgId, accountId, pick);
181
181
  const row = await this.db
182
182
  .insertInto("conversations")
183
183
  .values({
@@ -185,7 +185,7 @@ let ConversationsService = class ConversationsService {
185
185
  org_id: orgId,
186
186
  agent_id: agentId,
187
187
  account_id: accountId,
188
- environment_id: environmentId,
188
+ device_id: deviceId,
189
189
  })
190
190
  .returning(COLUMNS)
191
191
  .executeTakeFirstOrThrow();
@@ -205,12 +205,12 @@ let ConversationsService = class ConversationsService {
205
205
  const prior = await this.findCreated(orgId, accountId, agentId, input.clientMessageId);
206
206
  if (prior)
207
207
  return prior;
208
- const environmentId = await this.environments.forNew(orgId, accountId, pick);
208
+ const deviceId = await this.devices.forNew(orgId, accountId, pick);
209
209
  const next = await this.planSwitch(orgId, agent.definition, NO_SELECTION, input);
210
210
  const extra = await this.resolveExtra(orgId, accountId, input);
211
211
  const invoked = await this.prepareSkill(orgId, agentId, undefined, agent.definition, input);
212
212
  const id = randomUUID();
213
- const all = await this.createIn({ id, orgId, accountId, agentId, environmentId }, input, next, extra, invoked);
213
+ const all = await this.createIn({ id, orgId, accountId, agentId, deviceId }, input, next, extra, invoked);
214
214
  const written = all?.at(-1);
215
215
  if (!all || !written) {
216
216
  const raced = await this.findCreated(orgId, accountId, agentId, input.clientMessageId);
@@ -233,7 +233,7 @@ let ConversationsService = class ConversationsService {
233
233
  org_id: orgId,
234
234
  agent_id: conv.agentId,
235
235
  account_id: accountId,
236
- environment_id: conv.environmentId,
236
+ device_id: conv.deviceId,
237
237
  create_request_id: input.clientMessageId,
238
238
  })
239
239
  .onConflict((oc) => oc
@@ -482,16 +482,16 @@ let ConversationsService = class ConversationsService {
482
482
  LIMIT ${opts.limit + 1}
483
483
  )
484
484
  SELECT page.agent_id, page.latest_at, v.definition ->> 'name' AS agent_name,
485
- cs.id, cs.org_id, cs.account_id, cs.title, cs.title_source, cs.selection, cs.last_seq,
485
+ a.profile_avatar, a.profile_updated_at, cs.id, cs.org_id, cs.account_id, cs.title, cs.title_source, cs.selection, cs.last_seq,
486
486
  cs.created_at, cs.updated_at, cs.parent_conversation_id, cs.subagent_type,
487
- cs.archived_at, cs.environment_id, cs.activity
487
+ cs.archived_at, cs.device_id, cs.activity
488
488
  FROM page
489
489
  JOIN capybara.agents a ON a.id = page.agent_id
490
490
  JOIN capybara.agent_versions v ON v.agent_id = a.id AND v.version = a.current_version
491
491
  CROSS JOIN LATERAL (
492
492
  SELECT c.id, c.org_id, c.account_id, c.title, c.title_source, c.selection, c.last_seq,
493
493
  c.created_at, c.updated_at, c.parent_conversation_id, c.subagent_type,
494
- c.archived_at, c.environment_id, ${activitySql("c")} AS activity
494
+ c.archived_at, c.device_id, ${activitySql("c")} AS activity
495
495
  FROM capybara.conversations c
496
496
  WHERE c.org_id = ${orgId} AND c.account_id = ${accountId} AND c.kind = 'chat'
497
497
  AND c.deleted_at IS NULL AND ${archivedFilter} ${searchFilter} ${stateFilter}
@@ -506,7 +506,14 @@ let ConversationsService = class ConversationsService {
506
506
  for (const r of rows) {
507
507
  if (current?.agent.id !== r.agent_id) {
508
508
  current = {
509
- agent: { id: r.agent_id, name: r.agent_name ?? "" },
509
+ agent: {
510
+ id: r.agent_id,
511
+ name: r.agent_name ?? "",
512
+ profile: {
513
+ avatar: r.profile_avatar,
514
+ updatedAt: r.profile_updated_at.toISOString(),
515
+ },
516
+ },
510
517
  latestAt: r.latest_at,
511
518
  conversations: [],
512
519
  more: false,
@@ -952,7 +959,7 @@ ConversationsService = __decorate([
952
959
  __param(8, Inject(AttachmentsService)),
953
960
  __param(9, Inject(SkillInvoker)),
954
961
  __param(10, Inject(BackgroundTaskStopper)),
955
- __param(11, Inject(ConversationEnvironments)),
962
+ __param(11, Inject(ConversationDevices)),
956
963
  __param(12, Inject(TransactionHost))
957
964
  ], ConversationsService);
958
965
  export { ConversationsService };
@@ -1,24 +1,24 @@
1
- import { EnvironmentsService, type EnvironmentView } from "../environments/environments.service.js";
1
+ import { DevicesService, type DeviceView } from "../devices/devices.service.js";
2
2
  import { KernelDb } from "../infra/database/kernel-db.js";
3
3
  import { ConversationAccess } from "./access.js";
4
4
  import { ConversationsService } from "./conversations.service.js";
5
5
  /**
6
- * The environment a conversation works in, for its page (environments spec §9: shown read only):
6
+ * The device a conversation works in, for its page (environments spec §9: shown read only):
7
7
  * a conversation the viewer may not see → `conversation.not_found`. A sub-agent shows its root
8
- * conversation's environment. Null while the conversation is unbound, or when its environment is
8
+ * conversation's device. Null while the conversation is unbound, or when its device is
9
9
  * deleted or no longer its owner's (its sandbox tools then fail).
10
10
  */
11
- export declare class ConversationEnvironmentStatus {
11
+ export declare class ConversationDeviceStatus {
12
12
  /** Who may see the conversation (the rule of its event stream). */
13
13
  private readonly access;
14
- /** The conversation whose environment it works in: a sub-agent's root, else itself. */
14
+ /** The conversation whose device it works in: a sub-agent's root, else itself. */
15
15
  private readonly conversations;
16
- private readonly environments;
16
+ private readonly devices;
17
17
  private readonly db;
18
18
  constructor(
19
19
  /** Who may see the conversation (the rule of its event stream). */
20
20
  access: Pick<ConversationAccess, "isAccessible">,
21
- /** The conversation whose environment it works in: a sub-agent's root, else itself. */
22
- conversations: Pick<ConversationsService, "sandboxConversationOf">, environments: Pick<EnvironmentsService, "get">, db: KernelDb);
23
- get(orgId: string, conversationId: string, viewerAccountId: string): Promise<EnvironmentView | null>;
21
+ /** The conversation whose device it works in: a sub-agent's root, else itself. */
22
+ conversations: Pick<ConversationsService, "sandboxConversationOf">, devices: Pick<DevicesService, "get">, db: KernelDb);
23
+ get(orgId: string, conversationId: string, viewerAccountId: string): Promise<DeviceView | null>;
24
24
  }
@@ -8,31 +8,31 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
10
  import { Inject, Injectable } from "@nestjs/common";
11
- import { EnvironmentsService } from "../environments/environments.service.js";
11
+ import { DevicesService } from "../devices/devices.service.js";
12
12
  import { ApiError } from "../errors.js";
13
13
  import { KernelDb } from "../infra/database/kernel-db.js";
14
14
  import { UUID_RE } from "../ui/registry.js";
15
15
  import { ConversationAccess } from "./access.js";
16
16
  import { ConversationsService } from "./conversations.service.js";
17
17
  /**
18
- * The environment a conversation works in, for its page (environments spec §9: shown read only):
18
+ * The device a conversation works in, for its page (environments spec §9: shown read only):
19
19
  * a conversation the viewer may not see → `conversation.not_found`. A sub-agent shows its root
20
- * conversation's environment. Null while the conversation is unbound, or when its environment is
20
+ * conversation's device. Null while the conversation is unbound, or when its device is
21
21
  * deleted or no longer its owner's (its sandbox tools then fail).
22
22
  */
23
- let ConversationEnvironmentStatus = class ConversationEnvironmentStatus {
23
+ let ConversationDeviceStatus = class ConversationDeviceStatus {
24
24
  access;
25
25
  conversations;
26
- environments;
26
+ devices;
27
27
  db;
28
28
  constructor(
29
29
  /** Who may see the conversation (the rule of its event stream). */
30
30
  access,
31
- /** The conversation whose environment it works in: a sub-agent's root, else itself. */
32
- conversations, environments, db) {
31
+ /** The conversation whose device it works in: a sub-agent's root, else itself. */
32
+ conversations, devices, db) {
33
33
  this.access = access;
34
34
  this.conversations = conversations;
35
- this.environments = environments;
35
+ this.devices = devices;
36
36
  this.db = db;
37
37
  }
38
38
  async get(orgId, conversationId, viewerAccountId) {
@@ -40,32 +40,32 @@ let ConversationEnvironmentStatus = class ConversationEnvironmentStatus {
40
40
  !(await this.access.isAccessible(orgId, conversationId, viewerAccountId))) {
41
41
  throw new ApiError("conversation.not_found", "Conversation not found");
42
42
  }
43
- // a sub-agent works in its root conversation's environment (at every depth)
43
+ // a sub-agent works in its root conversation's device (at every depth)
44
44
  const root = await this.conversations.sandboxConversationOf(orgId, conversationId);
45
45
  const conv = await this.db
46
46
  .selectFrom("conversations")
47
- .select(["account_id", "environment_id"])
47
+ .select(["account_id", "device_id"])
48
48
  .where("id", "=", root)
49
49
  .where("org_id", "=", orgId)
50
50
  .executeTakeFirst();
51
- if (!conv?.environment_id)
51
+ if (!conv?.device_id)
52
52
  return null;
53
53
  try {
54
- // the environment as its owner sees it (only the owner may use a personal environment)
55
- return await this.environments.get(orgId, conv.account_id, conv.environment_id);
54
+ // the device as its owner sees it (only the owner may use a personal device)
55
+ return await this.devices.get(orgId, conv.account_id, conv.device_id);
56
56
  }
57
57
  catch (e) {
58
- if (e instanceof ApiError && e.code === "environment.not_found")
58
+ if (e instanceof ApiError && e.code === "device.not_found")
59
59
  return null;
60
60
  throw e;
61
61
  }
62
62
  }
63
63
  };
64
- ConversationEnvironmentStatus = __decorate([
64
+ ConversationDeviceStatus = __decorate([
65
65
  Injectable(),
66
66
  __param(0, Inject(ConversationAccess)),
67
67
  __param(1, Inject(ConversationsService)),
68
- __param(2, Inject(EnvironmentsService)),
68
+ __param(2, Inject(DevicesService)),
69
69
  __param(3, Inject(KernelDb))
70
- ], ConversationEnvironmentStatus);
71
- export { ConversationEnvironmentStatus };
70
+ ], ConversationDeviceStatus);
71
+ export { ConversationDeviceStatus };
@@ -132,7 +132,7 @@ export declare class EventLog {
132
132
  findByIdem(conversationId: string, idemKey: string): Promise<ConversationEvent | undefined>;
133
133
  /**
134
134
  * The conversation's latest event of `type` (by seq); undefined without one. `skills_catalog`
135
- * (0025) and `environment_paths` (0094) have partial indexes that answer it directly; other
135
+ * (0025) and `device_paths` (0094) have partial indexes that answer it directly; other
136
136
  * types scan the conversation's events backwards on the (conversation_id, seq) key, the whole
137
137
  * conversation when it has none.
138
138
  */
@@ -246,7 +246,7 @@ let EventLog = class EventLog {
246
246
  }
247
247
  /**
248
248
  * The conversation's latest event of `type` (by seq); undefined without one. `skills_catalog`
249
- * (0025) and `environment_paths` (0094) have partial indexes that answer it directly; other
249
+ * (0025) and `device_paths` (0094) have partial indexes that answer it directly; other
250
250
  * types scan the conversation's events backwards on the (conversation_id, seq) key, the whole
251
251
  * conversation when it has none.
252
252
  */
@@ -516,7 +516,7 @@ export declare const ConversationEventSchema: z.ZodDiscriminatedUnion<[z.ZodObje
516
516
  removed: z.ZodArray<z.ZodString>;
517
517
  }, z.core.$strip>;
518
518
  }, z.core.$strip>, z.ZodObject<{
519
- type: z.ZodLiteral<"environment_paths">;
519
+ type: z.ZodLiteral<"device_paths">;
520
520
  payload: z.ZodObject<{
521
521
  roots: z.ZodObject<{
522
522
  workspace: z.ZodString;
@@ -809,6 +809,7 @@ export declare const ConversationEventSchema: z.ZodDiscriminatedUnion<[z.ZodObje
809
809
  deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
810
810
  }, z.core.$strict>>;
811
811
  toolPolicies: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodEnum<{
812
+ allow: "allow";
812
813
  ask: "ask";
813
814
  deny: "deny";
814
815
  }>>>;
@@ -447,10 +447,10 @@ export const ConversationEventSchema = z.discriminatedUnion("type", [
447
447
  * The directories of the instance a sandbox tool call entered, when they differ from the
448
448
  * defaults (environments spec §13.1: a connected machine's real paths). Written once per
449
449
  * conversation and roots, before that call's result. **Model-visible**: rendered at its position
450
- * as a system message (`environmentPathsText`); a summary covering it is followed by the latest
450
+ * as a system message (`devicePathsText`); a summary covering it is followed by the latest
451
451
  * one again.
452
452
  */
453
- ev("environment_paths", z.object({
453
+ ev("device_paths", z.object({
454
454
  roots: z.object({
455
455
  workspace: z.string().min(1).max(4096),
456
456
  skills: z.string().min(1).max(4096),
@@ -1,4 +1,4 @@
1
- import { type ExtensionContext, type ExtensionManifest, type ExtensionPointRef, type Logger, type ToolHandler, type ToolSpec } from "@capybara-hq/plugin-sdk";
1
+ import { type ExtensionContext, type ExtensionManifest, type ExtensionPointRef, type Logger, resolveUiSlots, type ToolHandler, type ToolSpec } from "@capybara-hq/plugin-sdk";
2
2
  import type { Redis } from "ioredis";
3
3
  import { Kysely } from "kysely";
4
4
  import { type RegisteredHook } from "../extensions/hooks.js";
@@ -72,8 +72,15 @@ export interface ExtensionPointAccess {
72
72
  * required bootstrap plugins, see `extensions/enabled.ts`), not cached.
73
73
  */
74
74
  export declare function queryEnabledPlugins(db: Kysely<any>, orgId: string): Promise<Set<string>>;
75
+ /**
76
+ * Whether the account is, right now, an active super admin (one query): what a platform embed
77
+ * token and the platform refresh stream re-check.
78
+ */
79
+ export declare function currentPlatformAccount(db: KernelDeps["db"], accountId: string): Promise<boolean>;
75
80
  /** 插件的 PG schema 名:`plugin_<name>`,name 中的 `-` 换成 `_`。 */
76
81
  export declare function pluginSchemaName(name: string): string;
82
+ /** What {@link resolveUiSlots} returns for a manifest. */
83
+ export type UiResolution = ReturnType<typeof resolveUiSlots>;
77
84
  /** 内核视角的插件 ctx:插件契约之外还带宿主要用的登记信息与关闭方法。 */
78
85
  export type KernelExtensionContext = ExtensionContext & {
79
86
  /** 本实例的登记账(C17):每次登记记一笔,撤销时逐项撤销。 */
@@ -92,6 +99,8 @@ export type KernelExtensionContext = ExtensionContext & {
92
99
  registeredTools: RegisteredTool[];
93
100
  /** Hooks registered through `ctx.hooks.on` (registration order). */
94
101
  registeredHooks: RegisteredHook[];
102
+ /** The manifest's `ui` resolved against the slot catalog once per load (UI slots spec §3.2). */
103
+ uiResolution: UiResolution;
95
104
  /** 经 `ctx.ui.view` 注册的视图(按贡献 id)。 */
96
105
  uiViews: ReadonlyMap<string, UiRender>;
97
106
  /** 经 `ctx.ui.action` 注册的动作处理函数(按贡献 id)。 */
@@ -1,4 +1,4 @@
1
- import { EXTENSION_POINTS, ExtensionPermissionError, ExtensionPointUnavailableError, FILE_PREVIEW_EXTENSION_POINT, OBJECT_STORE_EXTENSION_POINT, parseExtensionPoint, validateFilePreviewProvider, validateToolSpec, } from "@capybara-hq/plugin-sdk";
1
+ import { EXTENSION_POINTS, ExtensionPermissionError, ExtensionPointUnavailableError, FILE_PREVIEW_EXTENSION_POINT, OBJECT_STORE_EXTENSION_POINT, parseExtensionPoint, resolveUiSlots, validateFilePreviewProvider, validateToolSpec, } from "@capybara-hq/plugin-sdk";
2
2
  import { Command, ConnectionBuilder, ControlledTransactionBuilder, Kysely, TransactionBuilder, } from "kysely";
3
3
  import { conversationTopic } from "../conversations/event-log.js";
4
4
  import { kernelDb } from "../db/kernel-schema.js";
@@ -7,7 +7,7 @@ import { checkHookRegistration } from "../extensions/hooks.js";
7
7
  import { RegistrationLedger } from "../extensions/ledger.js";
8
8
  import { audit } from "../identity/audit.js";
9
9
  import { PrefixedStorage } from "../storage/storage.service.js";
10
- import { canUsePlace, orgUiTopic, PluginUiRegistration, } from "../ui/registry.js";
10
+ import { canUseSlot, orgUiTopic, PLATFORM_UI_TOPIC, PluginUiRegistration, } from "../ui/registry.js";
11
11
  import { createBus } from "./bus.js";
12
12
  import { createKv } from "./kv.js";
13
13
  import { createLock } from "./lock.js";
@@ -39,6 +39,20 @@ async function currentEmbedRole(db, plugin, orgId, accountId) {
39
39
  .executeTakeFirst();
40
40
  return row?.role;
41
41
  }
42
+ /**
43
+ * Whether the account is, right now, an active super admin (one query): what a platform embed
44
+ * token and the platform refresh stream re-check.
45
+ */
46
+ export async function currentPlatformAccount(db, accountId) {
47
+ const row = await kernelDb(db)
48
+ .selectFrom("accounts")
49
+ .select("accounts.id")
50
+ .where("accounts.id", "=", accountId)
51
+ .where("accounts.status", "=", "active")
52
+ .where("accounts.is_super_admin", "=", true)
53
+ .executeTakeFirst();
54
+ return row !== undefined;
55
+ }
42
56
  /** `ui.invalidate` 目标的一条查询:插件在该组织启用,且(带对话时)对话属于该组织。 */
43
57
  async function invalidateTargetOk(db, plugin, orgId, conversationId) {
44
58
  const k = kernelDb(db);
@@ -248,7 +262,10 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
248
262
  ]);
249
263
  const uiReg = new PluginUiRegistration(manifest, deny);
250
264
  const embedTokens = deps.embedTokens;
251
- const uiPlaces = new Map((manifest.ui ?? []).map((c) => [c.id, c.place]));
265
+ const uiResolution = resolveUiSlots(manifest.ui);
266
+ const uiSlots = new Map(uiResolution.resolved.map((r) => [r.contribution.id, r.slot]));
267
+ /** Ids of the extension's `platform.page` contributions (their invalidate takes no orgId). */
268
+ const platformUi = new Set([...uiSlots].filter(([, s]) => s.id === "platform.page").map(([id]) => id));
252
269
  /** 校验能力可取用(非 brokered、已在清单声明),返回其登记信息。 */
253
270
  const checkExtensionPoint = (ref) => {
254
271
  const capName = parseExtensionPoint(ref).name;
@@ -482,9 +499,15 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
482
499
  });
483
500
  },
484
501
  // 目标先核对(一条查询):插件在 orgId 启用;带对话时对话属于 orgId。不满足就只记 debug、不发
485
- // (插件拿着过期或别的组织的 id 调用不是错误,但不能借它往别的组织的流里发刷新)
502
+ // (插件拿着过期或别的组织的 id 调用不是错误,但不能借它往别的组织的流里发刷新)。A `platform.page`
503
+ // contribution takes no orgId and refreshes the platform stream (super admins only)
486
504
  async invalidate(target) {
487
- const t = uiReg.target(target);
505
+ const t = uiReg.target(target, platformUi);
506
+ const msg = { kind: "ui", plugin: name, contribution: t.contribution };
507
+ if (t.scope === "platform") {
508
+ await kernelBus.publish(PLATFORM_UI_TOPIC, msg);
509
+ return;
510
+ }
488
511
  if (!(await invalidateTargetOk(deps.db, name, t.orgId, t.conversationId))) {
489
512
  deps.log.debug?.("plugin ui invalidate ignored: plugin not enabled or conversation not in org", {
490
513
  plugin: name,
@@ -494,22 +517,33 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
494
517
  });
495
518
  return;
496
519
  }
497
- const msg = { kind: "ui", plugin: name, contribution: t.contribution };
498
520
  await kernelBus.publish(t.conversationId !== undefined
499
521
  ? conversationTopic(t.conversationId)
500
522
  : orgUiTopic(t.orgId), msg);
501
523
  },
502
524
  // 只认签给本插件、未过期、未篡改的令牌(见 ui/embed-token.ts);再用一条查询核对此刻:本插件仍在该组织
503
525
  // 启用、组织未删除、账号 active 且仍是成员(每次查 PG、不缓存:停用插件、离职、停用账号后已签出的令牌立即失效)。
504
- // 返回的 role 是此刻的角色;组织页面的令牌在调用者已降为 guest 时失效(A38)。其余一律 null
526
+ // 返回的 role 是此刻的角色;令牌在此刻的角色低于贡献所在位置的 minRole 时失效(A38, UI slots spec §7)。
527
+ // A platform token: the contribution is a `platform.page` and the account is still an active
528
+ // super admin. A token of one scope never verifies for the other's slots. 其余一律 null
505
529
  async verifyEmbedToken(token) {
506
530
  const claims = embedTokens.verify(token, name);
507
531
  if (claims === null)
508
532
  return null;
509
- const role = await currentEmbedRole(deps.db, name, claims.orgId, claims.accountId);
510
- if (role === undefined)
533
+ const slot = uiSlots.get(claims.contribution);
534
+ if (claims.scope === "platform") {
535
+ if (slot?.id !== "platform.page")
536
+ return null;
537
+ return (await currentPlatformAccount(deps.db, claims.accountId)) ? claims : null;
538
+ }
539
+ if (claims.scope !== "org" || claims.orgId === undefined)
511
540
  return null;
512
- if (!canUsePlace(uiPlaces.get(claims.contribution) ?? "page", role))
541
+ // the contribution's slot as loaded now: never `platform.page` through an org token, and the
542
+ // current role still meets the slot's minRole (a demoted caller's token stops working)
543
+ if (slot === undefined || slot.id === "platform.page")
544
+ return null;
545
+ const role = await currentEmbedRole(deps.db, name, claims.orgId, claims.accountId);
546
+ if (role === undefined || !canUseSlot(slot, role))
513
547
  return null;
514
548
  return { ...claims, role };
515
549
  },
@@ -521,14 +555,15 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
521
555
  if (provided.has(extensionPoint)) {
522
556
  throw new Error(`plugin ${name}: extension point ${extensionPoint} provided more than once`);
523
557
  }
524
- if (extensionPoint === FILE_PREVIEW_EXTENSION_POINT)
525
- checkFilePreviewProvider(manifest, impl);
526
- provided.set(extensionPoint, impl);
558
+ const served = extensionPoint === FILE_PREVIEW_EXTENSION_POINT
559
+ ? checkFilePreviewProvider(manifest, impl, uiResolution, deps.log)
560
+ : impl;
561
+ provided.set(extensionPoint, served);
527
562
  ledger.add({
528
563
  kind: "provide",
529
564
  key: extensionPoint,
530
565
  dispose: async () => {
531
- if (provided.get(extensionPoint) === impl)
566
+ if (provided.get(extensionPoint) === served)
532
567
  provided.delete(extensionPoint);
533
568
  },
534
569
  });
@@ -547,6 +582,7 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
547
582
  provided,
548
583
  registeredTools,
549
584
  registeredHooks,
585
+ uiResolution,
550
586
  uiViews: uiReg.views,
551
587
  uiActions: uiReg.actions,
552
588
  ledger,
@@ -601,21 +637,46 @@ export function createExtensionContext(deps, manifest, deploymentConfig, extensi
601
637
  /**
602
638
  * A `file-preview@1` provider must be valid when it is provided (setup fails otherwise): the shape
603
639
  * ({@link validateFilePreviewProvider}), and every `embed` names a ui contribution of this extension
604
- * with `kind: "embed"` and `place: "file-preview"`.
640
+ * with `kind: "embed"` that resolved to the slot `file.preview` (from `slot` or the deprecated
641
+ * `place`). A previewer whose embed names an embed contribution dropped at load (unknown slot or
642
+ * slot version, UI slots spec §3.2) is left out instead, with one warn per load: the returned
643
+ * provider is what the kernel serves.
605
644
  */
606
- function checkFilePreviewProvider(manifest, impl) {
645
+ function checkFilePreviewProvider(manifest, impl, ui, log) {
607
646
  const problems = validateFilePreviewProvider(impl);
608
- if (problems.length === 0) {
609
- const embeds = new Set((manifest.ui ?? [])
610
- .filter((c) => c.kind === "embed" && c.place === "file-preview")
611
- .map((c) => c.id));
612
- impl.previewers.forEach((p, i) => {
613
- if (p.embed !== undefined && !embeds.has(p.embed)) {
614
- problems.push(`previewers[${i}].embed "${p.embed}" is not a ui contribution { kind: "embed", place: "file-preview" }`);
615
- }
616
- });
647
+ if (problems.length > 0) {
648
+ throw new Error(`plugin ${manifest.name}: invalid ${FILE_PREVIEW_EXTENSION_POINT} provider: ${problems.join("; ")}`);
617
649
  }
650
+ const embeds = new Set(ui.resolved
651
+ .filter((r) => r.contribution.kind === "embed" && r.slot.id === "file.preview")
652
+ .map((r) => r.contribution.id));
653
+ const droppedEmbeds = new Map(ui.dropped
654
+ .filter((d) => manifest.ui?.some((c) => c.id === d.id && c.kind === "embed"))
655
+ .map((d) => [d.id, d]));
656
+ const provider = impl;
657
+ const kept = [];
658
+ const dropped = [];
659
+ provider.previewers.forEach((p, i) => {
660
+ if (p.embed === undefined || embeds.has(p.embed)) {
661
+ kept.push(p);
662
+ return;
663
+ }
664
+ const d = droppedEmbeds.get(p.embed);
665
+ if (d !== undefined) {
666
+ dropped.push({ previewer: p.id, embed: p.embed, ref: d.ref, reason: d.reason });
667
+ return;
668
+ }
669
+ problems.push(`previewers[${i}].embed "${p.embed}" is not a ui contribution { kind: "embed", slot: "file.preview" }`);
670
+ });
618
671
  if (problems.length > 0) {
619
672
  throw new Error(`plugin ${manifest.name}: invalid ${FILE_PREVIEW_EXTENSION_POINT} provider: ${problems.join("; ")}`);
620
673
  }
674
+ if (dropped.length === 0)
675
+ return impl;
676
+ log.warn("plugin file previewers dropped", {
677
+ plugin: manifest.name,
678
+ version: manifest.version,
679
+ previewers: dropped,
680
+ });
681
+ return { ...provider, previewers: kept };
621
682
  }