@capybara-hq/kernel 0.1.0-rc.2 → 0.1.0-rc.4

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 (312) hide show
  1. package/dist/admin/admin.controller.d.ts +9 -4
  2. package/dist/admin/admin.controller.js +13 -4
  3. package/dist/admin/extensions.controller.d.ts +8 -1
  4. package/dist/admin/extensions.controller.js +22 -2
  5. package/dist/agents/agent-lookup.d.ts +3 -0
  6. package/dist/agents/agent-lookup.js +20 -2
  7. package/dist/agents/agent-profile.service.d.ts +29 -0
  8. package/dist/agents/agent-profile.service.js +117 -0
  9. package/dist/agents/agents.controller.d.ts +93 -3
  10. package/dist/agents/agents.controller.js +114 -4
  11. package/dist/agents/agents.module.js +6 -2
  12. package/dist/agents/agents.service.d.ts +13 -5
  13. package/dist/agents/agents.service.js +49 -13
  14. package/dist/agents/definition.d.ts +35 -8
  15. package/dist/agents/definition.js +203 -17
  16. package/dist/agents/instruction-files.d.ts +60 -0
  17. package/dist/agents/instruction-files.js +111 -0
  18. package/dist/agents/models.controller.d.ts +9 -3
  19. package/dist/agents/models.controller.js +19 -4
  20. package/dist/agents/profile.d.ts +96 -0
  21. package/dist/agents/profile.js +51 -0
  22. package/dist/agents/readiness.controller.d.ts +26 -0
  23. package/dist/agents/readiness.controller.js +56 -0
  24. package/dist/agents/templates.js +20 -5
  25. package/dist/background/background.controller.d.ts +38 -0
  26. package/dist/background/background.controller.js +87 -0
  27. package/dist/background/background.module.d.ts +10 -0
  28. package/dist/background/background.module.js +32 -0
  29. package/dist/background/finish.d.ts +43 -0
  30. package/dist/background/finish.js +94 -0
  31. package/dist/background/launch-lock.d.ts +14 -0
  32. package/dist/background/launch-lock.js +39 -0
  33. package/dist/background/launch.d.ts +36 -0
  34. package/dist/background/launch.js +70 -0
  35. package/dist/background/poll.job.d.ts +53 -0
  36. package/dist/background/poll.job.js +182 -0
  37. package/dist/background/render.d.ts +23 -0
  38. package/dist/background/render.js +48 -0
  39. package/dist/background/session.d.ts +37 -0
  40. package/dist/background/session.js +66 -0
  41. package/dist/background/status.d.ts +35 -0
  42. package/dist/background/status.js +57 -0
  43. package/dist/background/stop.d.ts +62 -0
  44. package/dist/background/stop.js +225 -0
  45. package/dist/background/store.d.ts +150 -0
  46. package/dist/background/store.js +351 -0
  47. package/dist/background/store.module.d.ts +6 -0
  48. package/dist/background/store.module.js +22 -0
  49. package/dist/background/tasks.service.d.ts +67 -0
  50. package/dist/background/tasks.service.js +186 -0
  51. package/dist/background/wake-rules.d.ts +57 -0
  52. package/dist/background/wake-rules.js +83 -0
  53. package/dist/background/wake.d.ts +28 -0
  54. package/dist/background/wake.js +57 -0
  55. package/dist/catalog/catalog-content.js +4 -1
  56. package/dist/catalog/claude/agents.js +15 -10
  57. package/dist/catalog/marketplaces.service.d.ts +1 -1
  58. package/dist/catalog/plugin-import.js +1 -1
  59. package/dist/catalog/plugin-upgrade.js +1 -1
  60. package/dist/channels/cards.d.ts +8 -2
  61. package/dist/channels/cards.js +17 -9
  62. package/dist/channels/connections.service.d.ts +16 -1
  63. package/dist/channels/connections.service.js +38 -4
  64. package/dist/channels/threads.d.ts +5 -0
  65. package/dist/channels/threads.js +8 -0
  66. package/dist/config/schema.d.ts +18 -0
  67. package/dist/config/schema.js +104 -2
  68. package/dist/conversations/access.js +2 -0
  69. package/dist/conversations/artifacts.d.ts +1 -1
  70. package/dist/conversations/artifacts.js +1 -1
  71. package/dist/conversations/attachments.service.d.ts +30 -0
  72. package/dist/conversations/attachments.service.js +130 -5
  73. package/dist/conversations/conversations.controller.d.ts +36 -5
  74. package/dist/conversations/conversations.controller.js +62 -12
  75. package/dist/conversations/conversations.module.js +3 -0
  76. package/dist/conversations/conversations.service.d.ts +44 -2
  77. package/dist/conversations/conversations.service.js +140 -12
  78. package/dist/conversations/event-log.d.ts +12 -1
  79. package/dist/conversations/event-log.js +29 -1
  80. package/dist/conversations/events.d.ts +81 -3
  81. package/dist/conversations/events.js +83 -16
  82. package/dist/conversations/queue.d.ts +3 -1
  83. package/dist/conversations/queue.js +13 -2
  84. package/dist/conversations/queue.service.js +3 -1
  85. package/dist/conversations/titles.d.ts +7 -0
  86. package/dist/conversations/titles.js +15 -0
  87. package/dist/db/kernel-schema.d.ts +60 -4
  88. package/dist/db/pool.d.ts +5 -0
  89. package/dist/db/pool.js +3 -0
  90. package/dist/errors.d.ts +8 -0
  91. package/dist/errors.js +8 -0
  92. package/dist/evals/recorded-tools.d.ts +27 -1
  93. package/dist/evals/recorded-tools.js +85 -10
  94. package/dist/evals/run-replay.d.ts +10 -2
  95. package/dist/evals/run-replay.js +49 -12
  96. package/dist/evals/step-replay.js +12 -6
  97. package/dist/evals/trajectory.d.ts +2 -2
  98. package/dist/evals/trajectory.js +1 -1
  99. package/dist/extensions/admin-ops.js +2 -0
  100. package/dist/extensions/admin-view.d.ts +3 -1
  101. package/dist/extensions/admin-view.js +10 -2
  102. package/dist/extensions/blobs.js +1 -0
  103. package/dist/extensions/config-issues.d.ts +13 -1
  104. package/dist/extensions/config-issues.js +22 -5
  105. package/dist/extensions/config-json-schema.d.ts +43 -7
  106. package/dist/extensions/config-json-schema.js +124 -58
  107. package/dist/extensions/deployment-config-store.d.ts +6 -0
  108. package/dist/extensions/deployment-config.d.ts +50 -3
  109. package/dist/extensions/deployment-config.js +125 -28
  110. package/dist/extensions/display-name.d.ts +22 -0
  111. package/dist/extensions/display-name.js +77 -0
  112. package/dist/extensions/extensions.module.js +6 -0
  113. package/dist/extensions/host.d.ts +26 -1
  114. package/dist/extensions/host.js +82 -9
  115. package/dist/extensions/org-config.controller.d.ts +11 -3
  116. package/dist/extensions/org-config.controller.js +14 -6
  117. package/dist/extensions/org-config.d.ts +6 -0
  118. package/dist/extensions/org-config.js +12 -13
  119. package/dist/extensions/package.d.ts +14 -1
  120. package/dist/extensions/package.js +51 -2
  121. package/dist/extensions/permission-view.d.ts +3 -0
  122. package/dist/extensions/point-defaults.controller.d.ts +34 -0
  123. package/dist/extensions/point-defaults.controller.js +71 -0
  124. package/dist/extensions/point-defaults.d.ts +64 -0
  125. package/dist/extensions/point-defaults.js +206 -0
  126. package/dist/extensions/registry.d.ts +1 -1
  127. package/dist/extensions/registry.js +2 -0
  128. package/dist/http/api.module.js +8 -0
  129. package/dist/http/nest-logger.d.ts +6 -5
  130. package/dist/http/nest-logger.js +24 -10
  131. package/dist/identity/auth.controller.js +9 -5
  132. package/dist/identity/cookies.d.ts +20 -5
  133. package/dist/identity/cookies.js +44 -6
  134. package/dist/identity/me.controller.d.ts +5 -1
  135. package/dist/identity/me.controller.js +12 -3
  136. package/dist/identity/sessions.d.ts +12 -0
  137. package/dist/identity/sessions.js +45 -0
  138. package/dist/identity/settings.js +1 -1
  139. package/dist/index.d.ts +1 -1
  140. package/dist/infra/config/kernel-config.service.js +6 -0
  141. package/dist/infra/database/database.module.js +1 -0
  142. package/dist/infra/events/kernel-events.d.ts +8 -0
  143. package/dist/infra/lifecycle/process-guards.js +4 -0
  144. package/dist/infra/logging/logging.module.d.ts +4 -2
  145. package/dist/infra/logging/logging.module.js +24 -6
  146. package/dist/infra/queue/redis-connection.d.ts +6 -0
  147. package/dist/infra/queue/redis-connection.js +7 -0
  148. package/dist/infra/redis/redis.module.js +6 -2
  149. package/dist/infra/tokens.d.ts +6 -1
  150. package/dist/infra/tokens.js +6 -1
  151. package/dist/lifecycle/kernel-lifecycle.js +5 -0
  152. package/dist/log.d.ts +13 -1
  153. package/dist/log.js +93 -17
  154. package/dist/models/purposes.d.ts +23 -0
  155. package/dist/models/purposes.js +31 -10
  156. package/dist/orgs/offboarding.d.ts +3 -1
  157. package/dist/orgs/offboarding.js +26 -16
  158. package/dist/orgs/settings.service.d.ts +7 -2
  159. package/dist/orgs/settings.service.js +15 -4
  160. package/dist/roles/worker.module.js +6 -0
  161. package/dist/runtime/context/build.d.ts +15 -13
  162. package/dist/runtime/context/build.js +45 -27
  163. package/dist/runtime/context/claude-tools.d.ts +3 -1
  164. package/dist/runtime/context/claude-tools.js +12 -12
  165. package/dist/runtime/context/compaction.js +4 -0
  166. package/dist/runtime/context/legacy-text.d.ts +22 -0
  167. package/dist/runtime/context/legacy-text.js +37 -0
  168. package/dist/runtime/context/skills.d.ts +29 -11
  169. package/dist/runtime/context/skills.js +37 -30
  170. package/dist/runtime/langgraph-loop.js +3 -2
  171. package/dist/runtime/loop.d.ts +5 -4
  172. package/dist/runtime/maintenance.d.ts +4 -2
  173. package/dist/runtime/maintenance.js +17 -5
  174. package/dist/runtime/model-call.d.ts +17 -1
  175. package/dist/runtime/model-call.js +4 -3
  176. package/dist/runtime/providers.d.ts +6 -0
  177. package/dist/runtime/providers.js +8 -0
  178. package/dist/runtime/run-finish.d.ts +1 -1
  179. package/dist/runtime/run-queue.d.ts +28 -5
  180. package/dist/runtime/run-queue.js +131 -35
  181. package/dist/runtime/run-worker.d.ts +2 -2
  182. package/dist/runtime/run-worker.js +20 -7
  183. package/dist/runtime/runtime.module.js +8 -3
  184. package/dist/runtime/step-log.d.ts +6 -0
  185. package/dist/runtime/step-log.js +16 -2
  186. package/dist/runtime/subagents/definition.d.ts +1 -6
  187. package/dist/runtime/subagents/definition.js +14 -13
  188. package/dist/runtime/subagents/dispatch.d.ts +2 -2
  189. package/dist/runtime/subagents/dispatch.js +2 -2
  190. package/dist/runtime/subagents/org-agents.js +2 -1
  191. package/dist/runtime/subagents/roster.d.ts +1 -1
  192. package/dist/runtime/subagents/roster.js +1 -1
  193. package/dist/runtime/subagents/skill-fork.d.ts +2 -2
  194. package/dist/runtime/subagents/skill-fork.js +2 -2
  195. package/dist/runtime/subagents/subagents.service.d.ts +3 -3
  196. package/dist/runtime/subagents/subagents.service.js +3 -3
  197. package/dist/runtime/usage-report.d.ts +2 -1
  198. package/dist/runtime/usage-report.js +2 -1
  199. package/dist/runtime/waits.d.ts +13 -7
  200. package/dist/runtime/waits.js +42 -16
  201. package/dist/sandbox/sandbox.module.js +6 -1
  202. package/dist/sandbox/sandbox.service.d.ts +61 -3
  203. package/dist/sandbox/sandbox.service.js +141 -7
  204. package/dist/skills/catalog.d.ts +4 -4
  205. package/dist/skills/catalog.js +4 -4
  206. package/dist/skills/changes.service.d.ts +2 -2
  207. package/dist/skills/changes.service.js +5 -4
  208. package/dist/skills/invocation-keys.d.ts +1 -1
  209. package/dist/skills/invocation-keys.js +1 -1
  210. package/dist/skills/invoke.d.ts +1 -1
  211. package/dist/skills/invoke.js +5 -4
  212. package/dist/tools/approvals.service.d.ts +6 -0
  213. package/dist/tools/approvals.service.js +21 -1
  214. package/dist/tools/builtin-names.d.ts +91 -0
  215. package/dist/tools/builtin-names.js +143 -0
  216. package/dist/tools/builtins/agent.d.ts +7 -7
  217. package/dist/tools/builtins/agent.js +7 -11
  218. package/dist/tools/builtins/ask-user.d.ts +1 -1
  219. package/dist/tools/builtins/ask-user.js +2 -2
  220. package/dist/tools/builtins/builtin-tools.d.ts +17 -3
  221. package/dist/tools/builtins/builtin-tools.js +36 -4
  222. package/dist/tools/builtins/read-tool-output.d.ts +1 -1
  223. package/dist/tools/builtins/read-tool-output.js +2 -2
  224. package/dist/tools/builtins/sandbox/bash.d.ts +4 -4
  225. package/dist/tools/builtins/sandbox/bash.js +259 -29
  226. package/dist/tools/builtins/sandbox/common.d.ts +30 -7
  227. package/dist/tools/builtins/sandbox/common.js +9 -5
  228. package/dist/tools/builtins/sandbox/deliver.d.ts +1 -1
  229. package/dist/tools/builtins/sandbox/deliver.js +12 -12
  230. package/dist/tools/builtins/sandbox/edit.d.ts +1 -1
  231. package/dist/tools/builtins/sandbox/edit.js +41 -30
  232. package/dist/tools/builtins/sandbox/file-state.d.ts +34 -0
  233. package/dist/tools/builtins/sandbox/file-state.js +34 -0
  234. package/dist/tools/builtins/sandbox/glob-match.d.ts +1 -1
  235. package/dist/tools/builtins/sandbox/glob-match.js +1 -1
  236. package/dist/tools/builtins/sandbox/glob.d.ts +1 -1
  237. package/dist/tools/builtins/sandbox/glob.js +4 -4
  238. package/dist/tools/builtins/sandbox/grep.d.ts +7 -4
  239. package/dist/tools/builtins/sandbox/grep.js +147 -30
  240. package/dist/tools/builtins/sandbox/index.d.ts +3 -1
  241. package/dist/tools/builtins/sandbox/index.js +7 -1
  242. package/dist/tools/builtins/sandbox/read.d.ts +2 -2
  243. package/dist/tools/builtins/sandbox/read.js +21 -14
  244. package/dist/tools/builtins/sandbox/task-output.d.ts +63 -0
  245. package/dist/tools/builtins/sandbox/task-output.js +304 -0
  246. package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
  247. package/dist/tools/builtins/sandbox/task-stop.js +112 -0
  248. package/dist/tools/builtins/sandbox/write.d.ts +1 -1
  249. package/dist/tools/builtins/sandbox/write.js +37 -33
  250. package/dist/tools/builtins/skill-load.d.ts +3 -3
  251. package/dist/tools/builtins/skill-load.js +32 -16
  252. package/dist/tools/builtins/skill-write.d.ts +4 -4
  253. package/dist/tools/builtins/skill-write.js +10 -10
  254. package/dist/tools/builtins/tool-search.d.ts +13 -9
  255. package/dist/tools/builtins/tool-search.js +25 -14
  256. package/dist/tools/builtins/web/errors.d.ts +8 -0
  257. package/dist/tools/builtins/web/errors.js +53 -0
  258. package/dist/tools/builtins/web/extract.d.ts +62 -0
  259. package/dist/tools/builtins/web/extract.js +267 -0
  260. package/dist/tools/builtins/web/fetch.d.ts +55 -0
  261. package/dist/tools/builtins/web/fetch.js +174 -0
  262. package/dist/tools/builtins/web/index.d.ts +13 -0
  263. package/dist/tools/builtins/web/index.js +12 -0
  264. package/dist/tools/builtins/web/page-cache.d.ts +25 -0
  265. package/dist/tools/builtins/web/page-cache.js +77 -0
  266. package/dist/tools/builtins/web/search.d.ts +25 -0
  267. package/dist/tools/builtins/web/search.js +209 -0
  268. package/dist/tools/builtins/web/url.d.ts +17 -0
  269. package/dist/tools/builtins/web/url.js +43 -0
  270. package/dist/tools/connectors.service.js +4 -4
  271. package/dist/tools/display-names.d.ts +9 -0
  272. package/dist/tools/display-names.js +24 -0
  273. package/dist/tools/drift.js +5 -5
  274. package/dist/tools/elicitation.js +1 -1
  275. package/dist/tools/info.d.ts +20 -4
  276. package/dist/tools/info.js +55 -32
  277. package/dist/tools/legacy-data.d.ts +34 -0
  278. package/dist/tools/legacy-data.js +76 -0
  279. package/dist/tools/legacy-keys.d.ts +51 -0
  280. package/dist/tools/legacy-keys.js +115 -0
  281. package/dist/tools/naming.d.ts +1 -5
  282. package/dist/tools/naming.js +1 -7
  283. package/dist/tools/oauth/flow-paths.d.ts +1 -1
  284. package/dist/tools/oauth/flow-paths.js +1 -1
  285. package/dist/tools/outputs.js +1 -1
  286. package/dist/tools/pipeline.d.ts +13 -7
  287. package/dist/tools/pipeline.js +112 -39
  288. package/dist/tools/policy.d.ts +1 -14
  289. package/dist/tools/policy.js +13 -19
  290. package/dist/tools/questions.controller.d.ts +1 -1
  291. package/dist/tools/questions.controller.js +1 -1
  292. package/dist/tools/questions.service.d.ts +1 -1
  293. package/dist/tools/registry.d.ts +38 -24
  294. package/dist/tools/registry.js +54 -47
  295. package/dist/tools/resources.d.ts +1 -1
  296. package/dist/tools/resources.js +1 -1
  297. package/dist/tools/tools.module.js +13 -1
  298. package/dist/tools/validate.js +1 -1
  299. package/package.json +3 -3
  300. package/src/migrations/0063_tool_keys_claude_code.sql +220 -0
  301. package/src/migrations/0064_account_last_org.sql +7 -0
  302. package/src/migrations/0065_conversation_archive.sql +8 -0
  303. package/src/migrations/0066_extension_display_name.sql +4 -0
  304. package/src/migrations/0067_agent_profiles.sql +20 -0
  305. package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
  306. package/src/migrations/0069_attachments_agent_idx.sql +3 -0
  307. package/src/migrations/0070_background_tasks.sql +37 -0
  308. package/src/migrations/0071_background_tasks_reserve.sql +6 -0
  309. package/src/migrations/0072_background_tasks_stopping.sql +5 -0
  310. package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
  311. package/dist/tools/builtins/sandbox/names.d.ts +0 -7
  312. package/dist/tools/builtins/sandbox/names.js +0 -20
