@capybara-hq/kernel 0.1.0-rc.12 → 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 (192) 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/marketplaces.service.d.ts +1 -1
  16. package/dist/channels/channels.module.js +2 -2
  17. package/dist/channels/inbound.d.ts +8 -8
  18. package/dist/channels/inbound.js +31 -31
  19. package/dist/channels/phrases.d.ts +27 -27
  20. package/dist/channels/phrases.js +27 -27
  21. package/dist/config/docs.js +1 -1
  22. package/dist/config/schema.d.ts +2 -2
  23. package/dist/config/schema.js +21 -21
  24. package/dist/conversations/conversations.controller.d.ts +11 -11
  25. package/dist/conversations/conversations.controller.js +15 -15
  26. package/dist/conversations/conversations.module.d.ts +1 -1
  27. package/dist/conversations/conversations.module.js +7 -7
  28. package/dist/conversations/conversations.schemas.js +1 -1
  29. package/dist/conversations/conversations.service.d.ts +14 -14
  30. package/dist/conversations/conversations.service.js +19 -19
  31. package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
  32. package/dist/conversations/{environment-status.js → device-status.js} +18 -18
  33. package/dist/conversations/event-log.d.ts +1 -1
  34. package/dist/conversations/event-log.js +1 -1
  35. package/dist/conversations/events.d.ts +1 -1
  36. package/dist/conversations/events.js +2 -2
  37. package/dist/ctx/create-ctx.d.ts +10 -1
  38. package/dist/ctx/create-ctx.js +86 -25
  39. package/dist/db/kernel-schema.d.ts +26 -23
  40. package/dist/{environments → devices}/access.d.ts +19 -19
  41. package/dist/{environments → devices}/access.js +28 -28
  42. package/dist/devices/conversation-devices.d.ts +75 -0
  43. package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
  44. package/dist/devices/devices.controller.d.ts +36 -0
  45. package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
  46. package/dist/devices/devices.module.d.ts +5 -13
  47. package/dist/devices/devices.module.js +16 -29
  48. package/dist/devices/devices.schemas.d.ts +3 -0
  49. package/dist/devices/devices.schemas.js +14 -0
  50. package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
  51. package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
  52. package/dist/devices/dto.d.ts +13 -54
  53. package/dist/devices/dto.js +7 -39
  54. package/dist/devices/label.d.ts +11 -0
  55. package/dist/{environments → devices}/label.js +7 -7
  56. package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
  57. package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
  58. package/dist/errors.d.ts +25 -25
  59. package/dist/errors.js +25 -25
  60. package/dist/evals/recorded-tools.d.ts +2 -2
  61. package/dist/evals/recorded-tools.js +6 -6
  62. package/dist/extensions/admin-ops.js +1 -0
  63. package/dist/extensions/admin-view.js +2 -0
  64. package/dist/extensions/effective-config.d.ts +6 -0
  65. package/dist/extensions/effective-config.js +18 -7
  66. package/dist/extensions/host.d.ts +13 -2
  67. package/dist/extensions/host.js +24 -3
  68. package/dist/extensions/instance.d.ts +12 -1
  69. package/dist/extensions/instance.js +13 -0
  70. package/dist/extensions/permission-view.d.ts +10 -1
  71. package/dist/files/previewers.d.ts +1 -1
  72. package/dist/files/previewers.js +1 -1
  73. package/dist/http/api.module.js +10 -6
  74. package/dist/http/gateway-routes.d.ts +1 -1
  75. package/dist/http/gateway-routes.js +1 -1
  76. package/dist/identity/settings.d.ts +32 -0
  77. package/dist/identity/settings.js +26 -2
  78. package/dist/infra/config/kernel-config.service.js +4 -4
  79. package/dist/kernel.module.js +3 -3
  80. package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
  81. package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
  82. package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
  83. package/dist/{devices → local-devices}/device-auth.js +51 -53
  84. package/dist/local-devices/device-auth.module.d.ts +7 -0
  85. package/dist/{devices → local-devices}/device-auth.module.js +5 -5
  86. package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
  87. package/dist/{devices → local-devices}/device-routes.js +2 -2
  88. package/dist/local-devices/dto.d.ts +66 -0
  89. package/dist/local-devices/dto.js +44 -0
  90. package/dist/{devices → local-devices}/keys.d.ts +11 -11
  91. package/dist/{devices → local-devices}/keys.js +11 -11
  92. package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
  93. package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
  94. package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
  95. package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
  96. package/dist/local-devices/local-devices.module.d.ts +16 -0
  97. package/dist/local-devices/local-devices.module.js +44 -0
  98. package/dist/{devices → local-devices}/machines.d.ts +26 -26
  99. package/dist/{devices → local-devices}/machines.js +71 -71
  100. package/dist/{devices → local-devices}/relay.d.ts +15 -15
  101. package/dist/{devices → local-devices}/relay.js +55 -55
  102. package/dist/{devices → local-devices}/targets.d.ts +8 -8
  103. package/dist/{devices → local-devices}/targets.js +14 -14
  104. package/dist/orgs/offboarding.d.ts +6 -6
  105. package/dist/orgs/offboarding.js +12 -12
  106. package/dist/orgs/settings.service.d.ts +28 -0
  107. package/dist/orgs/settings.service.js +20 -1
  108. package/dist/platform/exclusions.js +38 -3
  109. package/dist/platform/operation.js +6 -2
  110. package/dist/platform/ops/admin.ops.js +8 -2
  111. package/dist/platform/ops/conversations.ops.d.ts +3 -3
  112. package/dist/platform/ops/conversations.ops.js +9 -9
  113. package/dist/platform/ops/devices.ops.d.ts +26 -0
  114. package/dist/platform/ops/devices.ops.js +311 -0
  115. package/dist/platform/ops/org-settings.ops.js +2 -2
  116. package/dist/platform/ops/orgs.ops.js +1 -0
  117. package/dist/platform/ops/ui.ops.d.ts +8 -0
  118. package/dist/platform/ops/ui.ops.js +41 -0
  119. package/dist/platform/platform-ops.module.d.ts +3 -2
  120. package/dist/platform/platform-ops.module.js +8 -5
  121. package/dist/platform/route-schemas.js +6 -3
  122. package/dist/roles/gateway-role.d.ts +3 -3
  123. package/dist/roles/gateway-role.js +4 -4
  124. package/dist/roles/gateway.module.d.ts +1 -1
  125. package/dist/roles/gateway.module.js +5 -5
  126. package/dist/roles/worker.module.js +1 -1
  127. package/dist/runtime/context/build.d.ts +1 -1
  128. package/dist/runtime/context/build.js +6 -6
  129. package/dist/runtime/context/compaction.js +1 -1
  130. package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
  131. package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
  132. package/dist/runtime/maintenance.d.ts +1 -1
  133. package/dist/sandbox/jobs.d.ts +13 -13
  134. package/dist/sandbox/jobs.js +20 -20
  135. package/dist/sandbox/leases.d.ts +9 -9
  136. package/dist/sandbox/leases.js +14 -14
  137. package/dist/sandbox/providers.d.ts +8 -8
  138. package/dist/sandbox/providers.js +8 -8
  139. package/dist/sandbox/sandbox.module.d.ts +1 -1
  140. package/dist/sandbox/sandbox.module.js +1 -1
  141. package/dist/sandbox/sandbox.service.d.ts +76 -76
  142. package/dist/sandbox/sandbox.service.js +230 -230
  143. package/dist/tools/builtins/builtin-tools.d.ts +2 -2
  144. package/dist/tools/builtins/builtin-tools.js +5 -5
  145. package/dist/tools/builtins/platform.js +1 -1
  146. package/dist/tools/builtins/sandbox/bash.js +6 -6
  147. package/dist/tools/builtins/sandbox/common.d.ts +25 -25
  148. package/dist/tools/builtins/sandbox/common.js +51 -51
  149. package/dist/tools/builtins/sandbox/edit.js +2 -2
  150. package/dist/tools/builtins/sandbox/index.d.ts +1 -1
  151. package/dist/tools/builtins/sandbox/index.js +1 -1
  152. package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
  153. package/dist/tools/builtins/sandbox/task-output.js +10 -10
  154. package/dist/tools/builtins/sandbox/task-stop.js +2 -2
  155. package/dist/tools/builtins/sandbox/write.js +2 -2
  156. package/dist/tools/builtins/skill-load.d.ts +1 -1
  157. package/dist/tools/builtins/skill-load.js +2 -2
  158. package/dist/tools/pipeline.js +4 -3
  159. package/dist/tools/registry.d.ts +2 -2
  160. package/dist/tools/tools.module.js +3 -3
  161. package/dist/ui/admin-ui.controller.d.ts +56 -0
  162. package/dist/ui/admin-ui.controller.js +192 -0
  163. package/dist/ui/arrangement.d.ts +74 -0
  164. package/dist/ui/arrangement.js +98 -0
  165. package/dist/ui/embed-token.d.ts +2 -2
  166. package/dist/ui/embed-token.js +30 -5
  167. package/dist/ui/registry.d.ts +29 -14
  168. package/dist/ui/registry.js +31 -10
  169. package/dist/ui/slots.controller.d.ts +11 -0
  170. package/dist/ui/slots.controller.js +25 -0
  171. package/dist/ui/ui-stream.d.ts +20 -3
  172. package/dist/ui/ui-stream.js +25 -7
  173. package/dist/ui/ui.schemas.d.ts +66 -0
  174. package/dist/ui/ui.schemas.js +65 -0
  175. package/dist/ui/views.controller.d.ts +35 -49
  176. package/dist/ui/views.controller.js +48 -70
  177. package/dist/ui/views.d.ts +84 -18
  178. package/dist/ui/views.js +201 -38
  179. package/package.json +3 -3
  180. package/src/migrations/0105_devices_rename.sql +136 -0
  181. package/dist/devices/device-auth.module.d.ts +0 -7
  182. package/dist/environments/conversation-environments.d.ts +0 -75
  183. package/dist/environments/dto.d.ts +0 -25
  184. package/dist/environments/dto.js +0 -12
  185. package/dist/environments/environments.controller.d.ts +0 -36
  186. package/dist/environments/environments.module.d.ts +0 -8
  187. package/dist/environments/environments.module.js +0 -31
  188. package/dist/environments/environments.schemas.d.ts +0 -3
  189. package/dist/environments/environments.schemas.js +0 -14
  190. package/dist/environments/label.d.ts +0 -11
  191. package/dist/platform/ops/environments.ops.d.ts +0 -26
  192. package/dist/platform/ops/environments.ops.js +0 -311
