@openchamber/sdk 2.1.1 → 2.2.0
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 +18 -2
- package/DOCUMENTATION.md +2 -1
- package/dist/contract.d.ts +19 -3
- package/dist/contract.js +1 -0
- package/dist/host-version.d.ts +2 -1
- package/dist/host.d.ts +7 -0
- package/dist/host.js +59 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/manifest.d.ts +4 -4
- package/dist/manifest.js +4 -4
- package/dist/parse.d.ts +4 -2
- package/dist/protocol.d.ts +107 -4
- package/dist/protocol.js +43 -0
- package/dist/shells.d.ts +69 -0
- package/dist/shells.js +4 -0
- package/package.json +1 -1
package/API.md
CHANGED
|
@@ -218,6 +218,22 @@ Projects contain `id`, `name`, `directory`. Worktrees contain `directory`, `name
|
|
|
218
218
|
|
|
219
219
|
`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.
|
|
220
220
|
|
|
221
|
+
### Running shells
|
|
222
|
+
|
|
223
|
+
These methods need the `shells` capability. They expose the running shell commands in a scope — one session and its subagents, a registered project, or every session — and let the extension read their output and stop them. OpenChamber answers from its local store; no network read happens per request.
|
|
224
|
+
|
|
225
|
+
| Method | Result |
|
|
226
|
+
| --- | --- |
|
|
227
|
+
| `onRunningShells(scope, listener)` | subscription: the running shell commands in scope — one session and its subagents (`{ kind: 'session', sessionId }`), a registered project (`{ kind: 'project', projectId }`), or every session (`{ kind: 'global' }`) — oldest first, with each command's `background` flag, plus the ones that ended since OpenChamber started watching |
|
|
228
|
+
| `readShellOutput(shellId, { cursor?, tailBytes? })` | one page of a running or ended command's output; `tailBytes` is capped at 65536 |
|
|
229
|
+
| `stopShell(shellId)` | sends the agent the stop note first, then removes the command |
|
|
230
|
+
|
|
231
|
+
Await subscription registration to handle refusal, then retain its returned unsubscribe function. Each subscription sends an initial snapshot, then changes, and counts against the same 32-subscription limit as the workspace subscriptions. The snapshot is `{ kind: 'shells', scope, shells, ended }`, where `scope` echoes the subscription's scope; each shell is `{ id, sessionID, command, startedAt, background }`, at most 200, oldest first. `background` is `true` for a job the turn does not wait for, and `false` while the turn that ran it is blocked on it.
|
|
232
|
+
|
|
233
|
+
`ended` holds the commands in scope that OpenChamber saw running and saw end, oldest end first, at most 200 with the newest kept. Each adds `status`, `endedAt`, and `exit` when the command exited with a code. `status` is `exited`, `timeout`, `killed` (a signal), `stopped` (by a user: Stop in the app, `stopShell`, or aborting the turn that waited on it), or `unknown` (the end fell into a reconnect and OpenChamber only saw the command gone). The list lives in memory: it starts empty when the app loads and resets on a runtime switch, so keep anything you show across reloads in extension storage.
|
|
234
|
+
|
|
235
|
+
`readShellOutput` returns `{ output, cursor, skipped }`; omit `cursor` to start `tailBytes` before the end, and `skipped` says earlier output was dropped. OpenCode keeps an ended command's output until it evicts the command (the latest 25 ended commands per directory); a stopped command's output is removed with it. A shell OpenChamber has not seen, a stopped one, and one whose output OpenCode no longer keeps are `NOT_FOUND`; `stopShell` on a shell that is not running is `NOT_FOUND` too. An unapproved `shells` capability is `NOT_GRANTED`.
|
|
236
|
+
|
|
221
237
|
### Extension storage
|
|
222
238
|
|
|
223
239
|
`host.storage.get(key, options?)` returns JSON or `undefined` for a missing key. JSON `null` is a stored value. `set(key, value, options?)` and `delete(key, options?)` return `Promise<void>`; `keys(options?)` returns `Promise<string[]>` in sorted order.
|
|
@@ -449,7 +465,7 @@ Used by the OpenChamber host and by tools that validate packages. Guests rarely
|
|
|
449
465
|
"entry": "panel/index.html"
|
|
450
466
|
},
|
|
451
467
|
"attach": "dialog",
|
|
452
|
-
"capabilities": ["prompt", "sessions", "files"],
|
|
468
|
+
"capabilities": ["prompt", "sessions", "files", "shells"],
|
|
453
469
|
"filesystem": ["~/.config/opencode/opencode.json", "/tmp/acme/**"],
|
|
454
470
|
"actions": [
|
|
455
471
|
{ "id": "create-task", "label": "Create task from message", "icon": "add-circle", "where": "message", "roles": ["assistant"] },
|
|
@@ -475,7 +491,7 @@ Used by the OpenChamber host and by tools that validate packages. Guests rarely
|
|
|
475
491
|
| `panel.entry` | Optional visible-panel HTML path inside the package. No `..`, absolute path, or URL. Its scripts must be built. Omitting it removes the rail icon and visible views; `background.entry` can still run code. With neither entry, only `tools` plus package identity/version/engines are allowed. `hasGuestPage` means a visible panel, not background execution |
|
|
476
492
|
| `background.entry` | Optional package-local `.html` path. Loaded on demand for background actions and slash commands, preferred over `panel.entry` for these calls. Adds no rail icon. The file and its built scripts must exist. Malformed declarations are `invalid-background` |
|
|
477
493
|
| `attach` | `true` / `"panel"` → + menu opens rail; `"dialog"` → host window; omit/`false` → off menus. Object form `{ "mode": "panel" \| "dialog", "entry"?: "panel/attach.html" }`: `entry` (dialog only, same path rules as `panel.entry`, must exist with built scripts) is the page the dialog loads instead of `panel.entry` |
|
|
478
|
-
| `capabilities` | Optional list of `prompt`, `sessions`, `files`, `model`. `files` is read **and** write inside the open project; `model` is `generate
|
|
494
|
+
| `capabilities` | Optional list of `prompt`, `sessions`, `files`, `model`, `shells`. `files` is read **and** write inside the open project; `model` is `generate`; `shells` is the running-shell methods. Approved once at install |
|
|
479
495
|
| `actions` | Optional, 1–8 entries, unique kebab-case `id`, `label` 1–40 chars, optional `icon` with the `panel.icon` rules, `where: "message" \| "session"`, optional `mode: "open" \| "background"`. Message actions may narrow `roles` to `["user"]` / `["assistant"]`, default both. Session actions may request `payload: ["messages"]`, adding the `conversation` capability. Invalid shape is `invalid-actions`. Default `open` mode opens the guest with `ready.item`, using the attach dialog for `attach: "dialog"` and the rail otherwise. `background` calls `onAction` in a temporary hidden frame; see Background actions above |
|
|
480
496
|
| `commands` | Optional, 1–8 entries, unique `name` matching `/^[a-z][a-z0-9-]{0,23}$/`, optional `description` 1–80 chars (`invalid-commands`). `/name args` in the chat box calls `onResolve` instead of the model and attaches what it returns. A name the composer already has (built-in, OpenCode command, skill) is ignored with a console warning |
|
|
481
497
|
| `tools` | Optional, 1–16 entries that say how the extension's tool calls look in the chat. `match` is the full tool name OpenCode reports (`mcp.jira.search`, `jira_search`), 1–128 chars of `[A-Za-z0-9_.:-]`, with `*` allowed once at the end as a suffix wildcard (`mcp.jira.*`). Optional `name` (1–40, the header title when `title` is absent or renders empty), `icon` (Remixicon name or package `.svg` path, same rules as `panel.icon`; the SVG is drawn in the text colour at the glyph size), `title` / `subtitle` templates (1–200, `{input.path}` / `{output.path}` / `{metadata.path}` placeholders, a missing path renders empty, values are cut at 200), `output` `"auto"` (default) \| `"text"` \| `"json"` \| `"markdown"` \| `"code"` \| `"table"`, `language` (code only), `columns` (table only, 1–16 dotted paths; rows are the output array or `output.items`). Bad shape is `invalid-tools`. An exact `match` beats a wildcard from any extension; among equals the first extension wins. Only an enabled, fully approved extension's rules apply |
|
package/DOCUMENTATION.md
CHANGED
|
@@ -33,6 +33,7 @@ Public author pages live in `packages/docs/content/docs/sdk.mdx`, `sdk/host.mdx`
|
|
|
33
33
|
- `contributes.fileEditors` is 1 to `GUEST_FILE_EDITORS_MAX` (8) editors, each `{ id, title, match, entry }` (`FileEditorContribution`, `src/file-editor.ts`): unique kebab-case `id`, `title` 1 to `GUEST_FILE_EDITOR_TITLE_MAX` (60), `match` 1 to `GUEST_FILE_EDITOR_PATTERNS_MAX` (16) file-name globs (`isFileEditorPattern`: 1 to 128 characters, no `/`, `\` or NUL, not only wildcards; `matchesFileEditorPattern` compares the name case-insensitively, `*` any run, `?` one character), `entry` package-local `.html`, optional `content` `text` (default) or `binary` (`FileEditorContentKind`); anything else is `invalid-file-editors`. Like the status section, editors are frames of their own: without `panel.entry` or `background.entry` a package may still declare `capabilities`, `service`, `integration`, and `filesystem`, and `page`, `attach`, `actions`, `commands` are `invalid-panel`. The server checks each entry's HTML and built scripts at install, carries `fileEditors` on the catalog row, and counts them as runtime entries for serving and storage (`hasGuestFrame` in `server/lib/guests/catalog.js`). The host owns the file. Wire: host → guest `file-open { path, name, readOnly, encoding: 'text', content } | { ..., encoding: 'binary', bytes }` (a push, sent on `hello` and iframe load, never on other host-state pushes; `connectHost` drops a repeat of the same file), `file-snapshot { id, payload: { purpose: 'save' | 'handoff' } }` answered by guest `file-snapshot-result { id, payload: { snapshot: { content, version } | { bytes, version } } | { error } }` with no `result` back, and `file-saved { version }`; guest → host fire-and-forget `file-change { dirty, edited }`, `file-save`, and `file-unsupported` (no `id`, no answer). Bytes are a `Uint8Array<ArrayBuffer>`, copied by structured clone, so the host schema's `z.instanceof(Uint8Array)` holds in the receiving realm; `sameFileEditorDocument` compares them byte for byte for the repeat-push check. Content on both sides is capped at `GUEST_FILE_EDITOR_CONTENT_MAX` (20 000 000 characters or bytes, `fileEditorPayloadSize`); the guest refuses an oversized snapshot with an error instead of letting the host schema drop it. `onFileOpen` registration installs one capturing `keydown` listener that turns Cmd/Ctrl+S into `file-save`, because key events inside the frame never reach the host. `createFileSaveTracker` is the pure dirty bookkeeping: a written snapshot's version is marked saved, so edits made during the write stay dirty. The host side is `packages/ui/src/lib/guests/file-editor-channel.ts` (one channel per mounted editor; disconnect rejects every outstanding snapshot request), `PluginPane surface="file"`, and `components/views/files/GuestFileEditor.tsx`; the Files view contract is in that folder's `DOCUMENTATION.md`. VS Code and mobile keep the catalog empty, so files there stay with the host's own viewers.
|
|
34
34
|
- `contributes.page` is `true` or `{ entry, title? }`, requires `panel.entry`, and adds a user-opened full-screen page. `resolvePageEntry` resolves shorthand; the server validates its HTML/scripts and exposes `pageEntry`/`pageTitle`. `PluginPane surface="page"` uses the same sandbox. `useUIStore.openGuestPageId` is transient and mutually exclusive with other main pages. The sidebar menu opens it; `close()` or explicit session navigation closes it. Pages are not context-rail surfaces.
|
|
35
35
|
- `workspace.ts` owns project/worktree/session snapshots and storage types; `workspace-schemas.ts` validates their wire contracts. The existing `sessions` grant covers lists, subscriptions, opening sessions, and targeted creation. `lib/guests/workspace.ts` projects shared project, topology, session, and live-status stores; reads perform no network or git discovery. A registered observer is shared per runtime/extension/query and stops with its last listener. `PluginPane` limits each frame to 32 subscriptions and clears them on unmount, grant withdrawal, and runtime switch. Initial snapshots and updates have explicit loading/error coverage. `HostClient.onProjects/onWorktrees/onSessions` return promises of unsubscribe functions, so approval failures reach the caller.
|
|
36
|
+
- `shells.ts` owns the running-shell contract: the `shells` declared capability, the snapshot and result types, and `GUEST_SHELL_ID_MAX` (128), `GUEST_SHELLS_MAX` (200), and `GUEST_SHELL_OUTPUT_TAIL_MAX` (65536). Wire: guest `shells-subscribe` `{ subscriptionId, scope }` with scope `{ kind: 'session', sessionId }`, `{ kind: 'project', projectId }`, or `{ kind: 'global' }`, `shells-unsubscribe` `{ subscriptionId }`, `shell-output` `{ shellId, cursor?, tailBytes? }`, and `shell-stop` `{ shellId }`; host push `shells` `{ subscriptionId, snapshot }` where the snapshot carries `kind: 'shells'`, an echo of the requested `scope`, the running `shells`, and `ended` (`GuestEndedShell`: a running shell plus `status` from `GUEST_SHELL_END_STATUSES`, `endedAt`, optional integer `exit`). `lib/guests/shells.ts` projects `useBackgroundShellsStore` (the requested scope: a session and its subagents, a registered project's sessions matched by directory rather than by `projectID`, or every session; running oldest start first, ended oldest end first keeping the newest `GUEST_SHELLS_MAX`) from memory, so a read never hits the network or git; `observeGuestShells` shares one observer per runtime and scope. The store's `ended` list is the app's own observation of `shell.exited` / `shell.deleted` (see `sync/DOCUMENTATION.md`), so it is empty after a reload. `readGuestShellOutput` reads a running or ended shell in the directory it ran in, and answers `NOT_FOUND` for a shell the store never saw, a `stopped` one (OpenCode unlinks its output on removal), and an OpenCode 404 (evicted past the 25 retained exited commands per directory); other failures pass through. `PluginPane` wires the four effects, checks the `shells` grant per call, counts shell subscriptions against the frame's 32-subscription limit, and answers `stopShell` on a shell that is not running with `NOT_FOUND`. `opencodeClient.stopBackgroundShell` writes the agent's cancellation note before it kills the command and kills nothing when the note fails.
|
|
36
37
|
- `storage` is instance-owned JSON under the guest's namespace, without a new capability. `storage.js` serializes authorization, read-modify-write, and removal per namespace; writes use unique temporary files and rename. Missing keys differ from stored null; corrupt files and failed writes fail without clearing data. Device scope is an explicit SDK opt-in only when ready features advertise `deviceStorage`; it uses the host runtime key plus guest ID and server-issued installation `storageId`, and has no instance fallback. Different runtime identities remain separate even if a server duplicates a storage ID. URL-based runtime keys separate address aliases; saved-host and relay keys retain their existing identity rules. IndexedDB limits are 2 MiB per namespace and 16 MiB of serialized preference data across the database; browser metadata has separate overhead. A confirmed uninstall makes the namespace inaccessible, but an offline profile retains its bytes until site data is removed. Device storage does not promise secret or SSO storage. Limits and public result shapes live in `API.md`. For project data, extensions namespace keys with project IDs.
|
|
37
38
|
|
|
38
39
|
- Manifest `apiVersion` is `1`. Wire envelope `v` stays `1`. Any other value is `unsupported-api-version`. Optional `engines.openchamber` is `1.22.0` or `>=1.22.0`. Install refuses with `host-too-old` when this OpenChamber build is older. Package installs also need a semver `version` on `package.json` (`1.0.0`); the catalog exposes it and Settings → Extensions shows `v1.0.0` on the card. Already-installed packages without `version` still list; new installs without it fail as `invalid-manifest`.
|
|
@@ -51,7 +52,7 @@ Public author pages live in `packages/docs/content/docs/sdk.mdx`, `sdk/host.mdx`
|
|
|
51
52
|
- Host → guest `resolve` is `{ id, payload: { command, args } }`; the guest answers `resolve-result` with the same `id` and `{ item }` (a clamped `AttachIssueRequest` or `null`) or `{ error }` (1 to `GUEST_RESOLVE_ERROR_MAX` characters). The host waits `GUEST_REQUEST_TIMEOUT_MS`, then treats silence as a failure and never sends a `result` for a `resolve-result`. `badge` is `{ count }` with `count` an integer 0..999 or `null`; the host schema drops anything else.
|
|
52
53
|
- `ready` always carries `session` (`{ id, title, busy }` or `null`), `surface` (`panel` on the rail, `dialog` in the attach window, `page` full screen, `background` hidden, `status` in the Work Status panel, `file` as a Files view editor), `connection` (`{ connected, account }`), and `settings` (declared keys only). Title falls back to `id` when the host record has no title. `busy` is live `session_status` `busy` or `retry`. Missing status is `busy: false`, not an empty success that clears a previous snapshot. `model` is `providerID/id` when the host session record has both. `agent` is the session agent name when present. `surface` is which host chrome mounted the iframe. It is not `openSurface`. `item` is the attached item the surface was opened for (the user clicked that item's chip on the composer; the same `AttachIssueRequest` shape the guest handed to `attach`, with `text` filled from the chip's context) or `null` from the rail icon and the + menu. The host also pushes `item` when it changes while the frame is up; `onItem` replays the latest value. `ready.theme.tokens` is the host colour bag: surfaces (`background`, `elevated`, `mutedSurface`, `subtle`), text (`foreground`, `elevatedForeground`, `muted`), interaction (`border`, `hover`, `active`, `selection`, `selectionForeground`, `focus`), `primary` / `primaryForeground`, the four status colours, `font`, `mono`, and `radius`. `applyHostReady` writes it onto the iframe. The host also pushes `connection` and `settings` the same way as `session`. Access tokens never appear in `ready` or a result.
|
|
53
54
|
- `writeClipboard` text is 1–32000 characters. `compose` text is 1–16000 after trim. Compose default mode is `append`. Compose writes the chat composer. It does not send.
|
|
54
|
-
- `contributes.capabilities` is a list of `prompt`, `sessions`, `files`, and/or `
|
|
55
|
+
- `contributes.capabilities` is a list of `prompt`, `sessions`, `files`, `model`, and/or `shells` (`DECLARED_GUEST_CAPABILITIES`). `model` gates `generate`: `{ prompt, system?, maxOutputTokens? }` → `{ text }`, posted with a `GUEST_GENERATE_TIMEOUT_MS` (90s) timeout instead of the usual 20s because the model answers slowly; the host answers `NO_MODEL` when the small-model service resolves nothing (or only Claude Code) and `MODEL_FAILED` when the provider call fails. `requestedGuestCapabilities` adds `conversation`, `service`, `network`, `filesystem`, and `origins` from a session action with `payload: ["messages"]`, `contributes.service`, `contributes.integration`, `contributes.filesystem`, and `contributes.origins`; the user approves that whole list once at install (`PUT /api/guests/:id/capabilities`), and a package that later asks for more is re-approved. `hasGuestCapability` gates `prompt({ send })`, `startSession`, `request`, `serviceRequest`, the four file calls, and the three shell calls; a refusal is `NOT_GRANTED` (`NO_SERVICE` for the service).
|
|
55
56
|
- `contributes.filesystem` is 1 to 16 globs, each 1 to 256 characters, starting with `/` or `~/`, with no `..`, empty segment, NUL, or backslash (`isGuestFilesystemPattern`; parse failure is `invalid-filesystem`). `**` spans directories, `*` and `?` stay inside one segment, and a pattern ending in `/**` also matches the directory itself. The public catalog row carries the list as `filesystem` so the approval dialog can show it.
|
|
56
57
|
- `readFile` / `writeFile` / `listDir` / `stat` are `file-read` / `file-write` / `file-list` / `file-stat` on the wire. `guestFileScope` decides the grant: a relative path is `project` (capability `files`, joined to the open project; none open is `NO_DIRECTORY`), `/…` or `~/…` is `filesystem` (must match a declared pattern). The server compares canonical paths, so a symlink out of either tree is `BAD_PATH`, as is any `..` segment. Results are `{ content }`, `{ written: true }`, `{ entries: { name, kind }[] }`, and `{ kind, size, mtime }` where `kind` may be `missing`. `GUEST_FILE_PATH_MAX` (1024), `GUEST_FILE_CONTENT_MAX` (2 000 000 characters, read and write), `GUEST_FILE_LIST_MAX` (2000 entries). The client refuses an empty, oversized, NUL, or backslash path as `BAD_PATH` and oversized content as `FILE_TOO_LARGE` before posting; the host schema accepts only what `isGuestFilePath` does, so a dropped message cannot turn into `HOST_TIMEOUT`. Nothing about the write is logged, not even the path.
|
|
57
58
|
- `contributes.attach` is `true`, `false`, `"panel"`, `"dialog"`, or `{ "mode": "panel" | "dialog", "entry"?: string }`. `true` and `"panel"` add a + menu row that opens the rail. `"dialog"` opens a host window that mounts the same iframe. The object form's `entry` is an HTML page inside the package (same path rules as `panel.entry`, install checks it exists and that its scripts are built) that the dialog loads instead of `panel.entry`; it is only accepted with `mode: "dialog"`, and `resolveAttachEntry(contributes)` returns it or `null`. The public catalog row carries it as `attachEntry`. Clicking the guest's chip on the composer reopens that guest with the chip as `ready.item`: a dialog guest in the attach window, a panel guest on the rail. New Worktree shows the same dialog-mode guests next to GitHub and Linear. Omitted or `false` stays off those menus. Public 1.0 is web and desktop. VS Code and mobile mark the guest catalog `unsupported`. They do not show the row.
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { OPENCHAMBER_SDK_API_VERSION, OPENCHAMBER_SDK_CHANNEL } from './api-version.ts';
|
|
2
2
|
import type { FileEditorChange, FileEditorDocument, FileSnapshotRequest, FileSnapshotResultPayload } from './file-editor.ts';
|
|
3
|
+
import type { GuestRunningShellsSnapshot, GuestShellOutputRequest, GuestShellOutputResult, GuestShellStopResult, GuestShellsSubscription } from './shells.ts';
|
|
3
4
|
import type { GuestSessionWorktree, GuestStorageRequest, GuestStorageResult, GuestWorkspaceQuery, GuestWorkspaceSnapshot, GuestWorkspaceSubscription, GuestWorkspaceUpdate, GuestWorktree } from './workspace.ts';
|
|
4
5
|
import type { GuestStatusControl, GuestStatusControlEvent } from './status-controls.ts';
|
|
5
6
|
import type { GuestPopoverClosedEvent, GuestPopoverContext, GuestPopoverRequest } from './popover.ts';
|
|
@@ -166,7 +167,7 @@ export type GenerateRequest = {
|
|
|
166
167
|
export type GenerateResult = {
|
|
167
168
|
text: string;
|
|
168
169
|
};
|
|
169
|
-
export type HostResultPayload = GuestStorageResult | GuestWorkspaceSnapshot | GuestRequestResult | StartSessionResult | PromptResult | ServiceStatusResult | FileReadResult | FileWriteResult | FileListResult | FileStatResult | GenerateResult;
|
|
170
|
+
export type HostResultPayload = GuestStorageResult | GuestWorkspaceSnapshot | GuestShellOutputResult | GuestShellStopResult | GuestRequestResult | StartSessionResult | PromptResult | ServiceStatusResult | FileReadResult | FileWriteResult | FileListResult | FileStatResult | GenerateResult;
|
|
170
171
|
export declare const isStartSessionResult: (value: HostResultPayload | undefined) => value is StartSessionResult;
|
|
171
172
|
export declare const isPromptResult: (value: HostResultPayload | undefined) => value is PromptResult;
|
|
172
173
|
export declare const EMPTY_GUEST_CONNECTION: GuestConnection;
|
|
@@ -490,10 +491,17 @@ export type HostResultMessage = Envelope & {
|
|
|
490
491
|
error: string;
|
|
491
492
|
code: HostRequestErrorCode;
|
|
492
493
|
});
|
|
494
|
+
export type HostShellsMessage = Envelope & {
|
|
495
|
+
type: 'shells';
|
|
496
|
+
payload: {
|
|
497
|
+
subscriptionId: string;
|
|
498
|
+
snapshot: GuestRunningShellsSnapshot;
|
|
499
|
+
};
|
|
500
|
+
};
|
|
493
501
|
export type HostMessage = (Envelope & {
|
|
494
502
|
type: 'workspace';
|
|
495
503
|
payload: GuestWorkspaceUpdate;
|
|
496
|
-
}) | HostReadyMessage | HostDirectoryMessage | HostSessionMessage | HostConnectionMessage | HostSettingsMessage | HostSessionLifecycleMessage | HostItemMessage | HostStatusControlEventMessage | HostPopoverClosedMessage | HostResolveMessage | HostActionMessage | HostFileOpenMessage | HostFileSnapshotMessage | HostFileSavedMessage | HostResultMessage;
|
|
504
|
+
}) | HostShellsMessage | HostReadyMessage | HostDirectoryMessage | HostSessionMessage | HostConnectionMessage | HostSettingsMessage | HostSessionLifecycleMessage | HostItemMessage | HostStatusControlEventMessage | HostPopoverClosedMessage | HostResolveMessage | HostActionMessage | HostFileOpenMessage | HostFileSnapshotMessage | HostFileSavedMessage | HostResultMessage;
|
|
497
505
|
type GuestCall<Type extends string, Payload = never> = Envelope & {
|
|
498
506
|
type: Type;
|
|
499
507
|
id: string;
|
|
@@ -577,9 +585,17 @@ export type GuestFileSaveMessage = Envelope & {
|
|
|
577
585
|
export type GuestFileUnsupportedMessage = Envelope & {
|
|
578
586
|
type: 'file-unsupported';
|
|
579
587
|
};
|
|
588
|
+
export type GuestShellsSubscribeMessage = GuestCall<'shells-subscribe', GuestShellsSubscription>;
|
|
589
|
+
export type GuestShellsUnsubscribeMessage = GuestCall<'shells-unsubscribe', {
|
|
590
|
+
subscriptionId: string;
|
|
591
|
+
}>;
|
|
592
|
+
export type GuestShellOutputMessage = GuestCall<'shell-output', GuestShellOutputRequest>;
|
|
593
|
+
export type GuestShellStopMessage = GuestCall<'shell-stop', {
|
|
594
|
+
shellId: string;
|
|
595
|
+
}>;
|
|
580
596
|
export type GuestMessage = GuestCall<'workspace-read', GuestWorkspaceQuery> | GuestCall<'workspace-subscribe', GuestWorkspaceSubscription> | GuestCall<'workspace-unsubscribe', {
|
|
581
597
|
subscriptionId: string;
|
|
582
|
-
}> | GuestCall<'storage', GuestStorageRequest> | GuestCall<'open-session', {
|
|
598
|
+
}> | GuestShellsSubscribeMessage | GuestShellsUnsubscribeMessage | GuestShellOutputMessage | GuestShellStopMessage | GuestCall<'storage', GuestStorageRequest> | GuestCall<'open-session', {
|
|
583
599
|
sessionId: string;
|
|
584
600
|
}> | GuestHelloMessage | GuestToastMessage | GuestOpenUrlMessage | GuestOpenSurfaceMessage | GuestClipboardWriteMessage | GuestComposeMessage | GuestAttachMessage | GuestStartSessionMessage | GuestPromptMessage | GuestSessionLinkMessage | GuestCloseMessage | GuestOauthStartMessage | GuestOauthDisconnectMessage | GuestRequestMessage | GuestServiceRequestMessage | GuestServiceStatusMessage | GuestFileReadMessage | GuestFileWriteMessage | GuestFileListMessage | GuestFileStatMessage | GuestGenerateMessage | GuestBadgeMessage | GuestResizeMessage | GuestOpenCommitMessage | GuestStatusControlsMessage | GuestPopoverOpenMessage | GuestPopoverCloseMessage | GuestPopoverAnchorMessage | GuestActionResultMessage | GuestResolveResultMessage | GuestFileSnapshotResultMessage | GuestFileChangeMessage | GuestFileSaveMessage | GuestFileUnsupportedMessage;
|
|
585
601
|
export declare const isServiceStatusResult: (value: HostResultPayload | undefined) => value is ServiceStatusResult;
|
package/dist/contract.js
CHANGED
|
@@ -210,6 +210,7 @@ export const isFileStatResult = (value) => Boolean(value && 'kind' in value && '
|
|
|
210
210
|
export const isGenerateResult = (value) => Boolean(value && 'text' in value && String(value.text) === value.text && !('status' in value));
|
|
211
211
|
const HOST_PUSH_TYPES = new Set([
|
|
212
212
|
'workspace',
|
|
213
|
+
'shells',
|
|
213
214
|
'ready', 'directory', 'session', 'connection', 'settings', 'session-lifecycle', 'item', 'resolve', 'action',
|
|
214
215
|
'status-control-event', 'popover-closed',
|
|
215
216
|
'file-open', 'file-snapshot', 'file-saved',
|
package/dist/host-version.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** `1.22.0` or `>=1.22.0`. Ranges beyond a floor are not accepted. */
|
|
2
2
|
export declare const OPENCHAMBER_ENGINE_PATTERN: RegExp;
|
|
3
|
-
|
|
3
|
+
type OpenChamberVersionParts = {
|
|
4
4
|
major: number;
|
|
5
5
|
minor: number;
|
|
6
6
|
patch: number;
|
|
@@ -14,3 +14,4 @@ export declare const openChamberEngineMinimum: (engine: string) => string | null
|
|
|
14
14
|
* Unknown host versions fail closed when an engine is declared.
|
|
15
15
|
*/
|
|
16
16
|
export declare const hostMeetsOpenChamberEngine: (hostVersion: string, engine: string) => boolean;
|
|
17
|
+
export {};
|
package/dist/host.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { JsonValue } from './contract.ts';
|
|
|
4
4
|
import { type GuestPopoverClosedEvent, type GuestPopoverRequest } from './popover.ts';
|
|
5
5
|
import { type FileEditorChange, type FileEditorDocument, type FileEditorSnapshot, type FileSnapshotPurpose } from './file-editor.ts';
|
|
6
6
|
import { type AttachIssueRequest, type GuestActionItem, type ComposeRequest, type PromptRequest, type PromptResult, type SessionLifecycleEvent, type StartSessionRequest, type GuestConnection, type GuestItem, type GuestMessage, type GuestRequest, type GuestRequestResult, type GuestSettings, type HostReadyContext, type HostRequestErrorCode, type ResolveRequest, type SessionSnapshot, type StartSessionResult, type ToastRequest, type ServiceStatusResult, type FileListResult, type FileReadResult, type FileStatResult, type FileWriteResult, type GenerateRequest, type GenerateResult } from './contract.ts';
|
|
7
|
+
import { type GuestRunningShellsSnapshot, type GuestShellOutputResult, type GuestShellStopResult, type GuestShellsScope } from './shells.ts';
|
|
7
8
|
export type HostFrame = {
|
|
8
9
|
addEventListener: Window['addEventListener'];
|
|
9
10
|
removeEventListener: Window['removeEventListener'];
|
|
@@ -26,6 +27,12 @@ export type HostClient = {
|
|
|
26
27
|
onProjects: (listener: (snapshot: GuestProjectsSnapshot) => void) => Promise<() => void>;
|
|
27
28
|
onWorktrees: (projectId: string, listener: (snapshot: GuestWorktreesSnapshot) => void) => Promise<() => void>;
|
|
28
29
|
onSessions: (projectId: string, listener: (snapshot: GuestSessionsSnapshot) => void) => Promise<() => void>;
|
|
30
|
+
onRunningShells: (scope: GuestShellsScope, listener: (snapshot: GuestRunningShellsSnapshot) => void) => Promise<() => void>;
|
|
31
|
+
readShellOutput: (shellId: string, options?: {
|
|
32
|
+
cursor?: number;
|
|
33
|
+
tailBytes?: number;
|
|
34
|
+
}) => Promise<GuestShellOutputResult>;
|
|
35
|
+
stopShell: (shellId: string) => Promise<GuestShellStopResult>;
|
|
29
36
|
openSession: (sessionId: string) => Promise<void>;
|
|
30
37
|
storage: {
|
|
31
38
|
get: (key: string, options?: GuestStorageOptions) => Promise<JsonValue | undefined>;
|
package/dist/host.js
CHANGED
|
@@ -4,6 +4,7 @@ import { isGuestStatusControls } from "./status-controls.js";
|
|
|
4
4
|
import { isGuestPopoverRequest } from "./popover.js";
|
|
5
5
|
import { GUEST_FILE_EDITOR_CONTENT_MAX, GUEST_FILE_EDITOR_VERSION_MAX, fileEditorPayloadSize, sameFileEditorDocument, } from "./file-editor.js";
|
|
6
6
|
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, clampFrameHeight, isGuestCommitSha, clampPromptRequest, clampStartSessionRequest, readHostMessage, isGenerateResult, isFileListResult, isFileReadResult, isFileStatResult, isJsonValue, isFileWriteResult, isServiceStatusResult, isGuestRequestResult, isPromptResult, isStartSessionResult, } from "./contract.js";
|
|
7
|
+
import { GUEST_SHELL_ID_MAX, GUEST_SHELL_OUTPUT_TAIL_MAX } from "./shells.js";
|
|
7
8
|
// Structural, not `instanceof KeyboardEvent`: the frame's own realm owns that
|
|
8
9
|
// constructor, and non-browser runtimes have none.
|
|
9
10
|
const isKeyEvent = (event) => 'key' in event && 'metaKey' in event && 'ctrlKey' in event;
|
|
@@ -59,6 +60,7 @@ export const connectHost = (options = {}) => {
|
|
|
59
60
|
let saveShortcutInstalled = false;
|
|
60
61
|
const pending = new Map();
|
|
61
62
|
const workspaceListeners = new Map();
|
|
63
|
+
const shellsListeners = new Map();
|
|
62
64
|
let disposed = false;
|
|
63
65
|
const ids = { value: 0 };
|
|
64
66
|
let lastReady = null;
|
|
@@ -103,6 +105,12 @@ export const connectHost = (options = {}) => {
|
|
|
103
105
|
emit([listener], message.payload.snapshot);
|
|
104
106
|
return;
|
|
105
107
|
}
|
|
108
|
+
if (message.type === 'shells') {
|
|
109
|
+
const listener = shellsListeners.get(message.payload.subscriptionId);
|
|
110
|
+
if (listener)
|
|
111
|
+
emit([listener], message.payload.snapshot);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
106
114
|
if (message.type === 'ready') {
|
|
107
115
|
lastReady = message.payload;
|
|
108
116
|
lastLifecycle = lifecycleFromSession(message.payload.session);
|
|
@@ -372,6 +380,28 @@ export const connectHost = (options = {}) => {
|
|
|
372
380
|
post({ ...envelope, type: 'workspace-unsubscribe', id: nextId(ids), payload: { subscriptionId } });
|
|
373
381
|
};
|
|
374
382
|
};
|
|
383
|
+
const subscribeShells = async (scope, listener) => {
|
|
384
|
+
if (scope.kind === 'session')
|
|
385
|
+
requireIdentity(scope.sessionId);
|
|
386
|
+
if (scope.kind === 'project')
|
|
387
|
+
requireIdentity(scope.projectId);
|
|
388
|
+
const subscriptionId = nextId(ids);
|
|
389
|
+
shellsListeners.set(subscriptionId, listener);
|
|
390
|
+
try {
|
|
391
|
+
await request({ ...envelope, type: 'shells-subscribe', id: nextId(ids), payload: { subscriptionId, scope } });
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
shellsListeners.delete(subscriptionId);
|
|
395
|
+
if (!disposed)
|
|
396
|
+
post({ ...envelope, type: 'shells-unsubscribe', id: nextId(ids), payload: { subscriptionId } });
|
|
397
|
+
throw error;
|
|
398
|
+
}
|
|
399
|
+
return () => {
|
|
400
|
+
if (!shellsListeners.delete(subscriptionId) || disposed)
|
|
401
|
+
return;
|
|
402
|
+
post({ ...envelope, type: 'shells-unsubscribe', id: nextId(ids), payload: { subscriptionId } });
|
|
403
|
+
};
|
|
404
|
+
};
|
|
375
405
|
const storage = async (payload) => {
|
|
376
406
|
if ('key' in payload && (payload.key.length === 0 || payload.key.length > GUEST_STORAGE_KEY_MAX)) {
|
|
377
407
|
throw new HostRequestError('HOST_REJECTED', 'Storage key must contain 1 to 128 characters.');
|
|
@@ -432,6 +462,31 @@ export const connectHost = (options = {}) => {
|
|
|
432
462
|
listener(snapshot); }),
|
|
433
463
|
onSessions: (projectId, listener) => subscribeWorkspace({ kind: 'sessions', projectId }, (snapshot) => { if (snapshot.kind === 'sessions')
|
|
434
464
|
listener(snapshot); }),
|
|
465
|
+
onRunningShells: (scope, listener) => subscribeShells(scope, listener),
|
|
466
|
+
readShellOutput: async (shellId, options) => {
|
|
467
|
+
requireIdentity(shellId, GUEST_SHELL_ID_MAX);
|
|
468
|
+
const cursor = options?.cursor;
|
|
469
|
+
if (cursor !== undefined && (!Number.isInteger(cursor) || cursor < 0)) {
|
|
470
|
+
throw new HostRequestError('HOST_REJECTED', 'Shell output cursor must be a non-negative integer.');
|
|
471
|
+
}
|
|
472
|
+
const tailBytes = options?.tailBytes;
|
|
473
|
+
if (tailBytes !== undefined && (!Number.isInteger(tailBytes) || tailBytes < 1 || tailBytes > GUEST_SHELL_OUTPUT_TAIL_MAX)) {
|
|
474
|
+
throw new HostRequestError('HOST_REJECTED', `Shell output tailBytes must be an integer between 1 and ${GUEST_SHELL_OUTPUT_TAIL_MAX}.`);
|
|
475
|
+
}
|
|
476
|
+
const result = await send({ ...envelope, type: 'shell-output', id: nextId(ids), payload: { shellId, cursor, tailBytes } });
|
|
477
|
+
const output = result;
|
|
478
|
+
if (!output || typeof output.output !== 'string' || !Number.isFinite(output.cursor)) {
|
|
479
|
+
throw new HostRequestError('HOST_REJECTED', 'Host did not return shell output.');
|
|
480
|
+
}
|
|
481
|
+
return output;
|
|
482
|
+
},
|
|
483
|
+
stopShell: async (shellId) => {
|
|
484
|
+
requireIdentity(shellId, GUEST_SHELL_ID_MAX);
|
|
485
|
+
const result = (await send({ ...envelope, type: 'shell-stop', id: nextId(ids), payload: { shellId } }));
|
|
486
|
+
if (result?.stopped !== true)
|
|
487
|
+
throw new HostRequestError('HOST_REJECTED', 'Host did not stop the shell.');
|
|
488
|
+
return { stopped: true };
|
|
489
|
+
},
|
|
435
490
|
openSession: async (sessionId) => {
|
|
436
491
|
requireIdentity(sessionId);
|
|
437
492
|
await request({ ...envelope, type: 'open-session', id: nextId(ids), payload: { sessionId } });
|
|
@@ -856,6 +911,10 @@ export const connectHost = (options = {}) => {
|
|
|
856
911
|
post({ ...envelope, type: 'workspace-unsubscribe', id: nextId(ids), payload: { subscriptionId } });
|
|
857
912
|
}
|
|
858
913
|
workspaceListeners.clear();
|
|
914
|
+
for (const subscriptionId of shellsListeners.keys()) {
|
|
915
|
+
post({ ...envelope, type: 'shells-unsubscribe', id: nextId(ids), payload: { subscriptionId } });
|
|
916
|
+
}
|
|
917
|
+
shellsListeners.clear();
|
|
859
918
|
disposed = true;
|
|
860
919
|
resolveHandler = null;
|
|
861
920
|
actionHandler = null;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { GUEST_SCROLLBAR_CSS, GUEST_SCROLLBAR_SCRIPT } from './scrollbar-style.t
|
|
|
3
3
|
export { guestFramePolicy } from './frame-policy.ts';
|
|
4
4
|
export type { GuestLoadState, GuestProject, GuestWorktree, GuestSessionActivity, GuestSessionRecord, 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
|
+
export type { GuestRunningShell, GuestEndedShell, GuestShellEndStatus, GuestRunningShellsSnapshot, GuestShellsScope, GuestShellsSubscription, GuestShellOutputRequest, GuestShellOutputResult, GuestShellStopResult, } from './shells.ts';
|
|
7
|
+
export { GUEST_SHELL_END_STATUSES, GUEST_SHELL_ID_MAX, GUEST_SHELLS_MAX, GUEST_SHELL_OUTPUT_TAIL_MAX, } from './shells.ts';
|
|
6
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';
|
|
7
9
|
export type { GuestStatusControl, GuestStatusControlEvent, GuestStatusControlOption } from './status-controls.ts';
|
|
8
10
|
export type { OpenChamberManifestApiVersion } from './api-version.ts';
|
|
@@ -16,7 +18,7 @@ export type { HostClient, HostClientOptions, HostFrame } from './host.ts';
|
|
|
16
18
|
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.ts';
|
|
17
19
|
export type { GuestPopoverAnchor, GuestPopoverClosedEvent, GuestPopoverContext, GuestPopoverRequest, GuestPopoverSide } from './popover.ts';
|
|
18
20
|
export { clampAttachRequest, clampBadgeCount, clampFrameHeight, isGuestCommitSha, GUEST_COMMIT_SHA, 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';
|
|
19
|
-
export type { BadgeRequest, ActionResultPayload, GuestActionItem, GuestActionResultMessage, HostActionMessage, HostFileOpenMessage, HostFileSnapshotMessage, HostFileSavedMessage, GuestFileSnapshotResultMessage, GuestFileChangeMessage, GuestFileSaveMessage, GuestFileUnsupportedMessage, GuestBadgeMessage, GuestResizeMessage, GuestOpenCommitMessage, GuestStatusControlsMessage, GuestPopoverAnchorMessage, GuestPopoverCloseMessage, GuestPopoverOpenMessage, OpenCommitRequest, ResizeRequest, 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, HostStatusControlEventMessage, HostPopoverClosedMessage, HostMessage, HostReadyContext, HostReadyMessage, HostResultMessage, HostSessionLifecycleMessage, HostSessionMessage, HostSettingsMessage, HostTheme, HostThemeMode, HostThemeTokens, SessionSnapshot, ToastKind, ToastRequest, } from './contract.ts';
|
|
21
|
+
export type { BadgeRequest, ActionResultPayload, GuestActionItem, GuestActionResultMessage, HostActionMessage, HostFileOpenMessage, HostFileSnapshotMessage, HostFileSavedMessage, GuestFileSnapshotResultMessage, GuestFileChangeMessage, GuestFileSaveMessage, GuestFileUnsupportedMessage, GuestBadgeMessage, GuestResizeMessage, GuestOpenCommitMessage, GuestStatusControlsMessage, GuestPopoverAnchorMessage, GuestPopoverCloseMessage, GuestPopoverOpenMessage, OpenCommitRequest, ResizeRequest, 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, GuestShellOutputMessage, GuestShellsSubscribeMessage, GuestShellsUnsubscribeMessage, GuestShellStopMessage, GuestAttachMessage, GuestClipboardWriteMessage, GuestCloseMessage, GuestComposeMessage, GuestConnection, GuestHelloMessage, GuestMessage, GuestOauthDisconnectMessage, GuestOauthStartMessage, GuestOpenSurfaceMessage, GuestOpenUrlMessage, GuestRequest, GuestRequestMessage, GuestRequestMethod, GuestPromptMessage, GuestSessionLinkMessage, GuestStartSessionMessage, GuestRequestResult, GuestSettings, GuestToastMessage, GuestHostSurface, HostConnectionMessage, HostDirectoryMessage, HostItemMessage, HostStatusControlEventMessage, HostPopoverClosedMessage, HostMessage, HostReadyContext, HostReadyMessage, HostResultMessage, HostSessionLifecycleMessage, HostSessionMessage, HostSettingsMessage, HostShellsMessage, HostTheme, HostThemeMode, HostThemeTokens, SessionSnapshot, ToastKind, ToastRequest, } from './contract.ts';
|
|
20
22
|
export { EMPTY_GUEST_CONNECTION, GUEST_BADGE_MAX, GUEST_FRAME_HEIGHT_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';
|
|
21
23
|
export { BROWSER_CONTROL_ACTIONS, BROWSER_PROVIDER_ACTION_TIMEOUT_MS, BROWSER_PROVIDER_IDLE_MS, BROWSER_PROVIDER_OPEN_TIMEOUT_MS, BROWSER_PROVIDER_PATH, BROWSER_PROVIDER_RESPONSE_MAX, BROWSER_SCROLL_DIRECTIONS, BROWSER_VIEWPORT_MODES, isBrowserControlAction, readBrowserProviderRequest, } from './service-providers.ts';
|
|
22
24
|
export type { BrowserCaptureData, BrowserCaptureParameters, BrowserClickData, BrowserClickParameters, BrowserConsoleProblem, BrowserControlAction, BrowserElementBounds, BrowserInspectData, BrowserInspectParameters, BrowserNavigationData, BrowserOpenData, BrowserOpenParameters, BrowserProviderContext, BrowserProviderData, BrowserProviderRequest, BrowserProviderResult, BrowserResizeData, BrowserResizeParameters, BrowserScrollData, BrowserScrollDirection, BrowserScrollParameters, BrowserSnapshotData, BrowserSnapshotElement, BrowserSnapshotParameters, BrowserTab, BrowserTabTarget, BrowserTypeData, BrowserTypeParameters, BrowserViewportMode, BrowserViewportSummary, } from './service-providers.ts';
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export { OPENCHAMBER_SDK_API_VERSION, OPENCHAMBER_SDK_CHANNEL, OPENCHAMBER_SDK_M
|
|
|
2
2
|
export { GUEST_SCROLLBAR_CSS, GUEST_SCROLLBAR_SCRIPT } from "./scrollbar-style.js";
|
|
3
3
|
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
|
+
export { GUEST_SHELL_END_STATUSES, GUEST_SHELL_ID_MAX, GUEST_SHELLS_MAX, GUEST_SHELL_OUTPUT_TAIL_MAX, } from "./shells.js";
|
|
5
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";
|
|
6
7
|
export { compareOpenChamberVersions, hostMeetsOpenChamberEngine, openChamberEngineMinimum, OPENCHAMBER_ENGINE_PATTERN, parseOpenChamberVersion, } from "./host-version.js";
|
|
7
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, toPublicService, toPublicIntegration, } from "./manifest.js";
|
package/dist/manifest.d.ts
CHANGED
|
@@ -273,15 +273,15 @@ export declare const serviceProvides: (service: Pick<ServiceContribution, "provi
|
|
|
273
273
|
/**
|
|
274
274
|
* What a guest may do beyond drawing its own panel. The user approves the
|
|
275
275
|
* full list once, when the package is installed; a later package that asks
|
|
276
|
-
* for more is re-approved. `prompt`, `sessions`, `files`,
|
|
277
|
-
* declared under `contributes.capabilities`; `service`, `network`,
|
|
276
|
+
* for more is re-approved. `prompt`, `sessions`, `files`, `model`, and
|
|
277
|
+
* `shells` are declared under `contributes.capabilities`; `service`, `network`,
|
|
278
278
|
* `filesystem` and `origins` follow from `contributes.service`,
|
|
279
279
|
* `contributes.integration`, `contributes.filesystem` and `contributes.origins`. `model` is one-off text generation with the
|
|
280
280
|
* user's Small Model (`host.generate`), outside any session.
|
|
281
281
|
*/
|
|
282
|
-
export declare const GUEST_CAPABILITIES: readonly ["prompt", "sessions", "files", "model", "conversation", "service", "network", "filesystem", "origins"];
|
|
282
|
+
export declare const GUEST_CAPABILITIES: readonly ["prompt", "sessions", "files", "model", "shells", "conversation", "service", "network", "filesystem", "origins"];
|
|
283
283
|
export type GuestCapability = (typeof GUEST_CAPABILITIES)[number];
|
|
284
|
-
export declare const DECLARED_GUEST_CAPABILITIES: readonly ["prompt", "sessions", "files", "model"];
|
|
284
|
+
export declare const DECLARED_GUEST_CAPABILITIES: readonly ["prompt", "sessions", "files", "model", "shells"];
|
|
285
285
|
/** The capabilities a manifest may ask for directly. */
|
|
286
286
|
export type DeclaredGuestCapability = (typeof DECLARED_GUEST_CAPABILITIES)[number];
|
|
287
287
|
/** How many `contributes.origins` a package may declare. */
|
package/dist/manifest.js
CHANGED
|
@@ -96,14 +96,14 @@ export const serviceProvides = (service, role) => Boolean(service?.provides?.inc
|
|
|
96
96
|
/**
|
|
97
97
|
* What a guest may do beyond drawing its own panel. The user approves the
|
|
98
98
|
* full list once, when the package is installed; a later package that asks
|
|
99
|
-
* for more is re-approved. `prompt`, `sessions`, `files`,
|
|
100
|
-
* declared under `contributes.capabilities`; `service`, `network`,
|
|
99
|
+
* for more is re-approved. `prompt`, `sessions`, `files`, `model`, and
|
|
100
|
+
* `shells` are declared under `contributes.capabilities`; `service`, `network`,
|
|
101
101
|
* `filesystem` and `origins` follow from `contributes.service`,
|
|
102
102
|
* `contributes.integration`, `contributes.filesystem` and `contributes.origins`. `model` is one-off text generation with the
|
|
103
103
|
* user's Small Model (`host.generate`), outside any session.
|
|
104
104
|
*/
|
|
105
|
-
export const GUEST_CAPABILITIES = ['prompt', 'sessions', 'files', 'model', 'conversation', 'service', 'network', 'filesystem', 'origins'];
|
|
106
|
-
export const DECLARED_GUEST_CAPABILITIES = ['prompt', 'sessions', 'files', 'model'];
|
|
105
|
+
export const GUEST_CAPABILITIES = ['prompt', 'sessions', 'files', 'model', 'shells', 'conversation', 'service', 'network', 'filesystem', 'origins'];
|
|
106
|
+
export const DECLARED_GUEST_CAPABILITIES = ['prompt', 'sessions', 'files', 'model', 'shells'];
|
|
107
107
|
/** How many `contributes.origins` a package may declare. */
|
|
108
108
|
export const GUEST_ORIGINS_MAX = 8;
|
|
109
109
|
/** How many `contributes.filesystem` patterns a package may declare. */
|
package/dist/parse.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export declare const openChamberManifestSchema: z.ZodObject<{
|
|
|
44
44
|
requiresProject: z.ZodOptional<z.ZodBoolean>;
|
|
45
45
|
}, z.core.$strip>]>>;
|
|
46
46
|
capabilities: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
47
|
+
shells: "shells";
|
|
47
48
|
sessions: "sessions";
|
|
48
49
|
prompt: "prompt";
|
|
49
50
|
files: "files";
|
|
@@ -123,8 +124,8 @@ export declare const openChamberManifestSchema: z.ZodObject<{
|
|
|
123
124
|
label: z.ZodString;
|
|
124
125
|
icon: z.ZodOptional<z.ZodString>;
|
|
125
126
|
where: z.ZodEnum<{
|
|
126
|
-
message: "message";
|
|
127
127
|
session: "session";
|
|
128
|
+
message: "message";
|
|
128
129
|
}>;
|
|
129
130
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
130
131
|
background: "background";
|
|
@@ -218,6 +219,7 @@ export declare const packageManifestSchema: z.ZodObject<{
|
|
|
218
219
|
requiresProject: z.ZodOptional<z.ZodBoolean>;
|
|
219
220
|
}, z.core.$strip>]>>;
|
|
220
221
|
capabilities: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
222
|
+
shells: "shells";
|
|
221
223
|
sessions: "sessions";
|
|
222
224
|
prompt: "prompt";
|
|
223
225
|
files: "files";
|
|
@@ -297,8 +299,8 @@ export declare const packageManifestSchema: z.ZodObject<{
|
|
|
297
299
|
label: z.ZodString;
|
|
298
300
|
icon: z.ZodOptional<z.ZodString>;
|
|
299
301
|
where: z.ZodEnum<{
|
|
300
|
-
message: "message";
|
|
301
302
|
session: "session";
|
|
303
|
+
message: "message";
|
|
302
304
|
}>;
|
|
303
305
|
mode: z.ZodOptional<z.ZodEnum<{
|
|
304
306
|
background: "background";
|
package/dist/protocol.d.ts
CHANGED
|
@@ -92,6 +92,48 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
92
92
|
}, z.core.$strip>;
|
|
93
93
|
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
94
94
|
v: z.ZodLiteral<1>;
|
|
95
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
96
|
+
type: z.ZodLiteral<"shells">;
|
|
97
|
+
payload: z.ZodObject<{
|
|
98
|
+
subscriptionId: z.ZodString;
|
|
99
|
+
snapshot: z.ZodObject<{
|
|
100
|
+
kind: z.ZodLiteral<"shells">;
|
|
101
|
+
scope: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
102
|
+
kind: z.ZodLiteral<"session">;
|
|
103
|
+
sessionId: z.ZodString;
|
|
104
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
105
|
+
kind: z.ZodLiteral<"project">;
|
|
106
|
+
projectId: z.ZodString;
|
|
107
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
108
|
+
kind: z.ZodLiteral<"global">;
|
|
109
|
+
}, z.core.$strict>], "kind">;
|
|
110
|
+
shells: z.ZodArray<z.ZodObject<{
|
|
111
|
+
id: z.ZodString;
|
|
112
|
+
sessionID: z.ZodString;
|
|
113
|
+
command: z.ZodString;
|
|
114
|
+
startedAt: z.ZodNumber;
|
|
115
|
+
background: z.ZodBoolean;
|
|
116
|
+
}, z.core.$strict>>;
|
|
117
|
+
ended: z.ZodArray<z.ZodObject<{
|
|
118
|
+
id: z.ZodString;
|
|
119
|
+
sessionID: z.ZodString;
|
|
120
|
+
command: z.ZodString;
|
|
121
|
+
startedAt: z.ZodNumber;
|
|
122
|
+
background: z.ZodBoolean;
|
|
123
|
+
status: z.ZodEnum<{
|
|
124
|
+
exited: "exited";
|
|
125
|
+
timeout: "timeout";
|
|
126
|
+
killed: "killed";
|
|
127
|
+
stopped: "stopped";
|
|
128
|
+
unknown: "unknown";
|
|
129
|
+
}>;
|
|
130
|
+
exit: z.ZodOptional<z.ZodNumber>;
|
|
131
|
+
endedAt: z.ZodNumber;
|
|
132
|
+
}, z.core.$strict>>;
|
|
133
|
+
}, z.core.$strict>;
|
|
134
|
+
}, z.core.$strip>;
|
|
135
|
+
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
136
|
+
v: z.ZodLiteral<1>;
|
|
95
137
|
}, z.core.$strip>, z.ZodObject<{
|
|
96
138
|
type: z.ZodLiteral<"ready">;
|
|
97
139
|
payload: z.ZodObject<{
|
|
@@ -459,7 +501,13 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
459
501
|
data: z.ZodOptional<z.ZodJSONSchema>;
|
|
460
502
|
}, z.core.$strip>>;
|
|
461
503
|
}, z.core.$strip>>;
|
|
462
|
-
}, z.core.$strip>], "kind">, z.
|
|
504
|
+
}, z.core.$strip>], "kind">, z.ZodObject<{
|
|
505
|
+
output: z.ZodString;
|
|
506
|
+
cursor: z.ZodNumber;
|
|
507
|
+
skipped: z.ZodBoolean;
|
|
508
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
509
|
+
stopped: z.ZodLiteral<true>;
|
|
510
|
+
}, z.core.$strip>, z.ZodUnion<readonly [z.ZodObject<{
|
|
463
511
|
sessionId: z.ZodString;
|
|
464
512
|
sent: z.ZodEnum<{
|
|
465
513
|
failed: "failed";
|
|
@@ -511,9 +559,9 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
511
559
|
}>;
|
|
512
560
|
}, z.core.$strip>, z.ZodObject<{
|
|
513
561
|
status: z.ZodEnum<{
|
|
562
|
+
stopped: "stopped";
|
|
514
563
|
ready: "ready";
|
|
515
564
|
failed: "failed";
|
|
516
|
-
stopped: "stopped";
|
|
517
565
|
starting: "starting";
|
|
518
566
|
}>;
|
|
519
567
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -641,7 +689,7 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
641
689
|
} | {
|
|
642
690
|
sent: "failed" | "sent" | "no-model" | "skipped";
|
|
643
691
|
} | {
|
|
644
|
-
status: "
|
|
692
|
+
status: "stopped" | "ready" | "failed" | "starting";
|
|
645
693
|
} | {
|
|
646
694
|
content: string;
|
|
647
695
|
} | {
|
|
@@ -657,6 +705,12 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
657
705
|
mtime: number;
|
|
658
706
|
} | {
|
|
659
707
|
text: string;
|
|
708
|
+
} | {
|
|
709
|
+
output: string;
|
|
710
|
+
cursor: number;
|
|
711
|
+
skipped: boolean;
|
|
712
|
+
} | {
|
|
713
|
+
stopped: true;
|
|
660
714
|
};
|
|
661
715
|
error?: undefined;
|
|
662
716
|
code?: undefined;
|
|
@@ -778,7 +832,7 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
778
832
|
} | {
|
|
779
833
|
sent: "failed" | "sent" | "no-model" | "skipped";
|
|
780
834
|
} | {
|
|
781
|
-
status: "
|
|
835
|
+
status: "stopped" | "ready" | "failed" | "starting";
|
|
782
836
|
} | {
|
|
783
837
|
content: string;
|
|
784
838
|
} | {
|
|
@@ -794,6 +848,12 @@ export declare const hostMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
794
848
|
mtime: number;
|
|
795
849
|
} | {
|
|
796
850
|
text: string;
|
|
851
|
+
} | {
|
|
852
|
+
output: string;
|
|
853
|
+
cursor: number;
|
|
854
|
+
skipped: boolean;
|
|
855
|
+
} | {
|
|
856
|
+
stopped: true;
|
|
797
857
|
} | undefined;
|
|
798
858
|
}>>, z.ZodObject<{
|
|
799
859
|
type: z.ZodLiteral<"action">;
|
|
@@ -915,6 +975,49 @@ export declare const guestMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
915
975
|
}, z.core.$strip>;
|
|
916
976
|
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
917
977
|
v: z.ZodLiteral<1>;
|
|
978
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
979
|
+
type: z.ZodLiteral<"shells-subscribe">;
|
|
980
|
+
id: z.ZodString;
|
|
981
|
+
payload: z.ZodObject<{
|
|
982
|
+
subscriptionId: z.ZodString;
|
|
983
|
+
scope: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
984
|
+
kind: z.ZodLiteral<"session">;
|
|
985
|
+
sessionId: z.ZodString;
|
|
986
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
987
|
+
kind: z.ZodLiteral<"project">;
|
|
988
|
+
projectId: z.ZodString;
|
|
989
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
990
|
+
kind: z.ZodLiteral<"global">;
|
|
991
|
+
}, z.core.$strict>], "kind">;
|
|
992
|
+
}, z.core.$strict>;
|
|
993
|
+
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
994
|
+
v: z.ZodLiteral<1>;
|
|
995
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
996
|
+
type: z.ZodLiteral<"shells-unsubscribe">;
|
|
997
|
+
id: z.ZodString;
|
|
998
|
+
payload: z.ZodObject<{
|
|
999
|
+
subscriptionId: z.ZodString;
|
|
1000
|
+
}, z.core.$strict>;
|
|
1001
|
+
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
1002
|
+
v: z.ZodLiteral<1>;
|
|
1003
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1004
|
+
type: z.ZodLiteral<"shell-output">;
|
|
1005
|
+
id: z.ZodString;
|
|
1006
|
+
payload: z.ZodObject<{
|
|
1007
|
+
shellId: z.ZodString;
|
|
1008
|
+
cursor: z.ZodOptional<z.ZodNumber>;
|
|
1009
|
+
tailBytes: z.ZodOptional<z.ZodNumber>;
|
|
1010
|
+
}, z.core.$strict>;
|
|
1011
|
+
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
1012
|
+
v: z.ZodLiteral<1>;
|
|
1013
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1014
|
+
type: z.ZodLiteral<"shell-stop">;
|
|
1015
|
+
id: z.ZodString;
|
|
1016
|
+
payload: z.ZodObject<{
|
|
1017
|
+
shellId: z.ZodString;
|
|
1018
|
+
}, z.core.$strict>;
|
|
1019
|
+
channel: z.ZodLiteral<"openchamber.sdk">;
|
|
1020
|
+
v: z.ZodLiteral<1>;
|
|
918
1021
|
}, z.core.$strip>, z.ZodObject<{
|
|
919
1022
|
type: z.ZodLiteral<"storage">;
|
|
920
1023
|
id: z.ZodString;
|
package/dist/protocol.js
CHANGED
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { guestSessionWorktreeSchema, guestStorageRequestSchema, guestStorageResultSchema, guestWorkspaceQuerySchema, guestWorkspaceSnapshotSchema } from "./workspace-schemas.js";
|
|
3
3
|
import { guestStatusControlEventSchema, guestStatusControlsSchema } from "./status-control-schemas.js";
|
|
4
4
|
import { guestPopoverClosedEventSchema, guestPopoverDataSchema, guestPopoverRequestSchema } from "./popover-schemas.js";
|
|
5
|
+
import { GUEST_SHELL_END_STATUSES, GUEST_SHELL_ID_MAX, GUEST_SHELLS_MAX, GUEST_SHELL_OUTPUT_TAIL_MAX } from "./shells.js";
|
|
5
6
|
import { OPENCHAMBER_SDK_API_VERSION, OPENCHAMBER_SDK_CHANNEL } from "./api-version.js";
|
|
6
7
|
import { SERVICE_STATUS_VALUES, ATTACH_PROVIDER_ID, GUEST_ACCOUNT_MAX, GUEST_ATTACH_AUTHOR_MAX, GUEST_BADGE_MAX, GUEST_FRAME_HEIGHT_MAX, GUEST_COMMIT_SHA, GUEST_ITEM_MESSAGE_TEXT_MAX, GUEST_ITEM_SESSION_MAX, GUEST_RESOLVE_ERROR_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_COMPOSE_TEXT_MAX, GUEST_FILE_CONTENT_MAX, GUEST_FILE_ENTRY_KINDS, GUEST_FILE_LIST_MAX, GUEST_GENERATE_OUTPUT_TOKENS_MAX, GUEST_GENERATE_PROMPT_MAX, GUEST_GENERATE_SYSTEM_MAX, GUEST_GENERATE_TEXT_MAX, GUEST_FILE_PATH_MAX, GUEST_FILE_STAT_KINDS, GUEST_REQUEST_BODY_MAX, GUEST_REQUEST_PATH_MAX, GUEST_REQUEST_RESPONSE_MAX, GUEST_SESSION_AGENT_MAX, GUEST_SESSION_MODEL_MAX, GUEST_SETTING_VALUE_MAX, GUEST_TOAST_MAX, SESSION_LIFECYCLE_PHASES, SETTING_KEY, START_SESSION_SENT, isGuestFilePath, isGuestRequestPath, resolveHostRequestErrorCode, } from "./contract.js";
|
|
7
8
|
import { GUEST_FILE_EDITOR_CONTENT_MAX, GUEST_FILE_EDITOR_VERSION_MAX } from "./file-editor.js";
|
|
@@ -98,9 +99,19 @@ const fileStatResultPayloadSchema = z.object({
|
|
|
98
99
|
const generateResultPayloadSchema = z.object({
|
|
99
100
|
text: z.string().max(GUEST_GENERATE_TEXT_MAX),
|
|
100
101
|
});
|
|
102
|
+
const shellOutputResultPayloadSchema = z.object({
|
|
103
|
+
output: z.string(),
|
|
104
|
+
cursor: z.number(),
|
|
105
|
+
skipped: z.boolean(),
|
|
106
|
+
});
|
|
107
|
+
const shellStopResultPayloadSchema = z.object({
|
|
108
|
+
stopped: z.literal(true),
|
|
109
|
+
});
|
|
101
110
|
const hostResultPayloadSchema = z.union([
|
|
102
111
|
guestStorageResultSchema,
|
|
103
112
|
guestWorkspaceSnapshotSchema,
|
|
113
|
+
shellOutputResultPayloadSchema,
|
|
114
|
+
shellStopResultPayloadSchema,
|
|
104
115
|
startSessionResultPayloadSchema,
|
|
105
116
|
requestResultPayloadSchema,
|
|
106
117
|
promptResultPayloadSchema,
|
|
@@ -214,8 +225,36 @@ const hostResultSchema = z.object({
|
|
|
214
225
|
code: resolveHostRequestErrorCode(message.code),
|
|
215
226
|
};
|
|
216
227
|
});
|
|
228
|
+
const guestRunningShellSchema = z.object({
|
|
229
|
+
id: z.string().min(1).max(GUEST_SHELL_ID_MAX),
|
|
230
|
+
sessionID: z.string().min(1).max(1024),
|
|
231
|
+
command: z.string(),
|
|
232
|
+
startedAt: z.number().nonnegative(),
|
|
233
|
+
background: z.boolean(),
|
|
234
|
+
}).strict();
|
|
235
|
+
const guestEndedShellSchema = guestRunningShellSchema.extend({
|
|
236
|
+
status: z.enum(GUEST_SHELL_END_STATUSES),
|
|
237
|
+
exit: z.number().int().optional(),
|
|
238
|
+
endedAt: z.number().nonnegative(),
|
|
239
|
+
}).strict();
|
|
240
|
+
const guestShellsScopeSchema = z.discriminatedUnion('kind', [
|
|
241
|
+
z.object({ kind: z.literal('session'), sessionId: z.string().min(1).max(1024) }).strict(),
|
|
242
|
+
z.object({ kind: z.literal('project'), projectId: z.string().min(1).max(1024) }).strict(),
|
|
243
|
+
z.object({ kind: z.literal('global') }).strict(),
|
|
244
|
+
]);
|
|
245
|
+
const guestRunningShellsSnapshotSchema = z.object({
|
|
246
|
+
kind: z.literal('shells'),
|
|
247
|
+
scope: guestShellsScopeSchema,
|
|
248
|
+
shells: z.array(guestRunningShellSchema).max(GUEST_SHELLS_MAX),
|
|
249
|
+
ended: z.array(guestEndedShellSchema).max(GUEST_SHELLS_MAX),
|
|
250
|
+
}).strict();
|
|
217
251
|
export const hostMessageSchema = z.union([
|
|
218
252
|
z.object({ ...envelope, type: z.literal('workspace'), payload: z.object({ subscriptionId: z.string().min(1).max(128), snapshot: guestWorkspaceSnapshotSchema }) }),
|
|
253
|
+
z.object({
|
|
254
|
+
...envelope,
|
|
255
|
+
type: z.literal('shells'),
|
|
256
|
+
payload: z.object({ subscriptionId: z.string().min(1).max(128), snapshot: guestRunningShellsSnapshotSchema }),
|
|
257
|
+
}),
|
|
219
258
|
z.object({
|
|
220
259
|
...envelope,
|
|
221
260
|
type: z.literal('ready'),
|
|
@@ -332,6 +371,10 @@ export const guestMessageSchema = z.discriminatedUnion('type', [
|
|
|
332
371
|
z.object({ ...envelope, type: z.literal('workspace-read'), id: z.string().min(1), payload: guestWorkspaceQuerySchema }),
|
|
333
372
|
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 }) }),
|
|
334
373
|
z.object({ ...envelope, type: z.literal('workspace-unsubscribe'), id: z.string().min(1), payload: z.object({ subscriptionId: z.string().min(1).max(128) }) }),
|
|
374
|
+
z.object({ ...envelope, type: z.literal('shells-subscribe'), id: z.string().min(1), payload: z.object({ subscriptionId: z.string().min(1).max(128), scope: guestShellsScopeSchema }).strict() }),
|
|
375
|
+
z.object({ ...envelope, type: z.literal('shells-unsubscribe'), id: z.string().min(1), payload: z.object({ subscriptionId: z.string().min(1).max(128) }).strict() }),
|
|
376
|
+
z.object({ ...envelope, type: z.literal('shell-output'), id: z.string().min(1), payload: z.object({ shellId: z.string().min(1).max(GUEST_SHELL_ID_MAX), cursor: z.number().int().nonnegative().optional(), tailBytes: z.number().int().positive().max(GUEST_SHELL_OUTPUT_TAIL_MAX).optional() }).strict() }),
|
|
377
|
+
z.object({ ...envelope, type: z.literal('shell-stop'), id: z.string().min(1), payload: z.object({ shellId: z.string().min(1).max(GUEST_SHELL_ID_MAX) }).strict() }),
|
|
335
378
|
z.object({ ...envelope, type: z.literal('storage'), id: z.string().min(1), payload: guestStorageRequestSchema }),
|
|
336
379
|
z.object({
|
|
337
380
|
...envelope,
|
package/dist/shells.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export declare const GUEST_SHELL_ID_MAX = 128;
|
|
2
|
+
export declare const GUEST_SHELLS_MAX = 200;
|
|
3
|
+
export declare const GUEST_SHELL_OUTPUT_TAIL_MAX = 65536;
|
|
4
|
+
/** A shell command still running on behalf of a session. */
|
|
5
|
+
export type GuestRunningShell = {
|
|
6
|
+
id: string;
|
|
7
|
+
sessionID: string;
|
|
8
|
+
command: string;
|
|
9
|
+
startedAt: number;
|
|
10
|
+
/** True for a job the turn does not wait for; false while the turn that ran it is blocked on it. */
|
|
11
|
+
background: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare const GUEST_SHELL_END_STATUSES: readonly ["exited", "timeout", "killed", "stopped", "unknown"];
|
|
14
|
+
/**
|
|
15
|
+
* How a shell command ended: `exited` on its own (see `exit`), `timeout`,
|
|
16
|
+
* `killed` by a signal, `stopped` by a user (Stop, or aborting the turn that
|
|
17
|
+
* waited on it), or `unknown` when
|
|
18
|
+
* OpenChamber missed the end (a reconnect) and only saw the command gone.
|
|
19
|
+
*/
|
|
20
|
+
export type GuestShellEndStatus = (typeof GUEST_SHELL_END_STATUSES)[number];
|
|
21
|
+
/** A shell command OpenChamber saw running that has since ended. */
|
|
22
|
+
export type GuestEndedShell = GuestRunningShell & {
|
|
23
|
+
status: GuestShellEndStatus;
|
|
24
|
+
/** Exit code, when the command exited and OpenCode reported one. */
|
|
25
|
+
exit?: number;
|
|
26
|
+
endedAt: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Which running shells a subscription covers: one session and its subagents,
|
|
30
|
+
* every session of a registered project, or every session the app sees.
|
|
31
|
+
*/
|
|
32
|
+
export type GuestShellsScope = {
|
|
33
|
+
kind: 'session';
|
|
34
|
+
sessionId: string;
|
|
35
|
+
} | {
|
|
36
|
+
kind: 'project';
|
|
37
|
+
projectId: string;
|
|
38
|
+
} | {
|
|
39
|
+
kind: 'global';
|
|
40
|
+
};
|
|
41
|
+
export type GuestRunningShellsSnapshot = {
|
|
42
|
+
kind: 'shells';
|
|
43
|
+
/** Echo of the scope the subscription asked for. */
|
|
44
|
+
scope: GuestShellsScope;
|
|
45
|
+
shells: GuestRunningShell[];
|
|
46
|
+
/**
|
|
47
|
+
* Commands in scope that ended since OpenChamber started watching, oldest
|
|
48
|
+
* end first. Kept in memory only: empty after an app reload or runtime
|
|
49
|
+
* switch, and capped at `GUEST_SHELLS_MAX`, newest kept.
|
|
50
|
+
*/
|
|
51
|
+
ended: GuestEndedShell[];
|
|
52
|
+
};
|
|
53
|
+
export type GuestShellsSubscription = {
|
|
54
|
+
subscriptionId: string;
|
|
55
|
+
scope: GuestShellsScope;
|
|
56
|
+
};
|
|
57
|
+
export type GuestShellOutputRequest = {
|
|
58
|
+
shellId: string;
|
|
59
|
+
cursor?: number;
|
|
60
|
+
tailBytes?: number;
|
|
61
|
+
};
|
|
62
|
+
export type GuestShellOutputResult = {
|
|
63
|
+
output: string;
|
|
64
|
+
cursor: number;
|
|
65
|
+
skipped: boolean;
|
|
66
|
+
};
|
|
67
|
+
export type GuestShellStopResult = {
|
|
68
|
+
stopped: true;
|
|
69
|
+
};
|
package/dist/shells.js
ADDED