@openchamber/sdk 2.5.1 → 2.5.2
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 +26 -1
- package/DOCUMENTATION.md +3 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/manifest.d.ts +10 -1
- package/dist/manifest.js +9 -1
- package/dist/parse.d.ts +10 -2
- package/dist/parse.js +24 -5
- package/dist/protocol.d.ts +30 -0
- package/dist/schemas.d.ts +1 -0
- package/dist/schemas.js +1 -0
- package/dist/status-view-schemas.d.ts +166 -0
- package/dist/status-view-schemas.js +113 -0
- package/dist/status-view.d.ts +129 -0
- package/dist/status-view.js +15 -0
- package/dist/workspace-schemas.d.ts +9 -0
- package/dist/workspace-schemas.js +1 -0
- package/dist/workspace.d.ts +13 -0
- package/package.json +1 -1
package/API.md
CHANGED
|
@@ -215,7 +215,7 @@ Await subscription registration to handle refusal, then retain its returned unsu
|
|
|
215
215
|
|
|
216
216
|
Snapshots carry `state: 'loading' | 'ready' | 'error'`; session snapshots also carry per-directory `coverage`. Loading/error may retain data. Only `ready` establishes complete empty success. Reads use existing shared stores and hydration, never a git scan per extension request.
|
|
217
217
|
|
|
218
|
-
Projects contain `id`, `name`, `directory`. Worktrees contain `directory`, `name`, `branch`, and `status: 'ready' | 'pending' | 'invalid' | 'missing'`. Session records contain `id`, `title`, `projectId`, `directory`, `parentId`, `createdAt`, `updatedAt`, `archivedAt`, `worktree`, `activity`, `outcome`, and `
|
|
218
|
+
Projects contain `id`, `name`, `directory`. Worktrees contain `directory`, `name`, `branch`, and `status: 'ready' | 'pending' | 'invalid' | 'missing'`. Session records contain `id`, `title`, `projectId`, `directory`, `parentId`, `createdAt`, `updatedAt`, `archivedAt`, `worktree`, `activity`, `outcome`, `items`, and `links`. Item references contain only this extension's `id` and optional `data`. `links` is every thread linked to the session, whoever linked it (the user, the agent through `session.link`, this extension or another), each with `title`, `url`, `kind: 'issue' | 'change'` (`change` is a pull, merge or change request) and `linkedAt`; read-only, and a change to it sends a new snapshot. Hosts older than this field omit it.
|
|
219
219
|
|
|
220
220
|
`activity` is `unknown`, `idle`, `running`, `retrying`, `waiting-permission`, or `waiting-question` (the agent put a form to the user and is waiting on the answer). `outcome` is the last observed `completed` or `failed` turn, or `null` when unknown or working. Outcomes are in memory for the latest 2,000 observed sessions, reset on runtime switch, and are not reconstructed from persisted history. A later idle event preserves an observed failure until another run starts. `completed` never means the extension's task is Done. Blocking-request contents and approve/reply actions are not exposed.
|
|
221
221
|
|
|
@@ -253,6 +253,31 @@ Omit `options`, or pass `{ scope: 'instance' }`, for this existing server-owned
|
|
|
253
253
|
|
|
254
254
|
`setStatusControls` accepts zero to four declarations. A button is `{ kind: 'button', id, label, disabled? }`; a select is `{ kind: 'select', id, label, value, options, disabled? }`, with one to 16 unique options and a selected value in that list. IDs are kebab-case and at most 40 characters; labels are 1 to 60 characters; option values are 1 to 80 characters. Register `onStatusControl` synchronously after `connectHost`, then feature-gate `setStatusControls` with `features.statusControls`. Buttons receive no `value`; select events carry a declared value. The host rejects stale, unknown, disabled, or invalid controls. It accepts at most 20 changed control publications per second per frame and avoids semantic no-op updates. Controls exist only for the expanded, mounted status frame that registered them. Folding or hiding the section removes controls and listeners. A project change clears header controls; publish them again from `onDirectory`. Workspace subscriptions remain active. Old hosts return `UNSUPPORTED`; keep a body control visible until `setStatusControls` succeeds.
|
|
255
255
|
|
|
256
|
+
#### Sections the app draws
|
|
257
|
+
|
|
258
|
+
With `source`, the app draws the section itself and loads no frame: `{ source: { path: '/status', interval?: 2000 }, title?: 'Resources' }`. It needs `contributes.service`; a section with a source and no `entry` needs no `panel.entry` either. While the section is shown and expanded, the app sends `GET /status` to your service, then again `interval` ms (1000 to 60000, default 2000) after each answer. The query carries `locale` (the app's language, such as `uk` or `pt-BR`) and `directory` when the panel shows a project. Answer with JSON:
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"rows": [
|
|
263
|
+
{ "kind": "line", "id": "cpu", "label": "CPU", "content": { "kind": "bar", "value": 25, "tone": "info" }, "value": "25%" },
|
|
264
|
+
{ "kind": "line", "id": "app", "label": "OpenChamber", "value": "1.6 GB",
|
|
265
|
+
"content": { "kind": "chart", "values": [1.5e9, 1.6e9], "unit": "bytes", "step": 2, "tone": "accent" } },
|
|
266
|
+
{ "kind": "line", "id": "web", "label": "web", "dot": "success",
|
|
267
|
+
"content": { "kind": "chips", "chips": [{ "id": "port-5173", "label": ":5173", "url": "http://localhost:5173" }] },
|
|
268
|
+
"actions": [{ "kind": "button", "id": "stop-web", "label": "Stop", "variant": "destructive", "confirm": "Stop web?" }] },
|
|
269
|
+
{ "kind": "note", "id": "hint", "text": "Docker isn't running.", "tone": "warning" }
|
|
270
|
+
],
|
|
271
|
+
"controls": [{ "kind": "button", "id": "refresh", "label": "Refresh" }]
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
A `line` has a `label` and optionally an `icon` (a Remixicon name; an unknown one is left out), a status `dot`, one `content`, a `value` with `valueTone`, a `badge` `{ label, tone? }`, a `tooltip`, and up to two `actions`. `content` is a `bar` (`value` 0 to 100), a `chart` (`values` oldest first, at most 120; `max`; `unit` `bytes`, `percent` or `count` for the hover label; `step` seconds between points), `chips` (one to six, each with an optional `http(s)` `url` the chip opens), `text`, or a `segmented` choice of two to four options. Actions are a `button` (`variant` `default`, `outline` or `destructive`; `confirm` asks on the first click and acts on the second), a `switch` (`checked`), or a `select`. A `note` is a line of text, `muted` by default or tinted `info`, `warning` or `error`. `controls` are header controls in the `setStatusControls` shape. Tones are `default`, `muted`, `accent`, `success`, `warning`, `error` and `info`; the app takes their colours from its theme. At most 16 rows. Row ids are unique, and so are control ids across the whole answer. Types: `GuestStatusView` and friends in `@openchamber/sdk`; the app checks answers with `guestStatusViewSchema` from `@openchamber/sdk/schemas` and shows an error instead of an answer that does not parse.
|
|
276
|
+
|
|
277
|
+
When the user activates a control, the app posts `{ "id": "stop-web" }` to the same path, with `value` for a choice (`on` or `off` for a switch), and reads the section again as soon as you answer. Answer 2xx when it worked; otherwise the app shows an error toast with your `{ "message": "..." }` when the body has one. The choice shows at once and stays until a reading taken after your answer.
|
|
278
|
+
|
|
279
|
+
Keep `entry` beside `source` to support OpenChamber versions that predate it: they ignore `source` and load the frame. Web and desktop only, like every status section.
|
|
280
|
+
|
|
256
281
|
### File editors
|
|
257
282
|
|
|
258
283
|
`contributes.fileEditors` lists up to 8 editors: `{ id: 'canvas', title: 'Excalidraw', match: ['*.excalidraw', '*.excalidraw.md'], entry: 'editor/index.html' }`. `match` holds 1 to 16 file-name patterns, compared case-insensitively with the name only (no `/`); `*` is any run of characters, `?` one, and a pattern must have at least one character that is not a wildcard. `entry` is package `.html` with built scripts, checked at install. `content` is `"text"` (the default) or `"binary"`: a text editor claims only text files and gets the text with `\n` line endings (the host restores the file's own on write); a binary editor claims any matching file, gets its bytes as a `Uint8Array`, returns bytes, and has no source view, and the host saves its unsaved changes before it moves to or from fullscreen. When the user opens a matching file in Files, the viewer loads your page instead of its own preview; the first enabled, approved extension in the list wins, ahead of the built-in viewers. `ctx.surface` is `file`.
|
package/DOCUMENTATION.md
CHANGED
|
@@ -27,7 +27,8 @@ Public author pages live in `packages/docs/content/docs/sdk.mdx`, `sdk/host.mdx`
|
|
|
27
27
|
|
|
28
28
|
- Extension activity uses `useConfigStore.isConnected` plus live status records and directory `sessionStatusReady` authority. `useUIStore.eventStreamStatus` is an unmaintained diagnostic field, not a connection gate; its default `idle` must not hide known running or idle sessions as `unknown`.
|
|
29
29
|
|
|
30
|
-
- `contributes.statusSection` is `true` or `{ entry
|
|
30
|
+
- `contributes.statusSection` is `true` or `{ entry?, source?, title?, height?, defaultExpanded?, requiresProject? }` (`StatusSectionContribution`), the object form with `entry`, `source`, or both. `true` reuses `panel.entry` and fails as `invalid-status-section` without one; the object form's `entry` is package-local `.html`, `title` 1 to `GUEST_STATUS_SECTION_TITLE_MAX` (60), `height` `GUEST_STATUS_SECTION_HEIGHT_MIN`..`MAX` (24..320). `defaultExpanded` defaults to true and only applies when the user has no saved expansion choice. `requiresProject` defaults to false; when true, the actual Work Status directory controls both presence and body rendering. `resolveStatusSectionEntry` resolves shorthand. The object form is a frame of its own: without `panel.entry` or `background.entry` it permits `capabilities`, `service`, `integration`, and `filesystem`, and refuses `page`, `attach`, `actions`, and `commands` as `invalid-panel`, because those are opened or invoked elsewhere. The server validates the HTML/scripts, exposes `statusEntry`/`statusTitle`/`statusHeight`, and counts `statusEntry` as a runtime entry for serving and storage. The host mounts `PluginPane surface="status"` inside the Work Status panel (`components/chat/work-status/WorkStatusExtensionSection.tsx`, see that folder's `DOCUMENTATION.md`): the same sandbox, guest-scoped token, context, grants, approval, and pause gates as a panel. Guest `resize` (`host.setHeight`, `ResizeRequest { height }`, integer 0..`GUEST_FRAME_HEIGHT_MAX`) is a request answered with an empty result on every surface; only `status` sizes its frame from it, through `clampStatusSectionHeight`, and a page docked to a shared surface sizes its dock from it (`DockedGuestPage` in `ContextPanel`: thickness across the dock edge, at least `GUEST_SURFACE_DOCK_SIZE_MIN`, at most half the panel through CSS). Each frame's `setHeight` reaches only its own pane. A status frame never registers a command resolver, clears a badge, or closes rail tabs. Host-rendered controls exist only after a mounted, expanded status frame calls `setStatusControls`; folding, hiding, or retiring the frame removes them. A project change clears header controls; publish them again from `onDirectory`. Workspace subscriptions remain active.
|
|
31
|
+
- `contributes.statusSection.source` is `{ path, interval? }` (`StatusSectionSource`, `src/status-view.ts`): a section the host draws itself, with no frame. While the section is shown and expanded the host reads `GET path` from the extension's service through `/api/guests/:id/service/request`, the next read `interval` ms after the last one finished (`GUEST_STATUS_SOURCE_INTERVAL_MIN`..`MAX`, default 2000, resolved by `resolveStatusSectionSource`), with `query.locale` and, when the panel has a project, `query.directory`. The answer is a `GuestStatusView`: up to 16 rows, each a `line` (label, optional icon, dot, content, value, badge, tooltip, up to two actions) or a `note`; content is a `bar`, `chart`, `chips`, `text` or `segmented` choice; actions are a `button` (optional two-click `confirm`), `switch` or `select`; `controls` are header controls in the `setStatusControls` shape. Colours are theme tones (`GuestStatusTone`), never CSS. The host parses the answer with `guestStatusViewSchema` (`src/status-view-schemas.ts`, exported from `@openchamber/sdk/schemas`), which asserts at compile time that it equals the type, and refuses the whole answer when it does not parse. Activating a control posts `{ id, value? }` (`GuestStatusActionEvent`; a switch sends `on` or `off`) to the same path; a non-2xx answer may carry `{ message }` for the host's error toast. A source needs `contributes.service` (`invalid-status-section` without one) and makes the host the service's caller, so a source-only package needs no `panel.entry` or `background.entry` for its service; frame-only declarations (`capabilities`, `integration`, `filesystem`) still do. A section that declares both is drawn from `source` by hosts that know it; older hosts strip the unknown key and load `entry`, so an extension keeps `entry` for as long as it supports them.
|
|
31
32
|
- `openSurface(surfaceId)` posts `open-surface { surfaceId }`; an id that is not a context panel surface is `HOST_REJECTED`. The host (`lib/guests/open-surface.ts`) opens it the way its rail icon does, under the frame's directory, or under the directory the rail shows when the frame has none (a Work Status section in a chat draft without a project has none of its own). The result follows what the panel shows afterwards: a surface already on screen stays open where the icon would toggle it closed; one that did not open (`chat`, which needs a session beside it) is `UNSUPPORTED`; no directory yet is `NO_DIRECTORY`. VS Code and mobile answer `UNSUPPORTED` explicitly. A resolved call means the surface is on screen.
|
|
32
33
|
- `openCommit(sha)` posts `open-commit { sha }`. `sha` is 7 to 64 hex characters (`GUEST_COMMIT_SHA`); the client refuses anything else as `HOST_REJECTED` before posting and the host schema drops it. The host (`lib/guests/open-commit.ts`) reads the commit itself with `git.getGitLog(directory, { maxCount: 1, to: sha })` in the frame's current directory, checks the returned hash starts with the requested one (`NOT_FOUND` otherwise), selects it in `useCommitSelectionStore` under the Diff view's key (directory, current branch, git runtime key), and opens the context panel's Diff tab in `commit` scope. No project is `NO_DIRECTORY`. VS Code and mobile answer `UNSUPPORTED` explicitly; they load no guests today, so this is the contract for when they do. No capability is needed: it only shows the user their own history.
|
|
33
34
|
- Scrollbars in guest documents follow the app's overlay behavior: hidden at rest, shown on hover and for one second after the element last scrolled. `GUEST_SCROLLBAR_CSS` does the hiding and hover; `installGuestScrollbarActivity` (one capturing passive `scroll` listener per document) marks the scrolling element with `data-oc-scrolling`. The server appends both to every served guest HTML as `GUEST_SCROLLBAR_SCRIPT` (the function's own source), so already installed bundles get it without a rebuild; the UI kit installs it too for previews. An authored CSP that blocks inline scripts keeps the hover-only behavior. Forced-colors mode keeps system colors.
|
|
@@ -99,7 +100,7 @@ Actions, commands, and the badge are host chrome too. `useGuestActions` (`packag
|
|
|
99
100
|
|
|
100
101
|
Add a type when the host grows that hole, not before. Any new `connectHost` method ships with a `PluginPane` / `answerGuestMessage` branch in the same change.
|
|
101
102
|
|
|
102
|
-
Rebuild every example bundle after an SDK change (`bunx openchamber-guest-bundle` per entry, see `examples/README.md`); the built files are checked in.
|
|
103
|
+
Rebuild every example bundle after an SDK change (`bunx openchamber-guest-bundle` per entry, see `examples/README.md`); the built files are checked in. A Bun upgrade needs the same rebuild: the minifier names identifiers differently between releases, so a panel bundle built by the previous Bun no longer matches and `examples.test.ts` fails for every PR until the bundles are regenerated. Service bundles are not minified and keep matching.
|
|
103
104
|
|
|
104
105
|
## Anchored popovers
|
|
105
106
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
export { OPENCHAMBER_SDK_API_VERSION, OPENCHAMBER_SDK_CHANNEL, OPENCHAMBER_SDK_MANIFEST_API_VERSIONS } from './api-version.ts';
|
|
2
2
|
export { GUEST_SCROLLBAR_CSS, GUEST_SCROLLBAR_SCRIPT } from './scrollbar-style.ts';
|
|
3
3
|
export { guestFramePolicy } from './frame-policy.ts';
|
|
4
|
-
export type { GuestLoadState, GuestProject, GuestWorktree, GuestSessionActivity, GuestSessionRecord, GuestDirectoryCoverage, GuestProjectsSnapshot, GuestWorktreesSnapshot, GuestSessionsSnapshot, GuestWorkspaceSnapshot, GuestWorkspaceQuery, GuestWorkspaceSubscription, GuestWorkspaceUpdate, GuestStorageRequest, GuestStorageResult, GuestStorageOptions, GuestStorageScope, GuestSessionWorktree } from './workspace.ts';
|
|
4
|
+
export type { GuestLoadState, GuestProject, GuestWorktree, GuestSessionActivity, GuestSessionRecord, GuestSessionLink, GuestDirectoryCoverage, GuestProjectsSnapshot, GuestWorktreesSnapshot, GuestSessionsSnapshot, GuestWorkspaceSnapshot, GuestWorkspaceQuery, GuestWorkspaceSubscription, GuestWorkspaceUpdate, GuestStorageRequest, GuestStorageResult, GuestStorageOptions, GuestStorageScope, GuestSessionWorktree } from './workspace.ts';
|
|
5
5
|
export { GUEST_STORAGE_KEY_MAX, GUEST_STORAGE_KEYS_MAX, GUEST_STORAGE_VALUE_BYTES, GUEST_STORAGE_TOTAL_BYTES, GUEST_DEVICE_STORAGE_TOTAL_BYTES } from './workspace.ts';
|
|
6
6
|
export type { GuestRunningShell, GuestEndedShell, GuestShellEndStatus, GuestRunningShellsSnapshot, GuestShellsScope, GuestShellsSubscription, GuestShellOutputRequest, GuestShellOutputResult, GuestShellStopResult, } from './shells.ts';
|
|
7
7
|
export { GUEST_SHELL_END_STATUSES, GUEST_SHELL_ID_MAX, GUEST_SHELLS_MAX, GUEST_SHELL_OUTPUT_TAIL_MAX, } from './shells.ts';
|
|
8
8
|
export { GUEST_STATUS_CONTROLS_MAX, GUEST_STATUS_CONTROL_ID, GUEST_STATUS_CONTROL_LABEL_MAX, GUEST_STATUS_CONTROL_OPTIONS_MAX, GUEST_STATUS_CONTROL_VALUE_MAX } from './status-controls.ts';
|
|
9
9
|
export type { GuestStatusControl, GuestStatusControlEvent, GuestStatusControlOption } from './status-controls.ts';
|
|
10
|
+
export { GUEST_STATUS_SOURCE_INTERVAL_DEFAULT, GUEST_STATUS_SOURCE_INTERVAL_MAX, GUEST_STATUS_SOURCE_INTERVAL_MIN, GUEST_STATUS_VIEW_ACTIONS_MAX, GUEST_STATUS_VIEW_CHART_POINTS_MAX, GUEST_STATUS_VIEW_CHIPS_MAX, GUEST_STATUS_VIEW_ICON, GUEST_STATUS_VIEW_NOTE_MAX, GUEST_STATUS_VIEW_ROWS_MAX, GUEST_STATUS_VIEW_SEGMENTS_MAX, GUEST_STATUS_VIEW_SEGMENTS_MIN, GUEST_STATUS_VIEW_TEXT_MAX, } from './status-view.ts';
|
|
11
|
+
export type { GuestStatusAction, GuestStatusActionEvent, GuestStatusChartUnit, GuestStatusChip, GuestStatusContent, GuestStatusRow, GuestStatusTone, GuestStatusView, StatusSectionSource, } from './status-view.ts';
|
|
10
12
|
export type { OpenChamberManifestApiVersion } from './api-version.ts';
|
|
11
13
|
export { compareOpenChamberVersions, hostMeetsOpenChamberEngine, openChamberEngineMinimum, OPENCHAMBER_ENGINE_PATTERN, parseOpenChamberVersion, } from './host-version.ts';
|
|
12
|
-
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, GUEST_ORIGINS_MAX, GUEST_SERVICE_PROVIDES, GUEST_SURFACE_DOCKS, GUEST_SURFACE_DOCK_DEFAULT, GUEST_SURFACE_DOCK_SIZE_DEFAULT, GUEST_SURFACE_DOCK_SIZE_MAX, GUEST_SURFACE_DOCK_SIZE_MIN, GUEST_STATUS_SECTION_HEIGHT_DEFAULT, GUEST_STATUS_SECTION_HEIGHT_MAX, GUEST_STATUS_SECTION_HEIGHT_MIN, GUEST_STATUS_SECTION_TITLE_MAX, clampStatusSectionHeight, HOST_LINEAR_API_ORIGIN, isGuestFilesystemPattern, hasGuestCapability, hasGuestPage, isGuestApproved, isGuestPackageSvgIcon, requestedGuestCapabilities, resolveAttachEntry, resolvePageEntry, resolveStatusSectionEntry, resolveAttachMode, resolveIntegrationApi, resolveIntegrationAuth, serviceProvides, SOURCE_CONTROL_DEFAULT_INSTANCES_MAX, SOURCE_CONTROL_GUEST_ID_MAX, SOURCE_CONTROL_URL_TEMPLATES_MAX, SOURCE_CONTROL_URL_TEMPLATE_MAX, SOURCE_CONTROL_URL_TOKENS, sourceControlProviderIdOf, toPublicService, toPublicSourceControl, toPublicIntegration, } from './manifest.ts';
|
|
14
|
+
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, GUEST_ORIGINS_MAX, GUEST_SERVICE_PROVIDES, GUEST_SURFACE_DOCKS, GUEST_SURFACE_DOCK_DEFAULT, GUEST_SURFACE_DOCK_SIZE_DEFAULT, GUEST_SURFACE_DOCK_SIZE_MAX, GUEST_SURFACE_DOCK_SIZE_MIN, GUEST_STATUS_SECTION_HEIGHT_DEFAULT, GUEST_STATUS_SECTION_HEIGHT_MAX, GUEST_STATUS_SECTION_HEIGHT_MIN, GUEST_STATUS_SECTION_TITLE_MAX, clampStatusSectionHeight, HOST_LINEAR_API_ORIGIN, isGuestFilesystemPattern, hasGuestCapability, hasGuestPage, isGuestApproved, isGuestPackageSvgIcon, requestedGuestCapabilities, resolveAttachEntry, resolvePageEntry, resolveStatusSectionEntry, resolveStatusSectionSource, resolveAttachMode, resolveIntegrationApi, resolveIntegrationAuth, serviceProvides, SOURCE_CONTROL_DEFAULT_INSTANCES_MAX, SOURCE_CONTROL_GUEST_ID_MAX, SOURCE_CONTROL_URL_TEMPLATES_MAX, SOURCE_CONTROL_URL_TEMPLATE_MAX, SOURCE_CONTROL_URL_TOKENS, sourceControlProviderIdOf, toPublicService, toPublicSourceControl, toPublicIntegration, } from './manifest.ts';
|
|
13
15
|
export type { GuestServiceProvides, GuestSurfaceDock, 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, StatusSectionContribution, ParseManifestErrorCode, ParseManifestFailure, ParseManifestResult, ParseManifestSuccess, PublicService, PublicServicePermissions, PublicSourceControl, SourceControlCapabilities, SourceControlContribution, SourceControlMergeMethod, PublicGuestCapabilities, PublicIntegration, PublicIntegrationToken, PublicSocketBinding, ResolvedGuestApi, SocketBinding, SocketPlatform, } from './manifest.ts';
|
|
14
16
|
export { GUEST_FILE_EDITORS_MAX, GUEST_FILE_EDITOR_CONTENT_MAX, GUEST_FILE_EDITOR_PATTERNS_MAX, GUEST_FILE_EDITOR_PATTERN_MAX, GUEST_FILE_EDITOR_TITLE_MAX, GUEST_FILE_EDITOR_VERSION_MAX, createFileSaveTracker, fileEditorPayloadSize, isFileEditorPattern, matchesFileEditorPattern, } from './file-editor.ts';
|
|
15
17
|
export type { FileEditorChange, FileEditorContentKind, FileEditorContribution, FileEditorDocument, FileEditorSnapshot, FileSnapshotPurpose, FileSnapshotRequest, FileSnapshotResultPayload, } from './file-editor.ts';
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,9 @@ export { guestFramePolicy } from './frame-policy.js';
|
|
|
4
4
|
export { GUEST_STORAGE_KEY_MAX, GUEST_STORAGE_KEYS_MAX, GUEST_STORAGE_VALUE_BYTES, GUEST_STORAGE_TOTAL_BYTES, GUEST_DEVICE_STORAGE_TOTAL_BYTES } from './workspace.js';
|
|
5
5
|
export { GUEST_SHELL_END_STATUSES, GUEST_SHELL_ID_MAX, GUEST_SHELLS_MAX, GUEST_SHELL_OUTPUT_TAIL_MAX, } from './shells.js';
|
|
6
6
|
export { GUEST_STATUS_CONTROLS_MAX, GUEST_STATUS_CONTROL_ID, GUEST_STATUS_CONTROL_LABEL_MAX, GUEST_STATUS_CONTROL_OPTIONS_MAX, GUEST_STATUS_CONTROL_VALUE_MAX } from './status-controls.js';
|
|
7
|
+
export { GUEST_STATUS_SOURCE_INTERVAL_DEFAULT, GUEST_STATUS_SOURCE_INTERVAL_MAX, GUEST_STATUS_SOURCE_INTERVAL_MIN, GUEST_STATUS_VIEW_ACTIONS_MAX, GUEST_STATUS_VIEW_CHART_POINTS_MAX, GUEST_STATUS_VIEW_CHIPS_MAX, GUEST_STATUS_VIEW_ICON, GUEST_STATUS_VIEW_NOTE_MAX, GUEST_STATUS_VIEW_ROWS_MAX, GUEST_STATUS_VIEW_SEGMENTS_MAX, GUEST_STATUS_VIEW_SEGMENTS_MIN, GUEST_STATUS_VIEW_TEXT_MAX, } from './status-view.js';
|
|
7
8
|
export { compareOpenChamberVersions, hostMeetsOpenChamberEngine, openChamberEngineMinimum, OPENCHAMBER_ENGINE_PATTERN, parseOpenChamberVersion, } from './host-version.js';
|
|
8
|
-
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, GUEST_ORIGINS_MAX, GUEST_SERVICE_PROVIDES, GUEST_SURFACE_DOCKS, GUEST_SURFACE_DOCK_DEFAULT, GUEST_SURFACE_DOCK_SIZE_DEFAULT, GUEST_SURFACE_DOCK_SIZE_MAX, GUEST_SURFACE_DOCK_SIZE_MIN, GUEST_STATUS_SECTION_HEIGHT_DEFAULT, GUEST_STATUS_SECTION_HEIGHT_MAX, GUEST_STATUS_SECTION_HEIGHT_MIN, GUEST_STATUS_SECTION_TITLE_MAX, clampStatusSectionHeight, HOST_LINEAR_API_ORIGIN, isGuestFilesystemPattern, hasGuestCapability, hasGuestPage, isGuestApproved, isGuestPackageSvgIcon, requestedGuestCapabilities, resolveAttachEntry, resolvePageEntry, resolveStatusSectionEntry, resolveAttachMode, resolveIntegrationApi, resolveIntegrationAuth, serviceProvides, SOURCE_CONTROL_DEFAULT_INSTANCES_MAX, SOURCE_CONTROL_GUEST_ID_MAX, SOURCE_CONTROL_URL_TEMPLATES_MAX, SOURCE_CONTROL_URL_TEMPLATE_MAX, SOURCE_CONTROL_URL_TOKENS, sourceControlProviderIdOf, toPublicService, toPublicSourceControl, toPublicIntegration, } from './manifest.js';
|
|
9
|
+
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, GUEST_ORIGINS_MAX, GUEST_SERVICE_PROVIDES, GUEST_SURFACE_DOCKS, GUEST_SURFACE_DOCK_DEFAULT, GUEST_SURFACE_DOCK_SIZE_DEFAULT, GUEST_SURFACE_DOCK_SIZE_MAX, GUEST_SURFACE_DOCK_SIZE_MIN, GUEST_STATUS_SECTION_HEIGHT_DEFAULT, GUEST_STATUS_SECTION_HEIGHT_MAX, GUEST_STATUS_SECTION_HEIGHT_MIN, GUEST_STATUS_SECTION_TITLE_MAX, clampStatusSectionHeight, HOST_LINEAR_API_ORIGIN, isGuestFilesystemPattern, hasGuestCapability, hasGuestPage, isGuestApproved, isGuestPackageSvgIcon, requestedGuestCapabilities, resolveAttachEntry, resolvePageEntry, resolveStatusSectionEntry, resolveStatusSectionSource, resolveAttachMode, resolveIntegrationApi, resolveIntegrationAuth, serviceProvides, SOURCE_CONTROL_DEFAULT_INSTANCES_MAX, SOURCE_CONTROL_GUEST_ID_MAX, SOURCE_CONTROL_URL_TEMPLATES_MAX, SOURCE_CONTROL_URL_TEMPLATE_MAX, SOURCE_CONTROL_URL_TOKENS, sourceControlProviderIdOf, toPublicService, toPublicSourceControl, toPublicIntegration, } from './manifest.js';
|
|
9
10
|
export { GUEST_FILE_EDITORS_MAX, GUEST_FILE_EDITOR_CONTENT_MAX, GUEST_FILE_EDITOR_PATTERNS_MAX, GUEST_FILE_EDITOR_PATTERN_MAX, GUEST_FILE_EDITOR_TITLE_MAX, GUEST_FILE_EDITOR_VERSION_MAX, createFileSaveTracker, fileEditorPayloadSize, isFileEditorPattern, matchesFileEditorPattern, } from './file-editor.js';
|
|
10
11
|
export { connectHost, HostRequestError } from './host.js';
|
|
11
12
|
export { GUEST_POPOVER_COORDINATE_MAX, GUEST_POPOVER_DATA_DEPTH_MAX, GUEST_POPOVER_DATA_MAX, GUEST_POPOVER_HEIGHT_MAX, GUEST_POPOVER_HEIGHT_MIN, GUEST_POPOVER_ID, GUEST_POPOVER_SIDES, GUEST_POPOVER_WIDTH_MAX, GUEST_POPOVER_WIDTH_MIN, GUEST_POPOVER_CLOSE_REASONS, isGuestPopoverRequest, } from './popover.js';
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { OpenChamberManifestApiVersion } from './api-version.ts';
|
|
2
2
|
import type { FileEditorContribution } from './file-editor.ts';
|
|
3
|
+
import { type StatusSectionSource } from './status-view.ts';
|
|
3
4
|
export declare const PANEL_ID: RegExp;
|
|
4
5
|
/**
|
|
5
6
|
* The extension's identity on the rail, the Extensions card, and the approval
|
|
@@ -55,9 +56,15 @@ export type PageContribution = true | {
|
|
|
55
56
|
* this section and no rail panel. `title` replaces `panel.name` on the section
|
|
56
57
|
* header; `height` is the starting frame height in CSS px before the guest
|
|
57
58
|
* reports its own through `setHeight`.
|
|
59
|
+
*
|
|
60
|
+
* `source` makes the host draw the section itself from the service's answers
|
|
61
|
+
* (`status-view.ts`), without a frame. The object form needs `entry`,
|
|
62
|
+
* `source`, or both: a host that knows `source` uses it, an older one loads
|
|
63
|
+
* `entry`.
|
|
58
64
|
*/
|
|
59
65
|
export type StatusSectionContribution = true | {
|
|
60
|
-
entry
|
|
66
|
+
entry?: string;
|
|
67
|
+
source?: StatusSectionSource;
|
|
61
68
|
title?: string;
|
|
62
69
|
height?: number;
|
|
63
70
|
defaultExpanded?: boolean;
|
|
@@ -524,6 +531,8 @@ export declare const resolvePageEntry: (contributes: Pick<OpenChamberContributes
|
|
|
524
531
|
* has no panel page to reuse.
|
|
525
532
|
*/
|
|
526
533
|
export declare const resolveStatusSectionEntry: (contributes: Pick<OpenChamberContributes, 'panel' | 'statusSection'>) => string | null;
|
|
534
|
+
/** Where the host reads a source-backed section, with the interval resolved; `null` for a frame-only section. */
|
|
535
|
+
export declare const resolveStatusSectionSource: (contributes: Pick<OpenChamberContributes, 'statusSection'>) => Required<StatusSectionSource> | null;
|
|
527
536
|
/** Clamp a requested status section height to what the host allows. */
|
|
528
537
|
export declare const clampStatusSectionHeight: (height: number) => number;
|
|
529
538
|
export type OpenChamberEngines = {
|
package/dist/manifest.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GUEST_STATUS_SOURCE_INTERVAL_DEFAULT } from './status-view.js';
|
|
1
2
|
export const PANEL_ID = /^[a-z][a-z0-9-]*$/;
|
|
2
3
|
export const GUEST_SURFACE_DOCKS = ['top', 'bottom', 'left', 'right'];
|
|
3
4
|
export const GUEST_SURFACE_DOCK_DEFAULT = 'top';
|
|
@@ -213,7 +214,14 @@ export const resolveStatusSectionEntry = (contributes) => {
|
|
|
213
214
|
const section = contributes.statusSection;
|
|
214
215
|
if (!section)
|
|
215
216
|
return null;
|
|
216
|
-
return section === true ? contributes.panel.entry ?? null : section.entry;
|
|
217
|
+
return section === true ? contributes.panel.entry ?? null : section.entry ?? null;
|
|
218
|
+
};
|
|
219
|
+
/** Where the host reads a source-backed section, with the interval resolved; `null` for a frame-only section. */
|
|
220
|
+
export const resolveStatusSectionSource = (contributes) => {
|
|
221
|
+
const section = contributes.statusSection;
|
|
222
|
+
if (!section || section === true || !section.source)
|
|
223
|
+
return null;
|
|
224
|
+
return { path: section.source.path, interval: section.source.interval ?? GUEST_STATUS_SOURCE_INTERVAL_DEFAULT };
|
|
217
225
|
};
|
|
218
226
|
/** Clamp a requested status section height to what the host allows. */
|
|
219
227
|
export const clampStatusSectionHeight = (height) => {
|
package/dist/parse.d.ts
CHANGED
|
@@ -37,7 +37,11 @@ export declare const openChamberManifestSchema: z.ZodObject<{
|
|
|
37
37
|
title: z.ZodOptional<z.ZodString>;
|
|
38
38
|
}, z.core.$strip>]>>;
|
|
39
39
|
statusSection: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
40
|
-
entry: z.ZodString
|
|
40
|
+
entry: z.ZodOptional<z.ZodString>;
|
|
41
|
+
source: z.ZodOptional<z.ZodObject<{
|
|
42
|
+
path: z.ZodString;
|
|
43
|
+
interval: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
}, z.core.$strict>>;
|
|
41
45
|
title: z.ZodOptional<z.ZodString>;
|
|
42
46
|
height: z.ZodOptional<z.ZodNumber>;
|
|
43
47
|
defaultExpanded: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -322,7 +326,11 @@ export declare const packageManifestSchema: z.ZodObject<{
|
|
|
322
326
|
title: z.ZodOptional<z.ZodString>;
|
|
323
327
|
}, z.core.$strip>]>>;
|
|
324
328
|
statusSection: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
325
|
-
entry: z.ZodString
|
|
329
|
+
entry: z.ZodOptional<z.ZodString>;
|
|
330
|
+
source: z.ZodOptional<z.ZodObject<{
|
|
331
|
+
path: z.ZodString;
|
|
332
|
+
interval: z.ZodOptional<z.ZodNumber>;
|
|
333
|
+
}, z.core.$strict>>;
|
|
326
334
|
title: z.ZodOptional<z.ZodString>;
|
|
327
335
|
height: z.ZodOptional<z.ZodNumber>;
|
|
328
336
|
defaultExpanded: z.ZodOptional<z.ZodBoolean>;
|
package/dist/parse.js
CHANGED
|
@@ -2,6 +2,8 @@ import { z } from 'zod';
|
|
|
2
2
|
import { OPENCHAMBER_SDK_MANIFEST_API_VERSIONS } from './api-version.js';
|
|
3
3
|
import { OPENCHAMBER_ENGINE_PATTERN } from './host-version.js';
|
|
4
4
|
import { DECLARED_GUEST_CAPABILITIES, GUEST_ACTIONS_MAX, GUEST_ACTION_LABEL_MAX, GUEST_COMMANDS_MAX, GUEST_COMMAND_DESCRIPTION_MAX, GUEST_COMMAND_NAME, GUEST_FILESYSTEM_PATTERNS_MAX, GUEST_FILESYSTEM_PATTERN_MAX, GUEST_ORIGINS_MAX, GUEST_SERVICE_PROVIDES, 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, PANEL_ID, hasGuestPage, isGuestFilesystemPattern, isGuestPackageSvgIcon, isSafeAssetPath, resolveIntegrationAuth, GUEST_SURFACE_DOCKS, GUEST_SURFACE_DOCK_SIZE_MAX, GUEST_SURFACE_DOCK_SIZE_MIN, GUEST_STATUS_SECTION_HEIGHT_MAX, GUEST_STATUS_SECTION_HEIGHT_MIN, GUEST_STATUS_SECTION_TITLE_MAX, SOURCE_CONTROL_DEFAULT_INSTANCES_MAX, SOURCE_CONTROL_GUEST_ID_MAX, SOURCE_CONTROL_URL_TEMPLATES_MAX, SOURCE_CONTROL_URL_TEMPLATE_MAX, SOURCE_CONTROL_URL_TOKENS, } from './manifest.js';
|
|
5
|
+
import { isGuestRequestPath } from './contract.js';
|
|
6
|
+
import { GUEST_STATUS_SOURCE_INTERVAL_MAX, GUEST_STATUS_SOURCE_INTERVAL_MIN } from './status-view.js';
|
|
5
7
|
import { GUEST_FILE_EDITORS_MAX, GUEST_FILE_EDITOR_PATTERNS_MAX, GUEST_FILE_EDITOR_TITLE_MAX, isFileEditorPattern, } from './file-editor.js';
|
|
6
8
|
const isPanelIcon = (value) => (PANEL_ID.test(value) || isGuestPackageSvgIcon(value));
|
|
7
9
|
const isHttpsUrl = (value) => {
|
|
@@ -354,12 +356,16 @@ const contributesSchema = z.object({
|
|
|
354
356
|
title: z.string().trim().min(1).max(200).optional(),
|
|
355
357
|
})]).optional(),
|
|
356
358
|
statusSection: z.union([z.literal(true), z.object({
|
|
357
|
-
entry: z.string().trim().refine((value) => isSafeAssetPath(value) && value.toLowerCase().endsWith('.html')),
|
|
359
|
+
entry: z.string().trim().refine((value) => isSafeAssetPath(value) && value.toLowerCase().endsWith('.html')).optional(),
|
|
360
|
+
source: z.object({
|
|
361
|
+
path: z.string().trim().refine(isGuestRequestPath),
|
|
362
|
+
interval: z.number().int().min(GUEST_STATUS_SOURCE_INTERVAL_MIN).max(GUEST_STATUS_SOURCE_INTERVAL_MAX).optional(),
|
|
363
|
+
}).strict().optional(),
|
|
358
364
|
title: z.string().trim().min(1).max(GUEST_STATUS_SECTION_TITLE_MAX).optional(),
|
|
359
365
|
height: z.number().int().min(GUEST_STATUS_SECTION_HEIGHT_MIN).max(GUEST_STATUS_SECTION_HEIGHT_MAX).optional(),
|
|
360
366
|
defaultExpanded: z.boolean().optional(),
|
|
361
367
|
requiresProject: z.boolean().optional(),
|
|
362
|
-
})]).optional(),
|
|
368
|
+
}).refine((section) => section.entry !== undefined || section.source !== undefined)]).optional(),
|
|
363
369
|
capabilities: z.array(z.enum(DECLARED_GUEST_CAPABILITIES)).max(8).optional(),
|
|
364
370
|
integration: integrationSchema.optional(),
|
|
365
371
|
service: serviceSchema.optional(),
|
|
@@ -376,6 +382,10 @@ const contributesSchema = z.object({
|
|
|
376
382
|
/**
|
|
377
383
|
* Contributions that need either the panel or background execution frame.
|
|
378
384
|
*/
|
|
385
|
+
/** A section the host draws from the service's answers: the host is the service's caller. */
|
|
386
|
+
const hasStatusSource = (contributes) => (Boolean(contributes.statusSection && contributes.statusSection !== true && contributes.statusSection.source));
|
|
387
|
+
/** A section the host loads as a frame: `true`, or an object with an `entry`. */
|
|
388
|
+
const hasStatusFrame = (contributes) => (contributes.statusSection === true || Boolean(contributes.statusSection?.entry));
|
|
379
389
|
const runtimeContributions = (contributes) => {
|
|
380
390
|
const declared = [];
|
|
381
391
|
if (contributes.page !== undefined)
|
|
@@ -389,7 +399,8 @@ const runtimeContributions = (contributes) => {
|
|
|
389
399
|
// A service the host starts itself (it provides a role or a surface) needs
|
|
390
400
|
// no frame; one that only answers a panel's `serviceRequest` has no caller
|
|
391
401
|
// without one.
|
|
392
|
-
if (contributes.service !== undefined && !contributes.service.provides?.length && !contributes.service.surface
|
|
402
|
+
if (contributes.service !== undefined && !contributes.service.provides?.length && !contributes.service.surface
|
|
403
|
+
&& !hasStatusSource(contributes))
|
|
393
404
|
declared.push('service');
|
|
394
405
|
if (contributes.filesystem !== undefined)
|
|
395
406
|
declared.push('filesystem');
|
|
@@ -441,6 +452,14 @@ export const openChamberManifestSchema = z.object({
|
|
|
441
452
|
});
|
|
442
453
|
return;
|
|
443
454
|
}
|
|
455
|
+
// The host reads a source from the extension's service; without one it has nothing to ask.
|
|
456
|
+
if (hasStatusSource(contributes) && !contributes.service) {
|
|
457
|
+
ctx.addIssue({
|
|
458
|
+
code: 'custom', path: ['statusSection', 'source'],
|
|
459
|
+
message: 'contributes.statusSection.source is read from the extension\'s service; declare contributes.service.',
|
|
460
|
+
});
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
444
463
|
if (hasGuestPage(contributes))
|
|
445
464
|
return;
|
|
446
465
|
if (contributes.background) {
|
|
@@ -458,7 +477,7 @@ export const openChamberManifestSchema = z.object({
|
|
|
458
477
|
});
|
|
459
478
|
return;
|
|
460
479
|
}
|
|
461
|
-
if (contributes
|
|
480
|
+
if (hasStatusFrame(contributes) || contributes.fileEditors) {
|
|
462
481
|
// A status section or file editor frame runs code and may use what the
|
|
463
482
|
// package is granted, but it only hosts itself: things the host opens or
|
|
464
483
|
// invokes elsewhere need a panel or background entry.
|
|
@@ -558,7 +577,7 @@ const failureFromIssue = (issue) => {
|
|
|
558
577
|
if (path === 'contributes.statusSection' || path.startsWith('contributes.statusSection.')) {
|
|
559
578
|
return fail('invalid-status-section', issue.code === 'custom'
|
|
560
579
|
? issue.message
|
|
561
|
-
: `contributes.statusSection must be true or { entry
|
|
580
|
+
: `contributes.statusSection must be true or { entry?: "<package .html>", source?: { path: "/status", interval?: ${GUEST_STATUS_SOURCE_INTERVAL_MIN} to ${GUEST_STATUS_SOURCE_INTERVAL_MAX} }, title?: "1 to ${GUEST_STATUS_SECTION_TITLE_MAX} characters", height?: ${GUEST_STATUS_SECTION_HEIGHT_MIN} to ${GUEST_STATUS_SECTION_HEIGHT_MAX} } with entry, source, or both.`);
|
|
562
581
|
}
|
|
563
582
|
if (path === 'contributes.background' || path.startsWith('contributes.background.')) {
|
|
564
583
|
return fail('invalid-background', 'contributes.background needs an entry ending in .html inside the package.');
|
package/dist/protocol.d.ts
CHANGED
|
@@ -89,6 +89,15 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
89
89
|
id: z.ZodString;
|
|
90
90
|
data: z.ZodOptional<z.ZodJSONSchema>;
|
|
91
91
|
}, z.core.$strip>>;
|
|
92
|
+
links: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
93
|
+
title: z.ZodString;
|
|
94
|
+
url: z.ZodString;
|
|
95
|
+
kind: z.ZodEnum<{
|
|
96
|
+
change: "change";
|
|
97
|
+
issue: "issue";
|
|
98
|
+
}>;
|
|
99
|
+
linkedAt: z.ZodNumber;
|
|
100
|
+
}, z.core.$strip>>>;
|
|
92
101
|
}, z.core.$strip>>;
|
|
93
102
|
}, z.core.$strip>], "kind">;
|
|
94
103
|
}, z.core.$strip>;
|
|
@@ -503,6 +512,15 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
503
512
|
id: z.ZodString;
|
|
504
513
|
data: z.ZodOptional<z.ZodJSONSchema>;
|
|
505
514
|
}, z.core.$strip>>;
|
|
515
|
+
links: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
516
|
+
title: z.ZodString;
|
|
517
|
+
url: z.ZodString;
|
|
518
|
+
kind: z.ZodEnum<{
|
|
519
|
+
change: "change";
|
|
520
|
+
issue: "issue";
|
|
521
|
+
}>;
|
|
522
|
+
linkedAt: z.ZodNumber;
|
|
523
|
+
}, z.core.$strip>>>;
|
|
506
524
|
}, z.core.$strip>>;
|
|
507
525
|
}, z.core.$strip>], "kind">, z.ZodObject<{
|
|
508
526
|
output: z.ZodString;
|
|
@@ -645,6 +663,12 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
645
663
|
id: string;
|
|
646
664
|
data?: z.util.JSONType | undefined;
|
|
647
665
|
}[];
|
|
666
|
+
links?: {
|
|
667
|
+
title: string;
|
|
668
|
+
url: string;
|
|
669
|
+
kind: "change" | "issue";
|
|
670
|
+
linkedAt: number;
|
|
671
|
+
}[] | undefined;
|
|
648
672
|
}[];
|
|
649
673
|
} | {
|
|
650
674
|
status: number;
|
|
@@ -788,6 +812,12 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
788
812
|
id: string;
|
|
789
813
|
data?: z.util.JSONType | undefined;
|
|
790
814
|
}[];
|
|
815
|
+
links?: {
|
|
816
|
+
title: string;
|
|
817
|
+
url: string;
|
|
818
|
+
kind: "change" | "issue";
|
|
819
|
+
linkedAt: number;
|
|
820
|
+
}[] | undefined;
|
|
791
821
|
}[];
|
|
792
822
|
} | {
|
|
793
823
|
status: number;
|
package/dist/schemas.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { openChamberManifestSchema, PACKAGE_VERSION_PATTERN, packageManifestSche
|
|
|
2
2
|
export type { ManifestDocument } from './parse.ts';
|
|
3
3
|
export { guestStorageRequestSchema, guestStorageResultSchema, guestWorkspaceSnapshotSchema } from './workspace-schemas.ts';
|
|
4
4
|
export { guestStatusControlsSchema, guestStatusControlEventSchema } from './status-control-schemas.ts';
|
|
5
|
+
export { guestStatusViewSchema } from './status-view-schemas.ts';
|
|
5
6
|
export { guestPopoverClosedEventSchema, guestPopoverRequestSchema } from './popover-schemas.ts';
|
|
6
7
|
export { guestMessageSchema, hostMessageSchema, parseGuestMessage, parseHostMessage, } from './protocol.ts';
|
|
7
8
|
export { browserControlActionSchema, browserProviderResultSchema, sourceControlProviderMethodSchema, sourceControlProviderSchemasV1, } from './service-provider-schemas.ts';
|
package/dist/schemas.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export { openChamberManifestSchema, PACKAGE_VERSION_PATTERN, packageManifestSchema, parseManifest, parseManifestJson, } from './parse.js';
|
|
5
5
|
export { guestStorageRequestSchema, guestStorageResultSchema, guestWorkspaceSnapshotSchema } from './workspace-schemas.js';
|
|
6
6
|
export { guestStatusControlsSchema, guestStatusControlEventSchema } from './status-control-schemas.js';
|
|
7
|
+
export { guestStatusViewSchema } from './status-view-schemas.js';
|
|
7
8
|
export { guestPopoverClosedEventSchema, guestPopoverRequestSchema } from './popover-schemas.js';
|
|
8
9
|
export { guestMessageSchema, hostMessageSchema, parseGuestMessage, parseHostMessage, } from './protocol.js';
|
|
9
10
|
export { browserControlActionSchema, browserProviderResultSchema, sourceControlProviderMethodSchema, sourceControlProviderSchemasV1, } from './service-provider-schemas.js';
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** A service's answer to `GET <source.path>`. Row ids and control ids are each unique. */
|
|
3
|
+
export declare const guestStatusViewSchema: z.ZodObject<{
|
|
4
|
+
rows: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
5
|
+
kind: z.ZodLiteral<"line">;
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
label: z.ZodString;
|
|
8
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
9
|
+
dot: z.ZodOptional<z.ZodEnum<{
|
|
10
|
+
accent: "accent";
|
|
11
|
+
default: "default";
|
|
12
|
+
error: "error";
|
|
13
|
+
info: "info";
|
|
14
|
+
muted: "muted";
|
|
15
|
+
success: "success";
|
|
16
|
+
warning: "warning";
|
|
17
|
+
}>>;
|
|
18
|
+
content: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
19
|
+
kind: z.ZodLiteral<"bar">;
|
|
20
|
+
value: z.ZodNumber;
|
|
21
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
22
|
+
accent: "accent";
|
|
23
|
+
default: "default";
|
|
24
|
+
error: "error";
|
|
25
|
+
info: "info";
|
|
26
|
+
muted: "muted";
|
|
27
|
+
success: "success";
|
|
28
|
+
warning: "warning";
|
|
29
|
+
}>>;
|
|
30
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
31
|
+
kind: z.ZodLiteral<"chart">;
|
|
32
|
+
values: z.ZodArray<z.ZodNumber>;
|
|
33
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
35
|
+
accent: "accent";
|
|
36
|
+
default: "default";
|
|
37
|
+
error: "error";
|
|
38
|
+
info: "info";
|
|
39
|
+
muted: "muted";
|
|
40
|
+
success: "success";
|
|
41
|
+
warning: "warning";
|
|
42
|
+
}>>;
|
|
43
|
+
unit: z.ZodOptional<z.ZodEnum<{
|
|
44
|
+
bytes: "bytes";
|
|
45
|
+
count: "count";
|
|
46
|
+
percent: "percent";
|
|
47
|
+
}>>;
|
|
48
|
+
step: z.ZodOptional<z.ZodNumber>;
|
|
49
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
50
|
+
kind: z.ZodLiteral<"chips">;
|
|
51
|
+
chips: z.ZodArray<z.ZodObject<{
|
|
52
|
+
id: z.ZodString;
|
|
53
|
+
label: z.ZodString;
|
|
54
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
55
|
+
accent: "accent";
|
|
56
|
+
default: "default";
|
|
57
|
+
error: "error";
|
|
58
|
+
info: "info";
|
|
59
|
+
muted: "muted";
|
|
60
|
+
success: "success";
|
|
61
|
+
warning: "warning";
|
|
62
|
+
}>>;
|
|
63
|
+
url: z.ZodOptional<z.ZodString>;
|
|
64
|
+
}, z.core.$strict>>;
|
|
65
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
66
|
+
kind: z.ZodLiteral<"text">;
|
|
67
|
+
text: z.ZodString;
|
|
68
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
69
|
+
accent: "accent";
|
|
70
|
+
default: "default";
|
|
71
|
+
error: "error";
|
|
72
|
+
info: "info";
|
|
73
|
+
muted: "muted";
|
|
74
|
+
success: "success";
|
|
75
|
+
warning: "warning";
|
|
76
|
+
}>>;
|
|
77
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
78
|
+
kind: z.ZodLiteral<"segmented">;
|
|
79
|
+
id: z.ZodString;
|
|
80
|
+
label: z.ZodString;
|
|
81
|
+
value: z.ZodString;
|
|
82
|
+
options: z.ZodArray<z.ZodObject<{
|
|
83
|
+
value: z.ZodString;
|
|
84
|
+
label: z.ZodString;
|
|
85
|
+
}, z.core.$strict>>;
|
|
86
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
87
|
+
}, z.core.$strict>]>>;
|
|
88
|
+
value: z.ZodOptional<z.ZodString>;
|
|
89
|
+
valueTone: z.ZodOptional<z.ZodEnum<{
|
|
90
|
+
accent: "accent";
|
|
91
|
+
default: "default";
|
|
92
|
+
error: "error";
|
|
93
|
+
info: "info";
|
|
94
|
+
muted: "muted";
|
|
95
|
+
success: "success";
|
|
96
|
+
warning: "warning";
|
|
97
|
+
}>>;
|
|
98
|
+
badge: z.ZodOptional<z.ZodObject<{
|
|
99
|
+
label: z.ZodString;
|
|
100
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
101
|
+
accent: "accent";
|
|
102
|
+
default: "default";
|
|
103
|
+
error: "error";
|
|
104
|
+
info: "info";
|
|
105
|
+
muted: "muted";
|
|
106
|
+
success: "success";
|
|
107
|
+
warning: "warning";
|
|
108
|
+
}>>;
|
|
109
|
+
}, z.core.$strict>>;
|
|
110
|
+
tooltip: z.ZodOptional<z.ZodString>;
|
|
111
|
+
actions: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
112
|
+
kind: z.ZodLiteral<"button">;
|
|
113
|
+
id: z.ZodString;
|
|
114
|
+
label: z.ZodString;
|
|
115
|
+
variant: z.ZodOptional<z.ZodEnum<{
|
|
116
|
+
default: "default";
|
|
117
|
+
destructive: "destructive";
|
|
118
|
+
outline: "outline";
|
|
119
|
+
}>>;
|
|
120
|
+
confirm: z.ZodOptional<z.ZodString>;
|
|
121
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
122
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
123
|
+
kind: z.ZodLiteral<"switch">;
|
|
124
|
+
id: z.ZodString;
|
|
125
|
+
label: z.ZodString;
|
|
126
|
+
checked: z.ZodBoolean;
|
|
127
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
128
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
129
|
+
kind: z.ZodLiteral<"select">;
|
|
130
|
+
id: z.ZodString;
|
|
131
|
+
label: z.ZodString;
|
|
132
|
+
value: z.ZodString;
|
|
133
|
+
options: z.ZodArray<z.ZodObject<{
|
|
134
|
+
value: z.ZodString;
|
|
135
|
+
label: z.ZodString;
|
|
136
|
+
}, z.core.$strict>>;
|
|
137
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
138
|
+
}, z.core.$strict>]>>>;
|
|
139
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
140
|
+
kind: z.ZodLiteral<"note">;
|
|
141
|
+
id: z.ZodString;
|
|
142
|
+
text: z.ZodString;
|
|
143
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
144
|
+
error: "error";
|
|
145
|
+
info: "info";
|
|
146
|
+
muted: "muted";
|
|
147
|
+
warning: "warning";
|
|
148
|
+
}>>;
|
|
149
|
+
}, z.core.$strict>]>>;
|
|
150
|
+
controls: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
151
|
+
kind: z.ZodLiteral<"button">;
|
|
152
|
+
id: z.ZodString;
|
|
153
|
+
label: z.ZodString;
|
|
154
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
155
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
156
|
+
kind: z.ZodLiteral<"select">;
|
|
157
|
+
id: z.ZodString;
|
|
158
|
+
label: z.ZodString;
|
|
159
|
+
value: z.ZodString;
|
|
160
|
+
options: z.ZodArray<z.ZodObject<{
|
|
161
|
+
value: z.ZodString;
|
|
162
|
+
label: z.ZodString;
|
|
163
|
+
}, z.core.$strict>>;
|
|
164
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
165
|
+
}, z.core.$strict>], "kind">>>;
|
|
166
|
+
}, z.core.$strict>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { guestStatusControlsSchema } from './status-control-schemas.js';
|
|
3
|
+
import { GUEST_STATUS_CONTROL_ID, GUEST_STATUS_CONTROL_LABEL_MAX, GUEST_STATUS_CONTROL_OPTIONS_MAX, GUEST_STATUS_CONTROL_VALUE_MAX, } from './status-controls.js';
|
|
4
|
+
import { GUEST_STATUS_VIEW_ACTIONS_MAX, GUEST_STATUS_VIEW_CHART_POINTS_MAX, GUEST_STATUS_VIEW_CHIPS_MAX, GUEST_STATUS_VIEW_ICON, GUEST_STATUS_VIEW_NOTE_MAX, GUEST_STATUS_VIEW_ROWS_MAX, GUEST_STATUS_VIEW_SEGMENTS_MAX, GUEST_STATUS_VIEW_SEGMENTS_MIN, GUEST_STATUS_VIEW_TEXT_MAX, } from './status-view.js';
|
|
5
|
+
const idSchema = z.string().regex(GUEST_STATUS_CONTROL_ID);
|
|
6
|
+
const labelSchema = z.string().min(1).max(GUEST_STATUS_CONTROL_LABEL_MAX);
|
|
7
|
+
const valueSchema = z.string().min(1).max(GUEST_STATUS_CONTROL_VALUE_MAX);
|
|
8
|
+
const textSchema = z.string().min(1).max(GUEST_STATUS_VIEW_TEXT_MAX);
|
|
9
|
+
const toneSchema = z.enum(['default', 'muted', 'accent', 'success', 'warning', 'error', 'info']);
|
|
10
|
+
const finite = z.number().finite();
|
|
11
|
+
const isWebUrl = (value) => {
|
|
12
|
+
try {
|
|
13
|
+
const url = new URL(value);
|
|
14
|
+
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const optionSchema = z.object({ value: valueSchema, label: labelSchema }).strict();
|
|
21
|
+
/** One to `max` options with unique values, and `value` among them. */
|
|
22
|
+
const choiceSchema = (kind, min, max) => z.object({
|
|
23
|
+
kind: z.literal(kind),
|
|
24
|
+
id: idSchema,
|
|
25
|
+
label: labelSchema,
|
|
26
|
+
value: valueSchema,
|
|
27
|
+
options: z.array(optionSchema).min(min).max(max),
|
|
28
|
+
disabled: z.boolean().optional(),
|
|
29
|
+
}).strict().refine((choice) => new Set(choice.options.map((option) => option.value)).size === choice.options.length, { message: 'option values must be unique', path: ['options'] }).refine((choice) => choice.options.some((option) => option.value === choice.value), { message: 'value must be one of its options', path: ['value'] });
|
|
30
|
+
const chipSchema = z.object({
|
|
31
|
+
id: idSchema,
|
|
32
|
+
label: labelSchema,
|
|
33
|
+
tone: toneSchema.optional(),
|
|
34
|
+
url: z.string().max(2_000).refine(isWebUrl, { message: 'chip url must be http(s)' }).optional(),
|
|
35
|
+
}).strict();
|
|
36
|
+
const contentSchema = z.union([
|
|
37
|
+
z.object({ kind: z.literal('bar'), value: finite.min(0).max(100), tone: toneSchema.optional() }).strict(),
|
|
38
|
+
z.object({
|
|
39
|
+
kind: z.literal('chart'),
|
|
40
|
+
values: z.array(finite.min(0)).max(GUEST_STATUS_VIEW_CHART_POINTS_MAX),
|
|
41
|
+
max: finite.positive().optional(),
|
|
42
|
+
tone: toneSchema.optional(),
|
|
43
|
+
unit: z.enum(['bytes', 'percent', 'count']).optional(),
|
|
44
|
+
step: finite.positive().max(3_600).optional(),
|
|
45
|
+
}).strict(),
|
|
46
|
+
z.object({
|
|
47
|
+
kind: z.literal('chips'),
|
|
48
|
+
chips: z.array(chipSchema).min(1).max(GUEST_STATUS_VIEW_CHIPS_MAX),
|
|
49
|
+
}).strict(),
|
|
50
|
+
z.object({ kind: z.literal('text'), text: textSchema, tone: toneSchema.optional() }).strict(),
|
|
51
|
+
choiceSchema('segmented', GUEST_STATUS_VIEW_SEGMENTS_MIN, GUEST_STATUS_VIEW_SEGMENTS_MAX),
|
|
52
|
+
]);
|
|
53
|
+
const actionSchema = z.union([
|
|
54
|
+
z.object({
|
|
55
|
+
kind: z.literal('button'),
|
|
56
|
+
id: idSchema,
|
|
57
|
+
label: labelSchema,
|
|
58
|
+
variant: z.enum(['default', 'outline', 'destructive']).optional(),
|
|
59
|
+
confirm: labelSchema.optional(),
|
|
60
|
+
disabled: z.boolean().optional(),
|
|
61
|
+
}).strict(),
|
|
62
|
+
z.object({
|
|
63
|
+
kind: z.literal('switch'),
|
|
64
|
+
id: idSchema,
|
|
65
|
+
label: labelSchema,
|
|
66
|
+
checked: z.boolean(),
|
|
67
|
+
disabled: z.boolean().optional(),
|
|
68
|
+
}).strict(),
|
|
69
|
+
choiceSchema('select', 1, GUEST_STATUS_CONTROL_OPTIONS_MAX),
|
|
70
|
+
]);
|
|
71
|
+
const rowSchema = z.union([
|
|
72
|
+
z.object({
|
|
73
|
+
kind: z.literal('line'),
|
|
74
|
+
id: idSchema,
|
|
75
|
+
label: labelSchema,
|
|
76
|
+
icon: z.string().regex(GUEST_STATUS_VIEW_ICON).optional(),
|
|
77
|
+
dot: toneSchema.optional(),
|
|
78
|
+
content: contentSchema.optional(),
|
|
79
|
+
value: valueSchema.optional(),
|
|
80
|
+
valueTone: toneSchema.optional(),
|
|
81
|
+
badge: z.object({ label: labelSchema, tone: toneSchema.optional() }).strict().optional(),
|
|
82
|
+
tooltip: textSchema.optional(),
|
|
83
|
+
actions: z.array(actionSchema).max(GUEST_STATUS_VIEW_ACTIONS_MAX).optional(),
|
|
84
|
+
}).strict(),
|
|
85
|
+
z.object({
|
|
86
|
+
kind: z.literal('note'),
|
|
87
|
+
id: idSchema,
|
|
88
|
+
text: z.string().min(1).max(GUEST_STATUS_VIEW_NOTE_MAX),
|
|
89
|
+
tone: z.enum(['muted', 'info', 'warning', 'error']).optional(),
|
|
90
|
+
}).strict(),
|
|
91
|
+
]);
|
|
92
|
+
/** Every id a view's controls answer to: header controls, line actions, segmented choices. */
|
|
93
|
+
const controlIds = (view) => [
|
|
94
|
+
...(view.controls ?? []).map((control) => control.id),
|
|
95
|
+
...view.rows.flatMap((row) => (row.kind === 'line'
|
|
96
|
+
? [
|
|
97
|
+
...(row.actions ?? []).map((action) => action.id),
|
|
98
|
+
...(row.content?.kind === 'segmented' ? [row.content.id] : []),
|
|
99
|
+
]
|
|
100
|
+
: [])),
|
|
101
|
+
];
|
|
102
|
+
/** A service's answer to `GET <source.path>`. Row ids and control ids are each unique. */
|
|
103
|
+
export const guestStatusViewSchema = z.object({
|
|
104
|
+
rows: z.array(rowSchema).max(GUEST_STATUS_VIEW_ROWS_MAX),
|
|
105
|
+
controls: guestStatusControlsSchema.optional(),
|
|
106
|
+
}).strict().refine((view) => new Set(view.rows.map((row) => row.id)).size === view.rows.length, { message: 'row ids must be unique', path: ['rows'] }).refine((view) => {
|
|
107
|
+
const ids = controlIds(view);
|
|
108
|
+
return new Set(ids).size === ids.length;
|
|
109
|
+
}, { message: 'control ids must be unique across the view' });
|
|
110
|
+
const assertViewParsed = (value) => value;
|
|
111
|
+
const assertViewContract = (value) => value;
|
|
112
|
+
void assertViewParsed;
|
|
113
|
+
void assertViewContract;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { GuestStatusControl, GuestStatusControlOption } from './status-controls.ts';
|
|
2
|
+
/** Fastest the host asks a service for its section, in ms. */
|
|
3
|
+
export declare const GUEST_STATUS_SOURCE_INTERVAL_MIN = 1000;
|
|
4
|
+
/** Slowest polling a source may ask for, in ms. */
|
|
5
|
+
export declare const GUEST_STATUS_SOURCE_INTERVAL_MAX = 60000;
|
|
6
|
+
/** Polling interval when the manifest names none, in ms. */
|
|
7
|
+
export declare const GUEST_STATUS_SOURCE_INTERVAL_DEFAULT = 2000;
|
|
8
|
+
export declare const GUEST_STATUS_VIEW_ROWS_MAX = 16;
|
|
9
|
+
export declare const GUEST_STATUS_VIEW_ACTIONS_MAX = 2;
|
|
10
|
+
export declare const GUEST_STATUS_VIEW_CHIPS_MAX = 6;
|
|
11
|
+
export declare const GUEST_STATUS_VIEW_CHART_POINTS_MAX = 120;
|
|
12
|
+
export declare const GUEST_STATUS_VIEW_SEGMENTS_MIN = 2;
|
|
13
|
+
export declare const GUEST_STATUS_VIEW_SEGMENTS_MAX = 4;
|
|
14
|
+
export declare const GUEST_STATUS_VIEW_TEXT_MAX = 200;
|
|
15
|
+
export declare const GUEST_STATUS_VIEW_NOTE_MAX = 300;
|
|
16
|
+
export declare const GUEST_STATUS_VIEW_ICON: RegExp;
|
|
17
|
+
/** Where the host reads a source-backed section and how often. */
|
|
18
|
+
export type StatusSectionSource = {
|
|
19
|
+
/** Service path, such as `/status`. */
|
|
20
|
+
path: string;
|
|
21
|
+
/** Milliseconds between reads while the section is on screen. */
|
|
22
|
+
interval?: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Colours come from the theme, never from the extension: `accent` is the
|
|
26
|
+
* theme's primary, the status tones are its status colours, `muted` is
|
|
27
|
+
* secondary text.
|
|
28
|
+
*/
|
|
29
|
+
export type GuestStatusTone = 'default' | 'muted' | 'accent' | 'success' | 'warning' | 'error' | 'info';
|
|
30
|
+
/** How a chart's hover label formats a point. */
|
|
31
|
+
export type GuestStatusChartUnit = 'bytes' | 'percent' | 'count';
|
|
32
|
+
export type GuestStatusChip = {
|
|
33
|
+
id: string;
|
|
34
|
+
label: string;
|
|
35
|
+
tone?: GuestStatusTone;
|
|
36
|
+
/** An `http(s)` URL the chip opens; without one the chip is a label. */
|
|
37
|
+
url?: string;
|
|
38
|
+
};
|
|
39
|
+
/** What sits between a line's label and its value. */
|
|
40
|
+
export type GuestStatusContent = {
|
|
41
|
+
kind: 'bar';
|
|
42
|
+
value: number;
|
|
43
|
+
tone?: GuestStatusTone;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'chart';
|
|
46
|
+
/** Oldest first; the newest point sits at the right edge. */
|
|
47
|
+
values: number[];
|
|
48
|
+
/** Top of the chart; the largest value when omitted. */
|
|
49
|
+
max?: number;
|
|
50
|
+
tone?: GuestStatusTone;
|
|
51
|
+
unit?: GuestStatusChartUnit;
|
|
52
|
+
/** Seconds between points, for the hover's "12 s ago". */
|
|
53
|
+
step?: number;
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'chips';
|
|
56
|
+
chips: GuestStatusChip[];
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'text';
|
|
59
|
+
text: string;
|
|
60
|
+
tone?: GuestStatusTone;
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'segmented';
|
|
63
|
+
id: string;
|
|
64
|
+
label: string;
|
|
65
|
+
value: string;
|
|
66
|
+
options: GuestStatusControlOption[];
|
|
67
|
+
disabled?: boolean;
|
|
68
|
+
};
|
|
69
|
+
/** A control at the end of a line. Activating it posts `{ id, value? }` to the source path. */
|
|
70
|
+
export type GuestStatusAction = {
|
|
71
|
+
kind: 'button';
|
|
72
|
+
id: string;
|
|
73
|
+
label: string;
|
|
74
|
+
variant?: 'default' | 'outline' | 'destructive';
|
|
75
|
+
/** Asked on the first click; the second click acts. */
|
|
76
|
+
confirm?: string;
|
|
77
|
+
disabled?: boolean;
|
|
78
|
+
} | {
|
|
79
|
+
kind: 'switch';
|
|
80
|
+
id: string;
|
|
81
|
+
label: string;
|
|
82
|
+
checked: boolean;
|
|
83
|
+
disabled?: boolean;
|
|
84
|
+
} | {
|
|
85
|
+
kind: 'select';
|
|
86
|
+
id: string;
|
|
87
|
+
label: string;
|
|
88
|
+
value: string;
|
|
89
|
+
options: GuestStatusControlOption[];
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
};
|
|
92
|
+
export type GuestStatusRow = {
|
|
93
|
+
kind: 'line';
|
|
94
|
+
id: string;
|
|
95
|
+
label: string;
|
|
96
|
+
/** A Remixicon name, as in `panel.icon`. */
|
|
97
|
+
icon?: string;
|
|
98
|
+
/** A status dot before the label. */
|
|
99
|
+
dot?: GuestStatusTone;
|
|
100
|
+
content?: GuestStatusContent;
|
|
101
|
+
value?: string;
|
|
102
|
+
valueTone?: GuestStatusTone;
|
|
103
|
+
badge?: {
|
|
104
|
+
label: string;
|
|
105
|
+
tone?: GuestStatusTone;
|
|
106
|
+
};
|
|
107
|
+
tooltip?: string;
|
|
108
|
+
actions?: GuestStatusAction[];
|
|
109
|
+
} | {
|
|
110
|
+
kind: 'note';
|
|
111
|
+
id: string;
|
|
112
|
+
text: string;
|
|
113
|
+
tone?: 'muted' | 'info' | 'warning' | 'error';
|
|
114
|
+
};
|
|
115
|
+
/** The answer to `GET <source.path>`. */
|
|
116
|
+
export type GuestStatusView = {
|
|
117
|
+
rows: GuestStatusRow[];
|
|
118
|
+
/** Header controls, the same declarations `setStatusControls` takes. */
|
|
119
|
+
controls?: GuestStatusControl[];
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* The body of `POST <source.path>` when the user activates a control. A switch
|
|
123
|
+
* sends `on` or `off`; a select or segmented control sends the chosen value; a
|
|
124
|
+
* button sends no value.
|
|
125
|
+
*/
|
|
126
|
+
export type GuestStatusActionEvent = {
|
|
127
|
+
id: string;
|
|
128
|
+
value?: string;
|
|
129
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Fastest the host asks a service for its section, in ms. */
|
|
2
|
+
export const GUEST_STATUS_SOURCE_INTERVAL_MIN = 1_000;
|
|
3
|
+
/** Slowest polling a source may ask for, in ms. */
|
|
4
|
+
export const GUEST_STATUS_SOURCE_INTERVAL_MAX = 60_000;
|
|
5
|
+
/** Polling interval when the manifest names none, in ms. */
|
|
6
|
+
export const GUEST_STATUS_SOURCE_INTERVAL_DEFAULT = 2_000;
|
|
7
|
+
export const GUEST_STATUS_VIEW_ROWS_MAX = 16;
|
|
8
|
+
export const GUEST_STATUS_VIEW_ACTIONS_MAX = 2;
|
|
9
|
+
export const GUEST_STATUS_VIEW_CHIPS_MAX = 6;
|
|
10
|
+
export const GUEST_STATUS_VIEW_CHART_POINTS_MAX = 120;
|
|
11
|
+
export const GUEST_STATUS_VIEW_SEGMENTS_MIN = 2;
|
|
12
|
+
export const GUEST_STATUS_VIEW_SEGMENTS_MAX = 4;
|
|
13
|
+
export const GUEST_STATUS_VIEW_TEXT_MAX = 200;
|
|
14
|
+
export const GUEST_STATUS_VIEW_NOTE_MAX = 300;
|
|
15
|
+
export const GUEST_STATUS_VIEW_ICON = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
@@ -91,6 +91,15 @@ export declare const guestWorkspaceSnapshotSchema: z.ZodDiscriminatedUnion<[z.Zo
|
|
|
91
91
|
id: z.ZodString;
|
|
92
92
|
data: z.ZodOptional<z.ZodJSONSchema>;
|
|
93
93
|
}, z.core.$strip>>;
|
|
94
|
+
links: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
95
|
+
title: z.ZodString;
|
|
96
|
+
url: z.ZodString;
|
|
97
|
+
kind: z.ZodEnum<{
|
|
98
|
+
change: "change";
|
|
99
|
+
issue: "issue";
|
|
100
|
+
}>;
|
|
101
|
+
linkedAt: z.ZodNumber;
|
|
102
|
+
}, z.core.$strip>>>;
|
|
94
103
|
}, z.core.$strip>>;
|
|
95
104
|
}, z.core.$strip>], "kind">;
|
|
96
105
|
export declare const guestSessionWorktreeSchema: z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
@@ -21,6 +21,7 @@ export const guestWorkspaceSnapshotSchema = z.discriminatedUnion('kind', [
|
|
|
21
21
|
createdAt: z.number(), updatedAt: z.number(), archivedAt: z.number().nullable(), worktree: worktree.nullable(),
|
|
22
22
|
activity: z.enum(['unknown', 'idle', 'running', 'retrying', 'waiting-permission', 'waiting-question']),
|
|
23
23
|
outcome: z.enum(['completed', 'failed']).nullable(), items: z.array(z.object({ id: identity, data: z.json().optional() })),
|
|
24
|
+
links: z.array(z.object({ title: z.string(), url: z.string(), kind: z.enum(['issue', 'change']), linkedAt: z.number() })).optional(),
|
|
24
25
|
})),
|
|
25
26
|
}),
|
|
26
27
|
]);
|
package/dist/workspace.d.ts
CHANGED
|
@@ -13,6 +13,17 @@ export type GuestWorktree = {
|
|
|
13
13
|
};
|
|
14
14
|
/** `waiting-question` means the agent is waiting on an answer — a form it put to the user. */
|
|
15
15
|
export type GuestSessionActivity = 'unknown' | 'idle' | 'running' | 'retrying' | 'waiting-permission' | 'waiting-question';
|
|
16
|
+
/**
|
|
17
|
+
* A thread linked to a session, by whoever linked it: the user, the agent
|
|
18
|
+
* (`session.link`), this extension or another. `change` is a code change
|
|
19
|
+
* under review (a pull, merge or change request).
|
|
20
|
+
*/
|
|
21
|
+
export type GuestSessionLink = {
|
|
22
|
+
title: string;
|
|
23
|
+
url: string;
|
|
24
|
+
kind: 'issue' | 'change';
|
|
25
|
+
linkedAt: number;
|
|
26
|
+
};
|
|
16
27
|
export type GuestSessionRecord = {
|
|
17
28
|
id: string;
|
|
18
29
|
title: string;
|
|
@@ -30,6 +41,8 @@ export type GuestSessionRecord = {
|
|
|
30
41
|
id: string;
|
|
31
42
|
data?: JsonValue;
|
|
32
43
|
}[];
|
|
44
|
+
/** Every link on the session, read-only. Absent from hosts older than this field. */
|
|
45
|
+
links?: GuestSessionLink[];
|
|
33
46
|
};
|
|
34
47
|
export type GuestDirectoryCoverage = {
|
|
35
48
|
directory: string;
|