@@ -30,10 +30,11 @@ import { EmbedTokens } from "../ui/embed-token.js";
30
30
  import { ExtensionApprovals, planApprovals, readSnapshots, withPreApproved, } from "./approvals.js";
31
31
  import { ExtensionBlobIntegrityError } from "./blobs.js";
32
32
  import { toIssues } from "./config-issues.js";
33
+ import { configFormSchema, describeConfigUiProblems } from "./config-json-schema.js";
33
34
  import { HookRegistry } from "./hooks.js";
34
35
  import { ExtensionInstalls } from "./installs.js";
35
36
  import { ImportTracker, importExtensionModule, ManifestMismatchError, matchesSection, setupInstance, warnUpgrades, } from "./instance.js";
36
- import { permissionSetOfSection, readMigrationSql } from "./package.js";
37
+ import { declaredDisplayName, permissionSetOfSection, readMigrationSql } from "./package.js";
37
38
  import { blockingKeys, computePermissionSet, UI_VIEW_KEY_PREFIX, } from "./permission-set.js";
38
39
  import { ExtensionRegistry } from "./registry.js";
39
40
  import { ExtensionResolveError, resolveExtensions } from "./resolve.js";
@@ -298,12 +299,18 @@ let ExtensionHost = class ExtensionHost {
298
299
  for (const manifest of ordered)
299
300
  assertSecretsReachable(manifest);
300
301
  const sets = await permissionSets(ordered, dirs);
301
- return ordered.map((manifest) => ({
302
- source: "config",
303
- manifest,
304
- dir: dirs.get(manifest.name),
305
- permissions: sets.get(manifest.name),
306
- }));
302
+ const out = [];
303
+ for (const manifest of ordered) {
304
+ const dir = dirs.get(manifest.name);
305
+ out.push({
306
+ source: "config",
307
+ manifest,
308
+ dir,
309
+ permissions: sets.get(manifest.name),
310
+ displayName: (await declaredDisplayName(dir, manifest.name)).displayName ?? null,
311
+ });
312
+ }
313
+ return out;
307
314
  }
