@capybara-hq/kernel 0.1.0-rc.10 → 0.1.0-rc.12
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 +3 -0
- package/dist/agents/agents.schemas.d.ts +3 -0
- package/dist/agents/agents.service.js +11 -1
- package/dist/agents/definition.d.ts +1 -0
- package/dist/agents/definition.js +7 -3
- package/dist/agents/org-templates.js +4 -0
- package/dist/agents/pending-connectors.service.js +1 -1
- package/dist/catalog/catalog-content.d.ts +33 -1
- package/dist/catalog/catalog-content.js +65 -2
- package/dist/catalog/catalog-items.js +1 -0
- package/dist/catalog/catalog-scope.service.d.ts +29 -3
- package/dist/catalog/catalog-scope.service.js +82 -10
- package/dist/catalog/catalog.service.d.ts +7 -5
- package/dist/catalog/catalog.service.js +26 -5
- package/dist/catalog/claude/translate.js +3 -0
- package/dist/catalog/component-scope.controller.d.ts +18 -6
- package/dist/catalog/component-scope.controller.js +36 -13
- package/dist/catalog/component-scope.schemas.d.ts +4 -0
- package/dist/catalog/component-scope.service.d.ts +59 -9
- package/dist/catalog/component-scope.service.js +156 -27
- package/dist/catalog/component-state.d.ts +20 -3
- package/dist/catalog/component-state.js +40 -14
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/org-catalog.service.js +3 -0
- package/dist/catalog/owned-items.js +7 -0
- package/dist/catalog/platform-components.d.ts +23 -3
- package/dist/catalog/platform-components.js +118 -9
- package/dist/catalog/platform-migration.js +2 -1
- package/dist/catalog/plugin-import.d.ts +24 -4
- package/dist/catalog/plugin-import.js +41 -7
- package/dist/catalog/plugin-install.d.ts +20 -1
- package/dist/catalog/plugin-install.js +71 -1
- package/dist/catalog/plugin-package.d.ts +41 -4
- package/dist/catalog/plugin-package.js +127 -7
- package/dist/catalog/plugin-upgrade.d.ts +13 -2
- package/dist/catalog/plugin-upgrade.js +124 -6
- package/dist/catalog/unshare.js +1 -0
- package/dist/conversations/conversations.service.d.ts +9 -0
- package/dist/conversations/conversations.service.js +9 -2
- package/dist/conversations/events.d.ts +1 -0
- package/dist/db/kernel-schema.d.ts +54 -4
- package/dist/errors.d.ts +27 -0
- package/dist/errors.js +27 -0
- package/dist/http/api.module.js +7 -0
- package/dist/identity/accounts.d.ts +11 -4
- package/dist/identity/accounts.js +23 -10
- package/dist/identity/me.controller.d.ts +10 -10
- package/dist/identity/me.controller.js +8 -6
- package/dist/identity/me.schemas.d.ts +13 -3
- package/dist/identity/me.schemas.js +10 -2
- package/dist/identity/settings.d.ts +27 -0
- package/dist/identity/settings.js +64 -0
- package/dist/orgs/settings.service.d.ts +31 -0
- package/dist/orgs/settings.service.js +31 -1
- package/dist/platform/exclusions.js +26 -0
- package/dist/platform/operation.js +6 -2
- package/dist/platform/ops/admin.ops.d.ts +3 -1
- package/dist/platform/ops/admin.ops.js +25 -7
- package/dist/platform/ops/agents.ops.js +19 -6
- package/dist/platform/ops/components.ops.js +1 -0
- package/dist/platform/ops/org-settings.ops.d.ts +3 -1
- package/dist/platform/ops/org-settings.ops.js +33 -8
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/platform.ops.d.ts +3 -1
- package/dist/platform/ops/platform.ops.js +43 -16
- package/dist/platform/ops/themes.ops.d.ts +14 -0
- package/dist/platform/ops/themes.ops.js +47 -0
- package/dist/platform/platform-ops.module.d.ts +2 -1
- package/dist/platform/platform-ops.module.js +5 -0
- package/dist/platform/route-schemas.js +3 -0
- package/dist/runtime/subagents/definition.d.ts +3 -2
- package/dist/runtime/subagents/definition.js +2 -1
- package/dist/themes/render-css.d.ts +12 -0
- package/dist/themes/render-css.js +132 -0
- package/dist/themes/theme-delivery.service.d.ts +34 -0
- package/dist/themes/theme-delivery.service.js +111 -0
- package/dist/themes/theme-state.d.ts +95 -0
- package/dist/themes/theme-state.js +203 -0
- package/dist/themes/theme-usage.d.ts +61 -0
- package/dist/themes/theme-usage.js +98 -0
- package/dist/themes/themes-public.controller.d.ts +28 -0
- package/dist/themes/themes-public.controller.js +92 -0
- package/dist/themes/themes.controller.d.ts +13 -0
- package/dist/themes/themes.controller.js +38 -0
- package/dist/themes/themes.module.d.ts +3 -0
- package/dist/themes/themes.module.js +21 -0
- package/dist/themes/themes.schemas.d.ts +3 -0
- package/dist/themes/themes.schemas.js +2 -0
- package/dist/themes/themes.service.d.ts +50 -0
- package/dist/themes/themes.service.js +99 -0
- package/dist/tools/connector-account-policies.d.ts +51 -0
- package/dist/tools/connector-account-policies.js +165 -0
- package/dist/tools/connectors.controller.d.ts +35 -4
- package/dist/tools/connectors.controller.js +66 -7
- package/dist/tools/connectors.schemas.d.ts +11 -0
- package/dist/tools/connectors.schemas.js +11 -0
- package/dist/tools/connectors.service.d.ts +2 -0
- package/dist/tools/connectors.service.js +1 -0
- package/dist/tools/pipeline.d.ts +1 -1
- package/dist/tools/policy.d.ts +23 -1
- package/dist/tools/policy.js +99 -24
- package/dist/tools/tools.module.js +3 -0
- package/package.json +3 -3
- package/src/migrations/0102_themes.sql +64 -0
- package/src/migrations/0103_ui_theme_setting.sql +7 -0
- package/src/migrations/0104_connector_tool_account_policies.sql +16 -0
|
@@ -17,6 +17,7 @@ import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
|
17
17
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
18
18
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
19
19
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
20
|
+
import { assertThemeOnIn } from "../themes/theme-state.js";
|
|
20
21
|
import { IanaTimeZone } from "../time-zone.js";
|
|
21
22
|
import { OrgLock } from "./org-lock.js";
|
|
22
23
|
/**
|
|
@@ -33,6 +34,8 @@ import { OrgLock } from "./org-lock.js";
|
|
|
33
34
|
* `read-only` (writes listed as unavailable) or `off` (default `on`).
|
|
34
35
|
* - `timeZone`: the org's default time zone (IANA; absent = UTC) for senders without one of their
|
|
35
36
|
* own (run context spec §3.3); an invalid stored value reads as absent.
|
|
37
|
+
* - `theme`: the org's default theme and whether members may pick their own (themes spec §7);
|
|
38
|
+
* absent (or an invalid stored value) = follow the platform, personal picks allowed.
|
|
36
39
|
*/
|
|
37
40
|
/** 组织沙箱出站白名单的主机数上限。 */
|
|
38
41
|
export const ORG_SANDBOX_ALLOW_HOSTS_MAX = 200;
|
|
@@ -59,6 +62,19 @@ export const SandboxEgressSettingSchema = z
|
|
|
59
62
|
.optional(),
|
|
60
63
|
})
|
|
61
64
|
.strict();
|
|
65
|
+
/**
|
|
66
|
+
* The org's theme setting (themes spec §7): `id` a theme on in the org (a `platform_themes` id),
|
|
67
|
+
* null = follow the platform's default; `personal: "locked"` hides the personal picker in the org
|
|
68
|
+
* and resolution ignores personal picks there.
|
|
69
|
+
*/
|
|
70
|
+
export const OrgThemeSettingSchema = z
|
|
71
|
+
.object({
|
|
72
|
+
id: z.string().min(1).max(200).nullable(),
|
|
73
|
+
personal: z.enum(["allowed", "locked"]),
|
|
74
|
+
})
|
|
75
|
+
.strict();
|
|
76
|
+
/** The theme setting of an org that has none: follow the platform, personal picks allowed. */
|
|
77
|
+
export const DEFAULT_ORG_THEME = { id: null, personal: "allowed" };
|
|
62
78
|
export const OrgSettingsSchema = z.object({
|
|
63
79
|
toolSearch: z.enum(["on", "off"]).default("on").catch("on"),
|
|
64
80
|
locale: z.enum(["zh", "en"]).default("en").catch("en"),
|
|
@@ -69,6 +85,8 @@ export const OrgSettingsSchema = z.object({
|
|
|
69
85
|
wakeOnBackgroundTask: z.boolean().optional().catch(undefined),
|
|
70
86
|
/** The org's default time zone (run context spec §3.3); absent = UTC. */
|
|
71
87
|
timeZone: IanaTimeZone.optional().catch(undefined),
|
|
88
|
+
/** The org's default theme and personal lock (themes spec §7); absent = {@link DEFAULT_ORG_THEME}. */
|
|
89
|
+
theme: OrgThemeSettingSchema.optional().catch(undefined),
|
|
72
90
|
});
|
|
73
91
|
/** PATCH 体:只改给出的字段;未知字段 → 400。 */
|
|
74
92
|
export const OrgSettingsPatchSchema = z
|
|
@@ -83,6 +101,11 @@ export const OrgSettingsPatchSchema = z
|
|
|
83
101
|
sandboxEgress: SandboxEgressSettingSchema.nullable().optional(),
|
|
84
102
|
/** The org's default time zone (IANA); null clears it (UTC). */
|
|
85
103
|
timeZone: IanaTimeZone.nullable().optional(),
|
|
104
|
+
/**
|
|
105
|
+
* The org's default theme (`id`: a theme on in the org, else 400 `theme.not_available`; null
|
|
106
|
+
* follows the platform) and whether members may pick their own; null clears it.
|
|
107
|
+
*/
|
|
108
|
+
theme: OrgThemeSettingSchema.nullable().optional(),
|
|
86
109
|
})
|
|
87
110
|
.strict();
|
|
88
111
|
/**
|
|
@@ -204,10 +227,17 @@ let OrgSettingsService = class OrgSettingsService {
|
|
|
204
227
|
delete after.wakeOnBackgroundTask;
|
|
205
228
|
if (after.timeZone === undefined)
|
|
206
229
|
delete after.timeZone;
|
|
230
|
+
if (after.theme === undefined)
|
|
231
|
+
delete after.theme;
|
|
207
232
|
if (sameSettings(before, after))
|
|
208
233
|
return before;
|
|
234
|
+
// Lock order: the org row (orgLock above), then the theme's catalog item and its row FOR
|
|
235
|
+
// SHARE (assertThemeOnIn), then the check, so no scope writer changes what it read first
|
|
236
|
+
if (patch.theme?.id != null && patch.theme.id !== before.theme?.id) {
|
|
237
|
+
await assertThemeOnIn(this.db.db, orgId, patch.theme.id);
|
|
238
|
+
}
|
|
209
239
|
// 与存量合并:保留本版本不认识的键(清除的 sandboxEgress 不留在存量里)
|
|
210
|
-
const { sandboxEgress: _old, wakeOnBackgroundTask: _oldWake, timeZone: _oldZone, ...rest } = stored;
|
|
240
|
+
const { sandboxEgress: _old, wakeOnBackgroundTask: _oldWake, timeZone: _oldZone, theme: _oldTheme, ...rest } = stored;
|
|
211
241
|
await this.db
|
|
212
242
|
.updateTable("orgs")
|
|
213
243
|
.set({ settings: JSON.stringify({ ...rest, ...after }) })
|
|
@@ -608,6 +608,16 @@ export const PLATFORM_EXCLUSIONS = [
|
|
|
608
608
|
category: "secret",
|
|
609
609
|
reason: "Writes the caller's connector credentials",
|
|
610
610
|
},
|
|
611
|
+
{
|
|
612
|
+
route: "GET /api/v1/orgs/:orgId/connectors/:connectorId/tool-policies/me",
|
|
613
|
+
category: "internal",
|
|
614
|
+
reason: "Display list of the connector card's 权限 sheet; connectors.get gives an agent the tools and their org defaults",
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
route: "PUT /api/v1/orgs/:orgId/connectors/:connectorId/tool-policies/me",
|
|
618
|
+
category: "human-only",
|
|
619
|
+
reason: "A member's own tool policies decide what agents may call with their connection without asking; an agent must never loosen them for itself",
|
|
620
|
+
},
|
|
611
621
|
{
|
|
612
622
|
route: "DELETE /api/v1/orgs/:orgId/connectors/:connectorId/credentials/me",
|
|
613
623
|
category: "secret",
|
|
@@ -664,4 +674,20 @@ export const PLATFORM_EXCLUSIONS = [
|
|
|
664
674
|
category: "transport",
|
|
665
675
|
reason: "Server-sent event stream of UI invalidations",
|
|
666
676
|
},
|
|
677
|
+
// themes (themes spec §8-§9)
|
|
678
|
+
{
|
|
679
|
+
route: "GET /api/v1/themes/:id/:version/theme.css",
|
|
680
|
+
category: "transport",
|
|
681
|
+
reason: "Serves a theme version's stylesheet to the browser; an agent reads themes.list",
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
route: "GET /api/v1/themes/:id/:version/assets/:file",
|
|
685
|
+
category: "transport",
|
|
686
|
+
reason: "Serves a theme version's font and logo bytes to the browser",
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
route: "GET /api/v1/platform/theme",
|
|
690
|
+
category: "transport",
|
|
691
|
+
reason: "The platform default theme for the web's pages before sign-in; no session to act for",
|
|
692
|
+
},
|
|
667
693
|
];
|
|
@@ -12,7 +12,7 @@ export const operationDomain = (id) => id.slice(0, id.indexOf("."));
|
|
|
12
12
|
export const PLATFORM_DOMAINS = [
|
|
13
13
|
{
|
|
14
14
|
id: "platform",
|
|
15
|
-
description: "What this platform is, its tool families, what you and this agent can do, and your own preferences (time zone).",
|
|
15
|
+
description: "What this platform is, its tool families, what you and this agent can do, and your own preferences (time zone, theme).",
|
|
16
16
|
},
|
|
17
17
|
{ id: "skills", description: "The org's skill library: list, read, create, switch on or off." },
|
|
18
18
|
{
|
|
@@ -81,10 +81,14 @@ export const PLATFORM_DOMAINS = [
|
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
id: "org-settings",
|
|
84
|
-
description: "The org's settings (tool search, language, sandbox policy, the Platform tool switch): read and change.",
|
|
84
|
+
description: "The org's settings (tool search, language, sandbox policy, the Platform tool switch, the default theme): read and change.",
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
id: "environments",
|
|
88
88
|
description: "Your own cloud environments (the workspaces your conversations run in): list, read, create, rename, delete, wipe the files.",
|
|
89
89
|
},
|
|
90
|
+
{
|
|
91
|
+
id: "themes",
|
|
92
|
+
description: "The themes on in this org, the one in effect for you and the org's theme setting: list. Themes are set through your preferences, the org settings and the deployment settings.",
|
|
93
|
+
},
|
|
90
94
|
];
|
|
@@ -10,6 +10,7 @@ import { PricesService } from "../../models/prices.js";
|
|
|
10
10
|
import { ModelPurposesService } from "../../models/purposes.js";
|
|
11
11
|
import { OrgsService } from "../../orgs/orgs.service.js";
|
|
12
12
|
import { ProviderRegistry } from "../../runtime/providers.js";
|
|
13
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
13
14
|
import { PlatformOperations } from "../registry.js";
|
|
14
15
|
/**
|
|
15
16
|
* Admin console operations of the `Platform` tool (spec §14.2): the dashboard totals, the
|
|
@@ -30,7 +31,8 @@ export declare class AdminOperations implements OnModuleInit {
|
|
|
30
31
|
private readonly enablement;
|
|
31
32
|
private readonly prices;
|
|
32
33
|
private readonly purposes;
|
|
33
|
-
|
|
34
|
+
private readonly themes;
|
|
35
|
+
constructor(registry: PlatformOperations, extensions: ExtensionAdmin, orgs: OrgsService, accounts: AccountsService, catalogRequests: CatalogRequestsService, settings: SettingsService, providers: ProviderRegistry, displayNames: ExtensionDisplayNames, extensionRegistry: ExtensionRegistry, enablement: ModelEnablement, prices: PricesService, purposes: ModelPurposesService, themes: ThemesService);
|
|
34
36
|
private assertProvider;
|
|
35
37
|
onModuleInit(): void;
|
|
36
38
|
}
|
|
@@ -25,6 +25,7 @@ import { purposeTargetOf } from "../../models/purposes.controller.js";
|
|
|
25
25
|
import { ModelPurposesService, PURPOSE_PUT, withDeclaredByNames } from "../../models/purposes.js";
|
|
26
26
|
import { OrgsService } from "../../orgs/orgs.service.js";
|
|
27
27
|
import { ProviderRegistry } from "../../runtime/providers.js";
|
|
28
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
28
29
|
import { defineOperation } from "../operation.js";
|
|
29
30
|
import { PlatformOperations } from "../registry.js";
|
|
30
31
|
import { precheckBy, viaAgent } from "./errors.js";
|
|
@@ -38,6 +39,7 @@ const SettingsInput = DEPLOYMENT_SETTINGS_PATCH.pick({
|
|
|
38
39
|
customConnectors: true,
|
|
39
40
|
customSkills: true,
|
|
40
41
|
orgMarketplaceBrowse: true,
|
|
42
|
+
uiTheme: true,
|
|
41
43
|
}).strict();
|
|
42
44
|
const ProviderId = ModelProviderParams.shape.provider.describe("The model provider (models.platform-list), e.g. the plugin name of its extension.");
|
|
43
45
|
/** `provider/model` of a purpose target, or null. */
|
|
@@ -61,7 +63,8 @@ let AdminOperations = class AdminOperations {
|
|
|
61
63
|
enablement;
|
|
62
64
|
prices;
|
|
63
65
|
purposes;
|
|
64
|
-
|
|
66
|
+
themes;
|
|
67
|
+
constructor(registry, extensions, orgs, accounts, catalogRequests, settings, providers, displayNames, extensionRegistry, enablement, prices, purposes, themes) {
|
|
65
68
|
this.registry = registry;
|
|
66
69
|
this.extensions = extensions;
|
|
67
70
|
this.orgs = orgs;
|
|
@@ -74,6 +77,7 @@ let AdminOperations = class AdminOperations {
|
|
|
74
77
|
this.enablement = enablement;
|
|
75
78
|
this.prices = prices;
|
|
76
79
|
this.purposes = purposes;
|
|
80
|
+
this.themes = themes;
|
|
77
81
|
}
|
|
78
82
|
assertProvider(provider) {
|
|
79
83
|
if (!this.extensionRegistry.list("model-provider").some((e) => e.plugin === provider)) {
|
|
@@ -117,7 +121,7 @@ let AdminOperations = class AdminOperations {
|
|
|
117
121
|
}),
|
|
118
122
|
defineOperation({
|
|
119
123
|
id: "admin.update-settings",
|
|
120
|
-
description: "Change deployment settings (super admin); give only the keys to change: orgCreation (anyone or super_admin), priceCurrency (ISO 4217 code), customConnectors / customSkills (allow or deny: whether orgs may create their own instead of installing from the catalog), orgMarketplaceBrowse (true or false). Per-org limits are orgs.set-limits.",
|
|
124
|
+
description: "Change deployment settings (super admin); give only the keys to change: orgCreation (anyone or super_admin), priceCurrency (ISO 4217 code), customConnectors / customSkills (allow or deny: whether orgs may create their own instead of installing from the catalog), orgMarketplaceBrowse (true or false), uiTheme ({ id }: the platform default theme, a platform theme whose scope is all, or null for the built-in theme; it is what every org falls back to and what the sign-in pages show). Per-org limits are orgs.set-limits.",
|
|
121
125
|
input: SettingsInput.refine((b) => Object.keys(b).length > 0, {
|
|
122
126
|
message: "at least one setting is required",
|
|
123
127
|
}),
|
|
@@ -132,6 +136,10 @@ let AdminOperations = class AdminOperations {
|
|
|
132
136
|
code: "validation_failed",
|
|
133
137
|
next: "Fix the values as the message says (admin.settings shows the current ones).",
|
|
134
138
|
},
|
|
139
|
+
{
|
|
140
|
+
code: "theme.not_available",
|
|
141
|
+
next: "The platform default must be a platform theme whose scope is all, not disabled, and on in every organization. When the details list orgs, the theme is off in those organizations: tell the person their names, then choose another theme (plugins.components with kind theme lists them) or have it switched on in those organizations first; { id: null } sets the built-in theme.",
|
|
142
|
+
},
|
|
135
143
|
],
|
|
136
144
|
precheck: async (i) => {
|
|
137
145
|
const r = DeploymentSettingsBody.safeParse(i);
|
|
@@ -139,11 +147,20 @@ let AdminOperations = class AdminOperations {
|
|
|
139
147
|
? { ok: true }
|
|
140
148
|
: { ok: false, code: "validation_failed", message: r.error.issues[0]?.message ?? "" };
|
|
141
149
|
},
|
|
142
|
-
summary: (i) => {
|
|
143
|
-
const
|
|
150
|
+
summary: async (i) => {
|
|
151
|
+
const { uiTheme, ...rest } = i;
|
|
152
|
+
const parts = Object.entries(rest).map(([k, v]) => `${k}=${String(v)}`);
|
|
153
|
+
const zh = [...parts];
|
|
154
|
+
const en = [...parts];
|
|
155
|
+
if (uiTheme !== undefined) {
|
|
156
|
+
// the theme by its name (the super admin sees every theme), the built-in one by name
|
|
157
|
+
const name = uiTheme.id === null ? null : await this.themes.nameOf(uiTheme.id);
|
|
158
|
+
zh.push(`uiTheme=${uiTheme.id === null ? "内置主题" : (name?.zh ?? uiTheme.id)}`);
|
|
159
|
+
en.push(`uiTheme=${uiTheme.id === null ? "built-in theme" : (name?.en ?? uiTheme.id)}`);
|
|
160
|
+
}
|
|
144
161
|
return {
|
|
145
|
-
zh: `修改平台部署设置:${
|
|
146
|
-
en: `Change the deployment settings: ${
|
|
162
|
+
zh: `修改平台部署设置:${zh.join(",")}`,
|
|
163
|
+
en: `Change the deployment settings: ${en.join(", ")}`,
|
|
147
164
|
};
|
|
148
165
|
},
|
|
149
166
|
run: (input, ctx) => this.settings.update(input, ctx.actorAccountId, undefined, viaAgent("admin.update-settings", ctx)),
|
|
@@ -384,6 +401,7 @@ AdminOperations = __decorate([
|
|
|
384
401
|
__param(8, Inject(ExtensionRegistry)),
|
|
385
402
|
__param(9, Inject(ModelEnablement)),
|
|
386
403
|
__param(10, Inject(PricesService)),
|
|
387
|
-
__param(11, Inject(ModelPurposesService))
|
|
404
|
+
__param(11, Inject(ModelPurposesService)),
|
|
405
|
+
__param(12, Inject(ThemesService))
|
|
388
406
|
], AdminOperations);
|
|
389
407
|
export { AdminOperations };
|
|
@@ -40,6 +40,15 @@ const RouteSkills = Def.skills.unwrap();
|
|
|
40
40
|
const Skills = RouteSkills.pick({ pinned: true })
|
|
41
41
|
.extend({ orgSkills: RouteSkills.shape.orgSkills.unwrap() })
|
|
42
42
|
.strict();
|
|
43
|
+
/**
|
|
44
|
+
* Whether `next` sets an `allow` that `current` does not have (decision 2026-11-09: `allow` on a
|
|
45
|
+
* connector tool lets an agent call it without asking). Such a change is confirmed every time and
|
|
46
|
+
* never remembered, so an agent can never loosen its own policies on a grant the person remembered
|
|
47
|
+
* for ordinary edits.
|
|
48
|
+
*/
|
|
49
|
+
function addsAllow(next, current) {
|
|
50
|
+
return Object.entries(next ?? {}).some(([k, v]) => v === "allow" && current?.[k] !== "allow");
|
|
51
|
+
}
|
|
43
52
|
/** The definition fields an agent can set through the tool; the rest keep the web's defaults. */
|
|
44
53
|
const Fields = {
|
|
45
54
|
name: Def.name,
|
|
@@ -156,8 +165,10 @@ let AgentsOperations = class AgentsOperations {
|
|
|
156
165
|
* `agents.update`'s class (spec §13): `personal` (may be remembered) only on a private agent the
|
|
157
166
|
* actor owns; any other agent the actor may edit is shared, so each change is confirmed.
|
|
158
167
|
*/
|
|
159
|
-
async updateClass(agentId, ctx) {
|
|
168
|
+
async updateClass(agentId, toolPolicies, ctx) {
|
|
160
169
|
const a = await this.agents.get(ctx.orgId, agentId, ctx.actorAccountId);
|
|
170
|
+
if (addsAllow(toolPolicies, a.definition.toolPolicies))
|
|
171
|
+
return "org";
|
|
161
172
|
return a.visibility === "private" && a.ownerAccountId === ctx.actorAccountId
|
|
162
173
|
? "personal"
|
|
163
174
|
: "org";
|
|
@@ -221,6 +232,8 @@ let AgentsOperations = class AgentsOperations {
|
|
|
221
232
|
omits: ["memberIds", "profile"],
|
|
222
233
|
loosens: { visibility: "optional: the operation creates private agents only" },
|
|
223
234
|
confirm: "personal",
|
|
235
|
+
// an `allow` loosens: never on a remembered grant
|
|
236
|
+
confirmFor: async (i) => addsAllow(i.definition.toolPolicies, undefined) ? "org" : "personal",
|
|
224
237
|
summary: (i) => ({
|
|
225
238
|
zh: `新建私有智能体「${i.definition.name}」`,
|
|
226
239
|
en: `Create private agent "${i.definition.name}"`,
|
|
@@ -246,7 +259,7 @@ let AgentsOperations = class AgentsOperations {
|
|
|
246
259
|
}),
|
|
247
260
|
defineOperation({
|
|
248
261
|
id: "agents.update",
|
|
249
|
-
description: 'Change an agent you may edit: your own, private or shared, and as an org admin any agent of the org. Send the version you read from agents.get and only the fields to change; the others keep their value. The description (one short paragraph, "" removes it) is saved with the definition; the avatar and quick actions are changed with agents.update-profile. disabledTools replaces the whole list of turned-off tools (send [] to turn every tool on). A version that is no longer current is refused, so read the agent again first. The visibility cannot be changed here (that is done on the agents page of the web app). A change to your own private agent may be remembered by the person; a change to a shared agent is confirmed every time.',
|
|
262
|
+
description: 'Change an agent you may edit: your own, private or shared, and as an org admin any agent of the org. Send the version you read from agents.get and only the fields to change; the others keep their value. The description (one short paragraph, "" removes it) is saved with the definition; the avatar and quick actions are changed with agents.update-profile. disabledTools replaces the whole list of turned-off tools (send [] to turn every tool on). A version that is no longer current is refused, so read the agent again first. The visibility cannot be changed here (that is done on the agents page of the web app). A change to your own private agent may be remembered by the person; a change to a shared agent, or one that sets a tool policy to allow, is confirmed every time.',
|
|
250
263
|
input: z
|
|
251
264
|
.object({
|
|
252
265
|
agentId: AgentId,
|
|
@@ -289,7 +302,7 @@ let AgentsOperations = class AgentsOperations {
|
|
|
289
302
|
next: "The agent changed since you read it: read it again with agents.get, then send its current version.",
|
|
290
303
|
},
|
|
291
304
|
],
|
|
292
|
-
confirmFor: (i, ctx) => this.updateClass(i.agentId, ctx),
|
|
305
|
+
confirmFor: (i, ctx) => this.updateClass(i.agentId, i.toolPolicies, ctx),
|
|
293
306
|
summary: async (i, ctx) => {
|
|
294
307
|
const a = await this.agents.get(ctx.orgId, i.agentId, ctx.actorAccountId);
|
|
295
308
|
const name = named(a.definition.name);
|
|
@@ -353,7 +366,7 @@ let AgentsOperations = class AgentsOperations {
|
|
|
353
366
|
// needs no declaration: an input that accepts less than the route passes the parity test.
|
|
354
367
|
omits: ["expectedUpdatedAt"],
|
|
355
368
|
confirm: "personal",
|
|
356
|
-
confirmFor: (i, ctx) => this.updateClass(i.agentId, ctx),
|
|
369
|
+
confirmFor: (i, ctx) => this.updateClass(i.agentId, undefined, ctx),
|
|
357
370
|
errors: [
|
|
358
371
|
{
|
|
359
372
|
code: "agent.not_found",
|
|
@@ -493,7 +506,7 @@ let AgentsOperations = class AgentsOperations {
|
|
|
493
506
|
confirm: "personal",
|
|
494
507
|
// destructive: asked every time and never remembered, a shared agent as an org write
|
|
495
508
|
rememberable: false,
|
|
496
|
-
confirmFor: (i, ctx) => this.updateClass(i.agentId, ctx),
|
|
509
|
+
confirmFor: (i, ctx) => this.updateClass(i.agentId, undefined, ctx),
|
|
497
510
|
errors: [
|
|
498
511
|
{
|
|
499
512
|
code: "agent.not_found",
|
|
@@ -578,7 +591,7 @@ let AgentsOperations = class AgentsOperations {
|
|
|
578
591
|
authz: { orgAction: "agents.create" },
|
|
579
592
|
mirrors: ["POST /api/v1/orgs/:orgId/agents/:agentId/pending-connectors/:key/bind"],
|
|
580
593
|
confirm: "personal",
|
|
581
|
-
confirmFor: (i, ctx) => this.updateClass(i.agentId, ctx),
|
|
594
|
+
confirmFor: (i, ctx) => this.updateClass(i.agentId, undefined, ctx),
|
|
582
595
|
errors: [
|
|
583
596
|
{
|
|
584
597
|
code: "agent.pending_connector_not_found",
|
|
@@ -32,6 +32,7 @@ const LABEL = {
|
|
|
32
32
|
skill: { en: "platform skill", zh: "平台技能" },
|
|
33
33
|
agent_template: { en: "platform agent template", zh: "平台智能体模板" },
|
|
34
34
|
connector_template: { en: "platform connector template", zh: "平台连接器模板" },
|
|
35
|
+
theme: { en: "platform theme", zh: "平台主题" },
|
|
35
36
|
};
|
|
36
37
|
const REFUSED = {
|
|
37
38
|
"plugin.disabled": "This component is disabled by the super admin and cannot be switched on",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type OnModuleInit } from "@nestjs/common";
|
|
2
2
|
import { OrgSettingsService } from "../../orgs/settings.service.js";
|
|
3
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
3
4
|
import { PlatformOperations } from "../registry.js";
|
|
4
5
|
/**
|
|
5
6
|
* Org settings operations of the `Platform` tool (spec §14): read the settings every member sees,
|
|
@@ -11,6 +12,7 @@ import { PlatformOperations } from "../registry.js";
|
|
|
11
12
|
export declare class OrgSettingsOperations implements OnModuleInit {
|
|
12
13
|
private readonly registry;
|
|
13
14
|
private readonly settings;
|
|
14
|
-
|
|
15
|
+
private readonly themes;
|
|
16
|
+
constructor(registry: PlatformOperations, settings: OrgSettingsService, themes: ThemesService);
|
|
15
17
|
onModuleInit(): void;
|
|
16
18
|
}
|
|
@@ -10,6 +10,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
10
10
|
import { Inject, Injectable } from "@nestjs/common";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import { OrgSettingsPatchSchema, OrgSettingsService } from "../../orgs/settings.service.js";
|
|
13
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
13
14
|
import { defineOperation } from "../operation.js";
|
|
14
15
|
import { PlatformOperations } from "../registry.js";
|
|
15
16
|
import { precheckBy, viaAgent } from "./errors.js";
|
|
@@ -28,15 +29,17 @@ const show = (v) => (v === null ? "default" : JSON.stringify(v));
|
|
|
28
29
|
let OrgSettingsOperations = class OrgSettingsOperations {
|
|
29
30
|
registry;
|
|
30
31
|
settings;
|
|
31
|
-
|
|
32
|
+
themes;
|
|
33
|
+
constructor(registry, settings, themes) {
|
|
32
34
|
this.registry = registry;
|
|
33
35
|
this.settings = settings;
|
|
36
|
+
this.themes = themes;
|
|
34
37
|
}
|
|
35
38
|
onModuleInit() {
|
|
36
39
|
this.registry.register([
|
|
37
40
|
defineOperation({
|
|
38
41
|
id: "org-settings.get",
|
|
39
|
-
description: "Read this org's settings: toolSearch, locale, sandboxToolPolicy, platformTool (on, read-only or off), sandboxEgress and wakeOnBackgroundTask (absent means it follows the deployment), the deployment's sandbox egress default and the sandbox cpu / memory limits in effect.",
|
|
42
|
+
description: "Read this org's settings: toolSearch, locale, sandboxToolPolicy, platformTool (on, read-only or off), sandboxEgress and wakeOnBackgroundTask (absent means it follows the deployment), theme (the org's default theme id, null or absent following the platform, and personal: allowed or locked), the deployment's sandbox egress default and the sandbox cpu / memory limits in effect.",
|
|
40
43
|
input: z.object({}).strict(),
|
|
41
44
|
example: {},
|
|
42
45
|
authz: { orgAction: "org.read" },
|
|
@@ -50,7 +53,7 @@ let OrgSettingsOperations = class OrgSettingsOperations {
|
|
|
50
53
|
}),
|
|
51
54
|
defineOperation({
|
|
52
55
|
id: "org-settings.update",
|
|
53
|
-
description: "Change this org's settings (org admins). Give only the settings to change; null clears sandboxEgress or wakeOnBackgroundTask so they follow the deployment again. Setting platformTool to off or read-only takes effect from the next call and cuts this Platform tool off in the org, so say so before asking; an org admin switches it back on in the web settings.",
|
|
56
|
+
description: "Change this org's settings (org admins). Give only the settings to change; null clears sandboxEgress or wakeOnBackgroundTask so they follow the deployment again. theme: { id, personal } sets the org's default theme (a theme id from themes.list, or null to follow the platform) and whether members may pick their own (allowed) or not (locked); null clears it. Setting platformTool to off or read-only takes effect from the next call and cuts this Platform tool off in the org, so say so before asking; an org admin switches it back on in the web settings.",
|
|
54
57
|
input: OrgSettingsPatchSchema.refine((i) => Object.values(i).some((v) => v !== undefined), {
|
|
55
58
|
message: "give at least one setting",
|
|
56
59
|
}),
|
|
@@ -63,22 +66,43 @@ let OrgSettingsOperations = class OrgSettingsOperations {
|
|
|
63
66
|
code: "org.sandbox_egress_not_allowed",
|
|
64
67
|
next: "This deployment disables sandbox network access, so the org can only set sandboxEgress to none; ask the super admin to change sandbox.limits.egress.",
|
|
65
68
|
},
|
|
69
|
+
{
|
|
70
|
+
code: "theme.not_available",
|
|
71
|
+
next: "Pick a theme id that themes.list shows for this org, or null to follow the platform.",
|
|
72
|
+
},
|
|
66
73
|
{
|
|
67
74
|
code: "validation_failed",
|
|
68
75
|
next: "Fix the setting as the message says (org-settings.get shows the current values).",
|
|
69
76
|
},
|
|
70
77
|
],
|
|
71
78
|
precheck: (i) => precheckBy(async () => this.settings.check(i)),
|
|
72
|
-
summary: (i) => {
|
|
73
|
-
const
|
|
79
|
+
summary: async (i, ctx) => {
|
|
80
|
+
const { theme, ...rest } = i;
|
|
81
|
+
const parts = Object.entries(rest)
|
|
74
82
|
.filter(([, v]) => v !== undefined)
|
|
75
83
|
.map(([k, v]) => `${k} → ${show(v)}`);
|
|
84
|
+
const zhParts = [...parts];
|
|
85
|
+
const enParts = [...parts];
|
|
86
|
+
if (theme !== undefined) {
|
|
87
|
+
// the theme by its name when it is on in this org; any other id is shown as given
|
|
88
|
+
const name = theme?.id == null ? null : await this.themes.nameIn(ctx.orgId, theme.id);
|
|
89
|
+
if (theme === null) {
|
|
90
|
+
zhParts.push("theme → 清除(跟随平台,允许个人选择)");
|
|
91
|
+
enParts.push("theme → cleared (follow the platform, personal picks allowed)");
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const zh = theme.id === null ? "跟随平台" : (name?.zh ?? theme.id);
|
|
95
|
+
const en = theme.id === null ? "follow the platform" : (name?.en ?? theme.id);
|
|
96
|
+
zhParts.push(`theme → ${zh}(个人选择:${theme.personal === "locked" ? "锁定" : "允许"})`);
|
|
97
|
+
enParts.push(`theme → ${en} (personal picks ${theme.personal === "locked" ? "locked" : "allowed"})`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
76
100
|
const warn = i.platformTool === "off" || i.platformTool === "read-only";
|
|
77
101
|
return {
|
|
78
|
-
zh: `修改组织设置:${
|
|
102
|
+
zh: `修改组织设置:${zhParts.join(",")}${warn
|
|
79
103
|
? "(之后智能体不能再用平台工具" + (i.platformTool === "off" ? "" : "写入") + ")"
|
|
80
104
|
: ""}`,
|
|
81
|
-
en: `Update the org settings: ${
|
|
105
|
+
en: `Update the org settings: ${enParts.join(", ")}${warn
|
|
82
106
|
? `; from the next call the Platform tool is ${i.platformTool === "off" ? "off" : "read-only"} in this org`
|
|
83
107
|
: ""}`,
|
|
84
108
|
};
|
|
@@ -97,6 +121,7 @@ let OrgSettingsOperations = class OrgSettingsOperations {
|
|
|
97
121
|
OrgSettingsOperations = __decorate([
|
|
98
122
|
Injectable(),
|
|
99
123
|
__param(0, Inject(PlatformOperations)),
|
|
100
|
-
__param(1, Inject(OrgSettingsService))
|
|
124
|
+
__param(1, Inject(OrgSettingsService)),
|
|
125
|
+
__param(2, Inject(ThemesService))
|
|
101
126
|
], OrgSettingsOperations);
|
|
102
127
|
export { OrgSettingsOperations };
|
|
@@ -2,6 +2,7 @@ import { type OnModuleInit } from "@nestjs/common";
|
|
|
2
2
|
import { AgentsService } from "../../agents/agents.service.js";
|
|
3
3
|
import { AccountsService } from "../../identity/accounts.js";
|
|
4
4
|
import { OrgSettingsService } from "../../orgs/settings.service.js";
|
|
5
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
5
6
|
import { ToolRegistry } from "../../tools/registry.js";
|
|
6
7
|
import { PlatformActor } from "../actor.js";
|
|
7
8
|
import { PlatformOperations } from "../registry.js";
|
|
@@ -16,7 +17,8 @@ export declare class PlatformOperationsProvider implements OnModuleInit {
|
|
|
16
17
|
private readonly settings;
|
|
17
18
|
private readonly tools;
|
|
18
19
|
private readonly accounts;
|
|
19
|
-
|
|
20
|
+
private readonly themes;
|
|
21
|
+
constructor(registry: PlatformOperations, actor: PlatformActor, agents: AgentsService, settings: OrgSettingsService, tools: ToolRegistry, accounts: AccountsService, themes: ThemesService);
|
|
20
22
|
/**
|
|
21
23
|
* The agent's tools by the keys the model sees, as the registry resolves them for a run (tools
|
|
22
24
|
* default-on spec §8): every tool the org offers that the definition does not turn off, builtins
|
|
@@ -14,6 +14,7 @@ import { AccountsService } from "../../identity/accounts.js";
|
|
|
14
14
|
import { PreferencesSchema } from "../../identity/me.schemas.js";
|
|
15
15
|
import { can } from "../../orgs/roles.js";
|
|
16
16
|
import { effectiveSandboxEgress, OrgSettingsService } from "../../orgs/settings.service.js";
|
|
17
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
17
18
|
import { SANDBOX_TOOL_NAMES } from "../../tools/builtin-names.js";
|
|
18
19
|
import { ToolRegistry } from "../../tools/registry.js";
|
|
19
20
|
import { PlatformActor } from "../actor.js";
|
|
@@ -47,13 +48,15 @@ let PlatformOperationsProvider = class PlatformOperationsProvider {
|
|
|
47
48
|
settings;
|
|
48
49
|
tools;
|
|
49
50
|
accounts;
|
|
50
|
-
|
|
51
|
+
themes;
|
|
52
|
+
constructor(registry, actor, agents, settings, tools, accounts, themes) {
|
|
51
53
|
this.registry = registry;
|
|
52
54
|
this.actor = actor;
|
|
53
55
|
this.agents = agents;
|
|
54
56
|
this.settings = settings;
|
|
55
57
|
this.tools = tools;
|
|
56
58
|
this.accounts = accounts;
|
|
59
|
+
this.themes = themes;
|
|
57
60
|
}
|
|
58
61
|
/**
|
|
59
62
|
* The agent's tools by the keys the model sees, as the registry resolves them for a run (tools
|
|
@@ -152,7 +155,7 @@ let PlatformOperationsProvider = class PlatformOperationsProvider {
|
|
|
152
155
|
}),
|
|
153
156
|
defineOperation({
|
|
154
157
|
id: "platform.preferences",
|
|
155
|
-
description: "Read your own preferences: your time zone (an IANA name such as Asia/Shanghai
|
|
158
|
+
description: "Read your own preferences: your time zone (an IANA name such as Asia/Shanghai, or null when it follows the time zone of the browser you send messages from; the run context already tells you the zone in effect for this message) and your theme (a theme id, or null when you follow the org's theme; themes.list names them).",
|
|
156
159
|
input: EMPTY,
|
|
157
160
|
example: {},
|
|
158
161
|
// any signed-in person may call the route; every run's actor is a member of this org
|
|
@@ -163,8 +166,10 @@ let PlatformOperationsProvider = class PlatformOperationsProvider {
|
|
|
163
166
|
}),
|
|
164
167
|
defineOperation({
|
|
165
168
|
id: "platform.set-preferences",
|
|
166
|
-
description: "
|
|
167
|
-
input: PreferencesSchema,
|
|
169
|
+
description: "Change your own preferences; give only the ones to change, the others keep their values. timeZone: an IANA name such as Europe/Berlin, or null to follow the time zone of the browser you send messages from; it applies to the messages you send afterwards, on the web and in IM (the current run keeps its zone). theme: a theme id from themes.list (it applies in every org where that theme is on and personal picks are allowed), or null to follow the org's theme.",
|
|
170
|
+
input: PreferencesSchema.refine((i) => Object.values(i).some((v) => v !== undefined), {
|
|
171
|
+
message: "give timeZone, theme or both",
|
|
172
|
+
}),
|
|
168
173
|
example: { timeZone: "Asia/Shanghai" },
|
|
169
174
|
authz: { orgAction: "agents.use" },
|
|
170
175
|
mirrors: ["PUT /api/v1/me/preferences"],
|
|
@@ -174,20 +179,41 @@ let PlatformOperationsProvider = class PlatformOperationsProvider {
|
|
|
174
179
|
code: "validation_failed",
|
|
175
180
|
next: "Use an IANA time zone name such as Asia/Shanghai or America/New_York, or null.",
|
|
176
181
|
},
|
|
182
|
+
{
|
|
183
|
+
code: "theme.not_available",
|
|
184
|
+
next: "Pick a theme id that themes.list shows for this org, or null to follow the org's theme.",
|
|
185
|
+
},
|
|
177
186
|
],
|
|
178
187
|
summary: async (input, ctx) => {
|
|
179
|
-
const now =
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
const now = await this.accounts.preferences(ctx.actorAccountId);
|
|
189
|
+
const zh = [];
|
|
190
|
+
const en = [];
|
|
191
|
+
if (input.timeZone !== undefined) {
|
|
192
|
+
const from = now.timeZone;
|
|
193
|
+
zh.push(`把你的时区从「${from ?? "跟随浏览器"}」改为「${input.timeZone ?? "跟随浏览器"}」`);
|
|
194
|
+
en.push(`Change your time zone from "${from ?? "follow the browser"}" to "${input.timeZone ?? "follow the browser"}"`);
|
|
195
|
+
}
|
|
196
|
+
if (input.theme !== undefined) {
|
|
197
|
+
// only themes on in one of your orgs are named; any other id is shown as given
|
|
198
|
+
const name = async (id) => id === null
|
|
199
|
+
? null
|
|
200
|
+
: ((await this.themes.nameForAccount(ctx.actorAccountId, id)) ?? {
|
|
201
|
+
en: id,
|
|
202
|
+
zh: id,
|
|
203
|
+
});
|
|
204
|
+
const from = await name(now.theme);
|
|
205
|
+
const to = await name(input.theme);
|
|
206
|
+
const inZh = (n) => (n === null ? "跟随组织" : n.zh);
|
|
207
|
+
const inEn = (n) => (n === null ? "follow the org" : n.en);
|
|
208
|
+
zh.push(`把你的主题从「${inZh(from)}」改为「${inZh(to)}」`);
|
|
209
|
+
en.push(`Change your theme from "${inEn(from)}" to "${inEn(to)}"`);
|
|
210
|
+
}
|
|
211
|
+
return { zh: zh.join(";"), en: en.join("; ") };
|
|
189
212
|
},
|
|
190
|
-
run: async (input, ctx) => this.accounts.setPreferences(ctx.actorAccountId, {
|
|
213
|
+
run: async (input, ctx) => this.accounts.setPreferences(ctx.actorAccountId, {
|
|
214
|
+
timeZone: input.timeZone,
|
|
215
|
+
theme: input.theme,
|
|
216
|
+
}),
|
|
191
217
|
}),
|
|
192
218
|
]);
|
|
193
219
|
}
|
|
@@ -199,6 +225,7 @@ PlatformOperationsProvider = __decorate([
|
|
|
199
225
|
__param(2, Inject(AgentsService)),
|
|
200
226
|
__param(3, Inject(OrgSettingsService)),
|
|
201
227
|
__param(4, Inject(ToolRegistry)),
|
|
202
|
-
__param(5, Inject(AccountsService))
|
|
228
|
+
__param(5, Inject(AccountsService)),
|
|
229
|
+
__param(6, Inject(ThemesService))
|
|
203
230
|
], PlatformOperationsProvider);
|
|
204
231
|
export { PlatformOperationsProvider };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type OnModuleInit } from "@nestjs/common";
|
|
2
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
3
|
+
import { PlatformOperations } from "../registry.js";
|
|
4
|
+
/**
|
|
5
|
+
* Theme operations of the `Platform` tool (themes spec §9): the org's theme listing. Setting a
|
|
6
|
+
* theme goes through the settings operations (`platform.set-preferences`, `org-settings.update`,
|
|
7
|
+
* `admin.update-settings`).
|
|
8
|
+
*/
|
|
9
|
+
export declare class ThemesOperations implements OnModuleInit {
|
|
10
|
+
private readonly registry;
|
|
11
|
+
private readonly themes;
|
|
12
|
+
constructor(registry: PlatformOperations, themes: ThemesService);
|
|
13
|
+
onModuleInit(): void;
|
|
14
|
+
}
|