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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/dist/admin/admin.schemas.d.ts +5 -13
  2. package/dist/catalog/admin-catalog.controller.d.ts +39 -5
  3. package/dist/catalog/admin-catalog.controller.js +75 -6
  4. package/dist/catalog/admin-catalog.schemas.d.ts +10 -0
  5. package/dist/catalog/admin-catalog.schemas.js +7 -0
  6. package/dist/catalog/appearance.schemas.d.ts +10 -0
  7. package/dist/catalog/appearance.schemas.js +20 -0
  8. package/dist/catalog/appearance.service.d.ts +105 -0
  9. package/dist/catalog/appearance.service.js +306 -0
  10. package/dist/catalog/catalog-content.d.ts +9 -1
  11. package/dist/catalog/catalog-content.js +2 -1
  12. package/dist/catalog/catalog-files.d.ts +3 -2
  13. package/dist/catalog/catalog-files.js +8 -5
  14. package/dist/catalog/catalog-import.module.js +3 -0
  15. package/dist/catalog/catalog-items.d.ts +11 -0
  16. package/dist/catalog/catalog-items.js +21 -0
  17. package/dist/catalog/catalog-scope.service.d.ts +7 -0
  18. package/dist/catalog/catalog-scope.service.js +55 -15
  19. package/dist/catalog/catalog.service.js +10 -2
  20. package/dist/catalog/cli.js +3 -0
  21. package/dist/catalog/component-scope.service.d.ts +14 -1
  22. package/dist/catalog/component-scope.service.js +12 -2
  23. package/dist/catalog/marketplaces.service.d.ts +1 -1
  24. package/dist/catalog/org-catalog.controller.d.ts +5 -4
  25. package/dist/catalog/org-catalog.controller.js +5 -4
  26. package/dist/catalog/org-catalog.schemas.d.ts +18 -2
  27. package/dist/catalog/org-catalog.schemas.js +16 -2
  28. package/dist/catalog/org-catalog.service.js +8 -2
  29. package/dist/catalog/org-extension.controller.d.ts +27 -7
  30. package/dist/catalog/org-extension.controller.js +48 -6
  31. package/dist/catalog/plugin-import.d.ts +28 -4
  32. package/dist/catalog/plugin-import.js +96 -20
  33. package/dist/catalog/plugin-package.d.ts +4 -2
  34. package/dist/catalog/plugin-package.js +66 -12
  35. package/dist/catalog/plugin-upgrade.d.ts +15 -1
  36. package/dist/catalog/plugin-upgrade.js +18 -5
  37. package/dist/channels/connections.controller.d.ts +1 -1
  38. package/dist/channels/connections.controller.js +1 -1
  39. package/dist/channels/connections.service.d.ts +22 -5
  40. package/dist/channels/connections.service.js +56 -10
  41. package/dist/channels/webhook.d.ts +21 -1
  42. package/dist/channels/webhook.js +39 -4
  43. package/dist/client/client-access.service.d.ts +101 -0
  44. package/dist/client/client-access.service.js +294 -0
  45. package/dist/client/client-builds.service.d.ts +109 -0
  46. package/dist/client/client-builds.service.js +229 -0
  47. package/dist/client/client-delivery.controller.d.ts +25 -0
  48. package/dist/client/client-delivery.controller.js +66 -0
  49. package/dist/client/client-files.d.ts +48 -0
  50. package/dist/client/client-files.js +136 -0
  51. package/dist/client/client-reports.cron.d.ts +13 -0
  52. package/dist/client/client-reports.cron.js +42 -0
  53. package/dist/client/client-reports.service.d.ts +30 -0
  54. package/dist/client/client-reports.service.js +102 -0
  55. package/dist/client/client.controller.d.ts +45 -0
  56. package/dist/client/client.controller.js +121 -0
  57. package/dist/client/client.module.d.ts +7 -0
  58. package/dist/client/client.module.js +26 -0
  59. package/dist/client/client.schemas.d.ts +55 -0
  60. package/dist/client/client.schemas.js +27 -0
  61. package/dist/ctx/create-ctx.d.ts +19 -4
  62. package/dist/ctx/create-ctx.js +51 -3
  63. package/dist/db/kernel-schema.d.ts +58 -2
  64. package/dist/errors.d.ts +33 -0
  65. package/dist/errors.js +33 -0
  66. package/dist/extensions/admin-ops.d.ts +4 -1
  67. package/dist/extensions/admin-ops.js +22 -1
  68. package/dist/extensions/admin-view.d.ts +8 -0
  69. package/dist/extensions/admin-view.js +78 -0
  70. package/dist/extensions/blobs.d.ts +14 -1
  71. package/dist/extensions/blobs.js +48 -5
  72. package/dist/extensions/guide-places.d.ts +66 -0
  73. package/dist/extensions/guide-places.js +152 -0
  74. package/dist/extensions/host.d.ts +6 -1
  75. package/dist/extensions/host.js +23 -12
  76. package/dist/extensions/instance.d.ts +5 -1
  77. package/dist/extensions/instance.js +8 -0
  78. package/dist/extensions/ledger.d.ts +1 -1
  79. package/dist/extensions/package.d.ts +4 -3
  80. package/dist/extensions/package.js +5 -1
  81. package/dist/extensions/permission-set.d.ts +35 -5
  82. package/dist/extensions/permission-set.js +36 -5
  83. package/dist/extensions/permission-view.d.ts +38 -7
  84. package/dist/extensions/permission-view.js +27 -8
  85. package/dist/extensions/plugin-guides.d.ts +207 -54
  86. package/dist/extensions/plugin-guides.js +436 -165
  87. package/dist/extensions/sources.d.ts +6 -0
  88. package/dist/extensions/sources.js +2 -0
  89. package/dist/extensions/state.module.js +9 -1
  90. package/dist/http/api.module.js +16 -0
  91. package/dist/identity/settings.d.ts +41 -26
  92. package/dist/identity/settings.js +87 -4
  93. package/dist/infra/lock/lock.service.d.ts +8 -0
  94. package/dist/infra/lock/lock.service.js +27 -0
  95. package/dist/infra/throttler/named-throttlers.d.ts +8 -1
  96. package/dist/infra/throttler/named-throttlers.js +30 -1
  97. package/dist/infra/throttler/throttler.guard.js +1 -1
  98. package/dist/kernel.module.js +3 -0
  99. package/dist/orgs/settings.service.d.ts +2 -26
  100. package/dist/overrides.d.ts +3 -1
  101. package/dist/overrides.js +2 -0
  102. package/dist/platform/exclusions.js +37 -6
  103. package/dist/platform/operation.js +4 -0
  104. package/dist/platform/ops/admin.ops.js +17 -2
  105. package/dist/platform/ops/catalog-admin.ops.d.ts +19 -1
  106. package/dist/platform/ops/catalog-admin.ops.js +85 -2
  107. package/dist/platform/ops/connectors.ops.js +2 -0
  108. package/dist/platform/ops/org-plugins.ops.d.ts +7 -1
  109. package/dist/platform/ops/org-plugins.ops.js +63 -4
  110. package/dist/platform/ops/org-settings.ops.js +2 -2
  111. package/dist/platform/ops/orgs.ops.js +1 -0
  112. package/dist/platform/ops/setup.ops.d.ts +24 -0
  113. package/dist/platform/ops/setup.ops.js +212 -0
  114. package/dist/platform/ops/ui.ops.js +1 -1
  115. package/dist/platform/platform-ops.module.d.ts +2 -1
  116. package/dist/platform/platform-ops.module.js +7 -0
  117. package/dist/platform/route-schemas.js +8 -0
  118. package/dist/roles/worker.module.js +4 -0
  119. package/dist/setup/kernel-checks.d.ts +91 -0
  120. package/dist/setup/kernel-checks.js +295 -0
  121. package/dist/setup/oauth-token-probe.d.ts +47 -0
  122. package/dist/setup/oauth-token-probe.js +108 -0
  123. package/dist/setup/redact-check.d.ts +18 -0
  124. package/dist/setup/redact-check.js +46 -0
  125. package/dist/setup/setup-check-registry.d.ts +86 -0
  126. package/dist/setup/setup-check-registry.js +75 -0
  127. package/dist/setup/setup-checks.controller.d.ts +28 -0
  128. package/dist/setup/setup-checks.controller.js +78 -0
  129. package/dist/setup/setup-checks.schemas.d.ts +38 -0
  130. package/dist/setup/setup-checks.schemas.js +43 -0
  131. package/dist/setup/setup-checks.service.d.ts +144 -0
  132. package/dist/setup/setup-checks.service.js +683 -0
  133. package/dist/setup/setup-guides.controller.d.ts +18 -0
  134. package/dist/setup/setup-guides.controller.js +48 -0
  135. package/dist/setup/setup-guides.schemas.d.ts +10 -0
  136. package/dist/setup/setup-guides.schemas.js +6 -0
  137. package/dist/setup/setup-guides.service.d.ts +126 -0
  138. package/dist/setup/setup-guides.service.js +315 -0
  139. package/dist/setup/setup.module.d.ts +8 -0
  140. package/dist/setup/setup.module.js +31 -0
  141. package/dist/themes/render-css.d.ts +2 -1
  142. package/dist/themes/render-css.js +5 -2
  143. package/dist/themes/theme-delivery.service.d.ts +4 -2
  144. package/dist/themes/theme-delivery.service.js +8 -3
  145. package/dist/themes/theme-state.d.ts +28 -7
  146. package/dist/themes/theme-state.js +24 -6
  147. package/dist/themes/themes-public.controller.d.ts +7 -2
  148. package/dist/themes/themes-public.controller.js +11 -5
  149. package/dist/themes/themes.service.js +2 -2
  150. package/dist/tools/connectors.controller.d.ts +28 -11
  151. package/dist/tools/connectors.controller.js +49 -14
  152. package/dist/tools/connectors.schemas.d.ts +4 -0
  153. package/dist/tools/connectors.schemas.js +4 -0
  154. package/dist/tools/connectors.service.d.ts +30 -2
  155. package/dist/tools/connectors.service.js +98 -3
  156. package/dist/tools/credentials.d.ts +20 -0
  157. package/dist/tools/credentials.js +90 -1
  158. package/dist/tools/oauth/tokens.d.ts +20 -0
  159. package/dist/tools/oauth/tokens.js +49 -24
  160. package/dist/tools/pipeline.d.ts +3 -2
  161. package/dist/ui/arrangement.d.ts +41 -50
  162. package/dist/ui/arrangement.js +88 -15
  163. package/dist/ui/registry.d.ts +13 -3
  164. package/dist/ui/registry.js +15 -4
  165. package/dist/ui/ui.schemas.d.ts +4 -0
  166. package/dist/ui/views.d.ts +36 -9
  167. package/dist/ui/views.js +58 -28
  168. package/package.json +3 -3
  169. package/src/migrations/0106_setup_guides_v2.sql +10 -0
  170. package/src/migrations/0107_extension_client_builds.sql +50 -0