308
315
  /**
309
316
  * M-1: plugin → mount points where deployment state expects `policy` hooks. A per-replica copy of PG
@@ -351,6 +358,11 @@ let ExtensionHost = class ExtensionHost {
351
358
  retiring = new Map();
352
359
  /** 配置声明插件的清单与权限集合(含未加载的;后台列表与网页批准用)。 */
353
360
  declaredInfo = new Map();
361
+ /**
362
+ * Config-declared extensions' display names, read from their plugin directory's plugin.json at
363
+ * load (from the startup config, the same on every replica; never written elsewhere).
364
+ */
365
+ declaredDisplayNames = new Map();
354
366
  /** 导入过的插件名 → 来源与包(含未加载的;重名被跳过的一方不在这里)。 */
355
367
  sources = new Map();
356
368
  didLoad = false;
@@ -370,6 +382,8 @@ let ExtensionHost = class ExtensionHost {
370
382
  configValidity = new Map();
371
383
  /** 已告警过的「部署配置不合法」(插件名 → 说明;每个周期都会重新判定,同一说明只告警一次)。 */
372
384
  configWarned = new Map();
385
+ /** `<name>@<version>` whose invalid config UI hints were warned about (a log dedupe only). */
386
+ configUiWarned = new Set();
373
387
  /**
374
388
  * The host builds each extension's `ctx` from the injected kernel services: the pool for
375
389
  * `ctx.db` on the extension's schema, Redis for `kv` / `lock` / `bus` and the queues, the
@@ -461,6 +475,8 @@ let ExtensionHost = class ExtensionHost {
461
475
  manifest: p.manifest,
462
476
  set: p.permissions,
463
477
  });
478
+ if (p.displayName)
479
+ this.declaredDisplayNames.set(p.manifest.name, p.displayName);
464
480
  const valid = configValid.get(p.manifest.name);
465
481
  if (valid !== undefined)
466
482
  this.configValidity.set(p.manifest.name, valid);
@@ -516,6 +532,7 @@ let ExtensionHost = class ExtensionHost {
516
532
  this.installLoader = p.installs;
517
533
  const entries = await importEntries(p.config ?? [], this.resolveFrom);
518
534
  await this.claimNames(entries);
535
+ await this.noteDisplayNames(entries);
519
536
  const dirs = new Map(entries.map((e) => [e.manifest.name, e.dir]));
520
537
  const urls = new Map(entries.map((e) => [e.manifest.name, e.url]));
521
538
  // 有安装记录时:配置声明的插件若 requires 只能由安装记录满足,先挑出来,等安装记录加载完再解析与加载
@@ -584,6 +601,23 @@ let ExtensionHost = class ExtensionHost {
584
601
  });
585
602
  }
586
603
  }
604
+ /**
605
+ * Records each config-declared extension's display name from its plugin directory's plugin.json
606
+ * (spec §2.2); an invalid plugin.json only warns (no display name).
607
+ */
608
+ async noteDisplayNames(entries) {
609
+ for (const e of entries) {
610
+ const { displayName, problem } = await declaredDisplayName(e.dir, e.manifest.name);
611
+ if (displayName)
612
+ this.declaredDisplayNames.set(e.manifest.name, displayName);
613
+ if (problem !== undefined) {
614
+ this.log.warn("plugin.json of a config-declared extension is invalid; no display name", {
615
+ plugin: e.manifest.name,
616
+ problem,
617
+ });
618
+ }
619
+ }
620
+ }
587
621
  /**
588
622
  * Config-declared extensions also take their name (I4, an addition to Ruling P3): the
589
623
  * name is inserted into `extension_name_owners` with its npm package name (left alone when present).
@@ -1032,6 +1066,39 @@ let ExtensionHost = class ExtensionHost {
1032
1066
  });
1033
1067
  }
1034
1068
  }
1069
+ /**
1070
+ * Checks the config UI hints of a loaded module's deployment and org schemas (spec §4.1). Invalid
1071
+ * hints never fail the load: the form schemas drop their `x-ui` (`configFormSchema`), one warning
1072
+ * per `<name>@<version>` is logged, and the returned text goes into the status detail (null when
1073
+ * every hint is valid). The packer refuses such a package; this covers hand-made ones. It never
1074
+ * throws (it runs after the instance is active, before its status row is written): a conversion
1075
+ * that throws is warned about and reported in the detail the same way.
1076
+ */
1077
+ checkConfigUi(manifest) {
1078
+ const parts = [];
1079
+ for (const level of ["deployment", "org"]) {
1080
+ const schema = manifest.config?.[level];
1081
+ if (!schema)
1082
+ continue;
1083
+ try {
1084
+ const { problems } = configFormSchema(schema, level);
1085
+ if (problems.length > 0)
1086
+ parts.push(describeConfigUiProblems(level, problems));
1087
+ }
1088
+ catch (err) {
1089
+ parts.push(`${level} config UI hints could not be checked (${err instanceof Error ? err.message : String(err)})`);
1090
+ }
1091
+ }
1092
+ if (parts.length === 0)
1093
+ return null;
1094
+ const detail = parts.join("; ");
1095
+ const key = `${manifest.name}@${manifest.version}`;
1096
+ if (!this.configUiWarned.has(key)) {
1097
+ this.configUiWarned.add(key);
1098
+ this.log.warn("extension config UI hints are invalid and ignored: its config forms show plain fields", { plugin: manifest.name, version: manifest.version, detail });
1099
+ }
1100
+ return detail;
1101
+ }
1035
1102
  /** 给已有状态行补说明;失败只记 warn。 */
1036
1103
  async noteStatus(plugin, detail) {
1037
1104
  try {
@@ -1247,7 +1314,12 @@ let ExtensionHost = class ExtensionHost {
1247
1314
  this.unloadedForDependency.delete(name);
1248
1315
  const old = this.registry.activate(inst);
1249
1316
  this.loggedFailures.delete(name);
1250
- await this.writeStatus({ ...base, state: "loaded", reason: null, detail: null });
1317
+ await this.writeStatus({
1318
+ ...base,
1319
+ state: "loaded",
1320
+ reason: null,
1321
+ detail: this.checkConfigUi(manifest),
1322
+ });
1251
1323
  if (old)
1252
1324
  this.retire(old);
1253
1325
  return inst;
@@ -1294,6 +1366,7 @@ let ExtensionHost = class ExtensionHost {
1294
1366
  configurable: schema !== undefined,
1295
1367
  configValid: this.configValidity.get(name) ??
1296
1368
  (schema ? schema.safeParse(this.extensionConfig[name] ?? {}).success : true),
1369
+ displayName: this.declaredDisplayNames.get(name) ?? null,
1297
1370
  };
1298
1371
  });
1299
1372
  }
@@ -1947,7 +2020,7 @@ let ExtensionHost = class ExtensionHost {
1947
2020
  source: inst.source,
1948
2021
  state: "loaded",
1949
2022
  reason: null,
1950
- detail: null,
2023
+ detail: this.checkConfigUi(spec.manifest),
1951
2024
  });