@@ -1,13 +1,13 @@
1
- import type { ExtensionManifest, UiActionArgs, UiActionResult, UiContribution, UiRenderArgs, UiView } from "@capybara-hq/plugin-sdk";
1
+ import type { ExtensionManifest, UiActionArgs, UiActionResult, UiRenderArgs, UiSlotSpec, UiView } from "@capybara-hq/plugin-sdk";
2
2
  import { type OrgRole } from "../orgs/roles.js";
3
3
  /** 会话 id 的格式(UUID)。 */
4
4
  export declare const UUID_RE: RegExp;
5
- /** 组织页面(`place: "page"`)所需的最低角色(A38):guest 只用对话位置的贡献。 */
6
- export declare const PAGE_MIN_ROLE: OrgRole;
7
- /** Places on the conversation page (everything but an org page): they need a `conversationId`. */
8
- export declare const isConversationPlace: (place: UiContribution["place"]) => boolean;
9
- /** 该角色能否使用这个位置的贡献。 */
10
- export declare const canUsePlace: (place: UiContribution["place"], role: OrgRole) => boolean;
5
+ /**
6
+ * Whether an org role may use contributions in this slot (UI slots spec §7): never a `superAdmin`
7
+ * slot (`platform.page` is served only by the org-less platform routes), else the slot's
8
+ * `minRole`. The slot's scope rule (conversation, agent, file) is checked after this.
9
+ */
10
+ export declare function canUseSlot(slot: UiSlotSpec, role: OrgRole): boolean;
11
11
  /** 插件视图的 render 函数(`ctx.ui.view` 注册)。 */
