@capybara-hq/kernel 0.1.0-rc.10 → 0.1.0-rc.11
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/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.schemas.d.ts +4 -0
- package/dist/catalog/component-scope.service.d.ts +48 -9
- package/dist/catalog/component-scope.service.js +152 -27
- package/dist/catalog/component-state.d.ts +12 -3
- package/dist/catalog/component-state.js +21 -3
- 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 +37 -6
- 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/db/kernel-schema.d.ts +41 -4
- package/dist/errors.d.ts +25 -0
- package/dist/errors.js +25 -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 +16 -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/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/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/package.json +3 -3
- package/src/migrations/0102_themes.sql +64 -0
- package/src/migrations/0103_ui_theme_setting.sql +7 -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 }) })
|
|
@@ -664,4 +664,20 @@ export const PLATFORM_EXCLUSIONS = [
|
|
|
664
664
|
category: "transport",
|
|
665
665
|
reason: "Server-sent event stream of UI invalidations",
|
|
666
666
|
},
|
|
667
|
+
// themes (themes spec §8-§9)
|
|
668
|
+
{
|
|
669
|
+
route: "GET /api/v1/themes/:id/:version/theme.css",
|
|
670
|
+
category: "transport",
|
|
671
|
+
reason: "Serves a theme version's stylesheet to the browser; an agent reads themes.list",
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
route: "GET /api/v1/themes/:id/:version/assets/:file",
|
|
675
|
+
category: "transport",
|
|
676
|
+
reason: "Serves a theme version's font and logo bytes to the browser",
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
route: "GET /api/v1/platform/theme",
|
|
680
|
+
category: "transport",
|
|
681
|
+
reason: "The platform default theme for the web's pages before sign-in; no session to act for",
|
|
682
|
+
},
|
|
667
683
|
];
|
|
@@ -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 };
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { ThemesService } from "../../themes/themes.service.js";
|
|
13
|
+
import { defineOperation } from "../operation.js";
|
|
14
|
+
import { PlatformOperations } from "../registry.js";
|
|
15
|
+
/**
|
|
16
|
+
* Theme operations of the `Platform` tool (themes spec §9): the org's theme listing. Setting a
|
|
17
|
+
* theme goes through the settings operations (`platform.set-preferences`, `org-settings.update`,
|
|
18
|
+
* `admin.update-settings`).
|
|
19
|
+
*/
|
|
20
|
+
let ThemesOperations = class ThemesOperations {
|
|
21
|
+
registry;
|
|
22
|
+
themes;
|
|
23
|
+
constructor(registry, themes) {
|
|
24
|
+
this.registry = registry;
|
|
25
|
+
this.themes = themes;
|
|
26
|
+
}
|
|
27
|
+
onModuleInit() {
|
|
28
|
+
this.registry.register([
|
|
29
|
+
defineOperation({
|
|
30
|
+
id: "themes.list",
|
|
31
|
+
description: "List the themes on in this org (id, version, name, schemes, logo and the bg / panel / ink / accent swatches per scheme), the theme in effect for you here (resolved; null is the built-in theme) and the org's setting (its default theme id, null following the platform, and whether personal picks are allowed or locked). Use a theme id with platform.set-preferences to change your own theme, or with org-settings.update to change the org's default.",
|
|
32
|
+
input: z.object({}).strict(),
|
|
33
|
+
example: {},
|
|
34
|
+
authz: { orgAction: "org.read" },
|
|
35
|
+
mirrors: ["GET /api/v1/orgs/:orgId/themes"],
|
|
36
|
+
confirm: "read",
|
|
37
|
+
run: async (_input, ctx) => this.themes.forOrg(ctx.orgId, ctx.actorAccountId),
|
|
38
|
+
}),
|
|
39
|
+
]);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
ThemesOperations = __decorate([
|
|
43
|
+
Injectable(),
|
|
44
|
+
__param(0, Inject(PlatformOperations)),
|
|
45
|
+
__param(1, Inject(ThemesService))
|
|
46
|
+
], ThemesOperations);
|
|
47
|
+
export { ThemesOperations };
|
|
@@ -25,11 +25,12 @@ import { PluginsOperations } from "./ops/plugins.ops.js";
|
|
|
25
25
|
import { PreviewersOperations } from "./ops/previewers.ops.js";
|
|
26
26
|
import { RequestsOperations } from "./ops/requests.ops.js";
|
|
27
27
|
import { SkillsOperations } from "./ops/skills.ops.js";
|
|
28
|
+
import { ThemesOperations } from "./ops/themes.ops.js";
|
|
28
29
|
/**
|
|
29
30
|
* One provider per domain, each taking `PlatformOperations` as its first constructor argument:
|
|
30
31
|
* the parity test in `tools/checks` builds the operations from it without a Nest app.
|
|
31
32
|
*/
|
|
32
|
-
export declare const PLATFORM_OPERATION_PROVIDERS: readonly [typeof PlatformOperationsProvider, typeof SkillsOperations, typeof AgentsOperations, typeof AgentTemplatesOperations, typeof PluginsOperations, typeof MarketplacesOperations, typeof RequestsOperations, typeof ConnectorsOperations, typeof ExtensionsOperations, typeof ConversationsOperations, typeof ComponentsOperations, typeof AccountsOperations, typeof OrgsOperations, typeof AdminOperations, typeof CatalogAdminOperations, typeof OrgPluginsOperations, typeof ExtensionsAdminOperations, typeof ModelsOperations, typeof InboxOperations, typeof ApprovalsOperations, typeof ChannelsOperations, typeof OrgSettingsOperations, typeof EvalsOperations, typeof BackgroundOperations, typeof PreviewersOperations, typeof EnvironmentsOperations, typeof AgentSkillsOperations];
|
|
33
|
+
export declare const PLATFORM_OPERATION_PROVIDERS: readonly [typeof PlatformOperationsProvider, typeof SkillsOperations, typeof AgentsOperations, typeof AgentTemplatesOperations, typeof PluginsOperations, typeof MarketplacesOperations, typeof RequestsOperations, typeof ConnectorsOperations, typeof ExtensionsOperations, typeof ConversationsOperations, typeof ComponentsOperations, typeof AccountsOperations, typeof OrgsOperations, typeof AdminOperations, typeof CatalogAdminOperations, typeof OrgPluginsOperations, typeof ExtensionsAdminOperations, typeof ModelsOperations, typeof InboxOperations, typeof ApprovalsOperations, typeof ChannelsOperations, typeof OrgSettingsOperations, typeof EvalsOperations, typeof BackgroundOperations, typeof PreviewersOperations, typeof EnvironmentsOperations, typeof AgentSkillsOperations, typeof ThemesOperations];
|
|
33
34
|
/**
|
|
34
35
|
* The `Platform` tool's operations (ruling P2): one provider per domain, each registering its
|
|
35
36
|
* operations into `PlatformOperations` from `onModuleInit`. It imports the domain modules, which
|
|
@@ -20,6 +20,7 @@ import { ModelsModule } from "../models/models.module.js";
|
|
|
20
20
|
import { OrgsModule } from "../orgs/orgs.module.js";
|
|
21
21
|
import { ProvidersModule } from "../runtime/providers.js";
|
|
22
22
|
import { SkillsModule } from "../skills/skills.module.js";
|
|
23
|
+
import { ThemesModule } from "../themes/themes.module.js";
|
|
23
24
|
import { ToolsModule } from "../tools/tools.module.js";
|
|
24
25
|
import { AccountsOperations } from "./ops/accounts.ops.js";
|
|
25
26
|
import { AdminOperations } from "./ops/admin.ops.js";
|
|
@@ -48,6 +49,7 @@ import { PluginsOperations } from "./ops/plugins.ops.js";
|
|
|
48
49
|
import { PreviewersOperations } from "./ops/previewers.ops.js";
|
|
49
50
|
import { RequestsOperations } from "./ops/requests.ops.js";
|
|
50
51
|
import { SkillsOperations } from "./ops/skills.ops.js";
|
|
52
|
+
import { ThemesOperations } from "./ops/themes.ops.js";
|
|
51
53
|
import { PlatformModule } from "./platform.module.js";
|
|
52
54
|
/**
|
|
53
55
|
* One provider per domain, each taking `PlatformOperations` as its first constructor argument:
|
|
@@ -87,6 +89,8 @@ export const PLATFORM_OPERATION_PROVIDERS = [
|
|
|
87
89
|
// Task 11b: environments, agent skills
|
|
88
90
|
EnvironmentsOperations,
|
|
89
91
|
AgentSkillsOperations,
|
|
92
|
+
// themes (themes spec §9)
|
|
93
|
+
ThemesOperations,
|
|
90
94
|
];
|
|
91
95
|
/**
|
|
92
96
|
* The `Platform` tool's operations (ruling P2): one provider per domain, each registering its
|
|
@@ -115,6 +119,7 @@ PlatformOpsModule = __decorate([
|
|
|
115
119
|
EnvironmentsModule,
|
|
116
120
|
BackgroundModule,
|
|
117
121
|
FilesModule,
|
|
122
|
+
ThemesModule,
|
|
118
123
|
],
|
|
119
124
|
providers: [...PLATFORM_OPERATION_PROVIDERS],
|
|
120
125
|
})
|
|
@@ -20,6 +20,7 @@ import { INBOX_ROUTES } from "../inbox/inbox.schemas.js";
|
|
|
20
20
|
import { ORG_MODEL_ROUTES } from "../models/org-models.schemas.js";
|
|
21
21
|
import { ORG_ROUTES, ORG_SETTINGS_ROUTES } from "../orgs/orgs.schemas.js";
|
|
22
22
|
import { SKILL_ROUTES } from "../skills/skills.schemas.js";
|
|
23
|
+
import { THEME_ROUTES } from "../themes/themes.schemas.js";
|
|
23
24
|
import { APPROVAL_ROUTES } from "../tools/approvals.schemas.js";
|
|
24
25
|
import { CONNECTOR_ROUTES } from "../tools/connectors.schemas.js";
|
|
25
26
|
/**
|
|
@@ -60,4 +61,6 @@ export const ROUTE_SCHEMAS = [
|
|
|
60
61
|
...ENVIRONMENT_ROUTES,
|
|
61
62
|
// personal preferences (run context spec §3.4)
|
|
62
63
|
...ME_ROUTES,
|
|
64
|
+
// themes (themes spec §9)
|
|
65
|
+
...THEME_ROUTES,
|
|
63
66
|
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ParsedTheme } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
/**
|
|
3
|
+
* The stylesheet of a stored theme (themes spec §8): each scheme's overrides under
|
|
4
|
+
* `:root[data-theme="<scheme>"]` (a single-scheme theme: its whole scheme, the same block under
|
|
5
|
+
* both selectors, with `color-scheme: <scheme>`), an `@font-face` per font (`src` from
|
|
6
|
+
* `assetUrl(<the font's path as stored>)`, the one URL builder), and each font role's stack with
|
|
7
|
+
* the theme's families first, then the built-in stack. Every stored value is re-validated (token
|
|
8
|
+
* names against the overridable list, values against the SDK grammar, radius 0-16, families,
|
|
9
|
+
* paths, weights, styles, roles); one that fails is left out, and `onSkipped` (when given and
|
|
10
|
+
* something was skipped) is called once with the paths of every skipped value.
|
|
11
|
+
*/
|
|
12
|
+
export declare function renderThemeCss(theme: ParsedTheme, assetUrl: (pluginPath: string) => string, onSkipped?: (paths: string[]) => void): string;
|