@@ -53,19 +53,11 @@ export declare const DeploymentSettingsBody: z.ZodObject<{
53
53
  uiTheme: z.ZodOptional<z.ZodObject<{
54
54
  id: z.ZodNullable<z.ZodString>;
55
55
  }, z.core.$strict>>;
56
- uiArrangement: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
57
- "agent.detail.section": "agent.detail.section";
58
- "conversation.panel": "conversation.panel";
59
- "conversation.properties.section": "conversation.properties.section";
60
- "conversation.tool-result.card": "conversation.tool-result.card";
61
- "file.preview": "file.preview";
62
- "org.page": "org.page";
63
- "org.settings.section": "org.settings.section";
64
- "platform.page": "platform.page";
65
- }> & z.core.$partial, z.ZodNullable<z.ZodObject<{
66
- hidden: z.ZodArray<z.ZodString>;
67
- order: z.ZodArray<z.ZodString>;
68
- }, z.core.$strict>>>>;
56
+ uiArrangement: z.ZodOptional<z.ZodType<Partial<Record<"agent.detail.section" | "conversation.composer.frame" | "conversation.empty" | "conversation.panel" | "conversation.properties.section" | "conversation.tool-result.card" | "file.preview" | "org.page" | "org.settings.section" | "platform.page" | "shell.brand" | "shell.overlay", import("../ui/arrangement.js").UiArrangementEntry | null>>, unknown, z.core.$ZodTypeInternals<Partial<Record<"agent.detail.section" | "conversation.composer.frame" | "conversation.empty" | "conversation.panel" | "conversation.properties.section" | "conversation.tool-result.card" | "file.preview" | "org.page" | "org.settings.section" | "platform.page" | "shell.brand" | "shell.overlay", import("../ui/arrangement.js").UiArrangementEntry | null>>, unknown>>>;
57
+ clientExtensions: z.ZodOptional<z.ZodObject<{
58
+ enabled: z.ZodOptional<z.ZodBoolean>;
59
+ disabled: z.ZodOptional<z.ZodArray<z.ZodString>>;
60
+ }, z.core.$strict>>;
69
61
  }, z.core.$strict>;
