@capybara-hq/kernel 0.1.0-rc.12 → 0.1.0-rc.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/admin.schemas.d.ts +13 -0
- package/dist/agents/agent-lookup.d.ts +5 -0
- package/dist/agents/agent-lookup.js +15 -0
- package/dist/background/background.module.js +2 -2
- package/dist/background/launch-lock.d.ts +1 -1
- package/dist/background/launch-lock.js +1 -1
- package/dist/background/poll.job.d.ts +2 -2
- package/dist/background/poll.job.js +10 -10
- package/dist/background/stop.d.ts +1 -1
- package/dist/background/stop.js +3 -3
- package/dist/background/store.d.ts +5 -5
- package/dist/background/store.js +5 -5
- package/dist/background/tasks.service.d.ts +6 -6
- package/dist/background/tasks.service.js +13 -13
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/channels/channels.module.js +2 -2
- package/dist/channels/inbound.d.ts +8 -8
- package/dist/channels/inbound.js +31 -31
- package/dist/channels/phrases.d.ts +27 -27
- package/dist/channels/phrases.js +27 -27
- package/dist/config/docs.js +1 -1
- package/dist/config/schema.d.ts +2 -2
- package/dist/config/schema.js +21 -21
- package/dist/conversations/conversations.controller.d.ts +11 -11
- package/dist/conversations/conversations.controller.js +15 -15
- package/dist/conversations/conversations.module.d.ts +1 -1
- package/dist/conversations/conversations.module.js +7 -7
- package/dist/conversations/conversations.schemas.js +1 -1
- package/dist/conversations/conversations.service.d.ts +14 -14
- package/dist/conversations/conversations.service.js +19 -19
- package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
- package/dist/conversations/{environment-status.js → device-status.js} +18 -18
- package/dist/conversations/event-log.d.ts +1 -1
- package/dist/conversations/event-log.js +1 -1
- package/dist/conversations/events.d.ts +1 -1
- package/dist/conversations/events.js +2 -2
- package/dist/ctx/create-ctx.d.ts +10 -1
- package/dist/ctx/create-ctx.js +86 -25
- package/dist/db/kernel-schema.d.ts +26 -23
- package/dist/{environments → devices}/access.d.ts +19 -19
- package/dist/{environments → devices}/access.js +28 -28
- package/dist/devices/conversation-devices.d.ts +75 -0
- package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
- package/dist/devices/devices.controller.d.ts +36 -0
- package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
- package/dist/devices/devices.module.d.ts +5 -13
- package/dist/devices/devices.module.js +16 -29
- package/dist/devices/devices.schemas.d.ts +3 -0
- package/dist/devices/devices.schemas.js +14 -0
- package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
- package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
- package/dist/devices/dto.d.ts +13 -54
- package/dist/devices/dto.js +7 -39
- package/dist/devices/label.d.ts +11 -0
- package/dist/{environments → devices}/label.js +7 -7
- package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
- package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
- package/dist/errors.d.ts +25 -25
- package/dist/errors.js +25 -25
- package/dist/evals/recorded-tools.d.ts +2 -2
- package/dist/evals/recorded-tools.js +6 -6
- package/dist/extensions/admin-ops.js +1 -0
- package/dist/extensions/admin-view.js +2 -0
- package/dist/extensions/effective-config.d.ts +6 -0
- package/dist/extensions/effective-config.js +18 -7
- package/dist/extensions/host.d.ts +13 -2
- package/dist/extensions/host.js +24 -3
- package/dist/extensions/instance.d.ts +12 -1
- package/dist/extensions/instance.js +13 -0
- package/dist/extensions/permission-view.d.ts +10 -1
- package/dist/files/previewers.d.ts +1 -1
- package/dist/files/previewers.js +1 -1
- package/dist/http/api.module.js +10 -6
- package/dist/http/gateway-routes.d.ts +1 -1
- package/dist/http/gateway-routes.js +1 -1
- package/dist/identity/settings.d.ts +32 -0
- package/dist/identity/settings.js +26 -2
- package/dist/infra/config/kernel-config.service.js +4 -4
- package/dist/kernel.module.js +3 -3
- package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
- package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
- package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
- package/dist/{devices → local-devices}/device-auth.js +51 -53
- package/dist/local-devices/device-auth.module.d.ts +7 -0
- package/dist/{devices → local-devices}/device-auth.module.js +5 -5
- package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
- package/dist/{devices → local-devices}/device-routes.js +2 -2
- package/dist/local-devices/dto.d.ts +66 -0
- package/dist/local-devices/dto.js +44 -0
- package/dist/{devices → local-devices}/keys.d.ts +11 -11
- package/dist/{devices → local-devices}/keys.js +11 -11
- package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
- package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
- package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
- package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
- package/dist/local-devices/local-devices.module.d.ts +16 -0
- package/dist/local-devices/local-devices.module.js +44 -0
- package/dist/{devices → local-devices}/machines.d.ts +26 -26
- package/dist/{devices → local-devices}/machines.js +71 -71
- package/dist/{devices → local-devices}/relay.d.ts +15 -15
- package/dist/{devices → local-devices}/relay.js +55 -55
- package/dist/{devices → local-devices}/targets.d.ts +8 -8
- package/dist/{devices → local-devices}/targets.js +14 -14
- package/dist/orgs/offboarding.d.ts +6 -6
- package/dist/orgs/offboarding.js +12 -12
- package/dist/orgs/settings.service.d.ts +28 -0
- package/dist/orgs/settings.service.js +20 -1
- package/dist/platform/exclusions.js +38 -3
- package/dist/platform/operation.js +6 -2
- package/dist/platform/ops/admin.ops.js +8 -2
- package/dist/platform/ops/conversations.ops.d.ts +3 -3
- package/dist/platform/ops/conversations.ops.js +9 -9
- package/dist/platform/ops/devices.ops.d.ts +26 -0
- package/dist/platform/ops/devices.ops.js +311 -0
- package/dist/platform/ops/org-settings.ops.js +2 -2
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/ui.ops.d.ts +8 -0
- package/dist/platform/ops/ui.ops.js +41 -0
- package/dist/platform/platform-ops.module.d.ts +3 -2
- package/dist/platform/platform-ops.module.js +8 -5
- package/dist/platform/route-schemas.js +6 -3
- package/dist/roles/gateway-role.d.ts +3 -3
- package/dist/roles/gateway-role.js +4 -4
- package/dist/roles/gateway.module.d.ts +1 -1
- package/dist/roles/gateway.module.js +5 -5
- package/dist/roles/worker.module.js +1 -1
- package/dist/runtime/context/build.d.ts +1 -1
- package/dist/runtime/context/build.js +6 -6
- package/dist/runtime/context/compaction.js +1 -1
- package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
- package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
- package/dist/runtime/maintenance.d.ts +1 -1
- package/dist/sandbox/jobs.d.ts +13 -13
- package/dist/sandbox/jobs.js +20 -20
- package/dist/sandbox/leases.d.ts +9 -9
- package/dist/sandbox/leases.js +14 -14
- package/dist/sandbox/providers.d.ts +8 -8
- package/dist/sandbox/providers.js +8 -8
- package/dist/sandbox/sandbox.module.d.ts +1 -1
- package/dist/sandbox/sandbox.module.js +1 -1
- package/dist/sandbox/sandbox.service.d.ts +76 -76
- package/dist/sandbox/sandbox.service.js +230 -230
- package/dist/tools/builtins/builtin-tools.d.ts +2 -2
- package/dist/tools/builtins/builtin-tools.js +5 -5
- package/dist/tools/builtins/platform.js +1 -1
- package/dist/tools/builtins/sandbox/bash.js +6 -6
- package/dist/tools/builtins/sandbox/common.d.ts +25 -25
- package/dist/tools/builtins/sandbox/common.js +51 -51
- package/dist/tools/builtins/sandbox/edit.js +2 -2
- package/dist/tools/builtins/sandbox/index.d.ts +1 -1
- package/dist/tools/builtins/sandbox/index.js +1 -1
- package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
- package/dist/tools/builtins/sandbox/task-output.js +10 -10
- package/dist/tools/builtins/sandbox/task-stop.js +2 -2
- package/dist/tools/builtins/sandbox/write.js +2 -2
- package/dist/tools/builtins/skill-load.d.ts +1 -1
- package/dist/tools/builtins/skill-load.js +2 -2
- package/dist/tools/pipeline.js +4 -3
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/tools.module.js +3 -3
- package/dist/ui/admin-ui.controller.d.ts +56 -0
- package/dist/ui/admin-ui.controller.js +192 -0
- package/dist/ui/arrangement.d.ts +74 -0
- package/dist/ui/arrangement.js +98 -0
- package/dist/ui/embed-token.d.ts +2 -2
- package/dist/ui/embed-token.js +30 -5
- package/dist/ui/registry.d.ts +29 -14
- package/dist/ui/registry.js +31 -10
- package/dist/ui/slots.controller.d.ts +11 -0
- package/dist/ui/slots.controller.js +25 -0
- package/dist/ui/ui-stream.d.ts +20 -3
- package/dist/ui/ui-stream.js +25 -7
- package/dist/ui/ui.schemas.d.ts +66 -0
- package/dist/ui/ui.schemas.js +65 -0
- package/dist/ui/views.controller.d.ts +35 -49
- package/dist/ui/views.controller.js +48 -70
- package/dist/ui/views.d.ts +84 -18
- package/dist/ui/views.js +201 -38
- package/package.json +3 -3
- package/src/migrations/0105_devices_rename.sql +136 -0
- package/dist/devices/device-auth.module.d.ts +0 -7
- package/dist/environments/conversation-environments.d.ts +0 -75
- package/dist/environments/dto.d.ts +0 -25
- package/dist/environments/dto.js +0 -12
- package/dist/environments/environments.controller.d.ts +0 -36
- package/dist/environments/environments.module.d.ts +0 -8
- package/dist/environments/environments.module.js +0 -31
- package/dist/environments/environments.schemas.d.ts +0 -3
- package/dist/environments/environments.schemas.js +0 -14
- package/dist/environments/label.d.ts +0 -11
- package/dist/platform/ops/environments.ops.d.ts +0 -26
- package/dist/platform/ops/environments.ops.js +0 -311
package/dist/devices/dto.d.ts
CHANGED
|
@@ -1,66 +1,25 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
/**
|
|
3
|
-
export declare const
|
|
2
|
+
/** A device's name: trimmed, 1-64 characters (unique per person, case-insensitive). */
|
|
3
|
+
export declare const DeviceName: z.ZodString;
|
|
4
|
+
export declare const DeviceNameBody: z.ZodObject<{
|
|
4
5
|
name: z.ZodString;
|
|
5
|
-
os: z.ZodEnum<{
|
|
6
|
-
darwin: "darwin";
|
|
7
|
-
linux: "linux";
|
|
8
|
-
}>;
|
|
9
|
-
arch: z.ZodString;
|
|
10
|
-
programVersion: z.ZodString;
|
|
11
6
|
}, z.core.$strict>;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
deviceCode: z.ZodString;
|
|
15
|
-
}, z.core.$strict>;
|
|
16
|
-
export declare const DeviceUserCodeParams: z.ZodObject<{
|
|
17
|
-
userCode: z.ZodString;
|
|
7
|
+
export declare const DeviceParams: z.ZodObject<{
|
|
8
|
+
id: z.ZodString;
|
|
18
9
|
}, z.core.$strip>;
|
|
19
|
-
|
|
20
|
-
userCode: z.ZodString;
|
|
21
|
-
}, z.core.$strict>;
|
|
22
|
-
/**
|
|
23
|
-
* `POST /api/v1/device/confirm`: the org and exactly one of an existing device environment of the
|
|
24
|
-
* person's (`environmentId`) or the name of a new one (`name`).
|
|
25
|
-
*/
|
|
26
|
-
export declare const DeviceConfirmBody: z.ZodObject<{
|
|
27
|
-
userCode: z.ZodString;
|
|
28
|
-
orgId: z.ZodString;
|
|
29
|
-
environmentId: z.ZodOptional<z.ZodUUID>;
|
|
30
|
-
name: z.ZodOptional<z.ZodString>;
|
|
31
|
-
}, z.core.$strict>;
|
|
32
|
-
declare const DeviceAuthorizeBodyDto_base: import("../infra/validation/create-zod-dto.js").ZodDtoClass<z.ZodObject<{
|
|
10
|
+
declare const DeviceCreateBodyDto_base: import("../infra/validation/create-zod-dto.js").ZodDtoClass<z.ZodObject<{
|
|
33
11
|
name: z.ZodString;
|
|
34
|
-
os: z.ZodEnum<{
|
|
35
|
-
darwin: "darwin";
|
|
36
|
-
linux: "linux";
|
|
37
|
-
}>;
|
|
38
|
-
arch: z.ZodString;
|
|
39
|
-
programVersion: z.ZodString;
|
|
40
12
|
}, z.core.$strict>>;
|
|
41
|
-
export declare class
|
|
13
|
+
export declare class DeviceCreateBodyDto extends DeviceCreateBodyDto_base {
|
|
42
14
|
}
|
|
43
|
-
declare const
|
|
44
|
-
|
|
15
|
+
declare const DeviceRenameBodyDto_base: import("../infra/validation/create-zod-dto.js").ZodDtoClass<z.ZodObject<{
|
|
16
|
+
name: z.ZodString;
|
|
45
17
|
}, z.core.$strict>>;
|
|
46
|
-
export declare class
|
|
18
|
+
export declare class DeviceRenameBodyDto extends DeviceRenameBodyDto_base {
|
|
47
19
|
}
|
|
48
|
-
declare const
|
|
49
|
-
|
|
20
|
+
declare const DeviceParamsDto_base: import("../infra/validation/create-zod-dto.js").ZodDtoClass<z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
50
22
|
}, z.core.$strip>>;
|
|
51
|
-
export declare class
|
|
52
|
-
}
|
|
53
|
-
declare const DeviceUserCodeBodyDto_base: import("../infra/validation/create-zod-dto.js").ZodDtoClass<z.ZodObject<{
|
|
54
|
-
userCode: z.ZodString;
|
|
55
|
-
}, z.core.$strict>>;
|
|
56
|
-
export declare class DeviceUserCodeBodyDto extends DeviceUserCodeBodyDto_base {
|
|
57
|
-
}
|
|
58
|
-
declare const DeviceConfirmBodyDto_base: import("../infra/validation/create-zod-dto.js").ZodDtoClass<z.ZodObject<{
|
|
59
|
-
userCode: z.ZodString;
|
|
60
|
-
orgId: z.ZodString;
|
|
61
|
-
environmentId: z.ZodOptional<z.ZodUUID>;
|
|
62
|
-
name: z.ZodOptional<z.ZodString>;
|
|
63
|
-
}, z.core.$strict>>;
|
|
64
|
-
export declare class DeviceConfirmBodyDto extends DeviceConfirmBodyDto_base {
|
|
23
|
+
export declare class DeviceParamsDto extends DeviceParamsDto_base {
|
|
65
24
|
}
|
|
66
25
|
export {};
|
package/dist/devices/dto.js
CHANGED
|
@@ -1,44 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { EnvironmentName } from "../environments/dto.js";
|
|
3
2
|
import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
4
|
-
/**
|
|
5
|
-
export const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
arch: z.string().trim().min(1).max(32),
|
|
10
|
-
programVersion: z.string().trim().min(1).max(64),
|
|
11
|
-
})
|
|
12
|
-
.strict();
|
|
13
|
-
/** `POST /api/v1/device/token`: the secret device code from `authorize`. */
|
|
14
|
-
export const DeviceTokenBody = z.object({ deviceCode: z.string().min(1).max(200) }).strict();
|
|
15
|
-
/** A user code as typed (`XXXX-XXXX`; case, spaces and the dash are forgiven). */
|
|
16
|
-
const UserCode = z.string().min(1).max(32);
|
|
17
|
-
export const DeviceUserCodeParams = z.object({ userCode: UserCode });
|
|
18
|
-
export const DeviceUserCodeBody = z.object({ userCode: UserCode }).strict();
|
|
19
|
-
/**
|
|
20
|
-
* `POST /api/v1/device/confirm`: the org and exactly one of an existing device environment of the
|
|
21
|
-
* person's (`environmentId`) or the name of a new one (`name`).
|
|
22
|
-
*/
|
|
23
|
-
export const DeviceConfirmBody = z
|
|
24
|
-
.object({
|
|
25
|
-
userCode: UserCode,
|
|
26
|
-
orgId: z.string().min(1).max(100),
|
|
27
|
-
environmentId: z.uuid().optional(),
|
|
28
|
-
name: EnvironmentName.optional(),
|
|
29
|
-
})
|
|
30
|
-
.strict()
|
|
31
|
-
.refine((b) => (b.environmentId === undefined) !== (b.name === undefined), {
|
|
32
|
-
message: "Give exactly one of environmentId and name",
|
|
33
|
-
path: ["environmentId"],
|
|
34
|
-
});
|
|
35
|
-
export class DeviceAuthorizeBodyDto extends createZodDto(DeviceAuthorizeBody, "DeviceAuthorizeBody") {
|
|
3
|
+
/** A device's name: trimmed, 1-64 characters (unique per person, case-insensitive). */
|
|
4
|
+
export const DeviceName = z.string().trim().min(1).max(64);
|
|
5
|
+
export const DeviceNameBody = z.object({ name: DeviceName }).strict();
|
|
6
|
+
export const DeviceParams = z.object({ id: z.string().min(1).max(100) });
|
|
7
|
+
export class DeviceCreateBodyDto extends createZodDto(DeviceNameBody, "DeviceCreateBody") {
|
|
36
8
|
}
|
|
37
|
-
export class
|
|
9
|
+
export class DeviceRenameBodyDto extends createZodDto(DeviceNameBody, "DeviceRenameBody") {
|
|
38
10
|
}
|
|
39
|
-
export class
|
|
40
|
-
}
|
|
41
|
-
export class DeviceUserCodeBodyDto extends createZodDto(DeviceUserCodeBody, "DeviceUserCodeBody") {
|
|
42
|
-
}
|
|
43
|
-
export class DeviceConfirmBodyDto extends createZodDto(DeviceConfirmBody, "DeviceConfirmBody") {
|
|
11
|
+
export class DeviceParamsDto extends createZodDto(DeviceParams, "DeviceParams") {
|
|
44
12
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DeviceView } from "./devices.service.js";
|
|
2
|
+
/**
|
|
3
|
+
* A device's name for people outside the web (the IM `/device` list, the `Platform` tool): its
|
|
4
|
+
* own name, else 「个人设备」 / "Personal" for the default, else for a default demoted by a provider
|
|
5
|
+
* switch the default's name plus the provider's display name (its plugin id when it has none),
|
|
6
|
+
* e.g. 「个人设备(Docker 沙箱)」 / "Personal (Docker sandbox)", with " 2", " 3", … after the
|
|
7
|
+
* first of the same provider. The web builds the same label from its own messages.
|
|
8
|
+
*/
|
|
9
|
+
export declare function deviceLabel(v: Pick<DeviceView, "name" | "demotedFrom">, locale: "zh" | "en"): string;
|
|
10
|
+
/** The words the default device answers to in `/device <name>` besides its label. */
|
|
11
|
+
export declare const DEFAULT_DEVICE_ALIASES: readonly string[];
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const PERSONAL = { zh: "
|
|
1
|
+
const PERSONAL = { zh: "个人设备", en: "Personal" };
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* own name, else
|
|
3
|
+
* A device's name for people outside the web (the IM `/device` list, the `Platform` tool): its
|
|
4
|
+
* own name, else 「个人设备」 / "Personal" for the default, else for a default demoted by a provider
|
|
5
5
|
* switch the default's name plus the provider's display name (its plugin id when it has none),
|
|
6
|
-
* e.g.
|
|
6
|
+
* e.g. 「个人设备(Docker 沙箱)」 / "Personal (Docker sandbox)", with " 2", " 3", … after the
|
|
7
7
|
* first of the same provider. The web builds the same label from its own messages.
|
|
8
8
|
*/
|
|
9
|
-
export function
|
|
9
|
+
export function deviceLabel(v, locale) {
|
|
10
10
|
if (v.name !== null)
|
|
11
11
|
return v.name;
|
|
12
12
|
const d = v.demotedFrom;
|
|
@@ -18,8 +18,8 @@ export function environmentLabel(v, locale) {
|
|
|
18
18
|
? `${PERSONAL.zh}(${provider})${nth}`
|
|
19
19
|
: `${PERSONAL.en} (${provider})${nth}`;
|
|
20
20
|
}
|
|
21
|
-
/** The words the default
|
|
22
|
-
export const
|
|
21
|
+
/** The words the default device answers to in `/device <name>` besides its label. */
|
|
22
|
+
export const DEFAULT_DEVICE_ALIASES = [
|
|
23
23
|
PERSONAL.zh.toLowerCase(),
|
|
24
24
|
PERSONAL.en.toLowerCase(),
|
|
25
25
|
];
|
|
@@ -3,15 +3,15 @@ import { KernelDb } from "../infra/database/kernel-db.js";
|
|
|
3
3
|
import { LockService } from "../infra/lock/lock.service.js";
|
|
4
4
|
import type { KernelLogger } from "../log.js";
|
|
5
5
|
import { SandboxProviders } from "../sandbox/providers.js";
|
|
6
|
-
/** The job's name (`@LockedInterval`, run lock `cron:
|
|
7
|
-
export declare const LEGACY_CLEANUP_JOB = "
|
|
6
|
+
/** The job's name (`@LockedInterval`, run lock `cron:devices-legacy-cleanup`). */
|
|
7
|
+
export declare const LEGACY_CLEANUP_JOB = "devices-legacy-cleanup";
|
|
8
8
|
/** What one run did: rows destroyed and deleted, rows kept because their provider is not loaded. */
|
|
9
9
|
export interface LegacyCleanupResult {
|
|
10
10
|
destroyed: number;
|
|
11
11
|
kept: number;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* The cleanup of the per-conversation sandboxes of before
|
|
14
|
+
* The cleanup of the per-conversation sandboxes of before devices (spec
|
|
15
15
|
* 2026-11-07-environments-design §4.2 item 9): for up to {@link BATCH} rows of the legacy
|
|
16
16
|
* `sandboxes` table per tick, the row's provider destroys the instance and the file system named
|
|
17
17
|
* `cap-<conversationId>` (`destroyByName`, `destroyFileSystemByName`; also the instance of the
|
|
@@ -14,8 +14,8 @@ import { LockService } from "../infra/lock/lock.service.js";
|
|
|
14
14
|
import { LockedInterval } from "../infra/schedule/locked-interval.js";
|
|
15
15
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
16
16
|
import { SandboxProviders } from "../sandbox/providers.js";
|
|
17
|
-
/** The job's name (`@LockedInterval`, run lock `cron:
|
|
18
|
-
export const LEGACY_CLEANUP_JOB = "
|
|
17
|
+
/** The job's name (`@LockedInterval`, run lock `cron:devices-legacy-cleanup`). */
|
|
18
|
+
export const LEGACY_CLEANUP_JOB = "devices-legacy-cleanup";
|
|
19
19
|
/** Every 5 minutes, once per tick across replicas. */
|
|
20
20
|
const PERIOD_MS = 5 * 60_000;
|
|
21
21
|
/** Rows handled per tick. */
|
|
@@ -23,7 +23,7 @@ const BATCH = 50;
|
|
|
23
23
|
/** The time limit of one provider call. */
|
|
24
24
|
const CALL_TIMEOUT_MS = 120_000;
|
|
25
25
|
/**
|
|
26
|
-
* The cleanup of the per-conversation sandboxes of before
|
|
26
|
+
* The cleanup of the per-conversation sandboxes of before devices (spec
|
|
27
27
|
* 2026-11-07-environments-design §4.2 item 9): for up to {@link BATCH} rows of the legacy
|
|
28
28
|
* `sandboxes` table per tick, the row's provider destroys the instance and the file system named
|
|
29
29
|
* `cap-<conversationId>` (`destroyByName`, `destroyFileSystemByName`; also the instance of the
|
package/dist/errors.d.ts
CHANGED
|
@@ -283,40 +283,40 @@ export declare const ERROR_CODES: {
|
|
|
283
283
|
readonly "attachment.too_many_pending": 429;
|
|
284
284
|
readonly "sandbox.unavailable": 503;
|
|
285
285
|
readonly "sandbox.busy": 409;
|
|
286
|
-
/** The
|
|
287
|
-
readonly "
|
|
288
|
-
/** The
|
|
289
|
-
readonly "
|
|
290
|
-
/** The caller may see the
|
|
291
|
-
readonly "
|
|
292
|
-
/** The
|
|
293
|
-
readonly "
|
|
294
|
-
/** The person already has a live
|
|
295
|
-
readonly "
|
|
296
|
-
/** The person already has `
|
|
297
|
-
readonly "
|
|
286
|
+
/** The device is missing, deleted, or not the caller's (never 403, so ids cannot be probed). */
|
|
287
|
+
readonly "device.not_found": 404;
|
|
288
|
+
/** The cloud device's file system is gone at the provider; reset its files to start empty. */
|
|
289
|
+
readonly "device.files_lost": 409;
|
|
290
|
+
/** The caller may see the device but not use it (shared devices, later phases). */
|
|
291
|
+
readonly "device.forbidden": 403;
|
|
292
|
+
/** The device's provider is not the deployment's current one, or there is none. */
|
|
293
|
+
readonly "device.unavailable": 503;
|
|
294
|
+
/** The person already has a live device with this name (case-insensitive). */
|
|
295
|
+
readonly "device.name_taken": 409;
|
|
296
|
+
/** The person already has `devices.maxPersonal` live personal devices. */
|
|
297
|
+
readonly "device.limit_reached": 409;
|
|
298
298
|
/**
|
|
299
|
-
* A
|
|
300
|
-
*
|
|
299
|
+
* A local device's files are on its machine: they cannot be reset from the platform; run
|
|
300
|
+
* `capybara-device logout`, then `capybara-device login` into the device, on the machine
|
|
301
301
|
* (ruling R24).
|
|
302
302
|
*/
|
|
303
|
-
readonly "
|
|
304
|
-
/** The
|
|
305
|
-
readonly "
|
|
306
|
-
/** The
|
|
307
|
-
readonly "
|
|
303
|
+
readonly "device.files_on_device": 409;
|
|
304
|
+
/** The local device's machine is not connected now (no replica holds its lease). */
|
|
305
|
+
readonly "device.offline": 503;
|
|
306
|
+
/** The local device's machine runs a `capybara-device` too old for this kernel; update it. */
|
|
307
|
+
readonly "device.program_outdated": 426;
|
|
308
308
|
/** Device sign-in (RFC 8628 style): the person has not approved the code yet; keep polling. */
|
|
309
|
-
readonly "
|
|
309
|
+
readonly "device_sign_in.authorization_pending": 400;
|
|
310
310
|
/** Device sign-in: the program polls faster than the interval; add 5 seconds and keep polling. */
|
|
311
|
-
readonly "
|
|
311
|
+
readonly "device_sign_in.slow_down": 400;
|
|
312
312
|
/** Device sign-in: the code expired before it was approved; start over. */
|
|
313
|
-
readonly "
|
|
313
|
+
readonly "device_sign_in.expired": 400;
|
|
314
314
|
/** Device sign-in: the person denied the code. */
|
|
315
|
-
readonly "
|
|
315
|
+
readonly "device_sign_in.denied": 400;
|
|
316
316
|
/** Device sign-in: no pending code matches the one given. */
|
|
317
|
-
readonly "
|
|
317
|
+
readonly "device_sign_in.code_invalid": 404;
|
|
318
318
|
/** Device sign-in: the confirmation could not hand the credential to the program; start over. */
|
|
319
|
-
readonly "
|
|
319
|
+
readonly "device_sign_in.unavailable": 503;
|
|
320
320
|
/** The machine credential is unknown or revoked. */
|
|
321
321
|
readonly "device.credential_invalid": 401;
|
|
322
322
|
readonly "skill.not_found": 404;
|
package/dist/errors.js
CHANGED
|
@@ -283,40 +283,40 @@ export const ERROR_CODES = {
|
|
|
283
283
|
"attachment.too_many_pending": 429,
|
|
284
284
|
"sandbox.unavailable": 503,
|
|
285
285
|
"sandbox.busy": 409,
|
|
286
|
-
/** The
|
|
287
|
-
"
|
|
288
|
-
/** The
|
|
289
|
-
"
|
|
290
|
-
/** The caller may see the
|
|
291
|
-
"
|
|
292
|
-
/** The
|
|
293
|
-
"
|
|
294
|
-
/** The person already has a live
|
|
295
|
-
"
|
|
296
|
-
/** The person already has `
|
|
297
|
-
"
|
|
286
|
+
/** The device is missing, deleted, or not the caller's (never 403, so ids cannot be probed). */
|
|
287
|
+
"device.not_found": 404,
|
|
288
|
+
/** The cloud device's file system is gone at the provider; reset its files to start empty. */
|
|
289
|
+
"device.files_lost": 409,
|
|
290
|
+
/** The caller may see the device but not use it (shared devices, later phases). */
|
|
291
|
+
"device.forbidden": 403,
|
|
292
|
+
/** The device's provider is not the deployment's current one, or there is none. */
|
|
293
|
+
"device.unavailable": 503,
|
|
294
|
+
/** The person already has a live device with this name (case-insensitive). */
|
|
295
|
+
"device.name_taken": 409,
|
|
296
|
+
/** The person already has `devices.maxPersonal` live personal devices. */
|
|
297
|
+
"device.limit_reached": 409,
|
|
298
298
|
/**
|
|
299
|
-
* A
|
|
300
|
-
*
|
|
299
|
+
* A local device's files are on its machine: they cannot be reset from the platform; run
|
|
300
|
+
* `capybara-device logout`, then `capybara-device login` into the device, on the machine
|
|
301
301
|
* (ruling R24).
|
|
302
302
|
*/
|
|
303
|
-
"
|
|
304
|
-
/** The
|
|
305
|
-
"
|
|
306
|
-
/** The
|
|
307
|
-
"
|
|
303
|
+
"device.files_on_device": 409,
|
|
304
|
+
/** The local device's machine is not connected now (no replica holds its lease). */
|
|
305
|
+
"device.offline": 503,
|
|
306
|
+
/** The local device's machine runs a `capybara-device` too old for this kernel; update it. */
|
|
307
|
+
"device.program_outdated": 426,
|
|
308
308
|
/** Device sign-in (RFC 8628 style): the person has not approved the code yet; keep polling. */
|
|
309
|
-
"
|
|
309
|
+
"device_sign_in.authorization_pending": 400,
|
|
310
310
|
/** Device sign-in: the program polls faster than the interval; add 5 seconds and keep polling. */
|
|
311
|
-
"
|
|
311
|
+
"device_sign_in.slow_down": 400,
|
|
312
312
|
/** Device sign-in: the code expired before it was approved; start over. */
|
|
313
|
-
"
|
|
313
|
+
"device_sign_in.expired": 400,
|
|
314
314
|
/** Device sign-in: the person denied the code. */
|
|
315
|
-
"
|
|
315
|
+
"device_sign_in.denied": 400,
|
|
316
316
|
/** Device sign-in: no pending code matches the one given. */
|
|
317
|
-
"
|
|
317
|
+
"device_sign_in.code_invalid": 404,
|
|
318
318
|
/** Device sign-in: the confirmation could not hand the credential to the program; start over. */
|
|
319
|
-
"
|
|
319
|
+
"device_sign_in.unavailable": 503,
|
|
320
320
|
/** The machine credential is unknown or revoked. */
|
|
321
321
|
"device.credential_invalid": 401,
|
|
322
322
|
"skill.not_found": 404,
|
|
@@ -25,13 +25,13 @@ export interface RecordedCall {
|
|
|
25
25
|
/** The recorded call used release-candidate names; `toolKey` and `inputKey` are already the current ones. */
|
|
26
26
|
legacy?: true;
|
|
27
27
|
/**
|
|
28
|
-
* The roots of the latest `
|
|
28
|
+
* The roots of the latest `device_paths` event the original run had logged by this call's
|
|
29
29
|
* step (environments spec §13.1, ruling R22): set on every recorded call from the step where an
|
|
30
30
|
* event was logged onward. A replay that matches the call writes the event when the eval
|
|
31
31
|
* conversation's latest one differs, so a candidate whose first sandbox call lands in another
|
|
32
32
|
* step still gets the line, once.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
devicePaths?: SandboxRoots;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* The connectors and extensions an rc `<x>__<tool>` key can name, from positive evidence in the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { devicePathsChange } from "../runtime/context/device-paths.js";
|
|
2
2
|
import { assistantIdemKey } from "../runtime/model-call.js";
|
|
3
3
|
import { MATCH_IGNORED_FIELDS } from "../tools/builtin-names.js";
|
|
4
4
|
import { isLegacyPrefixedKey, legacyToolInput, legacyToolKey, } from "../tools/legacy-keys.js";
|
|
@@ -138,7 +138,7 @@ export function recordedCalls(s) {
|
|
|
138
138
|
started.set(p.callId, p.specHash);
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
-
//
|
|
141
|
+
// a device_paths event belongs to the step of the assistant message before it, and holds
|
|
142
142
|
// for that step's calls and every later step's (until the next one)
|
|
143
143
|
const pathsOf = new Map();
|
|
144
144
|
const assistants = own.filter((e) => e.type === "assistant_message").map((e) => e.seq);
|
|
@@ -148,7 +148,7 @@ export function recordedCalls(s) {
|
|
|
148
148
|
const end = assistants[i + 1] ?? Number.POSITIVE_INFINITY;
|
|
149
149
|
for (; next < own.length && own[next].seq < end; next++) {
|
|
150
150
|
const e = own[next];
|
|
151
|
-
if (e.type === "
|
|
151
|
+
if (e.type === "device_paths" && e.seq > a) {
|
|
152
152
|
current = e.payload.roots;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
@@ -179,7 +179,7 @@ export function recordedCalls(s) {
|
|
|
179
179
|
...(r.loadedTools !== undefined && { loadedTools: r.loadedTools }),
|
|
180
180
|
...(r.contentTypes !== undefined && { contentTypes: r.contentTypes }),
|
|
181
181
|
specHash: started.get(call.id) ?? "",
|
|
182
|
-
...(paths !== undefined && {
|
|
182
|
+
...(paths !== undefined && { devicePaths: paths }),
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
185
|
}
|
|
@@ -235,10 +235,10 @@ export class RecordedToolPipeline {
|
|
|
235
235
|
this.misses++;
|
|
236
236
|
// the original run had told the model the instance's directories by this call: so does the
|
|
237
237
|
// replay, when the eval conversation's latest record differs (as the sandbox tools write it)
|
|
238
|
-
const paths = rec?.
|
|
238
|
+
const paths = rec?.devicePaths;
|
|
239
239
|
const change = paths === undefined
|
|
240
240
|
? null
|
|
241
|
-
:
|
|
241
|
+
: devicePathsChange(await eventLog.latestOfType(ctx.conversationId, "device_paths"), paths, ctx.runId);
|
|
242
242
|
await eventLog.append(ctx.conversationId, [
|
|
243
243
|
...(change ? [change] : []),
|
|
244
244
|
{
|
|
@@ -519,6 +519,7 @@ function fallbackView(name, known, err) {
|
|
|
519
519
|
enabledOrgs: 0,
|
|
520
520
|
builtin: false,
|
|
521
521
|
installSource: null,
|
|
522
|
+
uiDropped: [],
|
|
522
523
|
error: `the change was saved, but its current status cannot be read: ${err instanceof Error ? err.message : String(err)}`,
|
|
523
524
|
};
|
|
524
525
|
}
|
|
@@ -440,6 +440,7 @@ let ExtensionAdmin = class ExtensionAdmin {
|
|
|
440
440
|
required: install?.required === true,
|
|
441
441
|
...scopeInfo,
|
|
442
442
|
installSource: install?.source ?? null,
|
|
443
|
+
uiDropped: this.host.uiDropped(s.name),
|
|
443
444
|
error: s.broken,
|
|
444
445
|
};
|
|
445
446
|
}
|
|
@@ -493,6 +494,7 @@ let ExtensionAdmin = class ExtensionAdmin {
|
|
|
493
494
|
required: install?.required === true,
|
|
494
495
|
...scopeInfo,
|
|
495
496
|
installSource: install?.source ?? null,
|
|
497
|
+
uiDropped: this.host.uiDropped(s.name),
|
|
496
498
|
};
|
|
497
499
|
});
|
|
498
500
|
}
|
|
@@ -92,6 +92,12 @@ export declare class EffectiveConfigs {
|
|
|
92
92
|
/** Secret values of a copy read here are masked in the logs. */
|
|
93
93
|
log: KernelLogger);
|
|
94
94
|
private get db();
|
|
95
|
+
/**
|
|
96
|
+
* The config of `plugin` for work done for the platform (a `platform.page` view, UI slots spec
|
|
97
|
+
* §7): the running instance's deployment config, no org copy applies; `notRunning` when the
|
|
98
|
+
* extension is not running on this replica.
|
|
99
|
+
*/
|
|
100
|
+
platform(plugin: string): EffectiveConfig;
|
|
95
101
|
/**
|
|
96
102
|
* The effective config of `plugin` for `orgId`. Following: the running platform config, `ok:
|
|
97
103
|
* false` when it leaves a required overridable field empty (the host loaded it with those
|
|
@@ -37,6 +37,11 @@ const OVERRIDE_KEY_PREFIX = "plugin-override:";
|
|
|
37
37
|
* distinct from the org-only `plugin-config:<plugin>:<path>` (spec A §5.8).
|
|
38
38
|
*/
|
|
39
39
|
export const overrideSecretKey = (plugin, path) => `${OVERRIDE_KEY_PREFIX}${plugin}:${path}`;
|
|
40
|
+
const notRunning = () => ({
|
|
41
|
+
ok: false,
|
|
42
|
+
notRunning: true,
|
|
43
|
+
issues: [{ path: "", segments: [], message: "the extension is not running" }],
|
|
44
|
+
});
|
|
40
45
|
/** The secret leaf paths of a deployment schema. */
|
|
41
46
|
export function secretLeafPaths(schema) {
|
|
42
47
|
return configFields(schema)
|
|
@@ -171,6 +176,17 @@ let EffectiveConfigs = class EffectiveConfigs {
|
|
|
171
176
|
get db() {
|
|
172
177
|
return this.kdb.db;
|
|
173
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* The config of `plugin` for work done for the platform (a `platform.page` view, UI slots spec
|
|
181
|
+
* §7): the running instance's deployment config, no org copy applies; `notRunning` when the
|
|
182
|
+
* extension is not running on this replica.
|
|
183
|
+
*/
|
|
184
|
+
platform(plugin) {
|
|
185
|
+
const inst = this.registry.current(plugin);
|
|
186
|
+
if (!inst)
|
|
187
|
+
return notRunning();
|
|
188
|
+
return { ok: true, config: inst.config, source: "platform" };
|
|
189
|
+
}
|
|
174
190
|
/**
|
|
175
191
|
* The effective config of `plugin` for `orgId`. Following: the running platform config, `ok:
|
|
176
192
|
* false` when it leaves a required overridable field empty (the host loaded it with those
|
|
@@ -180,13 +196,8 @@ let EffectiveConfigs = class EffectiveConfigs {
|
|
|
180
196
|
*/
|
|
181
197
|
async get(orgId, plugin) {
|
|
182
198
|
const inst = this.registry.current(plugin);
|
|
183
|
-
if (!inst)
|
|
184
|
-
return
|
|
185
|
-
ok: false,
|
|
186
|
-
notRunning: true,
|
|
187
|
-
issues: [{ path: "", segments: [], message: "the extension is not running" }],
|
|
188
|
-
};
|
|
189
|
-
}
|
|
199
|
+
if (!inst)
|
|
200
|
+
return notRunning();
|
|
190
201
|
const schema = inst.manifest.config?.deployment;
|
|
191
202
|
if (!schema)
|
|
192
203
|
return { ok: true, config: inst.config, source: "platform" };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ExtensionManifest, type ExtensionPointRef, type LocalizedName, type ToolHandler, type ToolSpec, type UiContribution } from "@capybara-hq/plugin-sdk";
|
|
1
|
+
import { type DroppedUiContribution, type ExtensionManifest, type ExtensionPointRef, type LocalizedName, type ToolHandler, type ToolSpec, type UiContribution, type UiSlotSpec } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import type { Redis } from "ioredis";
|
|
3
3
|
import type { core } from "zod";
|
|
4
4
|
import type { KernelAppOptions } from "../app.js";
|
|
@@ -24,10 +24,17 @@ import { type PermissionSet } from "./permission-set.js";
|
|
|
24
24
|
import { type ExtensionPointEntry, ExtensionRegistry } from "./registry.js";
|
|
25
25
|
import { type ExtensionSource, ReplicaStatusStore } from "./sources.js";
|
|
26
26
|
export { deploymentConfigHash };
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* One item of {@link ExtensionHost.uiContributions}: a UI contribution from the manifest whose slot
|
|
29
|
+
* resolved at load (dropped ones never appear), with its registered view / action (embeds have none).
|
|
30
|
+
*/
|
|
28
31
|
export interface LoadedUiContribution {
|
|
29
32
|
plugin: string;
|
|
30
33
|
contribution: UiContribution;
|
|
34
|
+
/** The catalog slot the contribution resolved to (from `slot`, or the deprecated `place`). */
|
|
35
|
+
slot: UiSlotSpec;
|
|
36
|
+
/** For a slot with anchors: the anchor it goes after (see `resolveUiSlots`). */
|
|
37
|
+
after?: string;
|
|
31
38
|
render?: UiRender;
|
|
32
39
|
action?: UiActionHandler;
|
|
33
40
|
}
|
|
@@ -494,6 +501,8 @@ export declare class ExtensionHost {
|
|
|
494
501
|
* 配置声明的插件启动时不设时限(见 {@link load})。
|
|
495
502
|
*/
|
|
496
503
|
private setup;
|
|
504
|
+
/** Logs once per load what slot resolution left out or flagged (UI slots spec §3.2). */
|
|
505
|
+
private logUiResolution;
|
|
497
506
|
/** 取能力实现:单选能力无需 providerName,多选能力必须指定。 */
|
|
498
507
|
get<T>(capability: ExtensionPointRef, providerName?: string): T;
|
|
499
508
|
/**
|
|
@@ -607,6 +616,8 @@ export declare class ExtensionHost {
|
|
|
607
616
|
* 是否在某组织启用由调用方另查(每次查询,不缓存)。
|
|
608
617
|
*/
|
|
609
618
|
uiContributions(): LoadedUiContribution[];
|
|
619
|
+
/** The UI contributions the loaded extension left out at load (UI slots spec §3.2); `[]` when not loaded. */
|
|
620
|
+
uiDropped(name: string): DroppedUiContribution[];
|
|
610
621
|
/** 串行执行生命周期操作(unload / reload 互不交错);宿主关闭后拒绝。 */
|
|
611
622
|
private serial;
|
|
612
623
|
/**
|
package/dist/extensions/host.js
CHANGED
|
@@ -1712,7 +1712,7 @@ let ExtensionHost = class ExtensionHost {
|
|
|
1712
1712
|
},
|
|
1713
1713
|
});
|
|
1714
1714
|
if (timeoutMs === undefined)
|
|
1715
|
-
return p;
|
|
1715
|
+
return p.then((inst) => this.logUiResolution(inst));
|
|
1716
1716
|
let timer;
|
|
1717
1717
|
let onClose = () => { };
|
|
1718
1718
|
const stop = new Promise((resolve) => {
|
|
@@ -1725,8 +1725,9 @@ let ExtensionHost = class ExtensionHost {
|
|
|
1725
1725
|
});
|
|
1726
1726
|
try {
|
|
1727
1727
|
const r = await Promise.race([p.then((inst) => ({ inst })), stop]);
|
|
1728
|
+
// a late instance that is disposed right away never logs its UI resolution
|
|
1728
1729
|
if (typeof r === "object")
|
|
1729
|
-
return r.inst;
|
|
1730
|
+
return this.logUiResolution(r.inst);
|
|
1730
1731
|
// setup 迟迟不返回:关闭它的 ctx(此后它的登记立即撤销),迟到完成的实例直接撤销
|
|
1731
1732
|
p.then((inst) => this.disposeQuietly(inst, 0), () => { });
|
|
1732
1733
|
if (this.settingUp === ctx)
|
|
@@ -1743,6 +1744,20 @@ let ExtensionHost = class ExtensionHost {
|
|
|
1743
1744
|
this.abort.signal.removeEventListener("abort", onClose);
|
|
1744
1745
|
}
|
|
1745
1746
|
}
|
|
1747
|
+
/** Logs once per load what slot resolution left out or flagged (UI slots spec §3.2). */
|
|
1748
|
+
logUiResolution(inst) {
|
|
1749
|
+
const at = { plugin: inst.name, version: inst.version };
|
|
1750
|
+
if (inst.uiDropped.length > 0) {
|
|
1751
|
+
this.log.warn("plugin ui contributions dropped", { ...at, dropped: inst.uiDropped });
|
|
1752
|
+
}
|
|
1753
|
+
if (inst.uiUnknownAnchors.length > 0) {
|
|
1754
|
+
this.log.warn("plugin ui anchors unknown", { ...at, anchors: inst.uiUnknownAnchors });
|
|
1755
|
+
}
|
|
1756
|
+
if (inst.uiDeprecatedPlace.length > 0) {
|
|
1757
|
+
this.log.info("plugin ui uses the deprecated place", { ...at, ids: inst.uiDeprecatedPlace });
|
|
1758
|
+
}
|
|
1759
|
+
return inst;
|
|
1760
|
+
}
|
|
1746
1761
|
/** 取能力实现:单选能力无需 providerName,多选能力必须指定。 */
|
|
1747
1762
|
get(capability, providerName) {
|
|
1748
1763
|
const providers = this.registry.all().filter((i) => i.provided.has(capability));
|
|
@@ -2087,17 +2102,23 @@ let ExtensionHost = class ExtensionHost {
|
|
|
2087
2102
|
* 是否在某组织启用由调用方另查(每次查询,不缓存)。
|
|
2088
2103
|
*/
|
|
2089
2104
|
uiContributions() {
|
|
2090
|
-
return this.registry.all().flatMap((i) =>
|
|
2105
|
+
return this.registry.all().flatMap((i) => i.ui.map(({ contribution: c, slot, after }) => {
|
|
2091
2106
|
const render = c.kind === "view" ? i.uiViews.get(c.id) : undefined;
|
|
2092
2107
|
const action = c.kind === "view" ? i.uiActions.get(c.id) : undefined;
|
|
2093
2108
|
return {
|
|
2094
2109
|
plugin: i.name,
|
|
2095
2110
|
contribution: c,
|
|
2111
|
+
slot,
|
|
2112
|
+
...(after !== undefined && { after }),
|
|
2096
2113
|
...(render !== undefined && { render }),
|
|
2097
2114
|
...(action !== undefined && { action }),
|
|
2098
2115
|
};
|
|
2099
2116
|
}));
|
|
2100
2117
|
}
|
|
2118
|
+
/** The UI contributions the loaded extension left out at load (UI slots spec §3.2); `[]` when not loaded. */
|
|
2119
|
+
uiDropped(name) {
|
|
2120
|
+
return [...(this.registry.current(name)?.uiDropped ?? [])];
|
|
2121
|
+
}
|
|
2101
2122
|
/** 串行执行生命周期操作(unload / reload 互不交错);宿主关闭后拒绝。 */
|
|
2102
2123
|
serial(fn) {
|
|
2103
2124
|
const guarded = () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ExtensionManifest, type ExtensionPointRef, type StaticExtensionManifest } from "@capybara-hq/plugin-sdk";
|
|
1
|
+
import { type DroppedUiContribution, type ExtensionManifest, type ExtensionPointRef, type ResolvedUiContribution, type StaticExtensionManifest } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import { type ExtensionPointAccess, type KernelDeps, type KernelExtensionContext, LiveConfig, type RegisteredTool, type Route } from "../ctx/create-ctx.js";
|
|
3
3
|
import type { UiActionHandler, UiRender } from "../ui/registry.js";
|
|
4
4
|
import type { RegisteredHook } from "./hooks.js";
|
|
@@ -44,6 +44,17 @@ export declare class ExtensionInstance {
|
|
|
44
44
|
readonly generation: number;
|
|
45
45
|
readonly manifest: ExtensionManifest;
|
|
46
46
|
readonly permissions: PermissionSet;
|
|
47
|
+
/** The manifest's UI contributions whose slot the catalog knows (UI slots spec §3.2), in manifest order. */
|
|
48
|
+
readonly ui: ResolvedUiContribution[];
|
|
49
|
+
/** The manifest's UI contributions left out at load (unknown slot or slot version). */
|
|
50
|
+
readonly uiDropped: DroppedUiContribution[];
|
|
51
|
+
/** `after` values that are not anchors of their slot (the contribution keeps the default position). */
|
|
52
|
+
readonly uiUnknownAnchors: {
|
|
53
|
+
id: string;
|
|
54
|
+
after: string;
|
|
55
|
+
}[];
|
|
56
|
+
/** Ids of contributions that still name the deprecated `place`. */
|
|
57
|
+
readonly uiDeprecatedPlace: string[];
|
|
47
58
|
private hash;
|
|
48
59
|
private readonly live;
|
|
49
60
|
readonly entryUrl: string;
|