1952
2025
  if (old)
1953
2026
  await this.disposeQuietly(old, drainMs);
@@ -1,24 +1,32 @@
1
+ import type { LocalizedName } from "@capybara-hq/plugin-sdk";
1
2
  import { z } from "zod";
2
3
  import { type Principal } from "../identity/principal.js";
3
4
  import { type OrgContext } from "../orgs/org.guard.js";
5
+ import { ExtensionDisplayNames } from "./display-name.js";
4
6
  import { OrgExtensionConfigs, type OrgExtensionView } from "./org-config.js";
5
7
  declare const PutBody: z.ZodObject<{
6
8
  enabled: z.ZodOptional<z.ZodBoolean>;
7
9
  config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
8
10
  force: z.ZodOptional<z.ZodBoolean>;
9
11
  }, z.core.$strict>;
12
+ /** One extension of the org list: the org view plus the plugin's display name. */
13
+ export type OrgExtensionItem = OrgExtensionView & {
14
+ displayName: LocalizedName | null;
15
+ };
10
16
  /**
11
17
  * Org-level extension enablement and config (`/api/v1/orgs/:orgId/extensions`); responses echo only
12
18
  * non-secret config and whether each secret is set.
13
19
  */
14
20
  export declare class OrgExtensionConfigsController {
15
21
  private readonly configs;
16
- constructor(configs: OrgExtensionConfigs);
22
+ private readonly displayNames;
23
+ constructor(configs: OrgExtensionConfigs, displayNames: ExtensionDisplayNames);
24
+ /** The org's extensions (also the channel plugin options: those providing `channel@1`). */
17
25
  list(org: OrgContext): Promise<{
18
- extensions: OrgExtensionView[];
26
+ extensions: OrgExtensionItem[];
19
27
  }>;
20
28
  put(principal: Principal, org: OrgContext, extension: string, body: z.infer<typeof PutBody>): Promise<{
21
- extension: OrgExtensionView;
29
+ extension: OrgExtensionItem;
22
30
  }>;
23
31
  }