12
12
  export type UiRender = (args: UiRenderArgs) => Promise<UiView>;
13
13
  /** 插件视图的动作处理函数(`ctx.ui.action` 注册)。 */
@@ -17,7 +17,22 @@ export type UiActionHandler = (args: UiActionArgs) => Promise<UiActionResult>;
17
17
  * 对话视图的刷新走会话主题 `conv.<id>`(与事件、增量共用),见 `conversationTopic`。
18
18
  */
19
19
  export declare const orgUiTopic: (orgId: string) => string;
20
- /** 界面刷新消息:`conv.<id>` 与 `org-ui.<orgId>` 上的 `{ kind: "ui", plugin, contribution }`。 */
20
+ /**
21
+ * The kernel bus topic of the platform refresh (namespace `kernel`): `ctx.ui.invalidate` of a
22
+ * `platform.page` contribution (no `orgId`), read by `GET /api/v1/admin/ui/stream`.
23
+ */
24
+ export declare const PLATFORM_UI_TOPIC = "platform-ui";
25
+ /** A checked `ui.invalidate` target: an org's (optionally one conversation's) or the platform's. */
26
+ export type UiInvalidateTarget = {
27
+ scope: "org";
28
+ orgId: string;
29
+ conversationId?: string;
30
+ contribution: string;
31
+ } | {
32
+ scope: "platform";
33
+ contribution: string;
34
+ };
35
+ /** 界面刷新消息:`conv.<id>`、`org-ui.<orgId>` 与 `platform-ui` 上的 `{ kind: "ui", plugin, contribution }`。 */
21
36
  export interface UiBusMessage {
22
37
  kind: "ui";
23
38
  plugin: string;
@@ -48,11 +63,11 @@ export declare class PluginUiRegistration {
48
63
  seal(): void;
49
64
  view(id: string, render: UiRender): void;
50
65
  action(id: string, handler: UiActionHandler): void;
51
- /** 校验 invalidate 的目标,返回规范化后的 `{ orgId, conversationId?, contribution }`。 */
52
- target(t: unknown): {
53
- orgId: string;
54
- conversationId?: string;
55
- contribution: string;
56
- };
66
+ /**
67
+ * 校验 invalidate 的目标。A contribution in `platform` (the ids of the extension's `platform.page`
68
+ * contributions) takes no `orgId` and no `conversationId`; every other contribution needs an
69
+ * `orgId`.
70
+ */
71
+ target(t: unknown, platform: ReadonlySet<string>): UiInvalidateTarget;
57
72
  private register;
58
73
  }
@@ -1,17 +1,24 @@
1
1
  import { roleAtLeast } from "../orgs/roles.js";
2
2
  /** 会话 id 的格式(UUID)。 */
3
3
  export const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4
- /** 组织页面(`place: "page"`)所需的最低角色(A38):guest 只用对话位置的贡献。 */
5
- export const PAGE_MIN_ROLE = "member";
6
- /** Places on the conversation page (everything but an org page): they need a `conversationId`. */
7
- export const isConversationPlace = (place) => place !== "page";
8
- /** 该角色能否使用这个位置的贡献。 */
9
- export const canUsePlace = (place, role) => place !== "page" || roleAtLeast(role, PAGE_MIN_ROLE);
4
+ /**
5
+ * Whether an org role may use contributions in this slot (UI slots spec §7): never a `superAdmin`
6
+ * slot (`platform.page` is served only by the org-less platform routes), else the slot's
7
+ * `minRole`. The slot's scope rule (conversation, agent, file) is checked after this.
8
+ */
9
+ export function canUseSlot(slot, role) {
10
+ return slot.minRole !== "superAdmin" && roleAtLeast(role, slot.minRole);
11
+ }
10
12
  /**
11
13
  * 组织级界面刷新的内核 bus 主题(命名空间 `kernel`):`org-ui.<orgId>`。
12
14
  * 对话视图的刷新走会话主题 `conv.<id>`(与事件、增量共用),见 `conversationTopic`。
13
15
  */
14
16
  export const orgUiTopic = (orgId) => `org-ui.${orgId}`;
17
+ /**
18
+ * The kernel bus topic of the platform refresh (namespace `kernel`): `ctx.ui.invalidate` of a
19
+ * `platform.page` contribution (no `orgId`), read by `GET /api/v1/admin/ui/stream`.
20
+ */
21
+ export const PLATFORM_UI_TOPIC = "platform-ui";
15
22
  /** 是否为界面刷新消息(bus 上的消息来自其他副本,按形状核对)。 */
16
23
  export function isUiBusMessage(m) {
17
24
  if (typeof m !== "object" || m === null)
@@ -52,13 +59,15 @@ export class PluginUiRegistration {
52
59
  action(id, handler) {
53
60
  this.register("action", this.actions, id, handler);
54
61
  }
55
- /** 校验 invalidate 的目标,返回规范化后的 `{ orgId, conversationId?, contribution }`。 */
56
- target(t) {
62
+ /**
63
+ * 校验 invalidate 的目标。A contribution in `platform` (the ids of the extension's `platform.page`
64
+ * contributions) takes no `orgId` and no `conversationId`; every other contribution needs an
65
+ * `orgId`.
66
+ */
67
+ target(t, platform) {
57
68
  const name = this.manifest.name;
58
69
  const x = (typeof t === "object" && t !== null ? t : {});
59
70
  const id = (v) => typeof v === "string" && v !== "" && v.length <= 200;
60
- if (!id(x.orgId))
61
- throw new Error(`plugin ${name}: ui.invalidate needs a non-empty orgId`);
62
71
  if (x.conversationId !== undefined &&
63
72
  (typeof x.conversationId !== "string" || !UUID_RE.test(x.conversationId))) {
64
73
  throw new Error(`plugin ${name}: ui.invalidate conversationId must be a UUID`);
@@ -66,7 +75,19 @@ export class PluginUiRegistration {
66
75
  if (typeof x.contribution !== "string" || !this.contributions.has(x.contribution)) {
67
76
  throw new Error(`plugin ${name}: ui.invalidate: ${JSON.stringify(x.contribution)} is not a ui contribution in the manifest`);
68
77
  }
78
+ if (platform.has(x.contribution)) {
79
+ if (x.orgId !== undefined) {
80
+ throw new Error(`plugin ${name}: ui.invalidate: ${x.contribution} is a platform page; omit orgId`);
81
+ }
82
+ if (x.conversationId !== undefined) {
83
+ throw new Error(`plugin ${name}: ui.invalidate: ${x.contribution} is a platform page; omit conversationId`);
84
+ }
85
+ return { scope: "platform", contribution: x.contribution };
86
+ }
87
+ if (!id(x.orgId))
88
+ throw new Error(`plugin ${name}: ui.invalidate needs a non-empty orgId`);
69
89
  return {
90
+ scope: "org",
70
91
  orgId: x.orgId,
71
92
  ...(x.conversationId !== undefined && { conversationId: x.conversationId }),
72
93
  contribution: x.contribution,
@@ -0,0 +1,11 @@
1
+ import { type UiSlotSpec } from "@capybara-hq/plugin-sdk";
2
+ /**
3
+ * The slot catalog (UI slots spec §3): every slot an extension can contribute to, verbatim from
4
+ * the SDK. Static, so any signed-in person may read it; no org is involved.
5
+ */
6
+ export declare class SlotsController {
7
+ /** `GET /api/v1/ui/slots` → `{ slots }`. */
8
+ slots(): {
9
+ slots: readonly UiSlotSpec[];
10
+ };
11
+ }
@@ -0,0 +1,25 @@
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
+ import { UI_SLOTS } from "@capybara-hq/plugin-sdk";
8
+ import { Controller, Get } from "@nestjs/common";
9
+ /**
10
+ * The slot catalog (UI slots spec §3): every slot an extension can contribute to, verbatim from
11
+ * the SDK. Static, so any signed-in person may read it; no org is involved.
12
+ */
13
+ let SlotsController = class SlotsController {
14
+ /** `GET /api/v1/ui/slots` → `{ slots }`. */
15
+ slots() {
16
+ return { slots: UI_SLOTS };
17
+ }
18
+ };
19
+ __decorate([
20
+ Get("slots")
21
+ ], SlotsController.prototype, "slots", null);
22
+ SlotsController = __decorate([
23
+ Controller("api/v1/ui")
24
+ ], SlotsController);
25
+ export { SlotsController };
@@ -6,20 +6,37 @@ import { GracefulShutdown } from "../infra/lifecycle/graceful-shutdown.service.j
6
6
  import { type OrgRole } from "../orgs/roles.js";
7
7
  import { type SseOutput, type StreamBus, type StreamHandle } from "../runtime/stream.js";
8
8
  export interface OrgUiStreamParams {
9
+ scope?: "org";
9
10
  orgId: string;
10
11
  viewerAccountId: string;
11
12
  credential: CredentialCheck;
12
13
  }
14
+ /** The platform refresh stream (`GET /api/v1/admin/ui/stream`): a super admin's, no org. */
15
+ export interface PlatformUiStreamParams {
16
+ scope: "platform";
17
+ viewerAccountId: string;
18
+ credential: CredentialCheck;
19
+ }
20
+ export type UiStreamParams = OrgUiStreamParams | PlatformUiStreamParams;
13
21
  /** The org role the org UI stream re-checks. */
14
22
  export declare class UiStreamMembership {
15
23
  private readonly db;
16
24
  constructor(db: KernelDb);
17
25
  /** 组织成员角色(一条查询):组织未删除、账号 active、仍有成员关系。 */
18
26
  role(orgId: string, accountId: string): Promise<OrgRole | undefined>;
27
+ /** Whether the account is an active super admin (one query). */
28
+ superAdmin(accountId: string): Promise<boolean>;
19
29
  }
30
+ /**
31
+ * The org refresh stream is member and above (UI slots spec §7): it carries `org.page` and
32
+ * `org.settings.section` refreshes; an `agent.detail.section` a guest views refreshes on navigation.
33
+ */
34
+ export declare const ORG_STREAM_MIN_ROLE: OrgRole;
20
35
  /**
21
36
  * 组织级界面刷新流(SSE):订阅内核主题 `org-ui.<orgId>`,把插件 `ctx.ui.invalidate`(不带对话)的刷新
22
- * 转发为 `event: ui`(`data: {"plugin","contribution"}`)。跨副本只经 Redis bus;进程内只持有连接本身的资源
37
+ * 转发为 `event: ui`(`data: {"plugin","contribution"}`)。The platform variant subscribes
38
+ * `platform-ui` (`invalidate` of a `platform.page`, no org) for a super admin, re-checked on the
39
+ * same interval (losing super admin ends it with `event: error`, code `forbidden`).跨副本只经 Redis bus;进程内只持有连接本身的资源
23
40
  * (订阅、心跳与复核定时器),停机时一并关闭。
24
41
  */
25
42
  export declare class OrgUiStreams {
@@ -33,9 +50,9 @@ export declare class OrgUiStreams {
33
50
  * an event stream. Without `GracefulShutdown` (a standalone HTTP application, tests only) the
34
51
  * streams end with their connections.
35
52
  */
36
- constructor(bus: StreamBus, membership: Pick<UiStreamMembership, "role">, config: Pick<KernelConfigService, "get">, log: Pick<Logger, "warn">, shutdown?: Pick<GracefulShutdown, "signal">);
53
+ constructor(bus: StreamBus, membership: Pick<UiStreamMembership, "role" | "superAdmin">, config: Pick<KernelConfigService, "get">, log: Pick<Logger, "warn">, shutdown?: Pick<GracefulShutdown, "signal">);
37
54
  /** 复核凭据与成员关系并订阅;失败时尚未写响应,调用方按普通错误返回。 */
38
- open(p: OrgUiStreamParams, out: SseOutput): Promise<StreamHandle>;
55
+ open(p: UiStreamParams, out: SseOutput): Promise<StreamHandle>;
39
56
  /** Closes every stream of this process (at shutdown) and latches, like `ConversationStreams`. */
40
57
  closeAll(): void;
41
58
  get size(): number;
@@ -8,6 +8,7 @@ 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, Optional } from "@nestjs/common";
11
+ import { currentPlatformAccount } from "../ctx/create-ctx.js";
11
12
  import { ApiError } from "../errors.js";
12
13
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
13
14
  import { KernelDb } from "../infra/database/kernel-db.js";
@@ -15,7 +16,9 @@ import { GracefulShutdown } from "../infra/lifecycle/graceful-shutdown.service.j
15
16
  import { KERNEL_BUS, KERNEL_LOGGER } from "../infra/tokens.js";
16
17
  import { roleAtLeast } from "../orgs/roles.js";
17
18
  import { endedStream, } from "../runtime/stream.js";
18
- import { isUiBusMessage, orgUiTopic, PAGE_MIN_ROLE, uiFrame } from "./registry.js";
19
+ import { isUiBusMessage, orgUiTopic, PLATFORM_UI_TOPIC, uiFrame } from "./registry.js";
20
+ /** The log field naming the stream: its org, or the platform scope. */
21
+ const whereOf = (p) => p.scope === "platform" ? { scope: "platform" } : { orgId: p.orgId };
19
22
  /** The org role the org UI stream re-checks. */
20
23
  let UiStreamMembership = class UiStreamMembership {
21
24
  db;
@@ -36,26 +39,39 @@ let UiStreamMembership = class UiStreamMembership {
36
39
  .executeTakeFirst();
37
40
  return row?.role;
38
41
  }
42
+ /** Whether the account is an active super admin (one query). */
43
+ superAdmin(accountId) {
44
+ return currentPlatformAccount(this.db.db, accountId);
45
+ }
39
46
  };
40
47
  UiStreamMembership = __decorate([
41
48
  Injectable(),
42
49
  __param(0, Inject(KernelDb))
43
50
  ], UiStreamMembership);
44
51
  export { UiStreamMembership };
52
+ /**
53
+ * The org refresh stream is member and above (UI slots spec §7): it carries `org.page` and
54
+ * `org.settings.section` refreshes; an `agent.detail.section` a guest views refreshes on navigation.
55
+ */
56
+ export const ORG_STREAM_MIN_ROLE = "member";
45
57
  async function authorize(d, p) {
46
58
  const denied = await p.credential();
47
59
  if (denied !== null)
48
60
  return denied;
61
+ if (p.scope === "platform")
62
+ return (await d.superAdmin(p.viewerAccountId)) ? null : "forbidden";
49
63
  const role = await d.memberRole(p.orgId, p.viewerAccountId);
50
64
  if (role === undefined)
51
65
  return "org.not_found";
52
- return roleAtLeast(role, PAGE_MIN_ROLE) ? null : "ui.not_found";
66
+ return roleAtLeast(role, ORG_STREAM_MIN_ROLE) ? null : "ui.not_found";
53
67
  }
54
68
  /** 慢客户端的积压上限(刷新帧很小,超过即说明客户端不读了)。 */
55
69
  const MAX_BACKLOG_BYTES = 1024 * 1024;
56
70
  /**
57
71
  * 组织级界面刷新流(SSE):订阅内核主题 `org-ui.<orgId>`,把插件 `ctx.ui.invalidate`(不带对话)的刷新
58
- * 转发为 `event: ui`(`data: {"plugin","contribution"}`)。跨副本只经 Redis bus;进程内只持有连接本身的资源
72
+ * 转发为 `event: ui`(`data: {"plugin","contribution"}`)。The platform variant subscribes
73
+ * `platform-ui` (`invalidate` of a `platform.page`, no org) for a super admin, re-checked on the
74
+ * same interval (losing super admin ends it with `event: error`, code `forbidden`).跨副本只经 Redis bus;进程内只持有连接本身的资源
59
75
  * (订阅、心跳与复核定时器),停机时一并关闭。
60
76
  */
61
77
  let OrgUiStreams = class OrgUiStreams {
@@ -73,6 +89,7 @@ let OrgUiStreams = class OrgUiStreams {
73
89
  this.d = {
74
90
  bus,
75
91
  memberRole: (orgId, accountId) => membership.role(orgId, accountId),
92
+ superAdmin: (accountId) => membership.superAdmin(accountId),
76
93
  config,
77
94
  log,
78
95
  };
@@ -140,7 +157,8 @@ class OrgUiConnection {
140
157
  this.onClosed = onClosed;
141
158
  }
142
159
  async subscribe() {
143
- const un = await this.d.bus.subscribe(orgUiTopic(this.p.orgId), (m) => {
160
+ const topic = this.p.scope === "platform" ? PLATFORM_UI_TOPIC : orgUiTopic(this.p.orgId);
161
+ const un = await this.d.bus.subscribe(topic, (m) => {
144
162
  // begin() 之前(响应头还没写)到达的刷新丢掉:网页连上后会先取一次视图
145
163
  if (this.begun && isUiBusMessage(m))
146
164
  this.write(uiFrame(m));
@@ -166,7 +184,7 @@ class OrgUiConnection {
166
184
  this.timers = [];
167
185
  const un = this.unsubscribe;
168
186
  this.unsubscribe = undefined;
169
- un?.().catch((err) => this.d.log.warn("org ui stream unsubscribe failed", { orgId: this.p.orgId, err }));
187
+ un?.().catch((err) => this.d.log.warn("org ui stream unsubscribe failed", { ...whereOf(this.p), err }));
170
188
  if (this.begun) {
171
189
  try {
172
190
  if (mode === "abort")
@@ -191,7 +209,7 @@ class OrgUiConnection {
191
209
  return;
192
210
  }
193
211
  if (this.out.backlog() > MAX_BACKLOG_BYTES) {
194
- this.d.log.warn("org ui stream client too slow; closing", { orgId: this.p.orgId });
212
+ this.d.log.warn("org ui stream client too slow; closing", whereOf(this.p));
195
213
  this.close("abort");
196
214
  }
197
215
  }
@@ -206,7 +224,7 @@ class OrgUiConnection {
206
224
  }
207
225
  catch (err) {
208
226
  this.d.log.warn("org ui stream access re-check failed; closing", {
209
- orgId: this.p.orgId,
227
+ ...whereOf(this.p),
210
228
  err,
211
229
  });
212
230
  code = "internal";
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ import type { RouteSchemas } from "../platform/route-schemas.js";
3
+ /** The contribution named in a view / action / embed path (`:plugin/:id`). */
4
+ export declare const ContributionParams: z.ZodObject<{
5
+ plugin: z.ZodString;
6
+ id: z.ZodString;
7
+ }, z.core.$strip>;
8
+ /** `GET contributions?slot=`: one catalog slot, or every org-reachable slot when omitted. */
9
+ export declare const ContributionsQuery: z.ZodObject<{
10
+ slot: z.ZodOptional<z.ZodEnum<{
11
+ "agent.detail.section": "agent.detail.section";
12
+ "conversation.panel": "conversation.panel";
13
+ "conversation.properties.section": "conversation.properties.section";
14
+ "conversation.tool-result.card": "conversation.tool-result.card";
15
+ "file.preview": "file.preview";
16
+ "org.page": "org.page";
17
+ "org.settings.section": "org.settings.section";
18
+ "platform.page": "platform.page";
19
+ }>>;
20
+ }, z.core.$strip>;
21
+ export declare const ViewQuery: z.ZodObject<{
22
+ conversationId: z.ZodOptional<z.ZodString>;
23
+ agentId: z.ZodOptional<z.ZodUUID>;
24
+ locale: z.ZodDefault<z.ZodEnum<{
25
+ en: "en";
26
+ zh: "zh";
27
+ }>>;
28
+ item: z.ZodOptional<z.ZodString>;
29
+ callId: z.ZodOptional<z.ZodString>;
30
+ key: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>;
32
+ export declare const ActionBody: z.ZodObject<{
33
+ actionId: z.ZodString;
34
+ payload: z.ZodOptional<z.ZodUnknown>;
35
+ answer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
36
+ conversationId: z.ZodOptional<z.ZodString>;
37
+ agentId: z.ZodOptional<z.ZodUUID>;
38
+ locale: z.ZodDefault<z.ZodEnum<{
39
+ en: "en";
40
+ zh: "zh";
41
+ }>>;
42
+ }, z.core.$strip>;
43
+ export declare const EmbedTokenBody: z.ZodDefault<z.ZodObject<{
44
+ conversationId: z.ZodOptional<z.ZodString>;
45
+ agentId: z.ZodOptional<z.ZodUUID>;
46
+ fileId: z.ZodOptional<z.ZodUUID>;
47
+ }, z.core.$strip>>;
48
+ /** `GET /api/v1/admin/ui/views/:plugin/:id?locale=`: a platform page takes no context id. */
49
+ export declare const PlatformViewQuery: z.ZodObject<{
50
+ locale: z.ZodDefault<z.ZodEnum<{
51
+ en: "en";
52
+ zh: "zh";
53
+ }>>;
54
+ }, z.core.$strip>;
55
+ /** `POST /api/v1/admin/ui/actions/:plugin/:id`: an action of a platform page (no context id). */
56
+ export declare const PlatformActionBody: z.ZodObject<{
57
+ actionId: z.ZodString;
58
+ payload: z.ZodOptional<z.ZodUnknown>;
59
+ answer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
60
+ locale: z.ZodDefault<z.ZodEnum<{
61
+ en: "en";
62
+ zh: "zh";
63
+ }>>;
64
+ }, z.core.$strip>;
65
+ /** The slot catalog route the Platform operation `ui.slots` mirrors (`check:platform-ops` key). */
66
+ export declare const UI_ROUTES: readonly RouteSchemas[];
@@ -0,0 +1,65 @@
1
+ import { UI_LIMITS, UI_SLOT_IDS } from "@capybara-hq/plugin-sdk";
2
+ import { z } from "zod";
3
+ /** The DTO schemas of the org UI routes (`views.controller.ts`). */
4
+ const Locale = z.enum(["zh", "en"]).default("en");
5
+ const Id = z.string().min(1).max(100);
6
+ /** The contribution named in a view / action / embed path (`:plugin/:id`). */
7
+ export const ContributionParams = z.object({ plugin: Id, id: Id });
8
+ /** `GET contributions?slot=`: one catalog slot, or every org-reachable slot when omitted. */
9
+ export const ContributionsQuery = z.object({ slot: z.enum(UI_SLOT_IDS).optional() });
10
+ export const ViewQuery = z
11
+ .object({
12
+ conversationId: z.string().min(1).max(100).optional(),
13
+ /** Only an agent view (`agent.detail.section`). */
14
+ agentId: z.uuid().optional(),
15
+ locale: Locale,
16
+ /** A panel opened from an open target: the item to scroll to. */
17
+ item: z.string().min(1).max(200).optional(),
18
+ /** An inline card: the tool call it hangs off, and its `ToolResult.card.key`. */
19
+ callId: z.string().min(1).max(200).optional(),
20
+ key: z.string().min(1).max(200).optional(),
21
+ })
22
+ .refine((q) => q.key === undefined || q.callId !== undefined, {
23
+ message: "key needs callId",
24
+ });
25
+ /**
26
+ * 表单答案(plugin-sdk 的 `FormAnswer`)。SDK 的 InputForm 没有单独的字段数 / 选项数上限,
27
+ * 这里沿用视图的上限:键数与多选数组长度 ≤ `UI_LIMITS.tableRows`,单个文本 ≤ `UI_LIMITS.textChars`。
28
+ */
29
+ const AnswerText = z.string().max(UI_LIMITS.textChars);
30
+ const FormAnswerSchema = z
31
+ .record(z.string().max(100), z.union([AnswerText, z.number(), z.boolean(), z.array(AnswerText).max(UI_LIMITS.tableRows)]))
32
+ .refine((a) => Object.keys(a).length <= UI_LIMITS.tableRows, {
33
+ message: `answer must have at most ${UI_LIMITS.tableRows} fields`,
34
+ });
35
+ /** 按钮 payload 的 JSON 序列化后 UTF-8 字节数(与 `validateUiView` 对按钮 payload 的上限一致)。 */
36
+ const payloadBytes = (v) => Buffer.byteLength(JSON.stringify(v) ?? "", "utf8");
37
+ export const ActionBody = z.object({
38
+ actionId: z.string().min(1).max(200),
39
+ payload: z
40
+ .unknown()
41
+ .optional()
42
+ .refine((v) => v === undefined || payloadBytes(v) <= UI_LIMITS.payloadBytes, {
43
+ message: `payload must be at most ${UI_LIMITS.payloadBytes} bytes as JSON`,
44
+ }),
45
+ answer: FormAnswerSchema.optional(),
46
+ conversationId: z.string().min(1).max(100).optional(),
47
+ /** Only an agent view (`agent.detail.section`). */
48
+ agentId: z.uuid().optional(),
49
+ locale: Locale,
50
+ });
51
+ export const EmbedTokenBody = z
52
+ .object({
53
+ conversationId: z.string().min(1).max(100).optional(),
54
+ /** Only an agent embed (`agent.detail.section`). */
55
+ agentId: z.uuid().optional(),
56
+ /** Only a `file.preview` embed: the file version it previews. */
57
+ fileId: z.uuid().optional(),
58
+ })
59
+ .default({});
60
+ /** `GET /api/v1/admin/ui/views/:plugin/:id?locale=`: a platform page takes no context id. */
61
+ export const PlatformViewQuery = z.object({ locale: Locale });
62
+ /** `POST /api/v1/admin/ui/actions/:plugin/:id`: an action of a platform page (no context id). */
63
+ export const PlatformActionBody = ActionBody.omit({ conversationId: true, agentId: true });
64
+ /** The slot catalog route the Platform operation `ui.slots` mirrors (`check:platform-ops` key). */
65
+ export const UI_ROUTES = [{ route: "GET /api/v1/ui/slots" }];
@@ -1,61 +1,45 @@
1
- import { type UiActionResult, type UiView } from "@capybara-hq/plugin-sdk";
1
+ import type { UiActionResult, UiView } from "@capybara-hq/plugin-sdk";
2
2
  import type { FastifyReply, FastifyRequest } from "fastify";
3
- import { z } from "zod";
3
+ import type { z } from "zod";
4
4
  import { ApiTokenService } from "../identity/api-tokens.js";
5
5
  import { type Principal } from "../identity/principal.js";
6
6
  import { SessionService } from "../identity/sessions.js";
7
7
  import { type OrgContext } from "../orgs/org.guard.js";
8
8
  import { EmbedTokens } from "./embed-token.js";
9
+ import { ActionBody, ContributionParams, ContributionsQuery, EmbedTokenBody, ViewQuery } from "./ui.schemas.js";
9
10
  import { OrgUiStreams } from "./ui-stream.js";
10
- import { type UiContributionItem, UiViews } from "./views.js";
11
- /** The contribution named in a view / action / embed path (`:plugin/:id`). */
12
- declare const ContributionParams: z.ZodObject<{
13
- plugin: z.ZodString;
14
- id: z.ZodString;
15
- }, z.core.$strip>;
16
- declare const ViewQuery: z.ZodObject<{
17
- conversationId: z.ZodOptional<z.ZodString>;
18
- locale: z.ZodDefault<z.ZodEnum<{
19
- en: "en";
20
- zh: "zh";
21
- }>>;
22
- item: z.ZodOptional<z.ZodString>;
23
- callId: z.ZodOptional<z.ZodString>;
24
- key: z.ZodOptional<z.ZodString>;
25
- }, z.core.$strip>;
26
- declare const ActionBody: z.ZodObject<{
27
- actionId: z.ZodString;
28
- payload: z.ZodOptional<z.ZodUnknown>;
29
- answer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
30
- conversationId: z.ZodOptional<z.ZodString>;
31
- locale: z.ZodDefault<z.ZodEnum<{
32
- en: "en";
33
- zh: "zh";
34
- }>>;
35
- }, z.core.$strip>;
36
- declare const EmbedTokenBody: z.ZodDefault<z.ZodObject<{
37
- conversationId: z.ZodOptional<z.ZodString>;
38
- fileId: z.ZodOptional<z.ZodUUID>;
39
- }, z.core.$strip>>;
11
+ import { type UiArrangementSlot, type UiContributionItem, UiViews } from "./views.js";
12
+ export declare const BEARER_RE: RegExp;
13
+ /** 嵌入页的同源代理前缀(网页 `/plugin-ui/<plugin>/<rest>` → 内核 `/plugins/<plugin>/ui/<rest>`)。 */
14
+ export declare const embedSrc: (plugin: string, path: string) => string;
40
15
  /**
41
16
  * 插件界面(第一档:渲染 schema;第二档:嵌入应用),会话鉴权、`ui.use`(只给人用,服务令牌 403):
42
- * - `GET /api/v1/orgs/:orgId/ui/contributions` → `{ items: { plugin, id, title, place, legacyPlace?, kind, path?, icon }[] }`
43
- * (place normalized: the old `conversation` is `panel` with `legacyPlace`; aliases and file-preview
44
- * embeds are not listed)
45
- * (`path` 仅 embed);
46
- * - `GET /api/v1/orgs/:orgId/ui/views/:plugin/:id?conversationId=&locale=&item=&callId=&key=` → `{ view }`
47
- * (`item`: the panel item to scroll to; `callId` / `key`: an inline card's tool call);
48
- * - `POST /api/v1/orgs/:orgId/ui/actions/:plugin/:id`(`{ actionId, payload?, answer?, conversationId?, locale? }`)
49
- * → `{ toast }` | `{ view }`;
50
- * - `GET /api/v1/orgs/:orgId/ui/stream`:组织级刷新 SSE(`event: ui`,`data: {"plugin","contribution"}`);
51
- * - `POST /api/v1/orgs/:orgId/ui/embeds/:plugin/:id/token`(`{ conversationId? }`)
17
+ * - `GET /api/v1/orgs/:orgId/ui/contributions?slot=` →
18
+ * `{ items: { plugin, id, title, slot, after?, kind, path?, icon }[] }`: every org-reachable slot
19
+ * (all but `platform.page`) or one slot; `after` is the resolved anchor of a slot with anchors,
20
+ * `path` only for an embed; aliases and `file.preview` contributions are not listed; ordered by
21
+ * extension name, then manifest order;
22
+ * - `GET /api/v1/orgs/:orgId/ui/arrangement` → `{ slots: { slot, source, items }[] }`: every
23
+ * org-arrangeable slot with the contributions the caller's role may use, in effective order, each
24
+ * marked `hidden` (the listing for the 界面位置 page; the lists above omit hidden ones, the
25
+ * view / action / embed routes below ignore the arrangement);
26
+ * - `GET /api/v1/orgs/:orgId/ui/views/:plugin/:id?conversationId=&agentId=&locale=&item=&callId=&key=`
27
+ * → `{ view }`(`item`: the panel item to scroll to; `callId` / `key`: an inline card's tool call);
28
+ * - `POST /api/v1/orgs/:orgId/ui/actions/:plugin/:id`
29
+ * (`{ actionId, payload?, answer?, conversationId?, agentId?, locale? }`)→ `{ toast }` | `{ view }`;
30
+ * - `GET /api/v1/orgs/:orgId/ui/stream`:组织级刷新 SSE(`event: ui`,`data: {"plugin","contribution"}`),
31
+ * member and above;
32
+ * - `POST /api/v1/orgs/:orgId/ui/embeds/:plugin/:id/token`(`{ conversationId?, agentId?, fileId? }`)
52
33
  * → `{ token, src: "/plugin-ui/<plugin>/<path 去掉 /ui/>", expiresAt, expiresIn }`:嵌入令牌
53
- * (300 秒,`expiresIn` 为秒数,见 `embed-token.ts`)。
54
- * 插件须在组织启用、贡献须是 embed;对话嵌入要求能访问该对话(否则 404)。令牌只给插件路由用,
55
- * 内核鉴权守卫不认它(它不是 API 令牌)。
34
+ * (300 秒,`expiresIn` 为秒数,见 `embed-token.ts`;`agentId` goes into the claims)。
35
+ * 令牌只给插件路由用,内核鉴权守卫不认它(它不是 API 令牌)。
56
36
  * 对话视图的刷新走现有的会话流 `/conversations/:id/stream`。
57
- * 角色(A38):组织页面(`place: "page"`,含组织级刷新流)只给 member 以上,guest 一律 404 `ui.not_found`、
58
- * 列表里也不出现;对话位置的贡献给能访问该对话的任何成员。插件收到的 `role` 来自 OrgGuard 查出的成员关系。
37
+ * Access (UI slots spec §7): every route checks the slot of the contribution it names, its
38
+ * `minRole` (guest for conversation and agent slots, member for `org.page`, admin for
39
+ * `org.settings.section`; `platform.page` never through these routes), then its scope rule
40
+ * (conversation: whoever can read it; agent: whoever can read the agent, in this org; org: the
41
+ * role alone; file: the previewer's read grant). Anything refused is 404 `ui.not_found`, the same
42
+ * as a contribution that does not exist. 插件收到的 `role` 来自 OrgGuard 查出的成员关系。
59
43
  */
60
44
  export declare class UiController {
61
45
  private readonly views;
@@ -64,9 +48,12 @@ export declare class UiController {
64
48
  private readonly tokens;
65
49
  private readonly embeds;
66
50
  constructor(views: UiViews, streams: OrgUiStreams, sessions: SessionService, tokens: ApiTokenService, embeds: EmbedTokens);
67
- contributions(principal: Principal, org: OrgContext): Promise<{
51
+ contributions(principal: Principal, org: OrgContext, q: z.infer<typeof ContributionsQuery>): Promise<{
68
52
  items: UiContributionItem[];
69
53
  }>;
54
+ arrangement(principal: Principal, org: OrgContext): Promise<{
55
+ slots: UiArrangementSlot[];
56
+ }>;
70
57
  view(principal: Principal, org: OrgContext, { plugin, id }: z.infer<typeof ContributionParams>, q: z.infer<typeof ViewQuery>): Promise<{
71
58
  view: UiView;
72
59
  }>;
@@ -80,4 +67,3 @@ export declare class UiController {
80
67
  /** 组织级刷新流:与会话流一样用 `reply.hijack()` 直接写原始响应;心跳与复核间隔同 `runtime.sse*`。 */
81
68
  stream(principal: Principal, org: OrgContext, req: FastifyRequest, reply: FastifyReply): Promise<void>;
82
69
  }
83
- export {};