@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.
- package/dist/admin/admin.schemas.d.ts +13 -0
- package/dist/agents/agent-lookup.d.ts +5 -0
- package/dist/agents/agent-lookup.js +15 -0
- package/dist/background/background.module.js +2 -2
- package/dist/background/launch-lock.d.ts +1 -1
- package/dist/background/launch-lock.js +1 -1
- package/dist/background/poll.job.d.ts +2 -2
- package/dist/background/poll.job.js +10 -10
- package/dist/background/stop.d.ts +1 -1
- package/dist/background/stop.js +3 -3
- package/dist/background/store.d.ts +5 -5
- package/dist/background/store.js +5 -5
- package/dist/background/tasks.service.d.ts +6 -6
- package/dist/background/tasks.service.js +13 -13
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/channels/channels.module.js +2 -2
- package/dist/channels/inbound.d.ts +8 -8
- package/dist/channels/inbound.js +31 -31
- package/dist/channels/phrases.d.ts +27 -27
- package/dist/channels/phrases.js +27 -27
- package/dist/config/docs.js +1 -1
- package/dist/config/schema.d.ts +2 -2
- package/dist/config/schema.js +21 -21
- package/dist/conversations/conversations.controller.d.ts +11 -11
- package/dist/conversations/conversations.controller.js +15 -15
- package/dist/conversations/conversations.module.d.ts +1 -1
- package/dist/conversations/conversations.module.js +7 -7
- package/dist/conversations/conversations.schemas.js +1 -1
- package/dist/conversations/conversations.service.d.ts +14 -14
- package/dist/conversations/conversations.service.js +19 -19
- package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
- package/dist/conversations/{environment-status.js → device-status.js} +18 -18
- package/dist/conversations/event-log.d.ts +1 -1
- package/dist/conversations/event-log.js +1 -1
- package/dist/conversations/events.d.ts +1 -1
- package/dist/conversations/events.js +2 -2
- package/dist/ctx/create-ctx.d.ts +10 -1
- package/dist/ctx/create-ctx.js +86 -25
- package/dist/db/kernel-schema.d.ts +26 -23
- package/dist/{environments → devices}/access.d.ts +19 -19
- package/dist/{environments → devices}/access.js +28 -28
- package/dist/devices/conversation-devices.d.ts +75 -0
- package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
- package/dist/devices/devices.controller.d.ts +36 -0
- package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
- package/dist/devices/devices.module.d.ts +5 -13
- package/dist/devices/devices.module.js +16 -29
- package/dist/devices/devices.schemas.d.ts +3 -0
- package/dist/devices/devices.schemas.js +14 -0
- package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
- package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
- package/dist/devices/dto.d.ts +13 -54
- package/dist/devices/dto.js +7 -39
- package/dist/devices/label.d.ts +11 -0
- package/dist/{environments → devices}/label.js +7 -7
- package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
- package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
- package/dist/errors.d.ts +25 -25
- package/dist/errors.js +25 -25
- package/dist/evals/recorded-tools.d.ts +2 -2
- package/dist/evals/recorded-tools.js +6 -6
- package/dist/extensions/admin-ops.js +1 -0
- package/dist/extensions/admin-view.js +2 -0
- package/dist/extensions/effective-config.d.ts +6 -0
- package/dist/extensions/effective-config.js +18 -7
- package/dist/extensions/host.d.ts +13 -2
- package/dist/extensions/host.js +24 -3
- package/dist/extensions/instance.d.ts +12 -1
- package/dist/extensions/instance.js +13 -0
- package/dist/extensions/permission-view.d.ts +10 -1
- package/dist/files/previewers.d.ts +1 -1
- package/dist/files/previewers.js +1 -1
- package/dist/http/api.module.js +10 -6
- package/dist/http/gateway-routes.d.ts +1 -1
- package/dist/http/gateway-routes.js +1 -1
- package/dist/identity/settings.d.ts +32 -0
- package/dist/identity/settings.js +26 -2
- package/dist/infra/config/kernel-config.service.js +4 -4
- package/dist/kernel.module.js +3 -3
- package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
- package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
- package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
- package/dist/{devices → local-devices}/device-auth.js +51 -53
- package/dist/local-devices/device-auth.module.d.ts +7 -0
- package/dist/{devices → local-devices}/device-auth.module.js +5 -5
- package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
- package/dist/{devices → local-devices}/device-routes.js +2 -2
- package/dist/local-devices/dto.d.ts +66 -0
- package/dist/local-devices/dto.js +44 -0
- package/dist/{devices → local-devices}/keys.d.ts +11 -11
- package/dist/{devices → local-devices}/keys.js +11 -11
- package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
- package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
- package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
- package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
- package/dist/local-devices/local-devices.module.d.ts +16 -0
- package/dist/local-devices/local-devices.module.js +44 -0
- package/dist/{devices → local-devices}/machines.d.ts +26 -26
- package/dist/{devices → local-devices}/machines.js +71 -71
- package/dist/{devices → local-devices}/relay.d.ts +15 -15
- package/dist/{devices → local-devices}/relay.js +55 -55
- package/dist/{devices → local-devices}/targets.d.ts +8 -8
- package/dist/{devices → local-devices}/targets.js +14 -14
- package/dist/orgs/offboarding.d.ts +6 -6
- package/dist/orgs/offboarding.js +12 -12
- package/dist/orgs/settings.service.d.ts +28 -0
- package/dist/orgs/settings.service.js +20 -1
- package/dist/platform/exclusions.js +38 -3
- package/dist/platform/operation.js +6 -2
- package/dist/platform/ops/admin.ops.js +8 -2
- package/dist/platform/ops/conversations.ops.d.ts +3 -3
- package/dist/platform/ops/conversations.ops.js +9 -9
- package/dist/platform/ops/devices.ops.d.ts +26 -0
- package/dist/platform/ops/devices.ops.js +311 -0
- package/dist/platform/ops/org-settings.ops.js +2 -2
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/ui.ops.d.ts +8 -0
- package/dist/platform/ops/ui.ops.js +41 -0
- package/dist/platform/platform-ops.module.d.ts +3 -2
- package/dist/platform/platform-ops.module.js +8 -5
- package/dist/platform/route-schemas.js +6 -3
- package/dist/roles/gateway-role.d.ts +3 -3
- package/dist/roles/gateway-role.js +4 -4
- package/dist/roles/gateway.module.d.ts +1 -1
- package/dist/roles/gateway.module.js +5 -5
- package/dist/roles/worker.module.js +1 -1
- package/dist/runtime/context/build.d.ts +1 -1
- package/dist/runtime/context/build.js +6 -6
- package/dist/runtime/context/compaction.js +1 -1
- package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
- package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
- package/dist/runtime/maintenance.d.ts +1 -1
- package/dist/sandbox/jobs.d.ts +13 -13
- package/dist/sandbox/jobs.js +20 -20
- package/dist/sandbox/leases.d.ts +9 -9
- package/dist/sandbox/leases.js +14 -14
- package/dist/sandbox/providers.d.ts +8 -8
- package/dist/sandbox/providers.js +8 -8
- package/dist/sandbox/sandbox.module.d.ts +1 -1
- package/dist/sandbox/sandbox.module.js +1 -1
- package/dist/sandbox/sandbox.service.d.ts +76 -76
- package/dist/sandbox/sandbox.service.js +230 -230
- package/dist/tools/builtins/builtin-tools.d.ts +2 -2
- package/dist/tools/builtins/builtin-tools.js +5 -5
- package/dist/tools/builtins/platform.js +1 -1
- package/dist/tools/builtins/sandbox/bash.js +6 -6
- package/dist/tools/builtins/sandbox/common.d.ts +25 -25
- package/dist/tools/builtins/sandbox/common.js +51 -51
- package/dist/tools/builtins/sandbox/edit.js +2 -2
- package/dist/tools/builtins/sandbox/index.d.ts +1 -1
- package/dist/tools/builtins/sandbox/index.js +1 -1
- package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
- package/dist/tools/builtins/sandbox/task-output.js +10 -10
- package/dist/tools/builtins/sandbox/task-stop.js +2 -2
- package/dist/tools/builtins/sandbox/write.js +2 -2
- package/dist/tools/builtins/skill-load.d.ts +1 -1
- package/dist/tools/builtins/skill-load.js +2 -2
- package/dist/tools/pipeline.js +4 -3
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/tools.module.js +3 -3
- package/dist/ui/admin-ui.controller.d.ts +56 -0
- package/dist/ui/admin-ui.controller.js +192 -0
- package/dist/ui/arrangement.d.ts +74 -0
- package/dist/ui/arrangement.js +98 -0
- package/dist/ui/embed-token.d.ts +2 -2
- package/dist/ui/embed-token.js +30 -5
- package/dist/ui/registry.d.ts +29 -14
- package/dist/ui/registry.js +31 -10
- package/dist/ui/slots.controller.d.ts +11 -0
- package/dist/ui/slots.controller.js +25 -0
- package/dist/ui/ui-stream.d.ts +20 -3
- package/dist/ui/ui-stream.js +25 -7
- package/dist/ui/ui.schemas.d.ts +66 -0
- package/dist/ui/ui.schemas.js +65 -0
- package/dist/ui/views.controller.d.ts +35 -49
- package/dist/ui/views.controller.js +48 -70
- package/dist/ui/views.d.ts +84 -18
- package/dist/ui/views.js +201 -38
- package/package.json +3 -3
- package/src/migrations/0105_devices_rename.sql +136 -0
- package/dist/devices/device-auth.module.d.ts +0 -7
- package/dist/environments/conversation-environments.d.ts +0 -75
- package/dist/environments/dto.d.ts +0 -25
- package/dist/environments/dto.js +0 -12
- package/dist/environments/environments.controller.d.ts +0 -36
- package/dist/environments/environments.module.d.ts +0 -8
- package/dist/environments/environments.module.js +0 -31
- package/dist/environments/environments.schemas.d.ts +0 -3
- package/dist/environments/environments.schemas.js +0 -14
- package/dist/environments/label.d.ts +0 -11
- package/dist/platform/ops/environments.ops.d.ts +0 -26
- package/dist/platform/ops/environments.ops.js +0 -311
package/dist/ui/registry.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { ExtensionManifest, UiActionArgs, UiActionResult,
|
|
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
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export declare
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
}
|
package/dist/ui/registry.js
CHANGED
|
@@ -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
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export
|
|
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
|
-
/**
|
|
56
|
-
|
|
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 };
|
package/dist/ui/ui-stream.d.ts
CHANGED
|
@@ -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"}
|
|
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:
|
|
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;
|
package/dist/ui/ui-stream.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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"}
|
|
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
|
|
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", {
|
|
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",
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* - `
|
|
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
|
-
*
|
|
55
|
-
* 内核鉴权守卫不认它(它不是 API 令牌)。
|
|
34
|
+
* (300 秒,`expiresIn` 为秒数,见 `embed-token.ts`;`agentId` goes into the claims)。
|
|
35
|
+
* 令牌只给插件路由用,内核鉴权守卫不认它(它不是 API 令牌)。
|
|
56
36
|
* 对话视图的刷新走现有的会话流 `/conversations/:id/stream`。
|
|
57
|
-
*
|
|
58
|
-
*
|
|
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 {};
|