24
32
  export {};
@@ -13,6 +13,7 @@ import { CurrentPrincipal, patTokenId, requireUser, } from "../identity/principa
13
13
  import { createZodDto } from "../infra/validation/create-zod-dto.js";
14
14
  import { ZBody } from "../infra/validation/zod-params.js";
15
15
  import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
16
+ import { ExtensionDisplayNames } from "./display-name.js";
16
17
  import { OrgExtensionConfigs } from "./org-config.js";
17
18
  const PutBody = z
18
19
  .object({
@@ -29,17 +30,23 @@ class OrgExtensionPutBody extends createZodDto(PutBody, "OrgExtensionPutBody") {
29
30
  */
30
31
  let OrgExtensionConfigsController = class OrgExtensionConfigsController {
31
32
  configs;
32
- constructor(configs) {
33
+ displayNames;
34
+ constructor(configs, displayNames) {
33
35
  this.configs = configs;
36
+ this.displayNames = displayNames;
34
37
  }
38
+ /** The org's extensions (also the channel plugin options: those providing `channel@1`). */
35
39
  async list(org) {
36
- return { extensions: await this.configs.list(org.orgId) };
40
+ const views = await this.configs.list(org.orgId);
41
+ const names = await this.displayNames.many(views.map((v) => v.plugin));
42
+ return {
43
+ extensions: views.map((v) => ({ ...v, displayName: names.get(v.plugin) ?? null })),
44
+ };
37
45
  }
38
46
  async put(principal, org, extension, body) {
39
47
  const p = requireUser(principal);
40
- return {
41
- extension: await this.configs.put(org.orgId, extension, body, p.account.id, patTokenId(p)),
42
- };
48
+ const view = await this.configs.put(org.orgId, extension, body, p.account.id, patTokenId(p));
49
+ return { extension: { ...view, displayName: await this.displayNames.get(view.plugin) } };
43
50
  }
44
51
  };
45
52
  __decorate([
@@ -57,6 +64,7 @@ __decorate([
57
64
  ], OrgExtensionConfigsController.prototype, "put", null);
58
65
  OrgExtensionConfigsController = __decorate([
59
66
  Controller("api/v1/orgs/:orgId/extensions"),
60
- __param(0, Inject(OrgExtensionConfigs))
67
+ __param(0, Inject(OrgExtensionConfigs)),
68
+ __param(1, Inject(ExtensionDisplayNames))
61
69
  ], OrgExtensionConfigsController);
62
70
  export { OrgExtensionConfigsController };
@@ -166,6 +166,12 @@ export declare class OrgExtensionConfigs {
166
166
  private manifest;
167
167
  private permissionsOf;
168
168
  private view;
169
+ /**
170
+ * The org schema's form JSON Schema, a copy (`x-ui` stripped when its hints are invalid; the host
171
+ * warns at load). Never throws: a hint conversion that throws serves the plain schema, or null
172
+ * (one warning per schema on this replica), so one hand-made package cannot fail the org's list.
173
+ */
174
+ private formSchema;
169
175
  /** 该组织在 `kernel` 命名空间下已设置的插件配置密钥键(不解密)。 */
170
176
  private setSecretKeys;
171
177
  }
@@ -22,7 +22,7 @@ import { KernelEvents } from "../infra/events/kernel-events.js";
22
22
  import { KERNEL_LOGGER, KEYRING } from "../infra/tokens.js";
23
23
  import { OrgLock } from "../orgs/org-lock.js";
24
24
  import { toIssues } from "./config-issues.js";
25
- import { configToJsonSchema } from "./config-json-schema.js";
25
+ import { configMessages, safeConfigFormSchema } from "./config-json-schema.js";
26
26
  import { enabledExtensionsQuery, requiredExtensions } from "./enabled.js";
27
27
  import { ExtensionHost } from "./host.js";
28
28
  import { ExtensionInstalls } from "./installs.js";
@@ -31,16 +31,6 @@ export { toIssues };
31
31
  /** 内核自己的 secrets 命名空间(plugin-sdk 把 `kernel` 列为保留插件名,插件不会与之相撞)。 */
32
32
  const SECRETS_NAMESPACE = "kernel";
33
33
  const secretKey = (plugin, path) => `plugin-config:${plugin}:${path}`;
34
- /** 清单不可变:每个组织级 schema 的 JSON Schema 转换结果按 schema 对象缓存(只读、无跨请求状态)。 */
35
- const jsonSchemaCache = new WeakMap();
36
- function orgJsonSchema(schema) {
37
- let js = jsonSchemaCache.get(schema);
38
- if (!js) {
39
- js = configToJsonSchema(schema);
40
- jsonSchemaCache.set(schema, js);
41
- }
42
- return structuredClone(js);
43
- }
44
34
  const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
45
35
  /** 按点路径设值,缺失的中间对象自动创建;中间节点不是对象时放弃(交给 schema 校验报错)。 */
46
36
  function setDeep(obj, path, value) {
@@ -258,7 +248,7 @@ let OrgExtensionConfigs = class OrgExtensionConfigs {
258
248
  if (input.config !== undefined || enabled) {
259
249
  const r = schema.safeParse(next);
260
250
  if (!r.success) {
261
- throw new ApiError("extension.config_invalid", `Invalid organization config for extension ${plugin}`, toIssues(r.error));
251
+ throw new ApiError("extension.config_invalid", `Invalid organization config for extension ${plugin}`, toIssues(r.error, configMessages(this.formSchema(plugin, manifest.version, schema))));
262
252
  }
263
253
  next = r.data;
264
254
  }
@@ -523,11 +513,20 @@ let OrgExtensionConfigs = class OrgExtensionConfigs {
523
513
  config,
524
514
  secrets: paths.map((p) => ({ path: p, set: setKeys.has(secretKey(m.name, p)) })),
525
515
  permissions: permissionGroups(this.permissionsOf(m.name)),
526
- orgConfigSchema: schema ? orgJsonSchema(schema) : null,
516
+ orgConfigSchema: schema ? this.formSchema(m.name, m.version, schema) : null,
527
517
  available: true,
528
518
  required,
529
519
  };
530
520
  }
521
+ /**
522
+ * The org schema's form JSON Schema, a copy (`x-ui` stripped when its hints are invalid; the host
523
+ * warns at load). Never throws: a hint conversion that throws serves the plain schema, or null
524
+ * (one warning per schema on this replica), so one hand-made package cannot fail the org's list.
525
+ */
526
+ formSchema(plugin, version, schema) {
527
+ const r = safeConfigFormSchema(schema, "org", (err, fallback) => this.log.warn("the org config form schema could not be built with its UI hints; hints dropped", { plugin, version, schema: fallback, err }));
528
+ return r ? structuredClone(r.schema) : null;
529
+ }
531
530
  /** 该组织在 `kernel` 命名空间下已设置的插件配置密钥键(不解密)。 */
532
531
  async setSecretKeys(db, orgId) {
533
532
  const rows = await db
@@ -1,4 +1,4 @@
1
- import { type PluginExtensionSection } from "@capybara-hq/plugin-sdk";
1
+ import { type LocalizedName, type PluginExtensionSection } from "@capybara-hq/plugin-sdk";
2
2
  import { ApiError } from "../errors.js";
3
3
  import { HOST_ZOD_VERSION, type PackageTgzLimits } from "../packages/tgz.js";
4
4
  import { type PermissionSet } from "./permission-set.js";
@@ -57,6 +57,8 @@ export interface ExtensionPackage {
57
57
  size: number;
58
58
  packageJson: Record<string, unknown>;
59
59
  section: ExtensionPackageSection;
60
+ /** The plugin.json `displayName`, when the plugin has one. */
61
+ displayName?: LocalizedName;
60
62
  files: {
61
63
  path: string;
62
64
  size: number;
@@ -105,6 +107,17 @@ export declare function readMigrationSql(root: string, section: Pick<PluginExten
105
107
  file: string;
106
108
  sql: string;
107
109
  }[]>;
110
+ /**
111
+ * The plugin.json `displayName` of the plugin a config-declared extension module belongs to: the
112
+ * `.capybara-plugin/plugin.json` beside the nearest `package.json` above the module's directory
113
+ * `dir`. Nothing when there is no such file or it names another plugin than the extension `name`
114
+ * (a module inside some other plugin's directory); `problem` when it cannot be read or is not a
115
+ * valid plugin.json (the extension then has no display name of its own).
116
+ */
117
+ export declare function declaredDisplayName(dir: string, name: string): Promise<{
118
+ displayName?: LocalizedName;
119
+ problem?: string;
120
+ }>;
108
121
  /**
109
122
  * Unpacks the package into `dir` (dropping the `package/` prefix). `dir` must not exist or be empty;
110
123
  * the unpack rules and limits are the same as {@link readExtensionPackage} (paths, file types, entry
@@ -1,6 +1,6 @@
1
1
  import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
- import { dirname, posix, relative, resolve as resolvePath } from "node:path";
3
- import { checkEntryImports, isSafePackagePath, PLUGIN_MANIFEST_FILE, } from "@capybara-hq/plugin-sdk";
2
+ import { dirname, join, posix, relative, resolve as resolvePath } from "node:path";
3
+ import { checkEntryImports, isSafePackagePath, PLUGIN_MANIFEST_FILE, parsePluginManifest, } from "@capybara-hq/plugin-sdk";
4
4
  import { init as lexerInit, parse as lexerParse } from "es-module-lexer";
5
5
  import { PluginPackageError, readPluginPackage } from "../catalog/plugin-package.js";
6
6
  import { pluginSchemaName } from "../ctx/create-ctx.js";
@@ -159,6 +159,7 @@ export async function readExtensionPackage(bytes, opts) {
159
159
  size: plugin.size,
160
160
  packageJson: plugin.packageJson,
161
161
  section: { ...ext, name: manifest.name, version: manifest.version },
162
+ ...(manifest.displayName !== undefined && { displayName: manifest.displayName }),
162
163
  files: [...files].map(([path, data]) => ({ path, size: data.byteLength })),
163
164
  migrationSql,
164
165
  };
@@ -206,6 +207,54 @@ export async function readMigrationSql(root, section) {
206
207
  out.push({ file, sql: await readFile(resolvePath(dir, file), "utf8") });
207
208
  return out;
208
209
  }
210
+ /**
211
+ * The plugin.json `displayName` of the plugin a config-declared extension module belongs to: the
212
+ * `.capybara-plugin/plugin.json` beside the nearest `package.json` above the module's directory
213
+ * `dir`. Nothing when there is no such file or it names another plugin than the extension `name`
214
+ * (a module inside some other plugin's directory); `problem` when it cannot be read or is not a
215
+ * valid plugin.json (the extension then has no display name of its own).
216
+ */
217
+ export async function declaredDisplayName(dir, name) {
218
+ let root;
219
+ for (let d = resolvePath(dir);;) {
220
+ try {
221
+ await readFile(join(d, "package.json"));
222
+ root = d;
223
+ break;
224
+ }
225
+ catch {
226
+ // none here: go up
227
+ }
228
+ const up = dirname(d);
229
+ if (up === d)
230
+ return {};
231
+ d = up;
232
+ }
233
+ let text;
234
+ try {
235
+ text = await readFile(join(root, PLUGIN_MANIFEST_FILE), "utf8");
236
+ }
237
+ catch {
238
+ return {};
239
+ }
240
+ let json;
241
+ try {
242
+ json = JSON.parse(text);
243
+ }
244
+ catch (e) {
245
+ return { problem: `${PLUGIN_MANIFEST_FILE} is not valid JSON: ${errMsg(e)}` };
246
+ }
247
+ // another plugin's plugin.json (valid or not) says nothing about this extension
248
+ const named = json?.name;
249
+ if (typeof named === "string" && named !== name)
250
+ return {};
251
+ const m = parsePluginManifest(json);
252
+ if ("errors" in m)
253
+ return { problem: m.errors.slice(0, 3).join("; ") };
254
+ if (m.name !== name)
255
+ return {};
256
+ return m.displayName === undefined ? {} : { displayName: m.displayName };
257
+ }
209
258
  /**
210
259
  * Unpacks the package into `dir` (dropping the `package/` prefix). `dir` must not exist or be empty;
211
260
  * the unpack rules and limits are the same as {@link readExtensionPackage} (paths, file types, entry
@@ -1,3 +1,4 @@
1
+ import type { LocalizedName } from "@capybara-hq/plugin-sdk";
1
2
  import { type PermissionSet } from "./permission-set.js";
2
3
  import type { ExtensionSource } from "./sources.js";
3
4
  /**
@@ -65,6 +66,8 @@ export declare function extensionNeedsAction(status: DeploymentExtensionStatus):
65
66
  /** One item of the admin extension list (`GET /api/v1/admin/extensions`). */
66
67
  export interface AdminExtensionView {
67
68
  name: string;
69
+ /** The plugin's display name (`ExtensionDisplayNames`); null when it has none. */
70
+ displayName: LocalizedName | null;
68
71
  version: string;
69
72
  source: ExtensionSource;
70
73
  /** 安装记录的包;配置声明为 null。 */
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ import { type Principal } from "../identity/principal.js";
3
+ import { type OrgContext } from "../orgs/org.guard.js";
4
+ import { ExtensionPointDefaults, type OrgPointDefaultView } from "./point-defaults.js";
5
+ declare const PointParams: z.ZodObject<{
6
+ point: z.ZodString;
7
+ }, z.core.$strip>;
8
+ declare const DefaultBody: z.ZodObject<{
9
+ extension: z.ZodString;
10
+ }, z.core.$strict>;
11
+ /**
12
+ * The org default provider of `org-default` extension points (web tools spec §6):
13
+ * - `GET /api/v1/orgs/:orgId/extension-points` (`org.extensions.manage`) → `{ points }`: each
14
+ * point with its candidate providers, the stored default and the effective provider;
15
+ * - `PUT /api/v1/orgs/:orgId/extension-points/:point/default` `{ extension }`
16
+ * (`org.extensions.manage`) → 204;
17
+ * - `GET /api/v1/orgs/:orgId/extension-points/available` (`agents.use`) → `{ points }`: whether
18
+ * each point has a provider now, without extension names (for the agent form).
19
+ */
20
+ export declare class ExtensionPointDefaultsController {
21
+ private readonly points;
22
+ constructor(points: ExtensionPointDefaults);
23
+ list(org: OrgContext): Promise<{
24
+ points: OrgPointDefaultView[];
25
+ }>;
26
+ available(org: OrgContext): Promise<{
27
+ points: {
28
+ point: string;
29
+ available: boolean;
30
+ }[];
31
+ }>;
32
+ setDefault(principal: Principal, org: OrgContext, { point }: z.infer<typeof PointParams>, body: z.infer<typeof DefaultBody>): Promise<void>;
33
+ }
34
+ export {};
@@ -0,0 +1,71 @@
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 { Controller, Get, HttpCode, Inject, Put } from "@nestjs/common";
11
+ import { z } from "zod";
12
+ import { CurrentPrincipal, requireUser } from "../identity/principal.js";
13
+ import { createZodDto } from "../infra/validation/create-zod-dto.js";
14
+ import { ZBody, ZParam } from "../infra/validation/zod-params.js";
15
+ import { CurrentOrg, OrgAction } from "../orgs/org.guard.js";
16
+ import { ExtensionPointDefaults } from "./point-defaults.js";
17
+ const PointParams = z.object({ point: z.string().min(1).max(100) });
18
+ const DefaultBody = z.object({ extension: z.string().min(1).max(214) }).strict();
19
+ class ExtensionPointParamsDto extends createZodDto(PointParams, "ExtensionPointParams") {
20
+ }
21
+ class ExtensionPointDefaultBodyDto extends createZodDto(DefaultBody, "ExtensionPointDefaultBody") {
22
+ }
23
+ /**
24
+ * The org default provider of `org-default` extension points (web tools spec §6):
25
+ * - `GET /api/v1/orgs/:orgId/extension-points` (`org.extensions.manage`) → `{ points }`: each
26
+ * point with its candidate providers, the stored default and the effective provider;
27
+ * - `PUT /api/v1/orgs/:orgId/extension-points/:point/default` `{ extension }`
28
+ * (`org.extensions.manage`) → 204;
29
+ * - `GET /api/v1/orgs/:orgId/extension-points/available` (`agents.use`) → `{ points }`: whether
30
+ * each point has a provider now, without extension names (for the agent form).
31
+ */
32
+ let ExtensionPointDefaultsController = class ExtensionPointDefaultsController {
33
+ points;
34
+ constructor(points) {
35
+ this.points = points;
36
+ }
37
+ async list(org) {
38
+ return { points: await this.points.list(org.orgId) };
39
+ }
40
+ async available(org) {
41
+ return { points: await this.points.available(org.orgId) };
42
+ }
43
+ async setDefault(principal, org, { point }, body) {
44
+ const p = requireUser(principal);
45
+ await this.points.setDefault(org.orgId, point, body.extension, p.account.id);
46
+ }
47
+ };
48
+ __decorate([
49
+ Get(),
50
+ OrgAction("org.extensions.manage"),
51
+ __param(0, CurrentOrg())
52
+ ], ExtensionPointDefaultsController.prototype, "list", null);
53
+ __decorate([
54
+ Get("available"),
55
+ OrgAction("agents.use"),
56
+ __param(0, CurrentOrg())
57
+ ], ExtensionPointDefaultsController.prototype, "available", null);
58
+ __decorate([
59
+ Put(":point/default"),
60
+ HttpCode(204),
61
+ OrgAction("org.extensions.manage"),
62
+ __param(0, CurrentPrincipal()),
63
+ __param(1, CurrentOrg()),
64
+ __param(2, ZParam(ExtensionPointParamsDto)),
65
+ __param(3, ZBody(ExtensionPointDefaultBodyDto))
66
+ ], ExtensionPointDefaultsController.prototype, "setDefault", null);
67
+ ExtensionPointDefaultsController = __decorate([
68
+ Controller("api/v1/orgs/:orgId/extension-points"),
69
+ __param(0, Inject(ExtensionPointDefaults))
70
+ ], ExtensionPointDefaultsController);
71
+ export { ExtensionPointDefaultsController };
@@ -0,0 +1,64 @@
1
+ import { KernelDb } from "../infra/database/kernel-db.js";
2
+ import { TransactionHost } from "../infra/database/transaction-host.js";
3
+ import type { KernelLogger } from "../log.js";
4
+ import { OrgExtensionConfigs } from "./org-config.js";
5
+ import { ExtensionRegistry } from "./registry.js";
6
+ /** The outcome of {@link ExtensionPointDefaults.resolve}. */
7
+ export type PointResolution<T> = {
8
+ ok: true;
9
+ extension: string;
10
+ impl: T;
11
+ orgConfig: unknown;
12
+ } | {
13
+ ok: false;
14
+ reason: "none" | "ambiguous";
15
+ };
16
+ /** One `org-default` extension point of an org (the admin view). */
17
+ export interface OrgPointDefaultView {
18
+ point: string;
19
+ /** The extensions that could serve the org now, by name. */
20
+ candidates: string[];
21
+ /** The stored default, also when it is not a candidate now. */
22
+ default: string | null;
23
+ /** The extension a call would use now; null when there is none or the choice is ambiguous. */
24
+ effective: string | null;
25
+ }
26
+ /**
27
+ * The org default provider of an `org-default` extension point (web tools spec §6). Per call,
28
+ * never cached in process: the candidates are the providers loaded on this replica that are
29
+ * enabled in the org, whose org config is valid and whose `configured()` (when present) does not
30
+ * return false. One candidate is used as is; several need the org's stored default
31
+ * (`capybara.org_extension_point_defaults`), else the choice is ambiguous. A stored default that
32
+ * is not a candidate (disabled, uninstalled, unconfigured) stays and counts again once it is one.
33
+ */
34
+ export declare class ExtensionPointDefaults {
35
+ private readonly kdb;
36
+ readonly txHost: TransactionHost;
37
+ private readonly registry;
38
+ private readonly orgConfigs;
39
+ private readonly log;
40
+ constructor(kdb: KernelDb, txHost: TransactionHost, registry: Pick<ExtensionRegistry, "list">, orgConfigs: Pick<OrgExtensionConfigs, "get">, log: KernelLogger);
41
+ /**
42
+ * The provider of `point` (the name without the major, e.g. `web-search`) for `orgId`, with the
43
+ * org's decrypted config to pass back to it. Throws when the point has no `selection`.
44
+ */
45
+ resolve<T>(orgId: string, point: string): Promise<PointResolution<T>>;
46
+ /** Every `org-default` point with its candidates, stored default and effective provider. */
47
+ list(orgId: string): Promise<OrgPointDefaultView[]>;
48
+ /** Whether each `org-default` point has a provider for the org now (no extension names). */
49
+ available(orgId: string): Promise<{
50
+ point: string;
51
+ available: boolean;
52
+ }[]>;
53
+ /**
54
+ * Stores `extension` as the org's default provider of `point`. 400 `validation_failed` unless
55
+ * the point is an `org-default` one and the extension provides it (loaded here) and is enabled
56
+ * in the org. Audited as `extension_point.default_set`.
57
+ */
58
+ setDefault(orgId: string, point: string, extension: string, actorId: string): Promise<void>;
59
+ /** The candidates of `point` in `orgId`, by extension name. */
60
+ private candidates;
61
+ private choose;
62
+ /** The org's stored defaults, point → extension. */
63
+ private storedDefaults;
64
+ }