@openchamber/sdk 1.23.2-preview.1 → 1.24.1
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/API.md +73 -27
- package/DOCUMENTATION.md +43 -4
- package/README.md +68 -5
- package/dist/contract.d.ts +36 -3
- package/dist/contract.js +1 -1
- package/dist/host.d.ts +7 -1
- package/dist/host.js +41 -8
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -0
- package/dist/manifest.d.ts +13 -8
- package/dist/manifest.js +2 -4
- package/dist/parse.d.ts +14 -0
- package/dist/parse.js +27 -8
- package/dist/protocol.d.ts +57 -1
- package/dist/protocol.js +24 -1
- package/dist/scrollbar-style.d.ts +2 -0
- package/dist/scrollbar-style.js +32 -0
- package/dist/ui/menu.js +5 -1
- package/dist/ui/select.js +5 -1
- package/dist/ui/style.js +33 -21
- package/dist/ui/theme.js +10 -0
- package/package.json +2 -2
package/dist/host.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OPENCHAMBER_SDK_API_VERSION, OPENCHAMBER_SDK_CHANNEL } from "./api-version.js";
|
|
2
2
|
import { GUEST_STORAGE_KEY_MAX, GUEST_STORAGE_VALUE_BYTES } from "./workspace.js";
|
|
3
|
-
import { GUEST_FILE_CONTENT_MAX, GUEST_FILE_PATH_MAX, GUEST_GENERATE_OUTPUT_TOKENS_MAX, GUEST_GENERATE_PROMPT_MAX, GUEST_GENERATE_SYSTEM_MAX, GUEST_GENERATE_TIMEOUT_MS, GUEST_REQUEST_TIMEOUT_MS, GUEST_RESOLVE_ERROR_MAX, isGuestFilePath, isGuestRequestPath, clampAttachRequest, clampBadgeCount, clampPromptRequest, clampStartSessionRequest, readHostMessage, isGenerateResult, isFileListResult, isFileReadResult, isFileStatResult, isJsonValue, isFileWriteResult, isServiceStatusResult, isGuestRequestResult, isPromptResult, isStartSessionResult, } from "./contract.js";
|
|
3
|
+
import { GUEST_FILE_CONTENT_MAX, GUEST_CLIPBOARD_TEXT_MAX, GUEST_TOAST_MAX, GUEST_FILE_PATH_MAX, GUEST_GENERATE_OUTPUT_TOKENS_MAX, GUEST_GENERATE_PROMPT_MAX, GUEST_GENERATE_SYSTEM_MAX, GUEST_GENERATE_TIMEOUT_MS, GUEST_REQUEST_TIMEOUT_MS, GUEST_RESOLVE_ERROR_MAX, isGuestFilePath, isGuestRequestPath, clampAttachRequest, clampBadgeCount, clampPromptRequest, clampStartSessionRequest, readHostMessage, isGenerateResult, isFileListResult, isFileReadResult, isFileStatResult, isJsonValue, isFileWriteResult, isServiceStatusResult, isGuestRequestResult, isPromptResult, isStartSessionResult, } from "./contract.js";
|
|
4
4
|
export class HostRequestError extends Error {
|
|
5
5
|
code;
|
|
6
6
|
constructor(code, message) {
|
|
@@ -32,6 +32,7 @@ export const connectHost = (options = {}) => {
|
|
|
32
32
|
const settingsListeners = new Set();
|
|
33
33
|
const itemListeners = new Set();
|
|
34
34
|
let resolveHandler = null;
|
|
35
|
+
let actionHandler = null;
|
|
35
36
|
const pending = new Map();
|
|
36
37
|
const workspaceListeners = new Map();
|
|
37
38
|
let disposed = false;
|
|
@@ -135,6 +136,23 @@ export const connectHost = (options = {}) => {
|
|
|
135
136
|
emit(itemListeners, message.payload.item);
|
|
136
137
|
return;
|
|
137
138
|
}
|
|
139
|
+
if (message.type === 'action') {
|
|
140
|
+
const answer = (payload) => {
|
|
141
|
+
if (!disposed)
|
|
142
|
+
post({ channel: OPENCHAMBER_SDK_CHANNEL, v: OPENCHAMBER_SDK_API_VERSION,
|
|
143
|
+
type: 'action-result', id: message.id, payload });
|
|
144
|
+
};
|
|
145
|
+
const handler = actionHandler;
|
|
146
|
+
if (!handler) {
|
|
147
|
+
answer({ ok: false, error: 'This extension does not handle background actions.' });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
Promise.resolve().then(() => handler(message.payload)).then(() => answer({ ok: true }), (error) => {
|
|
151
|
+
const text = (error instanceof Error ? error.message : String(error)).trim();
|
|
152
|
+
answer({ ok: false, error: (text || 'Action failed.').slice(0, GUEST_RESOLVE_ERROR_MAX) });
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
138
156
|
if (message.type === 'resolve') {
|
|
139
157
|
const answer = (payload) => {
|
|
140
158
|
post({
|
|
@@ -239,6 +257,11 @@ export const connectHost = (options = {}) => {
|
|
|
239
257
|
return result;
|
|
240
258
|
};
|
|
241
259
|
return {
|
|
260
|
+
onAction: (handler) => {
|
|
261
|
+
actionHandler = handler;
|
|
262
|
+
return () => { if (actionHandler === handler)
|
|
263
|
+
actionHandler = null; };
|
|
264
|
+
},
|
|
242
265
|
listProjects: async () => {
|
|
243
266
|
const result = await readWorkspace({ kind: 'projects' });
|
|
244
267
|
if (result.kind !== 'projects')
|
|
@@ -344,13 +367,22 @@ export const connectHost = (options = {}) => {
|
|
|
344
367
|
resolveHandler = null;
|
|
345
368
|
};
|
|
346
369
|
},
|
|
347
|
-
toast: (payload) =>
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
payload
|
|
353
|
-
|
|
370
|
+
toast: (payload) => {
|
|
371
|
+
const message = payload.message.trim();
|
|
372
|
+
if (!message || message.length > GUEST_TOAST_MAX) {
|
|
373
|
+
return Promise.reject(new HostRequestError('HOST_REJECTED', `Toast message must contain 1 to ${GUEST_TOAST_MAX} characters.`));
|
|
374
|
+
}
|
|
375
|
+
if (payload.copy && payload.copy !== true && (!payload.copy.text.length || payload.copy.text.length > GUEST_CLIPBOARD_TEXT_MAX)) {
|
|
376
|
+
return Promise.reject(new HostRequestError('HOST_REJECTED', `Toast copy text must contain 1 to ${GUEST_CLIPBOARD_TEXT_MAX} characters.`));
|
|
377
|
+
}
|
|
378
|
+
return request({
|
|
379
|
+
channel: OPENCHAMBER_SDK_CHANNEL,
|
|
380
|
+
v: OPENCHAMBER_SDK_API_VERSION,
|
|
381
|
+
type: 'toast',
|
|
382
|
+
id: nextId(ids),
|
|
383
|
+
payload: { ...payload, message },
|
|
384
|
+
});
|
|
385
|
+
},
|
|
354
386
|
openUrl: (url) => request({
|
|
355
387
|
channel: OPENCHAMBER_SDK_CHANNEL,
|
|
356
388
|
v: OPENCHAMBER_SDK_API_VERSION,
|
|
@@ -588,6 +620,7 @@ export const connectHost = (options = {}) => {
|
|
|
588
620
|
workspaceListeners.clear();
|
|
589
621
|
disposed = true;
|
|
590
622
|
resolveHandler = null;
|
|
623
|
+
actionHandler = null;
|
|
591
624
|
target.removeEventListener('message', onMessage);
|
|
592
625
|
for (const waiter of pending.values()) {
|
|
593
626
|
clearTimeout(waiter.timer);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export { OPENCHAMBER_SDK_API_VERSION, OPENCHAMBER_SDK_CHANNEL, OPENCHAMBER_SDK_MANIFEST_API_VERSIONS } from './api-version.ts';
|
|
2
|
+
export { GUEST_SCROLLBAR_CSS } from './scrollbar-style.ts';
|
|
2
3
|
export type { GuestLoadState, GuestProject, GuestWorktree, GuestSessionActivity, GuestSessionRecord, GuestDirectoryCoverage, GuestProjectsSnapshot, GuestWorktreesSnapshot, GuestSessionsSnapshot, GuestWorkspaceSnapshot, GuestWorkspaceQuery, GuestWorkspaceSubscription, GuestWorkspaceUpdate, GuestStorageRequest, GuestStorageResult, GuestSessionWorktree } from './workspace.ts';
|
|
3
4
|
export { GUEST_STORAGE_KEY_MAX, GUEST_STORAGE_KEYS_MAX, GUEST_STORAGE_VALUE_BYTES, GUEST_STORAGE_TOTAL_BYTES } from './workspace.ts';
|
|
4
5
|
export type { OpenChamberManifestApiVersion } from './api-version.ts';
|
|
5
6
|
export { compareOpenChamberVersions, hostMeetsOpenChamberEngine, openChamberEngineMinimum, OPENCHAMBER_ENGINE_PATTERN, parseOpenChamberVersion, } from './host-version.ts';
|
|
6
7
|
export { DECLARED_GUEST_CAPABILITIES, GUEST_ACTIONS_MAX, GUEST_ACTION_LABEL_MAX, GUEST_CAPABILITIES, GUEST_COMMANDS_MAX, GUEST_COMMAND_DESCRIPTION_MAX, GUEST_COMMAND_NAME, GUEST_TOOLS_MAX, GUEST_TOOL_COLUMNS_MAX, GUEST_TOOL_COLUMN_MAX, GUEST_TOOL_LANGUAGE_MAX, GUEST_TOOL_MATCH, GUEST_TOOL_MATCH_MAX, GUEST_TOOL_NAME_MAX, GUEST_TOOL_OUTPUTS, GUEST_TOOL_TEMPLATE_MAX, GUEST_TOOL_TEMPLATE_VALUE_MAX, guestActionsNeedConversation, GUEST_FILESYSTEM_PATTERN_MAX, GUEST_FILESYSTEM_PATTERNS_MAX, HOST_LINEAR_API_ORIGIN, isGuestFilesystemPattern, hasGuestCapability, hasGuestPage, isGuestApproved, isGuestPackageSvgIcon, requestedGuestCapabilities, resolveAttachEntry, resolvePageEntry, resolveAttachMode, resolveIntegrationApi, resolveIntegrationAuth, toPublicService, toPublicIntegration, } from './manifest.ts';
|
|
7
|
-
export type { ServiceContribution, ServicePermissions, GuestActionContribution, GuestActionPayload, GuestActionRole, GuestActionWhere, GuestCommandContribution, GuestToolContribution, GuestToolOutput, AttachContribution, AttachContributionObject, AttachMode, DeclaredGuestCapability, GuestAuthorization, GuestCapability, IntegrationAuth, IntegrationContribution, IntegrationHost, IntegrationHostProvider, IntegrationOAuth, IntegrationOAuthAccount, IntegrationSettingField, IntegrationToken, IntegrationTokenScheme, OpenChamberContributes, OpenChamberEngines, OpenChamberManifest, PanelContribution, PageContribution, ParseManifestErrorCode, ParseManifestFailure, ParseManifestResult, ParseManifestSuccess, PublicService, PublicServicePermissions, PublicGuestCapabilities, PublicIntegration, PublicIntegrationToken, PublicSocketBinding, ResolvedGuestApi, SocketBinding, SocketPlatform, } from './manifest.ts';
|
|
8
|
+
export type { ServiceContribution, ServicePermissions, GuestActionContribution, GuestActionPayload, GuestActionRole, GuestActionWhere, GuestCommandContribution, GuestToolContribution, GuestToolOutput, AttachContribution, AttachContributionObject, AttachMode, DeclaredGuestCapability, GuestAuthorization, GuestCapability, IntegrationAuth, IntegrationContribution, IntegrationHost, IntegrationHostProvider, IntegrationOAuth, IntegrationOAuthAccount, IntegrationSettingField, IntegrationToken, IntegrationTokenScheme, OpenChamberContributes, OpenChamberEngines, OpenChamberManifest, PanelContribution, BackgroundContribution, PageContribution, ParseManifestErrorCode, ParseManifestFailure, ParseManifestResult, ParseManifestSuccess, PublicService, PublicServicePermissions, PublicGuestCapabilities, PublicIntegration, PublicIntegrationToken, PublicSocketBinding, ResolvedGuestApi, SocketBinding, SocketPlatform, } from './manifest.ts';
|
|
8
9
|
export { connectHost, HostRequestError } from './host.ts';
|
|
9
10
|
export type { HostClient, HostClientOptions, HostFrame } from './host.ts';
|
|
10
11
|
export { clampAttachRequest, clampBadgeCount, clampPromptRequest, clampStartSessionRequest, guestFileScope, isAttachData, isJsonValue, isFileListResult, isFileReadResult, isFileStatResult, isGenerateResult, isFileWriteResult, isGuestFilePath, isGuestAttachItem, isGuestMessageItem, isGuestSessionItem, isServiceStatusResult, isGuestRequestPath, isGuestRequestResult, isHostRequestErrorCode, isPromptResult, isStartSessionResult, readHostMessage, resolveHostRequestErrorCode, } from './contract.ts';
|
|
11
|
-
export type { BadgeRequest, GuestBadgeMessage, GuestItem, GuestItemRole, GuestMessageItem, GuestResolveResultMessage, GuestSessionItem, GuestSessionItemMessage, HostResolveMessage, ResolveRequest, ResolveResultPayload, FileListEntry, FileListRequest, FileListResult, FileReadRequest, FileReadResult, FileStatRequest, FileStatResult, FileWriteRequest, FileWriteResult, GenerateRequest, GenerateResult, GuestFileEntryKind, GuestFileListMessage, GuestFileReadMessage, GuestFileScope, GuestFileStatKind, GuestFileStatMessage, GuestGenerateMessage, GuestFileWriteMessage, ServiceStatus, ServiceStatusResult, HostRequestErrorCode, AttachBranches, AttachIssueRequest, AttachThreadKind, JsonValue, HostResultPayload, PromptRequest, PromptResult, SessionLifecycleEvent, SessionLifecyclePhase, StartSessionRequest, StartSessionResult, StartSessionSent, ComposeRequest, GuestServiceRequestMessage, GuestServiceStatusMessage, GuestAttachMessage, GuestClipboardWriteMessage, GuestCloseMessage, GuestComposeMessage, GuestConnection, GuestHelloMessage, GuestMessage, GuestOauthDisconnectMessage, GuestOauthStartMessage, GuestOpenSurfaceMessage, GuestOpenUrlMessage, GuestRequest, GuestRequestMessage, GuestRequestMethod, GuestPromptMessage, GuestSessionLinkMessage, GuestStartSessionMessage, GuestRequestResult, GuestSettings, GuestToastMessage, GuestHostSurface, HostConnectionMessage, HostDirectoryMessage, HostItemMessage, HostMessage, HostReadyContext, HostReadyMessage, HostResultMessage, HostSessionLifecycleMessage, HostSessionMessage, HostSettingsMessage, HostTheme, HostThemeMode, HostThemeTokens, SessionSnapshot, ToastKind, ToastRequest, } from './contract.ts';
|
|
12
|
+
export type { BadgeRequest, ActionResultPayload, GuestActionItem, GuestActionResultMessage, HostActionMessage, GuestBadgeMessage, GuestItem, GuestItemRole, GuestMessageItem, GuestResolveResultMessage, GuestSessionItem, GuestSessionItemMessage, HostResolveMessage, ResolveRequest, ResolveResultPayload, FileListEntry, FileListRequest, FileListResult, FileReadRequest, FileReadResult, FileStatRequest, FileStatResult, FileWriteRequest, FileWriteResult, GenerateRequest, GenerateResult, GuestFileEntryKind, GuestFileListMessage, GuestFileReadMessage, GuestFileScope, GuestFileStatKind, GuestFileStatMessage, GuestGenerateMessage, GuestFileWriteMessage, ServiceStatus, ServiceStatusResult, HostRequestErrorCode, AttachBranches, AttachIssueRequest, AttachThreadKind, JsonValue, HostResultPayload, PromptRequest, PromptResult, SessionLifecycleEvent, SessionLifecyclePhase, StartSessionRequest, StartSessionResult, StartSessionSent, ComposeRequest, GuestServiceRequestMessage, GuestServiceStatusMessage, GuestAttachMessage, GuestClipboardWriteMessage, GuestCloseMessage, GuestComposeMessage, GuestConnection, GuestHelloMessage, GuestMessage, GuestOauthDisconnectMessage, GuestOauthStartMessage, GuestOpenSurfaceMessage, GuestOpenUrlMessage, GuestRequest, GuestRequestMessage, GuestRequestMethod, GuestPromptMessage, GuestSessionLinkMessage, GuestStartSessionMessage, GuestRequestResult, GuestSettings, GuestToastMessage, GuestHostSurface, HostConnectionMessage, HostDirectoryMessage, HostItemMessage, HostMessage, HostReadyContext, HostReadyMessage, HostResultMessage, HostSessionLifecycleMessage, HostSessionMessage, HostSettingsMessage, HostTheme, HostThemeMode, HostThemeTokens, SessionSnapshot, ToastKind, ToastRequest, } from './contract.ts';
|
|
12
13
|
export { EMPTY_GUEST_CONNECTION, GUEST_BADGE_MAX, GUEST_ITEM_MESSAGE_TEXT_MAX, GUEST_ITEM_SESSION_MAX, GUEST_RESOLVE_ERROR_MAX, GUEST_FILE_CONTENT_MAX, GUEST_FILE_ENTRY_KINDS, GUEST_FILE_LIST_MAX, GUEST_FILE_PATH_MAX, GUEST_GENERATE_OUTPUT_TOKENS_MAX, GUEST_GENERATE_PROMPT_MAX, GUEST_GENERATE_SYSTEM_MAX, GUEST_GENERATE_TEXT_MAX, GUEST_GENERATE_TIMEOUT_MS, GUEST_FILE_STAT_KINDS, SERVICE_STATUS_VALUES, HOST_REQUEST_ERROR_CODES, SESSION_LIFECYCLE_PHASES, START_SESSION_SENT, GUEST_ACCOUNT_MAX, GUEST_SESSION_AGENT_MAX, GUEST_SESSION_MODEL_MAX, GUEST_ATTACH_AUTHOR_MAX, GUEST_ATTACH_BRANCH_MAX, GUEST_ATTACH_DATA_MAX, GUEST_ATTACH_ID_MAX, GUEST_ATTACH_TEXT_MAX, GUEST_ATTACH_TITLE_MAX, GUEST_ATTACH_URL_MAX, GUEST_CLIPBOARD_TEXT_MAX, GUEST_TOAST_MAX, GUEST_COMPOSE_TEXT_MAX, GUEST_REQUEST_BODY_MAX, GUEST_REQUEST_PATH_MAX, GUEST_REQUEST_RESPONSE_MAX, GUEST_REQUEST_TIMEOUT_MS, GUEST_SETTING_VALUE_MAX, } from './contract.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { OPENCHAMBER_SDK_API_VERSION, OPENCHAMBER_SDK_CHANNEL, OPENCHAMBER_SDK_MANIFEST_API_VERSIONS } from "./api-version.js";
|
|
2
|
+
export { GUEST_SCROLLBAR_CSS } from "./scrollbar-style.js";
|
|
2
3
|
export { GUEST_STORAGE_KEY_MAX, GUEST_STORAGE_KEYS_MAX, GUEST_STORAGE_VALUE_BYTES, GUEST_STORAGE_TOTAL_BYTES } from "./workspace.js";
|
|
3
4
|
export { compareOpenChamberVersions, hostMeetsOpenChamberEngine, openChamberEngineMinimum, OPENCHAMBER_ENGINE_PATTERN, parseOpenChamberVersion, } from "./host-version.js";
|
|
4
5
|
export { DECLARED_GUEST_CAPABILITIES, GUEST_ACTIONS_MAX, GUEST_ACTION_LABEL_MAX, GUEST_CAPABILITIES, GUEST_COMMANDS_MAX, GUEST_COMMAND_DESCRIPTION_MAX, GUEST_COMMAND_NAME, GUEST_TOOLS_MAX, GUEST_TOOL_COLUMNS_MAX, GUEST_TOOL_COLUMN_MAX, GUEST_TOOL_LANGUAGE_MAX, GUEST_TOOL_MATCH, GUEST_TOOL_MATCH_MAX, GUEST_TOOL_NAME_MAX, GUEST_TOOL_OUTPUTS, GUEST_TOOL_TEMPLATE_MAX, GUEST_TOOL_TEMPLATE_VALUE_MAX, guestActionsNeedConversation, GUEST_FILESYSTEM_PATTERN_MAX, GUEST_FILESYSTEM_PATTERNS_MAX, HOST_LINEAR_API_ORIGIN, isGuestFilesystemPattern, hasGuestCapability, hasGuestPage, isGuestApproved, isGuestPackageSvgIcon, requestedGuestCapabilities, resolveAttachEntry, resolvePageEntry, resolveAttachMode, resolveIntegrationApi, resolveIntegrationAuth, toPublicService, toPublicIntegration, } from "./manifest.js";
|
package/dist/manifest.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { OpenChamberManifestApiVersion } from './api-version.ts';
|
|
|
2
2
|
export declare const PANEL_ID: RegExp;
|
|
3
3
|
/**
|
|
4
4
|
* The extension's identity on the rail, the Extensions card, and the approval
|
|
5
|
-
* dialog. `entry` is the panel page
|
|
6
|
-
*
|
|
5
|
+
* dialog. `entry` is the optional visible panel page. Code can instead run
|
|
6
|
+
* from `background.entry` without adding a rail icon.
|
|
7
7
|
*/
|
|
8
8
|
export type PanelContribution = {
|
|
9
9
|
id: string;
|
|
@@ -11,6 +11,10 @@ export type PanelContribution = {
|
|
|
11
11
|
icon: string;
|
|
12
12
|
entry?: string;
|
|
13
13
|
};
|
|
14
|
+
/** Sandboxed HTML loaded on demand for background actions and slash commands. */
|
|
15
|
+
export type BackgroundContribution = {
|
|
16
|
+
entry: string;
|
|
17
|
+
};
|
|
14
18
|
export type AttachMode = 'panel' | 'dialog';
|
|
15
19
|
/**
|
|
16
20
|
* Object form of `contributes.attach`. `entry` is an HTML page inside the
|
|
@@ -42,7 +46,7 @@ export declare const GUEST_COMMAND_DESCRIPTION_MAX = 80;
|
|
|
42
46
|
/** A slash command name: lower-case, digits and dashes, up to 24 characters. */
|
|
43
47
|
export declare const GUEST_COMMAND_NAME: RegExp;
|
|
44
48
|
/**
|
|
45
|
-
* A menu entry on a message or a session.
|
|
49
|
+
* A menu entry on a message or a session. By default it opens the guest with
|
|
46
50
|
* the message or session as `ready.item`. `roles` narrows a message action
|
|
47
51
|
* to user or assistant messages (default both); `payload: ["messages"]` on
|
|
48
52
|
* a session action asks for the conversation and needs the `conversation`
|
|
@@ -54,6 +58,8 @@ export type GuestActionContribution = {
|
|
|
54
58
|
/** Remixicon name or package `.svg` path, same as `panel.icon`. Falls back to the panel icon. */
|
|
55
59
|
icon?: string;
|
|
56
60
|
where: GuestActionWhere;
|
|
61
|
+
/** `background` calls `host.onAction` in a temporary hidden frame. Default: `open`. */
|
|
62
|
+
mode?: 'open' | 'background';
|
|
57
63
|
roles?: GuestActionRole[];
|
|
58
64
|
payload?: GuestActionPayload[];
|
|
59
65
|
};
|
|
@@ -231,6 +237,7 @@ export declare const GUEST_FILESYSTEM_PATTERN_MAX = 256;
|
|
|
231
237
|
export declare const isGuestFilesystemPattern: (value: string) => boolean;
|
|
232
238
|
export type OpenChamberContributes = {
|
|
233
239
|
panel: PanelContribution;
|
|
240
|
+
background?: BackgroundContribution;
|
|
234
241
|
attach?: AttachContribution;
|
|
235
242
|
page?: PageContribution;
|
|
236
243
|
capabilities?: DeclaredGuestCapability[];
|
|
@@ -254,10 +261,8 @@ export type PublicGuestCapabilities = {
|
|
|
254
261
|
};
|
|
255
262
|
export declare const requestedGuestCapabilities: (contributes: Pick<OpenChamberContributes, "capabilities" | "integration" | "service" | "filesystem" | "actions">) => GuestCapability[];
|
|
256
263
|
/**
|
|
257
|
-
* Whether the package ships a panel
|
|
258
|
-
*
|
|
259
|
-
* command, service, integration, or capability; parse refuses those without
|
|
260
|
-
* an entry. `tools` is the only contribution it may carry.
|
|
264
|
+
* Whether the package ships a visible panel. Background-only extensions can
|
|
265
|
+
* execute code but have no rail surface, attach picker, or full-screen page.
|
|
261
266
|
*/
|
|
262
267
|
export declare const hasGuestPage: (contributes: Pick<OpenChamberContributes, "panel">) => boolean;
|
|
263
268
|
export declare const isGuestApproved: (capabilities: PublicGuestCapabilities) => boolean;
|
|
@@ -277,7 +282,7 @@ export type OpenChamberManifest = {
|
|
|
277
282
|
engines?: OpenChamberEngines;
|
|
278
283
|
contributes: OpenChamberContributes;
|
|
279
284
|
};
|
|
280
|
-
export type ParseManifestErrorCode = 'not-object' | 'missing-openchamber' | 'unsupported-api-version' | 'invalid-engines' | 'invalid-version' | 'missing-panel' | 'invalid-panel' | 'invalid-panel-id' | 'invalid-panel-name' | 'invalid-panel-icon' | 'invalid-panel-entry' | 'invalid-attach' | 'invalid-page' | 'invalid-capabilities' | 'invalid-integration' | 'invalid-service' | 'invalid-filesystem' | 'invalid-actions' | 'invalid-commands' | 'invalid-tools';
|
|
285
|
+
export type ParseManifestErrorCode = 'not-object' | 'missing-openchamber' | 'unsupported-api-version' | 'invalid-engines' | 'invalid-version' | 'missing-panel' | 'invalid-panel' | 'invalid-panel-id' | 'invalid-panel-name' | 'invalid-panel-icon' | 'invalid-panel-entry' | 'invalid-background' | 'invalid-attach' | 'invalid-page' | 'invalid-capabilities' | 'invalid-integration' | 'invalid-service' | 'invalid-filesystem' | 'invalid-actions' | 'invalid-commands' | 'invalid-tools';
|
|
281
286
|
export type ParseManifestFailure = {
|
|
282
287
|
ok: false;
|
|
283
288
|
code: ParseManifestErrorCode;
|
package/dist/manifest.js
CHANGED
|
@@ -119,10 +119,8 @@ export const requestedGuestCapabilities = (contributes) => {
|
|
|
119
119
|
return GUEST_CAPABILITIES.filter((capability) => declared.has(capability));
|
|
120
120
|
};
|
|
121
121
|
/**
|
|
122
|
-
* Whether the package ships a panel
|
|
123
|
-
*
|
|
124
|
-
* command, service, integration, or capability; parse refuses those without
|
|
125
|
-
* an entry. `tools` is the only contribution it may carry.
|
|
122
|
+
* Whether the package ships a visible panel. Background-only extensions can
|
|
123
|
+
* execute code but have no rail surface, attach picker, or full-screen page.
|
|
126
124
|
*/
|
|
127
125
|
export const hasGuestPage = (contributes) => Boolean(contributes.panel.entry);
|
|
128
126
|
export const isGuestApproved = (capabilities) => (capabilities.requested.every((capability) => capabilities.granted.includes(capability)));
|
package/dist/parse.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export declare const openChamberManifestSchema: z.ZodObject<{
|
|
|
12
12
|
icon: z.ZodString;
|
|
13
13
|
entry: z.ZodOptional<z.ZodString>;
|
|
14
14
|
}, z.core.$strip>;
|
|
15
|
+
background: z.ZodOptional<z.ZodObject<{
|
|
16
|
+
entry: z.ZodString;
|
|
17
|
+
}, z.core.$strip>>;
|
|
15
18
|
attach: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
|
|
16
19
|
panel: "panel";
|
|
17
20
|
dialog: "dialog";
|
|
@@ -104,6 +107,10 @@ export declare const openChamberManifestSchema: z.ZodObject<{
|
|
|
104
107
|
message: "message";
|
|
105
108
|
session: "session";
|
|
106
109
|
}>;
|
|
110
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
111
|
+
background: "background";
|
|
112
|
+
open: "open";
|
|
113
|
+
}>>;
|
|
107
114
|
roles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
108
115
|
user: "user";
|
|
109
116
|
assistant: "assistant";
|
|
@@ -150,6 +157,9 @@ export declare const packageManifestSchema: z.ZodObject<{
|
|
|
150
157
|
icon: z.ZodString;
|
|
151
158
|
entry: z.ZodOptional<z.ZodString>;
|
|
152
159
|
}, z.core.$strip>;
|
|
160
|
+
background: z.ZodOptional<z.ZodObject<{
|
|
161
|
+
entry: z.ZodString;
|
|
162
|
+
}, z.core.$strip>>;
|
|
153
163
|
attach: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
|
|
154
164
|
panel: "panel";
|
|
155
165
|
dialog: "dialog";
|
|
@@ -242,6 +252,10 @@ export declare const packageManifestSchema: z.ZodObject<{
|
|
|
242
252
|
message: "message";
|
|
243
253
|
session: "session";
|
|
244
254
|
}>;
|
|
255
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
256
|
+
background: "background";
|
|
257
|
+
open: "open";
|
|
258
|
+
}>>;
|
|
245
259
|
roles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
246
260
|
user: "user";
|
|
247
261
|
assistant: "assistant";
|
package/dist/parse.js
CHANGED
|
@@ -149,6 +149,7 @@ const actionSchema = z.object({
|
|
|
149
149
|
label: z.string().trim().min(1).max(GUEST_ACTION_LABEL_MAX),
|
|
150
150
|
icon: z.string().trim().refine(isPanelIcon).optional(),
|
|
151
151
|
where: z.enum(['message', 'session']),
|
|
152
|
+
mode: z.enum(['open', 'background']).optional(),
|
|
152
153
|
roles: z.array(z.enum(['user', 'assistant'])).min(1).max(2).optional(),
|
|
153
154
|
payload: z.array(z.enum(['messages'])).max(1).optional(),
|
|
154
155
|
}).refine((value) => value.where === 'message' || value.roles === undefined, { path: ['roles'] })
|
|
@@ -178,6 +179,9 @@ const toolSchema = z.object({
|
|
|
178
179
|
const toolsSchema = z.array(toolSchema).min(1).max(GUEST_TOOLS_MAX);
|
|
179
180
|
const contributesSchema = z.object({
|
|
180
181
|
panel: panelSchema,
|
|
182
|
+
background: z.object({
|
|
183
|
+
entry: z.string().trim().refine((value) => isSafeAssetPath(value) && value.toLowerCase().endsWith('.html')),
|
|
184
|
+
}).optional(),
|
|
181
185
|
attach: attachSchema.optional(),
|
|
182
186
|
page: z.union([z.literal(true), z.object({
|
|
183
187
|
entry: z.string().trim().refine(isSafeAssetPath),
|
|
@@ -192,12 +196,9 @@ const contributesSchema = z.object({
|
|
|
192
196
|
tools: toolsSchema.optional(),
|
|
193
197
|
});
|
|
194
198
|
/**
|
|
195
|
-
*
|
|
196
|
-
* `panel.entry` there is nothing to open from the rail, the + menu, a menu
|
|
197
|
-
* action, or a slash command, and nothing to hand a capability, a service,
|
|
198
|
-
* an integration, or a filesystem grant to; only `tools` stays meaningful.
|
|
199
|
+
* Contributions that need either the panel or background execution frame.
|
|
199
200
|
*/
|
|
200
|
-
const
|
|
201
|
+
const runtimeContributions = (contributes) => {
|
|
201
202
|
const declared = [];
|
|
202
203
|
if (contributes.page !== undefined)
|
|
203
204
|
declared.push('page');
|
|
@@ -225,13 +226,28 @@ export const openChamberManifestSchema = z.object({
|
|
|
225
226
|
contributes: contributesSchema.superRefine((contributes, ctx) => {
|
|
226
227
|
if (hasGuestPage(contributes))
|
|
227
228
|
return;
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
if (contributes.background) {
|
|
230
|
+
const needsPanel = [];
|
|
231
|
+
if (contributes.page !== undefined)
|
|
232
|
+
needsPanel.push('page');
|
|
233
|
+
if (contributes.attach !== undefined && contributes.attach !== false)
|
|
234
|
+
needsPanel.push('attach');
|
|
235
|
+
if (contributes.actions?.some((action) => action.mode !== 'background'))
|
|
236
|
+
needsPanel.push('actions with mode "open"');
|
|
237
|
+
if (needsPanel.length > 0)
|
|
238
|
+
ctx.addIssue({
|
|
239
|
+
code: 'custom', path: ['panel'],
|
|
240
|
+
message: `${needsPanel.join(', ')} needs panel.entry; background-only actions must declare mode "background".`,
|
|
241
|
+
});
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const needsRuntime = runtimeContributions(contributes);
|
|
245
|
+
if (needsRuntime.length === 0)
|
|
230
246
|
return;
|
|
231
247
|
ctx.addIssue({
|
|
232
248
|
code: 'custom',
|
|
233
249
|
path: ['panel'],
|
|
234
|
-
message: `${
|
|
250
|
+
message: `${needsRuntime.map((key) => `contributes.${key}`).join(', ')} needs panel.entry or background.entry; an extension without either may only declare tools.`,
|
|
235
251
|
});
|
|
236
252
|
}),
|
|
237
253
|
});
|
|
@@ -293,6 +309,9 @@ const failureFromIssue = (issue) => {
|
|
|
293
309
|
if (path === 'contributes.page' || path.startsWith('contributes.page.')) {
|
|
294
310
|
return fail('invalid-page', 'contributes.page must be true or { entry: "<package HTML>", title?: "Page title" }.');
|
|
295
311
|
}
|
|
312
|
+
if (path === 'contributes.background' || path.startsWith('contributes.background.')) {
|
|
313
|
+
return fail('invalid-background', 'contributes.background needs an entry ending in .html inside the package.');
|
|
314
|
+
}
|
|
296
315
|
if (path === 'contributes.attach' || path.startsWith('contributes.attach.')) {
|
|
297
316
|
return fail('invalid-attach', 'contributes.attach must be true, false, "panel", "dialog", or { "mode": "panel" | "dialog", "entry"?: "<html inside the package, dialog only>" }.');
|
|
298
317
|
}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -116,6 +116,11 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
116
116
|
active: z.ZodString;
|
|
117
117
|
selectionForeground: z.ZodString;
|
|
118
118
|
primaryForeground: z.ZodString;
|
|
119
|
+
primaryText: z.ZodString;
|
|
120
|
+
successText: z.ZodString;
|
|
121
|
+
warningText: z.ZodString;
|
|
122
|
+
errorText: z.ZodString;
|
|
123
|
+
infoText: z.ZodString;
|
|
119
124
|
success: z.ZodString;
|
|
120
125
|
warning: z.ZodString;
|
|
121
126
|
error: z.ZodString;
|
|
@@ -138,6 +143,7 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
138
143
|
panel: "panel";
|
|
139
144
|
dialog: "dialog";
|
|
140
145
|
page: "page";
|
|
146
|
+
background: "background";
|
|
141
147
|
}>;
|
|
142
148
|
connection: z.ZodObject<{
|
|
143
149
|
connected: z.ZodBoolean;
|
|
@@ -746,8 +752,53 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
746
752
|
} | {
|
|
747
753
|
text: string;
|
|
748
754
|
} | undefined;
|
|
749
|
-
}
|
|
755
|
+
}>>, z.ZodObject<{
|
|
756
|
+
type: z.ZodLiteral<"action">;
|
|
757
|
+
id: z.ZodString;
|
|
758
|
+
payload: z.ZodUnion<readonly [z.ZodObject<{
|
|
759
|
+
kind: z.ZodLiteral<"message">;
|
|
760
|
+
action: z.ZodString;
|
|
761
|
+
sessionId: z.ZodString;
|
|
762
|
+
sessionTitle: z.ZodString;
|
|
763
|
+
directory: z.ZodNullable<z.ZodString>;
|
|
764
|
+
messageId: z.ZodString;
|
|
765
|
+
role: z.ZodEnum<{
|
|
766
|
+
user: "user";
|
|
767
|
+
assistant: "assistant";
|
|
768
|
+
}>;
|
|
769
|
+
text: z.ZodString;
|
|
770
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
771
|
+
kind: z.ZodLiteral<"session">;
|
|
772
|
+
action: z.ZodString;
|
|
773
|
+
sessionId: z.ZodString;
|
|
774
|
+
sessionTitle: z.ZodString;
|
|
775
|
+
directory: z.ZodNullable<z.ZodString>;
|
|
776
|
+
messages: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
777
|
+
id: z.ZodString;
|
|
778
|
+
role: z.ZodEnum<{
|
|
779
|
+
user: "user";
|
|
780
|
+
assistant: "assistant";
|
|
781
|
+
}>;
|
|
782
|
+
text: z.ZodString;
|
|
783
|
+
createdAt: z.ZodNumber;
|
|
784
|
+
}, z.core.$strip>>>;
|
|
785
|
+
truncated: z.ZodOptional<z.ZodBoolean>;
|
|
786
|
+
}, z.core.$strip>]>;
|
|
787
|
+
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
788
|
+
v: z.ZodLiteral<1>;
|
|
789
|
+
}, z.core.$strip>]>;
|
|
750
790
|
export declare const guestMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
791
|
+
type: z.ZodLiteral<"action-result">;
|
|
792
|
+
id: z.ZodString;
|
|
793
|
+
payload: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
794
|
+
ok: z.ZodLiteral<true>;
|
|
795
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
796
|
+
ok: z.ZodLiteral<false>;
|
|
797
|
+
error: z.ZodString;
|
|
798
|
+
}, z.core.$strip>], "ok">;
|
|
799
|
+
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
800
|
+
v: z.ZodLiteral<1>;
|
|
801
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
751
802
|
type: z.ZodLiteral<"workspace-read">;
|
|
752
803
|
id: z.ZodString;
|
|
753
804
|
payload: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -826,6 +877,11 @@ export declare const guestMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
826
877
|
success: "success";
|
|
827
878
|
}>;
|
|
828
879
|
message: z.ZodString;
|
|
880
|
+
copy: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
881
|
+
text: z.ZodString;
|
|
882
|
+
}, z.core.$strip>]>>;
|
|
883
|
+
dismiss: z.ZodOptional<z.ZodBoolean>;
|
|
884
|
+
persistent: z.ZodOptional<z.ZodBoolean>;
|
|
829
885
|
}, z.core.$strip>;
|
|
830
886
|
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
831
887
|
v: z.ZodLiteral<1>;
|
package/dist/protocol.js
CHANGED
|
@@ -22,6 +22,11 @@ const themeTokensSchema = z.object({
|
|
|
22
22
|
active: z.string().min(1),
|
|
23
23
|
selectionForeground: z.string().min(1),
|
|
24
24
|
primaryForeground: z.string().min(1),
|
|
25
|
+
primaryText: z.string().min(1),
|
|
26
|
+
successText: z.string().min(1),
|
|
27
|
+
warningText: z.string().min(1),
|
|
28
|
+
errorText: z.string().min(1),
|
|
29
|
+
infoText: z.string().min(1),
|
|
25
30
|
success: z.string().min(1),
|
|
26
31
|
warning: z.string().min(1),
|
|
27
32
|
error: z.string().min(1),
|
|
@@ -141,7 +146,7 @@ const readyPayloadSchema = z.object({
|
|
|
141
146
|
locale: z.string().min(1),
|
|
142
147
|
directory: z.string().nullable(),
|
|
143
148
|
session: sessionSnapshotSchema,
|
|
144
|
-
surface: z.enum(['panel', 'dialog', 'page']),
|
|
149
|
+
surface: z.enum(['panel', 'dialog', 'page', 'background']),
|
|
145
150
|
connection: guestConnectionSchema,
|
|
146
151
|
settings: guestSettingsSchema,
|
|
147
152
|
item: guestItemSchema,
|
|
@@ -248,9 +253,24 @@ export const hostMessageSchema = z.union([
|
|
|
248
253
|
}),
|
|
249
254
|
}),
|
|
250
255
|
hostResultSchema,
|
|
256
|
+
z.object({
|
|
257
|
+
...envelope,
|
|
258
|
+
type: z.literal('action'),
|
|
259
|
+
id: z.string().min(1),
|
|
260
|
+
payload: z.union([messageItemSchema, sessionItemSchema]),
|
|
261
|
+
}),
|
|
251
262
|
]);
|
|
252
263
|
const filePathSchema = z.string().min(1).max(GUEST_FILE_PATH_MAX).refine(isGuestFilePath);
|
|
253
264
|
export const guestMessageSchema = z.discriminatedUnion('type', [
|
|
265
|
+
z.object({
|
|
266
|
+
...envelope,
|
|
267
|
+
type: z.literal('action-result'),
|
|
268
|
+
id: z.string().min(1),
|
|
269
|
+
payload: z.discriminatedUnion('ok', [
|
|
270
|
+
z.object({ ok: z.literal(true) }),
|
|
271
|
+
z.object({ ok: z.literal(false), error: z.string().trim().min(1).max(GUEST_RESOLVE_ERROR_MAX) }),
|
|
272
|
+
]),
|
|
273
|
+
}),
|
|
254
274
|
z.object({ ...envelope, type: z.literal('workspace-read'), id: z.string().min(1), payload: guestWorkspaceQuerySchema }),
|
|
255
275
|
z.object({ ...envelope, type: z.literal('workspace-subscribe'), id: z.string().min(1), payload: z.object({ subscriptionId: z.string().min(1).max(128), query: guestWorkspaceQuerySchema }) }),
|
|
256
276
|
z.object({ ...envelope, type: z.literal('workspace-unsubscribe'), id: z.string().min(1), payload: z.object({ subscriptionId: z.string().min(1).max(128) }) }),
|
|
@@ -267,6 +287,9 @@ export const guestMessageSchema = z.discriminatedUnion('type', [
|
|
|
267
287
|
payload: z.object({
|
|
268
288
|
kind: z.enum(['info', 'success', 'error']),
|
|
269
289
|
message: z.string().trim().min(1).max(GUEST_TOAST_MAX),
|
|
290
|
+
copy: z.union([z.boolean(), z.object({ text: z.string().min(1).max(GUEST_CLIPBOARD_TEXT_MAX) })]).optional(),
|
|
291
|
+
dismiss: z.boolean().optional(),
|
|
292
|
+
persistent: z.boolean().optional(),
|
|
270
293
|
}),
|
|
271
294
|
}),
|
|
272
295
|
z.object({
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** Shared by served extension documents and the UI kit, including older guest bundles. */
|
|
2
|
+
export declare const GUEST_SCROLLBAR_CSS = "\n:root {\n --oc-scrollbar-thumb: color-mix(in srgb, var(--oc-muted, currentColor) 40%, transparent);\n --oc-scrollbar-thumb-hover: color-mix(in srgb, var(--oc-muted, currentColor) 65%, transparent);\n scrollbar-gutter: stable;\n}\n* {\n scrollbar-width: thin;\n scrollbar-color: var(--oc-scrollbar-thumb) transparent;\n}\n/* Chromium's standard scrollbar properties otherwise override its pseudo-elements. */\n@supports selector(::-webkit-scrollbar) {\n * { scrollbar-width: auto; scrollbar-color: auto; }\n ::-webkit-scrollbar { width: 6px; height: 6px; background: transparent; }\n :root::-webkit-scrollbar, body::-webkit-scrollbar { background: var(--oc-bg, inherit); }\n ::-webkit-scrollbar-track { background: transparent; }\n ::-webkit-scrollbar-thumb {\n background: var(--oc-scrollbar-thumb);\n border-radius: 999px;\n min-width: 24px;\n min-height: 24px;\n }\n ::-webkit-scrollbar-thumb:hover { background: var(--oc-scrollbar-thumb-hover); }\n ::-webkit-scrollbar-corner { background: transparent; }\n ::-webkit-scrollbar-button { display: none; width: 0; height: 0; }\n}\n@media (forced-colors: active) {\n * { scrollbar-color: auto; }\n ::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb:hover { background: CanvasText; }\n}\n";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Shared by served extension documents and the UI kit, including older guest bundles. */
|
|
2
|
+
export const GUEST_SCROLLBAR_CSS = `
|
|
3
|
+
:root {
|
|
4
|
+
--oc-scrollbar-thumb: color-mix(in srgb, var(--oc-muted, currentColor) 40%, transparent);
|
|
5
|
+
--oc-scrollbar-thumb-hover: color-mix(in srgb, var(--oc-muted, currentColor) 65%, transparent);
|
|
6
|
+
scrollbar-gutter: stable;
|
|
7
|
+
}
|
|
8
|
+
* {
|
|
9
|
+
scrollbar-width: thin;
|
|
10
|
+
scrollbar-color: var(--oc-scrollbar-thumb) transparent;
|
|
11
|
+
}
|
|
12
|
+
/* Chromium's standard scrollbar properties otherwise override its pseudo-elements. */
|
|
13
|
+
@supports selector(::-webkit-scrollbar) {
|
|
14
|
+
* { scrollbar-width: auto; scrollbar-color: auto; }
|
|
15
|
+
::-webkit-scrollbar { width: 6px; height: 6px; background: transparent; }
|
|
16
|
+
:root::-webkit-scrollbar, body::-webkit-scrollbar { background: var(--oc-bg, inherit); }
|
|
17
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
18
|
+
::-webkit-scrollbar-thumb {
|
|
19
|
+
background: var(--oc-scrollbar-thumb);
|
|
20
|
+
border-radius: 999px;
|
|
21
|
+
min-width: 24px;
|
|
22
|
+
min-height: 24px;
|
|
23
|
+
}
|
|
24
|
+
::-webkit-scrollbar-thumb:hover { background: var(--oc-scrollbar-thumb-hover); }
|
|
25
|
+
::-webkit-scrollbar-corner { background: transparent; }
|
|
26
|
+
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
|
|
27
|
+
}
|
|
28
|
+
@media (forced-colors: active) {
|
|
29
|
+
* { scrollbar-color: auto; }
|
|
30
|
+
::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb:hover { background: CanvasText; }
|
|
31
|
+
}
|
|
32
|
+
`;
|
package/dist/ui/menu.js
CHANGED
|
@@ -51,8 +51,12 @@ export const mountMenu = (root, initial) => {
|
|
|
51
51
|
setActive(actions(props.items).some((item) => item.id === activeId) ? activeId : null);
|
|
52
52
|
};
|
|
53
53
|
const close = () => {
|
|
54
|
-
|
|
54
|
+
// Removing a focused row fires `focusout` synchronously from inside the disposer, and
|
|
55
|
+
// that handler calls `close` again. Clearing the slot first makes the re-entry a no-op
|
|
56
|
+
// instead of a second `popup.remove()` that throws before the pick reaches `onChange`.
|
|
57
|
+
const dispose = closePopup;
|
|
55
58
|
closePopup = null;
|
|
59
|
+
dispose?.();
|
|
56
60
|
activeId = null;
|
|
57
61
|
triggerNode?.setAttribute('aria-expanded', 'false');
|
|
58
62
|
};
|
package/dist/ui/select.js
CHANGED
|
@@ -63,8 +63,12 @@ export const mountSelect = (root, initial) => {
|
|
|
63
63
|
setActive(options.some((option) => option.id === activeId) ? activeId : options[0]?.id ?? null);
|
|
64
64
|
};
|
|
65
65
|
const close = () => {
|
|
66
|
-
|
|
66
|
+
// Removing a focused row fires `focusout` synchronously from inside the disposer, and
|
|
67
|
+
// that handler calls `close` again. Clearing the slot first makes the re-entry a no-op
|
|
68
|
+
// instead of a second `popup.remove()` that throws before the pick reaches `onChange`.
|
|
69
|
+
const dispose = closePopup;
|
|
67
70
|
closePopup = null;
|
|
71
|
+
dispose?.();
|
|
68
72
|
query = '';
|
|
69
73
|
search.value = '';
|
|
70
74
|
trigger.setAttribute('aria-expanded', 'false');
|