@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.
- package/dist/admin/admin.controller.d.ts +9 -4
- package/dist/admin/admin.controller.js +13 -4
- package/dist/admin/extensions.controller.d.ts +8 -1
- package/dist/admin/extensions.controller.js +22 -2
- package/dist/agents/agent-lookup.d.ts +3 -0
- package/dist/agents/agent-lookup.js +20 -2
- package/dist/agents/agent-profile.service.d.ts +29 -0
- package/dist/agents/agent-profile.service.js +117 -0
- package/dist/agents/agents.controller.d.ts +93 -3
- package/dist/agents/agents.controller.js +114 -4
- package/dist/agents/agents.module.js +6 -2
- package/dist/agents/agents.service.d.ts +13 -5
- package/dist/agents/agents.service.js +49 -13
- package/dist/agents/definition.d.ts +35 -8
- package/dist/agents/definition.js +203 -17
- package/dist/agents/instruction-files.d.ts +60 -0
- package/dist/agents/instruction-files.js +111 -0
- package/dist/agents/models.controller.d.ts +9 -3
- package/dist/agents/models.controller.js +19 -4
- package/dist/agents/profile.d.ts +96 -0
- package/dist/agents/profile.js +51 -0
- package/dist/agents/readiness.controller.d.ts +26 -0
- package/dist/agents/readiness.controller.js +56 -0
- package/dist/agents/templates.js +20 -5
- package/dist/background/background.controller.d.ts +38 -0
- package/dist/background/background.controller.js +87 -0
- package/dist/background/background.module.d.ts +10 -0
- package/dist/background/background.module.js +32 -0
- package/dist/background/finish.d.ts +43 -0
- package/dist/background/finish.js +94 -0
- package/dist/background/launch-lock.d.ts +14 -0
- package/dist/background/launch-lock.js +39 -0
- package/dist/background/launch.d.ts +36 -0
- package/dist/background/launch.js +70 -0
- package/dist/background/poll.job.d.ts +53 -0
- package/dist/background/poll.job.js +182 -0
- package/dist/background/render.d.ts +23 -0
- package/dist/background/render.js +48 -0
- package/dist/background/session.d.ts +37 -0
- package/dist/background/session.js +66 -0
- package/dist/background/status.d.ts +35 -0
- package/dist/background/status.js +57 -0
- package/dist/background/stop.d.ts +62 -0
- package/dist/background/stop.js +225 -0
- package/dist/background/store.d.ts +150 -0
- package/dist/background/store.js +351 -0
- package/dist/background/store.module.d.ts +6 -0
- package/dist/background/store.module.js +22 -0
- package/dist/background/tasks.service.d.ts +67 -0
- package/dist/background/tasks.service.js +186 -0
- package/dist/background/wake-rules.d.ts +57 -0
- package/dist/background/wake-rules.js +83 -0
- package/dist/background/wake.d.ts +28 -0
- package/dist/background/wake.js +57 -0
- package/dist/catalog/catalog-content.js +4 -1
- package/dist/catalog/claude/agents.js +15 -10
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/plugin-import.js +1 -1
- package/dist/catalog/plugin-upgrade.js +1 -1
- package/dist/channels/cards.d.ts +8 -2
- package/dist/channels/cards.js +17 -9
- package/dist/channels/connections.service.d.ts +16 -1
- package/dist/channels/connections.service.js +38 -4
- package/dist/channels/threads.d.ts +5 -0
- package/dist/channels/threads.js +8 -0
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.js +104 -2
- package/dist/conversations/access.js +2 -0
- package/dist/conversations/artifacts.d.ts +1 -1
- package/dist/conversations/artifacts.js +1 -1
- package/dist/conversations/attachments.service.d.ts +30 -0
- package/dist/conversations/attachments.service.js +130 -5
- package/dist/conversations/conversations.controller.d.ts +36 -5
- package/dist/conversations/conversations.controller.js +62 -12
- package/dist/conversations/conversations.module.js +3 -0
- package/dist/conversations/conversations.service.d.ts +44 -2
- package/dist/conversations/conversations.service.js +140 -12
- package/dist/conversations/event-log.d.ts +12 -1
- package/dist/conversations/event-log.js +29 -1
- package/dist/conversations/events.d.ts +81 -3
- package/dist/conversations/events.js +83 -16
- package/dist/conversations/queue.d.ts +3 -1
- package/dist/conversations/queue.js +13 -2
- package/dist/conversations/queue.service.js +3 -1
- package/dist/conversations/titles.d.ts +7 -0
- package/dist/conversations/titles.js +15 -0
- package/dist/db/kernel-schema.d.ts +60 -4
- package/dist/db/pool.d.ts +5 -0
- package/dist/db/pool.js +3 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +8 -0
- package/dist/evals/recorded-tools.d.ts +27 -1
- package/dist/evals/recorded-tools.js +85 -10
- package/dist/evals/run-replay.d.ts +10 -2
- package/dist/evals/run-replay.js +49 -12
- package/dist/evals/step-replay.js +12 -6
- package/dist/evals/trajectory.d.ts +2 -2
- package/dist/evals/trajectory.js +1 -1
- package/dist/extensions/admin-ops.js +2 -0
- package/dist/extensions/admin-view.d.ts +3 -1
- package/dist/extensions/admin-view.js +10 -2
- package/dist/extensions/blobs.js +1 -0
- package/dist/extensions/config-issues.d.ts +13 -1
- package/dist/extensions/config-issues.js +22 -5
- package/dist/extensions/config-json-schema.d.ts +43 -7
- package/dist/extensions/config-json-schema.js +124 -58
- package/dist/extensions/deployment-config-store.d.ts +6 -0
- package/dist/extensions/deployment-config.d.ts +50 -3
- package/dist/extensions/deployment-config.js +125 -28
- package/dist/extensions/display-name.d.ts +22 -0
- package/dist/extensions/display-name.js +77 -0
- package/dist/extensions/extensions.module.js +6 -0
- package/dist/extensions/host.d.ts +26 -1
- package/dist/extensions/host.js +82 -9
- package/dist/extensions/org-config.controller.d.ts +11 -3
- package/dist/extensions/org-config.controller.js +14 -6
- package/dist/extensions/org-config.d.ts +6 -0
- package/dist/extensions/org-config.js +12 -13
- package/dist/extensions/package.d.ts +14 -1
- package/dist/extensions/package.js +51 -2
- package/dist/extensions/permission-view.d.ts +3 -0
- package/dist/extensions/point-defaults.controller.d.ts +34 -0
- package/dist/extensions/point-defaults.controller.js +71 -0
- package/dist/extensions/point-defaults.d.ts +64 -0
- package/dist/extensions/point-defaults.js +206 -0
- package/dist/extensions/registry.d.ts +1 -1
- package/dist/extensions/registry.js +2 -0
- package/dist/http/api.module.js +8 -0
- package/dist/http/nest-logger.d.ts +6 -5
- package/dist/http/nest-logger.js +24 -10
- package/dist/identity/auth.controller.js +9 -5
- package/dist/identity/cookies.d.ts +20 -5
- package/dist/identity/cookies.js +44 -6
- package/dist/identity/me.controller.d.ts +5 -1
- package/dist/identity/me.controller.js +12 -3
- package/dist/identity/sessions.d.ts +12 -0
- package/dist/identity/sessions.js +45 -0
- package/dist/identity/settings.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/infra/config/kernel-config.service.js +6 -0
- package/dist/infra/database/database.module.js +1 -0
- package/dist/infra/events/kernel-events.d.ts +8 -0
- package/dist/infra/lifecycle/process-guards.js +4 -0
- package/dist/infra/logging/logging.module.d.ts +4 -2
- package/dist/infra/logging/logging.module.js +24 -6
- package/dist/infra/queue/redis-connection.d.ts +6 -0
- package/dist/infra/queue/redis-connection.js +7 -0
- package/dist/infra/redis/redis.module.js +6 -2
- package/dist/infra/tokens.d.ts +6 -1
- package/dist/infra/tokens.js +6 -1
- package/dist/lifecycle/kernel-lifecycle.js +5 -0
- package/dist/log.d.ts +13 -1
- package/dist/log.js +93 -17
- package/dist/models/purposes.d.ts +23 -0
- package/dist/models/purposes.js +31 -10
- package/dist/orgs/offboarding.d.ts +3 -1
- package/dist/orgs/offboarding.js +26 -16
- package/dist/orgs/settings.service.d.ts +7 -2
- package/dist/orgs/settings.service.js +15 -4
- package/dist/roles/worker.module.js +6 -0
- package/dist/runtime/context/build.d.ts +15 -13
- package/dist/runtime/context/build.js +45 -27
- package/dist/runtime/context/claude-tools.d.ts +3 -1
- package/dist/runtime/context/claude-tools.js +12 -12
- package/dist/runtime/context/compaction.js +4 -0
- package/dist/runtime/context/legacy-text.d.ts +22 -0
- package/dist/runtime/context/legacy-text.js +37 -0
- package/dist/runtime/context/skills.d.ts +29 -11
- package/dist/runtime/context/skills.js +37 -30
- package/dist/runtime/langgraph-loop.js +3 -2
- package/dist/runtime/loop.d.ts +5 -4
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +17 -5
- package/dist/runtime/model-call.d.ts +17 -1
- package/dist/runtime/model-call.js +4 -3
- package/dist/runtime/providers.d.ts +6 -0
- package/dist/runtime/providers.js +8 -0
- package/dist/runtime/run-finish.d.ts +1 -1
- package/dist/runtime/run-queue.d.ts +28 -5
- package/dist/runtime/run-queue.js +131 -35
- package/dist/runtime/run-worker.d.ts +2 -2
- package/dist/runtime/run-worker.js +20 -7
- package/dist/runtime/runtime.module.js +8 -3
- package/dist/runtime/step-log.d.ts +6 -0
- package/dist/runtime/step-log.js +16 -2
- package/dist/runtime/subagents/definition.d.ts +1 -6
- package/dist/runtime/subagents/definition.js +14 -13
- package/dist/runtime/subagents/dispatch.d.ts +2 -2
- package/dist/runtime/subagents/dispatch.js +2 -2
- package/dist/runtime/subagents/org-agents.js +2 -1
- package/dist/runtime/subagents/roster.d.ts +1 -1
- package/dist/runtime/subagents/roster.js +1 -1
- package/dist/runtime/subagents/skill-fork.d.ts +2 -2
- package/dist/runtime/subagents/skill-fork.js +2 -2
- package/dist/runtime/subagents/subagents.service.d.ts +3 -3
- package/dist/runtime/subagents/subagents.service.js +3 -3
- package/dist/runtime/usage-report.d.ts +2 -1
- package/dist/runtime/usage-report.js +2 -1
- package/dist/runtime/waits.d.ts +13 -7
- package/dist/runtime/waits.js +42 -16
- package/dist/sandbox/sandbox.module.js +6 -1
- package/dist/sandbox/sandbox.service.d.ts +61 -3
- package/dist/sandbox/sandbox.service.js +141 -7
- package/dist/skills/catalog.d.ts +4 -4
- package/dist/skills/catalog.js +4 -4
- package/dist/skills/changes.service.d.ts +2 -2
- package/dist/skills/changes.service.js +5 -4
- package/dist/skills/invocation-keys.d.ts +1 -1
- package/dist/skills/invocation-keys.js +1 -1
- package/dist/skills/invoke.d.ts +1 -1
- package/dist/skills/invoke.js +5 -4
- package/dist/tools/approvals.service.d.ts +6 -0
- package/dist/tools/approvals.service.js +21 -1
- package/dist/tools/builtin-names.d.ts +91 -0
- package/dist/tools/builtin-names.js +143 -0
- package/dist/tools/builtins/agent.d.ts +7 -7
- package/dist/tools/builtins/agent.js +7 -11
- package/dist/tools/builtins/ask-user.d.ts +1 -1
- package/dist/tools/builtins/ask-user.js +2 -2
- package/dist/tools/builtins/builtin-tools.d.ts +17 -3
- package/dist/tools/builtins/builtin-tools.js +36 -4
- package/dist/tools/builtins/read-tool-output.d.ts +1 -1
- package/dist/tools/builtins/read-tool-output.js +2 -2
- package/dist/tools/builtins/sandbox/bash.d.ts +4 -4
- package/dist/tools/builtins/sandbox/bash.js +259 -29
- package/dist/tools/builtins/sandbox/common.d.ts +30 -7
- package/dist/tools/builtins/sandbox/common.js +9 -5
- package/dist/tools/builtins/sandbox/deliver.d.ts +1 -1
- package/dist/tools/builtins/sandbox/deliver.js +12 -12
- package/dist/tools/builtins/sandbox/edit.d.ts +1 -1
- package/dist/tools/builtins/sandbox/edit.js +41 -30
- package/dist/tools/builtins/sandbox/file-state.d.ts +34 -0
- package/dist/tools/builtins/sandbox/file-state.js +34 -0
- package/dist/tools/builtins/sandbox/glob-match.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob-match.js +1 -1
- package/dist/tools/builtins/sandbox/glob.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob.js +4 -4
- package/dist/tools/builtins/sandbox/grep.d.ts +7 -4
- package/dist/tools/builtins/sandbox/grep.js +147 -30
- package/dist/tools/builtins/sandbox/index.d.ts +3 -1
- package/dist/tools/builtins/sandbox/index.js +7 -1
- package/dist/tools/builtins/sandbox/read.d.ts +2 -2
- package/dist/tools/builtins/sandbox/read.js +21 -14
- package/dist/tools/builtins/sandbox/task-output.d.ts +63 -0
- package/dist/tools/builtins/sandbox/task-output.js +304 -0
- package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
- package/dist/tools/builtins/sandbox/task-stop.js +112 -0
- package/dist/tools/builtins/sandbox/write.d.ts +1 -1
- package/dist/tools/builtins/sandbox/write.js +37 -33
- package/dist/tools/builtins/skill-load.d.ts +3 -3
- package/dist/tools/builtins/skill-load.js +32 -16
- package/dist/tools/builtins/skill-write.d.ts +4 -4
- package/dist/tools/builtins/skill-write.js +10 -10
- package/dist/tools/builtins/tool-search.d.ts +13 -9
- package/dist/tools/builtins/tool-search.js +25 -14
- package/dist/tools/builtins/web/errors.d.ts +8 -0
- package/dist/tools/builtins/web/errors.js +53 -0
- package/dist/tools/builtins/web/extract.d.ts +62 -0
- package/dist/tools/builtins/web/extract.js +267 -0
- package/dist/tools/builtins/web/fetch.d.ts +55 -0
- package/dist/tools/builtins/web/fetch.js +174 -0
- package/dist/tools/builtins/web/index.d.ts +13 -0
- package/dist/tools/builtins/web/index.js +12 -0
- package/dist/tools/builtins/web/page-cache.d.ts +25 -0
- package/dist/tools/builtins/web/page-cache.js +77 -0
- package/dist/tools/builtins/web/search.d.ts +25 -0
- package/dist/tools/builtins/web/search.js +209 -0
- package/dist/tools/builtins/web/url.d.ts +17 -0
- package/dist/tools/builtins/web/url.js +43 -0
- package/dist/tools/connectors.service.js +4 -4
- package/dist/tools/display-names.d.ts +9 -0
- package/dist/tools/display-names.js +24 -0
- package/dist/tools/drift.js +5 -5
- package/dist/tools/elicitation.js +1 -1
- package/dist/tools/info.d.ts +20 -4
- package/dist/tools/info.js +55 -32
- package/dist/tools/legacy-data.d.ts +34 -0
- package/dist/tools/legacy-data.js +76 -0
- package/dist/tools/legacy-keys.d.ts +51 -0
- package/dist/tools/legacy-keys.js +115 -0
- package/dist/tools/naming.d.ts +1 -5
- package/dist/tools/naming.js +1 -7
- package/dist/tools/oauth/flow-paths.d.ts +1 -1
- package/dist/tools/oauth/flow-paths.js +1 -1
- package/dist/tools/outputs.js +1 -1
- package/dist/tools/pipeline.d.ts +13 -7
- package/dist/tools/pipeline.js +112 -39
- package/dist/tools/policy.d.ts +1 -14
- package/dist/tools/policy.js +13 -19
- package/dist/tools/questions.controller.d.ts +1 -1
- package/dist/tools/questions.controller.js +1 -1
- package/dist/tools/questions.service.d.ts +1 -1
- package/dist/tools/registry.d.ts +38 -24
- package/dist/tools/registry.js +54 -47
- package/dist/tools/resources.d.ts +1 -1
- package/dist/tools/resources.js +1 -1
- package/dist/tools/tools.module.js +13 -1
- package/dist/tools/validate.js +1 -1
- package/package.json +3 -3
- package/src/migrations/0063_tool_keys_claude_code.sql +220 -0
- package/src/migrations/0064_account_last_org.sql +7 -0
- package/src/migrations/0065_conversation_archive.sql +8 -0
- package/src/migrations/0066_extension_display_name.sql +4 -0
- package/src/migrations/0067_agent_profiles.sql +20 -0
- package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
- package/src/migrations/0069_attachments_agent_idx.sql +3 -0
- package/src/migrations/0070_background_tasks.sql +37 -0
- package/src/migrations/0071_background_tasks_reserve.sql +6 -0
- package/src/migrations/0072_background_tasks_stopping.sql +5 -0
- package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
- package/dist/tools/builtins/sandbox/names.d.ts +0 -7
- package/dist/tools/builtins/sandbox/names.js +0 -20
package/dist/extensions/host.js
CHANGED
|
@@ -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
|
-
|
|
302
|
-
|
|
303
|
-
manifest
|
|
304
|
-
|
|
305
|
-
|
|
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({
|
|
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:
|
|
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
|
-
|
|
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:
|
|
26
|
+
extensions: OrgExtensionItem[];
|
|
19
27
|
}>;
|
|
20
28
|
put(principal: Principal, org: OrgContext, extension: string, body: z.infer<typeof PutBody>): Promise<{
|
|
21
|
-
extension:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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 {
|
|
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 ?
|
|
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
|
+
}
|