70
62
  export declare const PurposeParams: z.ZodObject<{
71
63
  purpose: z.ZodString;
@@ -1,8 +1,13 @@
1
+ import type { SuggestedAppearance } from "@capybara-hq/plugin-sdk";
1
2
  import type { FastifyReply } from "fastify";
2
3
  import { z } from "zod";
4
+ import { type ClientBuildSummary, ClientBuilds } from "../client/client-builds.service.js";
5
+ import { PluginGuides, type RenderedSetupGuide } from "../extensions/plugin-guides.js";
3
6
  import { PluginIcons } from "../extensions/plugin-icons.js";
4
7
  import { type Principal } from "../identity/principal.js";
5
- import { CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
8
+ import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
9
+ import { AppearanceApplyBody } from "./appearance.schemas.js";
10
+ import { type AppearanceResult, AppearanceService } from "./appearance.service.js";
6
11
  import { type CatalogItemDetail, type CatalogItemView, CatalogService, type PermissionsMismatch } from "./catalog.service.js";
7
12
  import { CatalogScopeService, type ScopePreview } from "./catalog-scope.service.js";
8
13
  import { OrgCatalogService } from "./org-catalog.service.js";
@@ -38,7 +43,10 @@ export declare class AdminCatalogController {
38
43
  private readonly scope;
39
44
  private readonly updater;
40
45
  private readonly icons;
41
- constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, icons: PluginIcons);
46
+ private readonly appearance;
47
+ private readonly clientBuilds;
48
+ private readonly guides;
49
+ constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, icons: PluginIcons, appearance: AppearanceService, clientBuilds: ClientBuilds, guides: PluginGuides);
42
50
  /**
43
51
  * Prepares the import of an uploaded plugin (an npm-pack tgz as the raw body,
44
52
  * `application/octet-stream`, at most `packages.maxBytes`): reads and checks the whole plugin
@@ -113,17 +121,43 @@ export declare class AdminCatalogController {
113
121
  nextOffset: number | null;
114
122
  }>;
115
123
  /**
116
- * 条目详情与各版本,另给出 `hasIcon`(最新版本有图标,`GET items/:id/icon` 可取);不存在 → 404
117
- * `catalog.item_not_found`。
124
+ * The item with its versions, plus `hasIcon` (the latest version has an icon, served by `GET
125
+ * items/:id/icon`) and `suggestedAppearance` (the platform version's, null without one: the page
126
+ * offers 应用此插件的外观 when set). Each version carries `client`: its extension package's
127
+ * client build (files with sizes, total, client API version; null without one), what the
128
+ * permission confirmation of an org's upload shows in its 客户端代码 group (client extensions spec
129
+ * §5.4). Unknown -> 404 `catalog.item_not_found`.
118
130
  */
119
- get(id: string): Promise<CatalogItemDetail & {
131
+ get(id: string): Promise<Omit<CatalogItemDetail, "versions"> & {
132
+ versions: (CatalogItemDetail["versions"][number] & {
133
+ client: ClientBuildSummary | null;
134
+ })[];
120
135
  hasIcon: boolean;
136
+ suggestedAppearance: SuggestedAppearance | null;
121
137
  }>;
138
+ /**
139
+ * 应用此插件的外观 (client extensions spec §6.5): sets the plugin's suggested theme as the platform
140
+ * default theme and each suggested replacement as the platform arrangement's `use` of its slot, in
141
+ * one transaction. `dryRun: true` answers the same changes and writes nothing. A theme that cannot
142
+ * be the platform default -> 400 `theme.not_available` (nothing written); a replacement not
143
+ * available on the platform is skipped. No such item, or no suggestion -> 404
144
+ * `catalog.item_not_found`.
145
+ */
146
+ applyAppearance(principal: Principal, id: string, body: z.infer<typeof AppearanceApplyBody>): Promise<AppearanceResult>;
122
147
  /**
123
148
  * The item's icon (disabled items included; same response headers as the org side, see
124
149
  * `sendCatalogIcon`). No icon -> 404 `catalog.icon_not_found`.
125
150
  */
126
151
  icon(id: string, reply: FastifyReply): Promise<void>;
152
+ /**
153
+ * A setup guide of the item as the platform sees it (spec 2026-11-09-setup-guides-v2-design.md
154
+ * §9.3; the admin console's connector template page): any live item, the admin audience, no org
155
+ * (`orgName` unresolved, reason `no_org`), no target, no checks run. Unknown item -> 404
156
+ * `catalog.item_not_found`, unknown guide -> 404 `catalog.guide_not_found`.
157
+ */
158
+ guide(itemId: string, guideId: string, q: z.infer<typeof AdminCatalogGuideQuery>): Promise<{
159
+ guide: RenderedSetupGuide;
160
+ }>;
127
161
  /**
128
162
  * What a scope change (`{ scope, orgs? }`, `orgs` only with `named`) or a disable
129
163
  * (`{ disabled: true }`) would take away: `{ affected: [{ orgId, orgName, agents,
@@ -9,12 +9,16 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
9
9
  };
10
10
  import { Controller, Delete, Get, HttpCode, Inject, Param, Post, Put, Req, Res, } from "@nestjs/common";
11
11
  import { z } from "zod";
12
+ import { ClientBuilds } from "../client/client-builds.service.js";
12
13
  import { ApiError } from "../errors.js";
14
+ import { PluginGuides } from "../extensions/plugin-guides.js";
13
15
  import { PluginIcons } from "../extensions/plugin-icons.js";
14
16
  import { CurrentPrincipal, patTokenId, requireUser, SuperAdmin, } from "../identity/principal.js";
15
17
  import { createZodDto } from "../infra/validation/create-zod-dto.js";
16
18
  import { ZBody, ZQuery } from "../infra/validation/zod-params.js";
17
- import { CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
19
+ import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
20
+ import { AppearanceApplyBody } from "./appearance.schemas.js";
21
+ import { AppearanceService, suggestedAppearanceOf, } from "./appearance.service.js";
18
22
  import { CatalogService, } from "./catalog.service.js";
19
23
  import { CatalogScopeService } from "./catalog-scope.service.js";
20
24
  import { sendCatalogIcon } from "./org-catalog.controller.js";
@@ -42,6 +46,8 @@ class CatalogImportConfirmBody extends createZodDto(ConfirmBody, "CatalogImportC
42
46
  }
43
47
  class CatalogGitImportBody extends createZodDto(GitBody, "CatalogGitImportBody") {
44
48
  }
49
+ class AdminCatalogGuideQueryDto extends createZodDto(AdminCatalogGuideQuery, "AdminCatalogGuideQuery") {
50
+ }
45
51
  class CatalogItemsQueryDto extends createZodDto(CatalogItemsQuery, "CatalogItemsQuery") {
46
52
  }
47
53
  class CatalogNpmImportBody extends createZodDto(NpmBody, "CatalogNpmImportBody") {
@@ -62,6 +68,8 @@ class CatalogUpdatePreviewBodyDto extends createZodDto(CatalogUpdatePreviewBody,
62
68
  }
63
69
  class CatalogUpdateBodyDto extends createZodDto(CatalogUpdateBody, "CatalogUpdateBody") {
64
70
  }
71
+ class AppearanceApplyBodyDto extends createZodDto(AppearanceApplyBody, "AppearanceApplyBody") {
72
+ }
65
73
  /**
66
74
  * The platform catalog (`/api/v1/admin/catalog/*`, super admins): plugin import (upload / npm
67
75
  * prepare, then confirm, which installs the plugin's extension), the item list and detail, scope and
@@ -75,13 +83,19 @@ let AdminCatalogController = class AdminCatalogController {
75
83
  scope;
76
84
  updater;
77
85
  icons;
78
- constructor(catalog, pluginImport, orgCatalog, scope, updater, icons) {
86
+ appearance;
87
+ clientBuilds;
88
+ guides;
89
+ constructor(catalog, pluginImport, orgCatalog, scope, updater, icons, appearance, clientBuilds, guides) {
79
90
  this.catalog = catalog;
80
91
  this.pluginImport = pluginImport;
81
92
  this.orgCatalog = orgCatalog;
82
93
  this.scope = scope;
83
94
  this.updater = updater;
84
95
  this.icons = icons;
96
+ this.appearance = appearance;
97
+ this.clientBuilds = clientBuilds;
98
+ this.guides = guides;
85
99
  }
86
100
  /**
87
101
  * Prepares the import of an uploaded plugin (an npm-pack tgz as the raw body,
@@ -175,12 +189,42 @@ let AdminCatalogController = class AdminCatalogController {
175
189
  return { ...page, items: page.items.map((i) => ({ ...i, icon: icons.get(i.id) ?? null })) };
176
190
  }
177
191
  /**
178
- * 条目详情与各版本,另给出 `hasIcon`(最新版本有图标,`GET items/:id/icon` 可取);不存在 → 404
179
- * `catalog.item_not_found`。
192
+ * The item with its versions, plus `hasIcon` (the latest version has an icon, served by `GET
193
+ * items/:id/icon`) and `suggestedAppearance` (the platform version's, null without one: the page
194
+ * offers 应用此插件的外观 when set). Each version carries `client`: its extension package's
195
+ * client build (files with sizes, total, client API version; null without one), what the
196
+ * permission confirmation of an org's upload shows in its 客户端代码 group (client extensions spec
197
+ * §5.4). Unknown -> 404 `catalog.item_not_found`.
180
198
  */
181
199
  async get(id) {
182
200
  const detail = await this.catalog.get(id);
183
- return { ...detail, hasIcon: await this.orgCatalog.hasIcon(id) };
201
+ const platform = detail.versions.find((v) => v.version === detail.item.platformVersion);
202
+ const [hasIcon, builds] = await Promise.all([
203
+ this.orgCatalog.hasIcon(id),
204
+ this.clientBuilds.summaries(detail.versions.flatMap((v) => (v.extensionSha256 === null ? [] : [v.extensionSha256]))),
205
+ ]);
206
+ return {
207
+ ...detail,
208
+ versions: detail.versions.map((v) => ({
209
+ ...v,
210
+ client: v.extensionSha256 === null ? null : (builds.get(v.extensionSha256) ?? null),
211
+ })),
212
+ hasIcon,
213
+ suggestedAppearance: suggestedAppearanceOf(platform?.manifest),
214
+ };
215
+ }
216
+ /**
217
+ * 应用此插件的外观 (client extensions spec §6.5): sets the plugin's suggested theme as the platform
218
+ * default theme and each suggested replacement as the platform arrangement's `use` of its slot, in
219
+ * one transaction. `dryRun: true` answers the same changes and writes nothing. A theme that cannot
220
+ * be the platform default -> 400 `theme.not_available` (nothing written); a replacement not
221
+ * available on the platform is skipped. No such item, or no suggestion -> 404
222
+ * `catalog.item_not_found`.
223
+ */
224
+ applyAppearance(principal, id, body) {
225
+ const actor = requireUser(principal);
226
+ const tokenId = patTokenId(actor);
227
+ return this.appearance.apply({ platform: true }, id, { accountId: actor.account.id, ...(tokenId !== undefined && { tokenId }) }, body.dryRun === true);
184
228
  }
185
229
  /**
186
230
  * The item's icon (disabled items included; same response headers as the org side, see
@@ -189,6 +233,15 @@ let AdminCatalogController = class AdminCatalogController {
189
233
  async icon(id, reply) {
190
234
  await sendCatalogIcon(reply, await this.orgCatalog.icon(id, true));
191
235
  }
236
+ /**
237
+ * A setup guide of the item as the platform sees it (spec 2026-11-09-setup-guides-v2-design.md
238
+ * §9.3; the admin console's connector template page): any live item, the admin audience, no org
239
+ * (`orgName` unresolved, reason `no_org`), no target, no checks run. Unknown item -> 404
240
+ * `catalog.item_not_found`, unknown guide -> 404 `catalog.guide_not_found`.
241
+ */
242
+ async guide(itemId, guideId, q) {
243
+ return { guide: await this.guides.renderForPlatform(itemId, guideId, q) };
244
+ }
192
245
  /**
193
246
  * What a scope change (`{ scope, orgs? }`, `orgs` only with `named`) or a disable
194
247
  * (`{ disabled: true }`) would take away: `{ affected: [{ orgId, orgName, agents,
@@ -326,11 +379,24 @@ __decorate([
326
379
  Get("items/:id"),
327
380
  __param(0, Param("id"))
328
381
  ], AdminCatalogController.prototype, "get", null);
382
+ __decorate([
383
+ Post("items/:id/appearance"),
384
+ HttpCode(200),
385
+ __param(0, CurrentPrincipal()),
386
+ __param(1, Param("id")),
387
+ __param(2, ZBody(AppearanceApplyBodyDto))
388
+ ], AdminCatalogController.prototype, "applyAppearance", null);
329
389
  __decorate([
330
390
  Get("items/:id/icon"),
331
391
  __param(0, Param("id")),
332
392
  __param(1, Res())
333
393
  ], AdminCatalogController.prototype, "icon", null);
394
+ __decorate([
395
+ Get(":itemId/guides/:guideId"),
396
+ __param(0, Param("itemId")),
397
+ __param(1, Param("guideId")),
398
+ __param(2, ZQuery(AdminCatalogGuideQueryDto))
399
+ ], AdminCatalogController.prototype, "guide", null);
334
400
  __decorate([
335
401
  Post("items/:id/scope/preview"),
336
402
  HttpCode(200),
@@ -395,6 +461,9 @@ AdminCatalogController = __decorate([
395
461
  __param(2, Inject(OrgCatalogService)),
396
462
  __param(3, Inject(CatalogScopeService)),
397
463
  __param(4, Inject(PlatformPluginUpdater)),
398
- __param(5, Inject(PluginIcons))
464
+ __param(5, Inject(PluginIcons)),
465
+ __param(6, Inject(AppearanceService)),
466
+ __param(7, Inject(ClientBuilds)),
467
+ __param(8, Inject(PluginGuides))
399
468
  ], AdminCatalogController);
400
469
  export { AdminCatalogController };
@@ -69,4 +69,14 @@ export declare const CatalogDisabledBody: z.ZodObject<{
69
69
  export declare const CatalogShownBody: z.ZodObject<{
70
70
  shownToOthers: z.ZodBoolean;
71
71
  }, z.core.$strict>;
72
+ /**
73
+ * `GET :itemId/guides/:guideId`, the super admin's preview of a setup guide (spec
74
+ * 2026-11-09-setup-guides-v2-design.md §9.3): only the document language; no org, no target.
75
+ */
76
+ export declare const AdminCatalogGuideQuery: z.ZodObject<{
77
+ locale: z.ZodOptional<z.ZodEnum<{
78
+ en: "en";
79
+ zh: "zh";
80
+ }>>;
81
+ }, z.core.$strict>;
72
82
  export declare const ADMIN_CATALOG_ROUTES: readonly RouteSchemas[];
@@ -52,6 +52,13 @@ export const CatalogDisabledBody = z
52
52
  .object({ disabled: z.boolean(), scopeHash: CatalogHash.optional() })
53
53
  .strict();
54
54
  export const CatalogShownBody = z.object({ shownToOthers: z.boolean() }).strict();
55
+ /**
56
+ * `GET :itemId/guides/:guideId`, the super admin's preview of a setup guide (spec
57
+ * 2026-11-09-setup-guides-v2-design.md §9.3): only the document language; no org, no target.
58
+ */
59
+ export const AdminCatalogGuideQuery = z
60
+ .object({ locale: z.enum(["en", "zh"]).optional() })
61
+ .strict();
55
62
  export const ADMIN_CATALOG_ROUTES = [
56
63
  { route: "GET /api/v1/admin/catalog/items", query: CatalogItemsQuery },
57
64
  { route: "GET /api/v1/admin/catalog/items/:id", params: CatalogIdPathParams },
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+ import type { RouteSchemas } from "../platform/route-schemas.js";
3
+ /**
4
+ * The body of both "apply this plugin's appearance" routes (client extensions spec §6.5):
5
+ * `dryRun: true` answers what would change and writes nothing (the confirm dialog's preview).
6
+ */
7
+ export declare const AppearanceApplyBody: z.ZodObject<{
8
+ dryRun: z.ZodOptional<z.ZodBoolean>;
9
+ }, z.core.$strict>;
10
+ export declare const APPEARANCE_ROUTES: readonly RouteSchemas[];
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ import { CatalogIdPathParams } from "./admin-catalog.schemas.js";
3
+ import { OrgExtensionParams } from "./org-extension.schemas.js";
4
+ /**
5
+ * The body of both "apply this plugin's appearance" routes (client extensions spec §6.5):
6
+ * `dryRun: true` answers what would change and writes nothing (the confirm dialog's preview).
7
+ */
8
+ export const AppearanceApplyBody = z.object({ dryRun: z.boolean().optional() }).strict();
9
+ export const APPEARANCE_ROUTES = [
10
+ {
11
+ route: "POST /api/v1/admin/catalog/items/:id/appearance",
12
+ params: CatalogIdPathParams,
13
+ body: AppearanceApplyBody,
14
+ },
15
+ {
16
+ route: "POST /api/v1/orgs/:orgId/extensions/:extension/appearance",
17
+ params: OrgExtensionParams,
18
+ body: AppearanceApplyBody,
19
+ },
20
+ ];
@@ -0,0 +1,105 @@
1
+ import { type SuggestedAppearance } from "@capybara-hq/plugin-sdk";
2
+ import { ExtensionHost } from "../extensions/host.js";
3
+ import { SettingsService } from "../identity/settings.js";
4
+ import { SuperAdminLock } from "../identity/super-admin.js";
5
+ import { KernelDb } from "../infra/database/kernel-db.js";
6
+ import { TransactionHost } from "../infra/database/transaction-host.js";
7
+ import { OrgLock } from "../orgs/org-lock.js";
8
+ import { OrgSettingsService } from "../orgs/settings.service.js";
9
+ /** Where the suggestion is applied: the platform defaults, or one org's. */
10
+ export type AppearanceLevel = {
11
+ platform: true;
12
+ } | {
13
+ orgId: string;
14
+ };
15
+ /** Why a replacement of the suggestion was left out (client extensions spec §6.5). */
16
+ export type AppearanceSkipReason = "unknown-slot" | "not-available" | "not-eligible";
17
+ /**
18
+ * What applying a suggestion changes at its level: the default theme (`from`: the theme in effect,
19
+ * null for none; `to`: the `platform_themes` id; null when the plugin suggests no theme or it is
20
+ * in effect already), each replacement slot's `use` (`to`: the contribution key
21
+ * `<extension>/<contribution>`; `from`: the key in effect, null for the built-in; a slot that
22
+ * already uses it is not listed) and what was skipped, in plugin.json order. At org level `from`
23
+ * is the org's own entry, else the platform's: `followsPlatform` says which (absent at platform
24
+ * level), and when the org follows a platform that already uses the suggestion nothing is pinned.
25
+ */
26
+ export interface AppearanceResult {
27
+ theme: {
28
+ from: string | null;
29
+ to: string;
30
+ followsPlatform?: boolean;
31
+ } | null;
32
+ replacements: {
33
+ slot: string;
34
+ from: string | null;
35
+ to: string;
36
+ followsPlatform?: boolean;
37
+ }[];
38
+ skipped: {
39
+ what: string;
40
+ reason: AppearanceSkipReason;
41
+ }[];
42
+ }
43
+ /** Who applies it: the account, the PAT when one made the call, and extra audit detail. */
44
+ export interface AppearanceActor {
45
+ accountId: string;
46
+ tokenId?: string;
47
+ /** Merged into the settings writer's audit detail (the Platform tool's `via: "agent"`). */
48
+ auditDetail?: Record<string, unknown>;
49
+ }
50
+ /** The suggestion of a plugin's catalog version, or null (none, or not an object). */
51
+ export declare function suggestedAppearanceOf(manifest: unknown): SuggestedAppearance | null;
52
+ /**
53
+ * "Apply this plugin's appearance" (client extensions spec §6.5): one step that sets the plugin's
54
+ * suggested theme as the level's default theme and each suggested replacement as the level's `use`
55
+ * of its single slot. The writes go through the settings writers (`SettingsService.update` for the
56
+ * platform, `OrgSettingsService.update` for an org), so their validation, theme checks, lock order
57
+ * (the level's lock, then catalog item, theme row, `uiTheme` row) and audit apply, both settings in
58
+ * one call and one transaction: a theme that cannot be set (`theme.not_available`) refuses the
59
+ * whole call; a replacement that cannot be used where it is set is skipped, never refused (the
60
+ * arrangement keeps unknown keys anyway). A dry run computes the same answer and writes nothing.
61
+ */
62
+ export declare class AppearanceService {
63
+ private readonly db;
64
+ readonly txHost: TransactionHost;
65
+ private readonly settings;
66
+ private readonly orgSettings;
67
+ private readonly adminLock;
68
+ private readonly orgLock;
69
+ private readonly host;
70
+ constructor(db: KernelDb, txHost: TransactionHost, settings: SettingsService, orgSettings: OrgSettingsService, adminLock: SuperAdminLock, orgLock: OrgLock, host: ExtensionHost);
71
+ /**
72
+ * The suggestions of the live plugins named `names`, from the version their components come from
73
+ * (`platform_synced_version`, else the latest); a plugin without one maps to null.
74
+ */
75
+ suggestions(names: readonly string[]): Promise<Map<string, SuggestedAppearance | null>>;
76
+ /** The live catalog item `itemId` with its suggestion; else `catalog.item_not_found`. */
77
+ private platformItem;
78
+ /**
79
+ * The live plugin of extension `extension`, which must be on in the org, with its suggestion;
80
+ * else `extension.not_found`.
81
+ */
82
+ private orgItem;
83
+ /**
84
+ * Applies (or, with `dryRun`, previews) the suggestion of `item` at `level`: for the platform,
85
+ * `item` is the catalog item id (`POST /api/v1/admin/catalog/items/:id/appearance`, super
86
+ * admin); for an org, the extension name (`POST /api/v1/orgs/:orgId/extensions/:extension/
87
+ * appearance`, `org.update`). The writers re-check the actor under their lock.
88
+ */
89
+ apply(level: AppearanceLevel, item: string, actor: AppearanceActor, dryRun: boolean): Promise<AppearanceResult>;
90
+ /** Refuses (`theme.not_available`) a theme the level's writer would refuse; reads only. */
91
+ private assertThemeSettable;
92
+ private applyPlatform;
93
+ private applyOrg;
94
+ /**
95
+ * What applying `found` at `level` changes, from the stored settings (no writes): the level's
96
+ * own, and at org level the platform's it follows where it stores nothing.
97
+ */
98
+ private plan;
99
+ }
100
+ /**
101
+ * The suggested appearance action: its own module, since it writes through the org settings
102
+ * writer (`OrgsModule`, which imports `CatalogModule`) and the deployment settings writer.
103
+ */
104
+ export declare class AppearanceModule {
105
+ }