mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-24 02:02:42 +00:00
* feat(app): workspace labels baseline Existing labels implementation, committed as-is as the baseline for the UI redesign. Server, protocol, catalog store and sync are sound; the UI layer is reworked in the commits that follow. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): show workspace labels on the sidebar meta line Labels could be assigned and then appeared nowhere. They now draw as a chip on the workspace meta row, after the host, change request, checks and service, and they can be switched off from the Show submenu like any other item on that line. One palette, not two. `baseColors.workspaceLabel` was ten raw Tailwind 500s spanning a 1.9:1 to 4.5:1 contrast range — the exact set identity-colors.ts was written to replace. Label color is now the identity color of the same name, so a chip, a host badge and a CI check on one row sit in one contrast band. `workspace-labels/colors.ts` and its per-file `labelColorViolet` blocks are gone; `chip.tsx` and `swatch.tsx` are the only places a label color becomes ink. A row resolves its labels against its own host's catalog and nothing else. The cross-host projection answers too, but two hosts may give one name two colors and the merge settles that by target precedence and then alphabetical serverId — a row painted in a color its host never assigned is lying about the one thing the color is for. The meta row's doc comment argued against tinted chrome on that line. The chip is a deliberate exception — everything else there reports state and shares the state colors, a label is a name a person chose — so the comment now says that instead of contradicting the code. Alignment: - The chip is exactly as tall as the line: text at the row's 16pt lineHeight, no vertical padding, so a labelled row is the same height as an unlabelled one. - A label run that opens the line hangs left by the chip's own padding, landing the name on the rail the title above it uses. Mid-line the ground stays in the flow. - The swatch row reaches 44pt through hitSlop growing outward from a 20pt swatch, replacing ten 44pt colored blobs in the manager modal. - The picker's raw `<Plus>`, `<CheckSquare>` and `<Square>` go through withUnistyles with module-level mappings, at the menu's 14pt. Also fixes a bug this change exposed: `SidebarRowItemsSchema` is a strict object, so adding an item without a key there fails the whole settings write and silently loses every other Show toggle with it. A test now covers each item in SIDEBAR_ROW_ITEMS. Phase 1 of the workspace labels redesign. The filter menu, the picker's interaction model and the manager modal's layout are later phases. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): one Labels filter page with tri-state rows Filtering by label cost three levels: Display -> Labels -> Include -> a page of labels, or -> Exclude -> the same page again. It is now one page: every label across every host, one row each, leading with its colour dot. A row cycles off -> include -> exclude -> off. Include is MenuItem's own check; exclude is lucide's X, the check's own pair, at the same 16 in the same trailing slot, so the column does not shift as a row cycles. Exclude also dims the row, because a state you have to identify by its glyph is not one you read at a glance. Unlabelled is a row in the same list, with a hollow ring where the others carry their colour. Match any / all still appears only once two labels are included. Clear is absent, not disabled, when nothing is filtered. Manage labels sits at the bottom below a separator. The whole root row is gone when no host has a label — unless a filter is still active, since the merged catalog only counts online hosts and losing one would otherwise strand a filter that is still hiding workspaces. The page is titled Labels, so its rows stop repeating the word: "Match any", "Match all", "Clear filter". The two Match rows sit directly under the list they qualify and only appear once two labels are included, so the subject is already on screen. All nine locales move together, translated rather than transliterated — Arabic keeps its noun, where "أي" is a determiner that needs one to stay grammatical. SidebarLabelFilter collapses from four collections plus match to one Record<labelKey, "include" | "exclude"> plus match: a tri-state row is one value per label, so include and exclude can no longer disagree about the same name. Unlabelled keys off the empty string, which normalizeWorkspaceLabelName makes unreachable for a real label. toggleSidebarLabelSelection, countSidebarLabelSelections, sidebarLabelSelectionIncludes and deduplicateSidebarLabelNames go with the old shape; setLabelFilter becomes cycleLabelFilter and setLabelMatch, so the store owns its own transitions. No migration: labels are unreleased, so the old persisted shape never shipped, and migrateSidebarViewState already resets on a safeParse failure. The e2e manager step asserted "Red label color" on a swatch that Phase 1 renamed to "Red"; the selector follows the code, and the accessibility.color key behind the old string is deleted from all nine locales as unreferenced. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): assign labels on the menu's own rails The assign picker was a search box, a create row that unfolded an inline form under it, and hand-rolled label rows whose 44x44 checkbox pushed every dot and name off the rail the rows above them sat on. Nothing lined up with anything. Rows are `MenuItem` now: the colour dot in the 16pt leading slot, assignment as the trailing check the engine already draws for a chosen row. Using the engine's row is the alignment fix; there is no second row implementation to keep in step. Every press toggles and the menu stays open — assigning labels is multi-select, so the dual-target model (`source: "row" | "checkbox"`, `shouldCloseWorkspaceLabelPicker`) is gone along with the model's `close` dependency. You leave by dismissing the menu. Search is deleted. Nobody has enough labels to search, and the field was the thing pushing the list down the surface. `workspaceLabels.search` and `createNamed` go with it across all nine locales; `clearSearch` stays because the manager modal still owns a search field (Phase 4's copy, untouched here). `Create label` moves below a separator at the bottom and opens a page that replaces the list: a name field, the swatch row, one commit row. Picking a colour picks a colour — it no longer creates the label. A failed create keeps the draft and shows the error on the page; a successful one creates, assigns, and returns to the list with the row ticked. Both menus share one page definition. `SidebarWorkspaceMenu` and `SidebarWorkspaceContextMenu` each built the same `pages` memo; they now call `useWorkspaceLabelMenuPages`. Menu engine, all of it forced by putting a text input on a menu page: - `MenuTextField` — the form kit's `FormTextInput` carries a screen's geometry and lands its text 4pt inside the labels above it. This one is drawn as a row's own fill, so the box and the text sit on the row's two rails at once. - `MenuPageDefinition.hoverIntent` — a page you type into is not one the pointer opens or dismisses. Without it the create flyout opened on a pointer passing over the row, and threw the draft away when the mouse drifted off it while the hands were on the keyboard. - The sheet keeps `keyboardBehavior="interactive"`, not `extend`. With `enableDynamicSizing` the largest snap point is the content's own height, so a short page did not grow and the keyboard came up over the field. Caught on an iOS simulator, fixed, and re-shot. - `MenuItem` announces `selected` as `aria-checked`. The deleted checkbox said so; a check drawn and never announced would have been an accessibility regression. Tri-state rows (the filter page's exclude) still cannot announce themselves — menu-wide, still Phase 5's. `sidebar-workspace-row.tsx`'s `isTouchPlatform = platformIsNative || isCompact` is kept deliberately. On a compact web viewport there is no hover, so the row's trailing actions and kebab were unreachable and the labels menu with them; this is the documented `isHovered || isNative || isCompact` shape from CLAUDE.md. Evidence: /tmp/labels-p3-{wide,compact}-{light,dark}-{list,create}.png, the create page on iOS with the keyboard up (/tmp/labels-p3-native-compact-keyboard.png) and the clipped sheet it replaced (-before.png). `packages/app/e2e/browser/workspace-labels.spec.ts` rewritten for the new model, daemon-backed failure coverage kept for both the toggle and the create path, green with the menu unit suites. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): edit a label in one operation `workspace.label.rename.request` and `workspace.label.recolor.request` become one `workspace.label.update.request { name, newName?, color? }`. Both old RPCs are deleted outright — no COMPAT shim, because the labels feature is unreleased and neither name has ever been on a wire a user owns. The `workspaceLabels` capability flag stays; that one is how a new app detects an old daemon. Two calls could land half-applied, which left the catalog in a state nobody asked for and the UI with nothing true to say. One catalog commit now applies the name, the colour, or both. Renaming onto a name the host already has is rejected rather than merged, and the check runs inside the planner so a refused collision applies neither field. A label keeping its own key is not colliding with itself, so case-only edits pass. The manager modal follows: - The host selector is `HostFilter`, the pill History and Schedules use. `includeAllHost` is now a prop: a surface that edits one host's catalog cannot carry out "all". - Search moves to the sheet header, where it spans the header's own rails. As a body control it capped at the component's 420pt and left a hole on the right whenever a host filter wasn't beside it. `workspaceLabels.clearSearch` goes with the box that had a clear button. - A row no longer opens an editor. It carries a pencil in its trailing slot, hover-revealed on web and always visible on native and compact, on the canonical plain-View hover pattern with the press on an inner Pressable. - The edit view is a name field, the swatch row, and one Save that issues one update. Delete keeps its confirm and its affected-workspace count, and moves to `outline` — red belongs to the dialog, not to the surface that opens it. - Copy says edit, never rename or recolor, in all nine locales. `workspaceLabelErrorMessage` drops the `requestType=… code=…` the daemon client appends to every RPC failure. That is what a log wants, not what a user reads under a name field. `workspaceLabels.accessibility.color` stays deleted: the swatch's accessible name is already the colour's name, so nothing needed it back. Co-authored-by: Christoph Leiter <christoph@leiter.io> * chore(app): converge the labels phases The sweep at the end of the labels redesign: the three items earlier phases found and kept out of their own commits, one cross-phase pass, and the docs. `AdaptiveModalSheet`'s close button reaches its target with `hitSlop` instead of `padding`, which had inset its glyph 8pt from the rail the title, the search field and every trailing glyph below it sit on. This is shared chrome, so it moves the close glyph in every sheet in the app; measured on four of them across both paths — the labels manager desktop and compact, the shortcuts dialog, the rename sheet — and each one's trailing rail now agrees with its leading one. `MenuItem` takes `selected: boolean | "mixed"`. A tri-state row was silent to a screen reader: the check announced itself after the last phase, but exclude had no state at all, so an excluded label was indistinguishable from an untouched one. `"mixed"` is ARIA's own third state, the engine still draws the check only for `true`, and the row keeps supplying its own trailing mark — nothing in the menu engine learns what a label is. CLAUDE.md's platform-gating rules said "NEVER use `onPointerEnter`/ `onPointerLeave`", which is the opposite of what `docs/hover.md` and `constants/platform.ts` both mandate. It now names the real rule — hover on a plain `View`, press on a separate inner `Pressable`, and no `onHoverIn`/ `onHoverOut` on a `Pressable` that contains other pressables — and links the doc that owns it rather than restating it. The cross-phase pass turned up one real defect: the replica cache never learned about labels. `StoredWorkspaceSchema` had no `labels`, so a restored workspace came back unlabelled, and since the directory cursor is current on reconnect the daemon has nothing newer to send — the chips stayed gone for the whole session and the filter matched nothing. An optional field, a serializer line, and an assertion in the restore spec. Everything else measured onto its rails already. Left alone and logged: the per-row `Map` in `useWorkspaceLabelDefinitions`, and the display menu closing when the sidebar swaps to its empty state, which is confined to that swap and predates every phase here. `docs/architecture.md` and `docs/data-model.md` described rename and recolor; they now describe the one update commit, which fields it rewrites, and the per-host resolution a row's chips use. `docs/menus.md` documents the third item state where it already documents the other two. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): split the labels filter into include and exclude controls The Labels page rotated one row through off -> include -> exclude -> off, which billed the rare operation to the common one: clearing an include cost two presses and routed through exclude, so the sidebar visibly re-filtered into a state nobody asked for on the way out. The row now owns include and a control on its trailing rail owns exclude. Each is one press each way and neither is reached through the other. `cycleLabelFilter` becomes `toggleLabelInclude` and `toggleLabelExclude`; the store's map shape is unchanged, and setting either state clears the other for that label, so including an excluded row is still one press. A row is never both, so the trailing rail holds exactly one 16pt glyph in every state: the check, a permanent `X`, or the same `X` revealed on hover. `X` rather than a circle-slash for the reason Phase 2 settled it — `Ban` fills its box where the check does not, and the column twitches. The control fades rather than mounts and takes its 44pt target from `hitSlop`, so neither revealing it nor changing state moves anything: measured 453-469 on every row, wide and compact. The control carries a tooltip, gated to web where hover exists. It portals into the overlay root above the flyout with no backdrop of its own, and resting on it does not read as the pointer leaving the surface, so the menu stays up. Accessibility: the control is a `checkbox` named "Exclude {label}" with its own checked state, and it stays in the tree at opacity 0 on rows that have no visible mark, so it is reachable without hover. Keyboard focus reveals it, so tabbing to it never means pressing something invisible. The row keeps Phase 5's `selected="mixed"` for exclude. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): put include and exclude on their own rails on every label row Phase 6 gave the row include and its trailing rail a hover-revealed exclude. The rotation was gone but the awkwardness was not: `X` is the glyph this app dismisses things with, so on a filter row it reads as delete rather than exclude, and one rail with a changing occupant still means the row's trailing area keeps changing identity as you read down the column. Both controls are now on every row in fixed positions, and state is which one is lit. Nothing appears, disappears, swaps places or shifts: the check box is 429-445 and the ban box 453-469 on an included row, an excluded row and an untouched one alike, wide and compact. Because the ban is always there, include -> exclude is one press instead of two. The row still includes, and the check is that same action named. `Ban` rather than `X`. Phase 2 rejected it because its ink fills its 16pt box where a check's does not, so the column twitched when the two swapped on one rail. Nothing swaps here, so what is left is a weight difference: the ban is drawn at 14 inside a 16pt box, which is the visible optical correction available before it stops being a glyph. The box is what the rail is measured from and it stays 16. Lit is `foreground`, unlit `foregroundExtraMuted`. Not `foregroundMuted`, which is the obvious choice and is wrong here specifically: the Match rows further down the same page carry `MenuItem`'s own check in that colour to mean *selected*, so an unlit check in the same ink would say the opposite thing eight pixels above it. Excluded keeps Phase 2's dimmed row. Accessibility: the row keeps `selected` — `true` include, `"mixed"` exclude — and the two buttons carry no checked state of their own, so a label's state is announced once and its two controls read as the actions they are. Both buttons take a tooltip, gated to web with `enabledOnDesktop={isWeb}`, because on non-compact native `TooltipContent` falls back to a `Modal` with its own backdrop. Deleted with it: the `isHovered || isFocused || isNative || isCompact` reveal, the `opacity: 0` mounting, the hover-tracking `View` and the focus plumbing that existed to keep an invisible control reachable. Net -7 lines of code on this row, all of the growth in comments. The store is unchanged; both buttons and the row press map onto `toggleLabelInclude` / `toggleLabelExclude` as they are. The e2e's hover-reveal and `toHaveCount(0)` steps encoded the deleted behaviour and are replaced by a rail measurement taken in every state — relative to the row, since filtering moves the anchor the menu hangs off, and behind a settle poll, since the flyout scales in and a box read mid-animation is not a rail. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): reveal the label filter's controls, and stop the empty state closing the menu Phase 7 put the check and the ban on every label row at all times, which made a resting list of labels read as two columns of buttons with a filter somewhere behind them. A row now shows its own state and nothing else — a marked row its mark, an untouched row nothing — and hovering any row brings both controls up, the mark you have lit and the other one unlit beside it. So the column you read down is the filter, and the row you are pointing at is the one offering to change it. Nothing about the rails changed. The two boxes are laid out in every state and only their ink comes and goes: check 429-445, ban 453-469 on an included row, an excluded row, an untouched one, hovered or not, wide and compact. The reveal is opacity, never mounting, so it cannot move the row out from under the pointer that fired it. Hover is tracked on a plain `View` wrapping the `MenuItem` with the presses on the buttons inside it, since `MenuItem` is itself a `Pressable` (docs/hover.md); each control counts its own keyboard focus as revealed, so tabbing to one never means pressing something invisible; and `pointerEvents` follows visibility so a hidden control cannot be clicked. On native and compact there is no pointer, so both simply stand there. Everything Phase 7 settled is kept: `Ban` at 14 in a 16pt box, `foregroundExtraMuted` for unlit against `foregroundMuted` meaning *selected* eight pixels below, `spacing[2]` between the two with `hitSlop` tiling the gap, the row owning `aria-checked` while the buttons stay plain named actions, and both tooltips gated `enabledOnDesktop={isWeb}`. --- Excluding a label that empties the sidebar closed the display menu. Logged since Phase 2, narrowed in Phase 5 to the empty-state swap, owned by nobody. `SidebarLabelFilterEmptyState` was a component rendered *instead of* the list, with its own container and scroll view, and both branches were handed the same header element. Different subtrees, so React unmounted the header on the swap — and the header holds the display menu's trigger, so the popover went with its anchor. The empty state is now a body: both list modes render it where their groups would go, inside the scroll they already own and below the header they already render, and the swap can no longer reach anything above it. Cleared from that same still-open page, the way back out is the swap in reverse and it holds too. `ProjectModeList` was already the right shape — its "no projects yet" body sits below the header — but its header was conditional on `unpinnedProjects.length > 0 || hasActiveHostFilter`, which is the same bug written as a guard: keep the header when there is a filter to undo. The label filter joins that condition rather than getting a second mechanism. Both empty states move into `sidebar/empty-states.tsx` so the two list modes can render either without importing each other, which also leaves the card's geometry defined once instead of once per body. Still conditional, and left alone: a sidebar with no projects and no filter has no header at all, so clearing the last host filter on an empty sidebar closes the menu the same way. That one is the onboarding empty state, where a section heading over "Add a project" would be a heading over nothing, and no menu is reachable in the state it lands in. The e2e gets the step that would have caught this: exclude into the empty state, assert the page you pressed on is still up, clear from it, assert the same. Verified by reverting both list files to Phase 7 and watching it fail on "element(s) not found". Phase 7's rail assertions are kept as they are — offsets within the row, behind a settle poll — and joined by computed-opacity reads for the four states of the reveal. Evidence: /tmp/labels-qa-p8/, 28 shots plus INDEX.md — the resting list, a hovered row, an included row with the pointer away, and the empty state with the menu still open over it, at wide and compact in both schemes. Co-authored-by: Christoph Leiter <christoph@leiter.io> * feat(app): make the label filter include-only Phases 2, 6, 7 and 8 each tried to give exclusion a comfortable shape inside a 232pt menu row: tri-state rotation, a hover-revealed control, two permanent buttons, two hover-or-lit buttons. Every fix bought a new awkwardness, because two controls in one menu row is a lot of machinery for a filter. The label filter is now the host filter — one tap in, one tap out — and nobody has ever complained about that one. A row is a plain `MenuItem` with the colour dot leading and the engine's own check trailing. Nothing else. Which makes the alignment law trivial to satisfy, and that is the point. Deleted rather than disabled, since 6, 7 and 8 are in the branch history if exclusion ever comes back: both trailing controls, the hover-tracking `View`, the `opacity: 0` mounting, the focus/blur plumbing, the `pointerEvents` gating, both tooltips and their `enabledOnDesktop={isWeb}` gates, the lit/unlit token pair, `Ban`, and the two rails they held. `SidebarLabelFilter` collapses onto the shape of `hostFilters` sitting three fields above it in the same store: `labels: string[]` plus `match`, one `toggleLabelFilter`, one `clearLabelFilter`. The exclude arm of `filterWorkspacesByLabels` goes with it, and `filter.include` / `includeLabel` / `exclude` / `excludeLabel` leave all nine locales. Persisted version 4 with no migration — the record shape never shipped, and `createValidatedPersistStorage` drops state that fails the current schema before `migrate` ever runs. Two things this leaves unused, both deleted: - `MenuItem`'s `selected: boolean | "mixed"`, added in Phase 5 so a tri-state row could announce itself. The filter row was the only caller, so the union collapses back to `boolean` and the two `selected === true` guards that existed for `"mixed"` go back to plain truthiness. - The `docs/menus.md` paragraphs from Phases 7 and 8 on hover-revealing a pressable trailing control inside a menu row. No caller does that any more, so the doc was describing a pattern the codebase no longer has. Kept: `SIDEBAR_UNLABELLED_LABEL_KEY`, because `Unlabelled` is still a row and now includes like any other; `Match any` / `Match all`, because multi-select include still means two different things. Phase 8's empty-state fix is untouched and still holds — `hasActiveSidebarLabelFilter` is what the header's survival condition reads, and it answers the same question against the new shape. Evidence: /tmp/labels-qa-p9/, 12 shots plus INDEX.md — resting, two selected, and the empty state with the menu still open over it, at wide and compact in both schemes. Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): give label-grouped rows their project icons, and label groups a tag Grouping the sidebar by label rendered every workspace row with its placeholder initial. The same workspace under status or project grouping showed its real project icon. The components were reused; the data feeding them was not. One component served both grouping modes and threaded the icon map through correctly. Fourteen lines above it, a second `useProjectIcons` call was gated on `groupMode === "status"`, written when status was the only mode that put icons on rows. Phase 2 extended the render branch to `status || label` and left the gate alone. Nothing forces a render branch and the data it renders to agree, and these two were far enough apart to drift in silence. Reuse buys you one implementation of the drawing; it buys you nothing about who decides what to fetch. So the fix is the shape, not the line. There is now one `useProjectIcons` call for every mode, and its targets come from `buildSidebarProjection` — the same function that produced the rows, from the same `projects` list. A mode can only render a row for a project the projection already knows about, so the map cannot disagree with the screen. The gate is gone rather than extended: extending it would leave the identical trap for the next grouping mode. `useProjectIcons` dedupes by `serverId:projectId` and caches through `useQueries`, so the gate was a premature optimization that bought a bug. Pinned by `sidebar-projection.test.ts`: for each of the three modes, every project view key the projection will render — pinned rows, grouped rows, project headers and the rows under them — has an icon target. Red on the old gate: restoring `groupMode === "status" ? … : []` in its new home fails project and label grouping with `['project', 'other-project']` uncovered, and status passes, which is exactly the bug's signature. The sibling sweep over everything `SidebarStatusModeWrapper` is handed found one more of the same shape, correct today: the projection chose its shortcut sections with `status || label`, so a fourth mode would have silently walked the project rows. Both the groups and the sections now come from one exhaustive `switch` on the mode, which makes the next mode a compile error rather than an empty list. `workspaceEntriesByKey` is already written the safe way round (`!== "project"`), and the rest — host badges, pinning support, the empty-filter state — never read the mode at all. Two names moved with the shape: `SidebarStatusModeWrapper` is `SidebarGroupedModeList`, and its branch is `groupMode !== "project"`, so a new mode lands in the grouped list instead of the project list's `else`. Also: label group headers draw lucide `Tag` instead of `CircleDot`, in the label's colour, muted for `Unlabelled` — the glyph the Labels menu and the workspace menu already use for this feature. It keeps `StatusGroupIcon`'s 14 with no optical nudge, and that is measured rather than assumed: in the header's leading slot both ink a 14x14 box at the same offset, and the tag lays down 76 ink pixels to the circle's 84, so reaching the corners of its box costs it no weight beside the status glyphs. QA: /tmp/labels-qa-p10/ — wide and compact, light and dark, label grouping and the same workspaces under status grouping, plus the hover chevron swap, the glyph zooms, and a before/after pair taken with the fix reverted to the bug's shape. Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): align label chip typography Co-authored-by: Christoph Leiter <christoph@leiter.io> * docs: format architecture module table Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): narrow workspace labels workflow Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): mirror bottom sheet test exports Co-authored-by: Christoph Leiter <christoph@leiter.io> * test(desktop): assert project browse by destination Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): retain empty projects without label filters Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): preserve status grouping test contract Co-authored-by: Christoph Leiter <christoph@leiter.io> * fix(app): retain filters after label load failures Co-authored-by: Christoph Leiter <christoph@leiter.io> --------- Co-authored-by: Christoph Leiter <christoph@leiter.io>
6900 lines
237 KiB
TypeScript
6900 lines
237 KiB
TypeScript
import { z } from "zod";
|
|
import { TerminalActivitySchema } from "./terminal-activity.js";
|
|
import { CLIENT_CAPS } from "./client-capabilities.js";
|
|
import { AGENT_LIFECYCLE_STATUSES } from "./agent-lifecycle.js";
|
|
import { MAX_EXPLICIT_AGENT_TITLE_CHARS } from "./agent-title-limits.js";
|
|
import { AgentProviderSchema } from "./provider-manifest.js";
|
|
import { TOOL_CALL_ICON_NAMES } from "./agent-types.js";
|
|
import { WORKSPACE_LABEL_COLORS } from "./workspace-labels.js";
|
|
import {
|
|
ChatCreateRequestSchema,
|
|
ChatListRequestSchema,
|
|
ChatInspectRequestSchema,
|
|
ChatDeleteRequestSchema,
|
|
ChatPostRequestSchema,
|
|
ChatReadRequestSchema,
|
|
ChatWaitRequestSchema,
|
|
ChatCreateResponseSchema,
|
|
ChatListResponseSchema,
|
|
ChatInspectResponseSchema,
|
|
ChatDeleteResponseSchema,
|
|
ChatPostResponseSchema,
|
|
ChatReadResponseSchema,
|
|
ChatWaitResponseSchema,
|
|
} from "./chat/rpc-schemas.js";
|
|
import {
|
|
ScheduleCreateRequestSchema,
|
|
ScheduleListRequestSchema,
|
|
ScheduleInspectRequestSchema,
|
|
ScheduleLogsRequestSchema,
|
|
SchedulePauseRequestSchema,
|
|
ScheduleResumeRequestSchema,
|
|
ScheduleDeleteRequestSchema,
|
|
ScheduleRunOnceRequestSchema,
|
|
ScheduleUpdateRequestSchema,
|
|
ScheduleCreateResponseSchema,
|
|
ScheduleListResponseSchema,
|
|
ScheduleInspectResponseSchema,
|
|
ScheduleLogsResponseSchema,
|
|
SchedulePauseResponseSchema,
|
|
ScheduleResumeResponseSchema,
|
|
ScheduleDeleteResponseSchema,
|
|
ScheduleRunOnceResponseSchema,
|
|
ScheduleUpdateResponseSchema,
|
|
} from "./schedule/rpc-schemas.js";
|
|
import {
|
|
LoopRunRequestSchema,
|
|
LoopListRequestSchema,
|
|
LoopInspectRequestSchema,
|
|
LoopLogsRequestSchema,
|
|
LoopStopRequestSchema,
|
|
LoopRunResponseSchema,
|
|
LoopListResponseSchema,
|
|
LoopInspectResponseSchema,
|
|
LoopLogsResponseSchema,
|
|
LoopStopResponseSchema,
|
|
} from "./loop/rpc-schemas.js";
|
|
import {
|
|
BrowserAutomationExecuteRequestSchema,
|
|
BrowserAutomationExecuteResponseSchema,
|
|
} from "./browser-automation/rpc-schemas.js";
|
|
import { BrowserAutomationHostCapabilitySchema } from "./browser-automation/capabilities.js";
|
|
import {
|
|
PaseoConfigRawSchema,
|
|
PaseoLifecycleCommandRawSchema,
|
|
PaseoMetadataGenerationEntrySchema,
|
|
PaseoMetadataGenerationSchema,
|
|
PaseoScriptEntryRawSchema,
|
|
PaseoWorktreeConfigRawSchema,
|
|
PaseoConfigRevisionSchema,
|
|
ProjectConfigRpcErrorSchema,
|
|
type PaseoConfigRaw,
|
|
type PaseoConfigRevision,
|
|
type PaseoMetadataGeneration,
|
|
type PaseoMetadataGenerationEntry,
|
|
type PaseoScriptEntryRaw,
|
|
type ProjectConfigRpcError,
|
|
} from "./paseo-config-schema.js";
|
|
export {
|
|
PaseoConfigRawSchema,
|
|
PaseoLifecycleCommandRawSchema,
|
|
PaseoMetadataGenerationEntrySchema,
|
|
PaseoMetadataGenerationSchema,
|
|
PaseoScriptEntryRawSchema,
|
|
PaseoWorktreeConfigRawSchema,
|
|
type PaseoConfigRaw,
|
|
type PaseoConfigRevision,
|
|
type PaseoMetadataGeneration,
|
|
type PaseoMetadataGenerationEntry,
|
|
type PaseoScriptEntryRaw,
|
|
type ProjectConfigRpcError,
|
|
};
|
|
// ---------------------------------------------------------------------------
|
|
// Mutable daemon config schemas (shared between server store and client)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const MutableDaemonProviderModelSchema = z
|
|
.object({
|
|
id: z.string().min(1),
|
|
label: z.string().min(1),
|
|
description: z.string().optional(),
|
|
isDefault: z.boolean().optional(),
|
|
})
|
|
.passthrough();
|
|
|
|
const MutableDaemonProviderConfigSchema = z
|
|
.object({
|
|
enabled: z.boolean().optional(),
|
|
additionalModels: z.array(MutableDaemonProviderModelSchema).optional(),
|
|
})
|
|
.passthrough();
|
|
|
|
const MutableStructuredGenerationProviderSchema = z
|
|
.object({
|
|
provider: z.string().min(1),
|
|
model: z.string().min(1).optional(),
|
|
thinkingOptionId: z.string().min(1).optional(),
|
|
})
|
|
.passthrough();
|
|
|
|
const MutableMetadataGenerationConfigSchema = z
|
|
.object({
|
|
providers: z.array(MutableStructuredGenerationProviderSchema).default([]),
|
|
})
|
|
.passthrough();
|
|
|
|
export const TerminalProfileSchema = z
|
|
.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
command: z.string(),
|
|
args: z.array(z.string()).optional(),
|
|
icon: z.string().optional(),
|
|
})
|
|
.passthrough();
|
|
|
|
export type TerminalProfile = z.infer<typeof TerminalProfileSchema>;
|
|
|
|
/**
|
|
* A named launch bundle: a provider plus the agent-config values a client would
|
|
* otherwise set one control at a time. Field names mirror `AgentSessionConfig`
|
|
* so applying a profile is a copy rather than a translation table.
|
|
*
|
|
* There is deliberately no system prompt here. `AgentSessionConfig.systemPrompt`
|
|
* is creation-only, so a profile carrying one would apply when starting a new
|
|
* agent and silently do nothing when applied to a running one.
|
|
*/
|
|
export const AgentProfileSchema = z
|
|
.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
/** A key into the client's icon registry, not a glyph. Unknown keys draw the default. */
|
|
icon: z.string().optional(),
|
|
/** An identity colour name shared with host badges. Unknown values draw unthemed. */
|
|
color: z.string().optional(),
|
|
provider: z.string(),
|
|
model: z.string().optional(),
|
|
modeId: z.string().optional(),
|
|
thinkingOptionId: z.string().optional(),
|
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
|
/** Free text, surfaced to orchestrating agents by the `list_profiles` MCP tool. */
|
|
notes: z.string().optional(),
|
|
})
|
|
.passthrough();
|
|
|
|
export type AgentProfile = z.infer<typeof AgentProfileSchema>;
|
|
|
|
const MutableBrowserToolsConfigSchema = z
|
|
.object({
|
|
enabled: z.boolean().default(false),
|
|
})
|
|
.passthrough();
|
|
const MutableRelayConfigSchema = z
|
|
.object({
|
|
enabled: z.boolean(),
|
|
})
|
|
.passthrough();
|
|
|
|
export const PluginIdSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
|
|
export const DirectoryPluginSourceSchema = z
|
|
.object({
|
|
source: z.literal("directory"),
|
|
path: z.string().min(1),
|
|
enabled: z.boolean().optional(),
|
|
})
|
|
.strict();
|
|
|
|
export const PluginSourceSchema = z.discriminatedUnion("source", [DirectoryPluginSourceSchema]);
|
|
|
|
export type PluginSource = z.infer<typeof PluginSourceSchema>;
|
|
|
|
export const AgentSkillSelectionSchema = z.discriminatedUnion("mode", [
|
|
z.object({ mode: z.literal("all") }).strict(),
|
|
z.object({ mode: z.literal("custom"), skills: z.array(z.string()) }).strict(),
|
|
]);
|
|
export type AgentSkillSelection = z.infer<typeof AgentSkillSelectionSchema>;
|
|
|
|
export const MutableDaemonConfigSchema = z
|
|
.object({
|
|
// COMPAT(relayConfig): added in v0.2.6, remove after 2027-01-31 when old daemons are unsupported.
|
|
relay: MutableRelayConfigSchema.optional(),
|
|
mcp: z
|
|
.object({
|
|
enabled: z.boolean().optional(),
|
|
injectIntoAgents: z.boolean(),
|
|
})
|
|
.passthrough(),
|
|
hostnames: z.union([z.literal(true), z.array(z.string())]).optional(),
|
|
cors: z
|
|
.object({
|
|
allowedOrigins: z.array(z.string()),
|
|
})
|
|
.passthrough()
|
|
.optional(),
|
|
trustedProxies: z.union([z.literal(true), z.array(z.string())]).optional(),
|
|
git: z
|
|
.object({
|
|
maxProcessesPerSecond: z.number().int().positive(),
|
|
maxProcessConcurrency: z.number().int().positive(),
|
|
})
|
|
.optional(),
|
|
app: z.object({ baseUrl: z.string() }).optional(),
|
|
catalogRefreshTimeoutMs: z.number().int().positive().optional(),
|
|
browserTools: MutableBrowserToolsConfigSchema.default({ enabled: false }),
|
|
providers: z.record(z.string(), MutableDaemonProviderConfigSchema).default({}),
|
|
metadataGeneration: MutableMetadataGenerationConfigSchema.default({ providers: [] }),
|
|
autoArchiveAfterMerge: z.boolean().default(false),
|
|
enableTerminalAgentHooks: z.boolean().default(false),
|
|
appendSystemPrompt: z.string().default(""),
|
|
terminalProfiles: z.array(TerminalProfileSchema).optional(),
|
|
agentProfiles: z.array(AgentProfileSchema).optional(),
|
|
skills: z.object({ selection: AgentSkillSelectionSchema.optional() }).strict().optional(),
|
|
pluginsEnabled: z.boolean().optional(),
|
|
plugins: z.record(PluginIdSchema, PluginSourceSchema).optional(),
|
|
})
|
|
.passthrough();
|
|
|
|
export const MutableDaemonConfigPatchSchema = z
|
|
.object({
|
|
relay: MutableRelayConfigSchema.partial().optional(),
|
|
mcp: z.object({ injectIntoAgents: z.boolean().optional() }).passthrough().optional(),
|
|
browserTools: MutableBrowserToolsConfigSchema.partial().optional(),
|
|
providers: z
|
|
.record(z.string(), MutableDaemonProviderConfigSchema.partial().passthrough())
|
|
.optional(),
|
|
removeProviders: z.array(z.string().min(1)).optional(),
|
|
metadataGeneration: MutableMetadataGenerationConfigSchema.partial().optional(),
|
|
autoArchiveAfterMerge: z.boolean().optional(),
|
|
enableTerminalAgentHooks: z.boolean().optional(),
|
|
appendSystemPrompt: z.string().optional(),
|
|
terminalProfiles: z.array(TerminalProfileSchema).optional(),
|
|
agentProfiles: z.array(AgentProfileSchema).optional(),
|
|
pluginsEnabled: z.boolean().optional(),
|
|
plugins: z.record(PluginIdSchema, PluginSourceSchema).optional(),
|
|
})
|
|
.partial()
|
|
.passthrough();
|
|
|
|
export type MutableDaemonConfig = z.infer<typeof MutableDaemonConfigSchema>;
|
|
export type MutableDaemonConfigPatch = z.infer<typeof MutableDaemonConfigPatchSchema>;
|
|
import type {
|
|
AgentCapabilityFlags,
|
|
AgentModelDefinition,
|
|
AgentMode,
|
|
AgentPermissionRequest,
|
|
AgentPermissionResponse,
|
|
AgentPersistenceHandle,
|
|
ProviderStatus,
|
|
AgentRuntimeInfo,
|
|
AgentTimelineItem,
|
|
AgentProviderNotice,
|
|
ToolCallDetail,
|
|
ToolCallTimelineItem,
|
|
AgentUsage,
|
|
} from "./agent-types.js";
|
|
|
|
export const AgentStatusSchema = z.enum(AGENT_LIFECYCLE_STATUSES);
|
|
|
|
const AgentModeSchema: z.ZodType<AgentMode> = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
icon: z.string().optional(),
|
|
colorTier: z.string().optional(),
|
|
});
|
|
|
|
const ProviderStatusSchema: z.ZodType<ProviderStatus> = z.enum([
|
|
"ready",
|
|
"loading",
|
|
"error",
|
|
"unavailable",
|
|
]);
|
|
|
|
const AgentSelectOptionSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
isDefault: z.boolean().optional(),
|
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
|
|
const AgentProviderNoticeSchema: z.ZodType<AgentProviderNotice> = z.discriminatedUnion("type", [
|
|
z.object({ type: z.literal("info"), message: z.string() }),
|
|
z.object({ type: z.literal("warning"), message: z.string() }),
|
|
z.object({ type: z.literal("error"), message: z.string() }),
|
|
]);
|
|
|
|
export const AgentFeatureToggleSchema = z.object({
|
|
type: z.literal("toggle"),
|
|
id: z.string(),
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
tooltip: z.string().optional(),
|
|
icon: z.string().optional(),
|
|
value: z.boolean(),
|
|
});
|
|
|
|
export const AgentFeatureSelectSchema = z.object({
|
|
type: z.literal("select"),
|
|
id: z.string(),
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
tooltip: z.string().optional(),
|
|
icon: z.string().optional(),
|
|
value: z.string().nullable(),
|
|
options: z.array(AgentSelectOptionSchema),
|
|
});
|
|
|
|
export const AgentFeatureSchema = z.discriminatedUnion("type", [
|
|
AgentFeatureToggleSchema,
|
|
AgentFeatureSelectSchema,
|
|
]);
|
|
|
|
const AgentModelDefinitionSchema = z.object({
|
|
provider: AgentProviderSchema,
|
|
id: z.string(),
|
|
aliases: z.array(z.string()).optional(),
|
|
isSelectable: z.boolean().optional(),
|
|
label: z.string(),
|
|
description: z.string().optional(),
|
|
isDefault: z.boolean().optional(),
|
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
contextWindowMaxTokens: z.number().optional(),
|
|
thinkingOptions: z.array(AgentSelectOptionSchema).optional(),
|
|
defaultThinkingOptionId: z.string().optional(),
|
|
}) satisfies z.ZodType<AgentModelDefinition>;
|
|
|
|
export const ProviderSnapshotEntrySchema = z.object({
|
|
provider: AgentProviderSchema,
|
|
status: ProviderStatusSchema,
|
|
enabled: z.boolean().optional().default(true),
|
|
source: z.enum(["builtin", "custom"]).optional(),
|
|
error: z.string().optional(),
|
|
models: z.array(AgentModelDefinitionSchema).optional(),
|
|
modes: z.array(AgentModeSchema).optional(),
|
|
fetchedAt: z.string().optional(),
|
|
label: z.string().optional(),
|
|
description: z.string().optional(),
|
|
defaultModeId: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const CompactProviderSnapshotModelSchema = AgentModelDefinitionSchema.omit({
|
|
provider: true,
|
|
thinkingOptions: true,
|
|
}).extend({
|
|
thinkingSet: z.number().int().nonnegative().optional(),
|
|
});
|
|
|
|
export const ProviderSnapshotThinkingSetSchema = z.object({
|
|
options: z.array(AgentSelectOptionSchema),
|
|
defaultOptionId: z.string().optional(),
|
|
});
|
|
|
|
export const CompactProviderSnapshotEntrySchema = ProviderSnapshotEntrySchema.omit({
|
|
models: true,
|
|
}).extend({
|
|
models: z.array(CompactProviderSnapshotModelSchema).optional(),
|
|
});
|
|
|
|
export const CompactProviderSnapshotSchema = z.object({
|
|
entries: z.array(CompactProviderSnapshotEntrySchema),
|
|
thinkingSets: z.array(ProviderSnapshotThinkingSetSchema),
|
|
});
|
|
|
|
const AgentCapabilityFlagsSchema: z.ZodType<AgentCapabilityFlags> = z
|
|
.object({
|
|
supportsStreaming: z.boolean(),
|
|
supportsSessionPersistence: z.boolean(),
|
|
supportsSessionListing: z.boolean().optional(),
|
|
supportsDynamicModes: z.boolean(),
|
|
supportsMcpServers: z.boolean(),
|
|
supportsReasoningStream: z.boolean(),
|
|
supportsToolInvocations: z.boolean(),
|
|
// COMPAT(rewind): added in v0.1.X, drop when floor >= v0.1.X.
|
|
supportsRewindConversation: z.boolean().optional().default(false),
|
|
// COMPAT(rewind): added in v0.1.X, drop when floor >= v0.1.X.
|
|
supportsRewindFiles: z.boolean().optional().default(false),
|
|
// COMPAT(rewind): added in v0.1.X, drop when floor >= v0.1.X.
|
|
supportsRewindBoth: z.boolean().optional().default(false),
|
|
})
|
|
.catchall(z.boolean());
|
|
|
|
const AgentUsageSchema: z.ZodType<AgentUsage> = z.object({
|
|
inputTokens: z.number().optional(),
|
|
cachedInputTokens: z.number().optional(),
|
|
outputTokens: z.number().optional(),
|
|
totalCostUsd: z.number().optional(),
|
|
contextWindowMaxTokens: z.number().optional(),
|
|
contextWindowUsedTokens: z.number().optional(),
|
|
});
|
|
|
|
const McpStdioServerConfigSchema = z.object({
|
|
type: z.literal("stdio"),
|
|
command: z.string(),
|
|
args: z.array(z.string()).optional(),
|
|
env: z.record(z.string(), z.string()).optional(),
|
|
alwaysLoad: z.boolean().optional(),
|
|
});
|
|
|
|
const McpHttpServerConfigSchema = z.object({
|
|
type: z.literal("http"),
|
|
url: z.string(),
|
|
headers: z.record(z.string(), z.string()).optional(),
|
|
alwaysLoad: z.boolean().optional(),
|
|
});
|
|
|
|
const McpSseServerConfigSchema = z.object({
|
|
type: z.literal("sse"),
|
|
url: z.string(),
|
|
headers: z.record(z.string(), z.string()).optional(),
|
|
alwaysLoad: z.boolean().optional(),
|
|
});
|
|
|
|
const McpServerConfigSchema = z.discriminatedUnion("type", [
|
|
McpStdioServerConfigSchema,
|
|
McpHttpServerConfigSchema,
|
|
McpSseServerConfigSchema,
|
|
]);
|
|
|
|
const ProviderOptionsSchema = z.record(z.string(), z.json());
|
|
|
|
const McpToolRefSchema = z
|
|
.object({
|
|
kind: z.literal("mcp"),
|
|
server: z.string().trim().min(1),
|
|
tool: z.string().trim().min(1),
|
|
})
|
|
.strict();
|
|
|
|
const ToolPolicySchema = z
|
|
.object({
|
|
preapproved: z.array(McpToolRefSchema),
|
|
})
|
|
.strict();
|
|
|
|
const AgentSessionConfigSchema = z.object({
|
|
provider: AgentProviderSchema,
|
|
cwd: z.string(),
|
|
modeId: z.string().optional(),
|
|
model: z.string().optional(),
|
|
thinkingOptionId: z.string().optional(),
|
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
|
title: z.string().trim().min(1).max(MAX_EXPLICIT_AGENT_TITLE_CHARS).optional().nullable(),
|
|
providerOptions: ProviderOptionsSchema.optional(),
|
|
toolPolicy: ToolPolicySchema.optional(),
|
|
systemPrompt: z.string().optional(),
|
|
mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
|
|
});
|
|
|
|
const AgentPermissionUpdateSchema = z.record(z.string(), z.unknown());
|
|
const AgentPermissionActionSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
behavior: z.enum(["allow", "deny"]),
|
|
variant: z.enum(["primary", "secondary", "danger"]).optional(),
|
|
intent: z.enum(["implement", "implement_resume", "dismiss"]).optional(),
|
|
});
|
|
|
|
export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
|
|
z.discriminatedUnion("behavior", [
|
|
z.object({
|
|
behavior: z.literal("allow"),
|
|
selectedActionId: z.string().optional(),
|
|
updatedInput: z.record(z.string(), z.unknown()).optional(),
|
|
updatedPermissions: z.array(AgentPermissionUpdateSchema).optional(),
|
|
}),
|
|
z.object({
|
|
behavior: z.literal("deny"),
|
|
selectedActionId: z.string().optional(),
|
|
message: z.string().optional(),
|
|
interrupt: z.boolean().optional(),
|
|
}),
|
|
]);
|
|
|
|
export const AgentPermissionRequestPayloadSchema: z.ZodType<AgentPermissionRequest, unknown> =
|
|
z.object({
|
|
id: z.string(),
|
|
provider: AgentProviderSchema,
|
|
name: z.string(),
|
|
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
|
|
title: z.string().optional(),
|
|
description: z.string().optional(),
|
|
input: z.record(z.string(), z.unknown()).optional(),
|
|
detail: z.lazy(() => ToolCallDetailPayloadSchema).optional(),
|
|
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
|
|
actions: z.array(AgentPermissionActionSchema).optional(),
|
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
|
|
const UnknownValueSchema = z.union([
|
|
z.null(),
|
|
z.boolean(),
|
|
z.number(),
|
|
z.string(),
|
|
z.array(z.unknown()),
|
|
z.object({}).passthrough(),
|
|
]);
|
|
|
|
const NonNullUnknownSchema = z.union([
|
|
z.boolean(),
|
|
z.number(),
|
|
z.string(),
|
|
z.array(z.unknown()),
|
|
z.object({}).passthrough(),
|
|
]);
|
|
|
|
const WorktreeSetupCommandSnapshotSchema = z.object({
|
|
index: z.number().int().positive(),
|
|
command: z.string(),
|
|
cwd: z.string(),
|
|
log: z.string().optional().default(""),
|
|
status: z.enum(["running", "completed", "failed"]),
|
|
exitCode: z.number().nullable(),
|
|
durationMs: z.number().nonnegative().optional(),
|
|
});
|
|
|
|
const WorktreeSetupDetailPayloadSchema = z.object({
|
|
type: z.literal("worktree_setup"),
|
|
worktreePath: z.string(),
|
|
branchName: z.string(),
|
|
log: z.string(),
|
|
commands: z.array(WorktreeSetupCommandSnapshotSchema),
|
|
truncated: z.boolean().optional(),
|
|
});
|
|
|
|
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, unknown> = z.discriminatedUnion(
|
|
"type",
|
|
[
|
|
WorktreeSetupDetailPayloadSchema,
|
|
z.object({
|
|
type: z.literal("shell"),
|
|
command: z.string(),
|
|
cwd: z.string().optional(),
|
|
output: z.string().optional(),
|
|
exitCode: z.number().nullable().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("read"),
|
|
filePath: z.string(),
|
|
content: z.string().optional(),
|
|
offset: z.number().optional(),
|
|
limit: z.number().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("edit"),
|
|
filePath: z.string(),
|
|
oldString: z.string().optional(),
|
|
newString: z.string().optional(),
|
|
unifiedDiff: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("write"),
|
|
filePath: z.string(),
|
|
content: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("search"),
|
|
query: z.string(),
|
|
toolName: z.enum(["search", "grep", "glob", "web_search"]).optional(),
|
|
content: z.string().optional(),
|
|
filePaths: z.array(z.string()).optional(),
|
|
webResults: z
|
|
.array(
|
|
z.object({
|
|
title: z.string(),
|
|
url: z.string(),
|
|
}),
|
|
)
|
|
.optional(),
|
|
annotations: z.array(z.string()).optional(),
|
|
numFiles: z.number().optional(),
|
|
numMatches: z.number().optional(),
|
|
durationMs: z.number().optional(),
|
|
durationSeconds: z.number().optional(),
|
|
truncated: z.boolean().optional(),
|
|
mode: z.enum(["content", "files_with_matches", "count"]).optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("fetch"),
|
|
url: z.string(),
|
|
prompt: z.string().optional(),
|
|
result: z.string().optional(),
|
|
code: z.number().optional(),
|
|
codeText: z.string().optional(),
|
|
bytes: z.number().optional(),
|
|
durationMs: z.number().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("sub_agent"),
|
|
subAgentType: z.string().optional(),
|
|
description: z.string().optional(),
|
|
childSessionId: z.string().optional(),
|
|
log: z.string(),
|
|
// Compat cruft for clients <= 0.1.65-beta.3 that required this field. Producers still
|
|
// emit `[]`; nothing reads it. Drop the field (and the `[]` emissions) once those
|
|
// clients are no longer in the field.
|
|
actions: z
|
|
.array(
|
|
z.object({
|
|
index: z.number().int().positive(),
|
|
toolName: z.string(),
|
|
summary: z.string().optional(),
|
|
}),
|
|
)
|
|
.optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("plain_text"),
|
|
label: z.string().optional(),
|
|
text: z.string().optional(),
|
|
icon: z.enum(TOOL_CALL_ICON_NAMES).optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("plan"),
|
|
text: z.string(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("unknown"),
|
|
input: UnknownValueSchema,
|
|
output: UnknownValueSchema,
|
|
}),
|
|
],
|
|
);
|
|
|
|
const ToolCallBasePayloadSchema = z.object({
|
|
type: z.literal("tool_call"),
|
|
callId: z.string(),
|
|
name: z.string(),
|
|
detail: ToolCallDetailPayloadSchema,
|
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
|
|
const ToolCallRunningPayloadSchema = ToolCallBasePayloadSchema.extend({
|
|
status: z.literal("running"),
|
|
error: z.null(),
|
|
});
|
|
|
|
const ToolCallCompletedPayloadSchema = ToolCallBasePayloadSchema.extend({
|
|
status: z.literal("completed"),
|
|
error: z.null(),
|
|
});
|
|
|
|
const ToolCallFailedPayloadSchema = ToolCallBasePayloadSchema.extend({
|
|
status: z.literal("failed"),
|
|
error: NonNullUnknownSchema,
|
|
});
|
|
|
|
const ToolCallCanceledPayloadSchema = ToolCallBasePayloadSchema.extend({
|
|
status: z.literal("canceled"),
|
|
error: z.null(),
|
|
});
|
|
|
|
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem, unknown> =
|
|
z.discriminatedUnion("status", [
|
|
ToolCallRunningPayloadSchema,
|
|
ToolCallCompletedPayloadSchema,
|
|
ToolCallFailedPayloadSchema,
|
|
ToolCallCanceledPayloadSchema,
|
|
]);
|
|
|
|
// zod-aot 0.20.4 miscompiles this as a nested discriminated union by omitting
|
|
// the inner tool_call branch from the generated outer dispatch.
|
|
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, unknown> = z.union([
|
|
z.object({
|
|
type: z.literal("user_message"),
|
|
text: z.string(),
|
|
messageId: z.string().optional(),
|
|
clientMessageId: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("assistant_message"),
|
|
text: z.string(),
|
|
messageId: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("reasoning"),
|
|
text: z.string(),
|
|
}),
|
|
ToolCallTimelineItemPayloadSchema,
|
|
z.object({
|
|
type: z.literal("todo"),
|
|
items: z.array(
|
|
z.object({
|
|
text: z.string(),
|
|
completed: z.boolean(),
|
|
id: z.string().optional(),
|
|
status: z.enum(["pending", "in_progress", "completed"]).optional(),
|
|
activeForm: z.string().optional(),
|
|
}),
|
|
),
|
|
}),
|
|
z.object({
|
|
type: z.literal("error"),
|
|
message: z.string(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("compaction"),
|
|
status: z.enum(["loading", "completed"]),
|
|
trigger: z.enum(["auto", "manual"]).optional(),
|
|
preTokens: z.number().optional(),
|
|
}),
|
|
]);
|
|
|
|
export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
|
|
z.object({
|
|
type: z.literal("thread_started"),
|
|
sessionId: z.string(),
|
|
provider: AgentProviderSchema,
|
|
}),
|
|
z.object({
|
|
type: z.literal("turn_started"),
|
|
provider: AgentProviderSchema,
|
|
turnId: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("turn_completed"),
|
|
provider: AgentProviderSchema,
|
|
turnId: z.string().optional(),
|
|
usage: AgentUsageSchema.optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("turn_failed"),
|
|
provider: AgentProviderSchema,
|
|
turnId: z.string().optional(),
|
|
error: z.string(),
|
|
code: z.string().optional(),
|
|
diagnostic: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("turn_canceled"),
|
|
provider: AgentProviderSchema,
|
|
turnId: z.string().optional(),
|
|
reason: z.string(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("timeline"),
|
|
provider: AgentProviderSchema,
|
|
item: AgentTimelineItemPayloadSchema,
|
|
turnId: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("permission_requested"),
|
|
provider: AgentProviderSchema,
|
|
request: AgentPermissionRequestPayloadSchema,
|
|
}),
|
|
z.object({
|
|
type: z.literal("permission_resolved"),
|
|
provider: AgentProviderSchema,
|
|
requestId: z.string(),
|
|
resolution: AgentPermissionResponseSchema,
|
|
}),
|
|
z.object({
|
|
type: z.literal("attention_required"),
|
|
provider: AgentProviderSchema,
|
|
reason: z.enum(["finished", "error", "permission"]),
|
|
timestamp: z.string(),
|
|
shouldNotify: z.boolean(),
|
|
notification: z
|
|
.object({
|
|
title: z.string(),
|
|
body: z.string(),
|
|
data: z.object({
|
|
serverId: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
agentId: z.string(),
|
|
reason: z.enum(["finished", "error", "permission"]),
|
|
}),
|
|
})
|
|
.optional(),
|
|
}),
|
|
]);
|
|
|
|
const AgentPersistenceHandleSchema: z.ZodType<AgentPersistenceHandle | null> = z
|
|
.object({
|
|
provider: AgentProviderSchema,
|
|
sessionId: z.string(),
|
|
nativeHandle: z.string().optional(),
|
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
})
|
|
.nullable();
|
|
|
|
const AgentRuntimeInfoSchema: z.ZodType<AgentRuntimeInfo> = z.object({
|
|
provider: AgentProviderSchema,
|
|
sessionId: z.string().nullable(),
|
|
model: z.string().nullable().optional(),
|
|
thinkingOptionId: z.string().nullable().optional(),
|
|
modeId: z.string().nullable().optional(),
|
|
extra: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
|
|
const AgentActiveTurnPayloadSchema = z.object({
|
|
turnId: z.string(),
|
|
startedAt: z.string().nullable(),
|
|
});
|
|
|
|
export const AgentSnapshotPayloadSchema = z.object({
|
|
id: z.string(),
|
|
provider: AgentProviderSchema,
|
|
cwd: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
model: z.string().nullable(),
|
|
features: z.array(AgentFeatureSchema).optional(),
|
|
thinkingOptionId: z.string().nullable().optional(),
|
|
effectiveThinkingOptionId: z.string().nullable().optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string(),
|
|
lastUserMessageAt: z.string().nullable(),
|
|
status: AgentStatusSchema,
|
|
activeTurn: AgentActiveTurnPayloadSchema.nullable().optional(),
|
|
capabilities: AgentCapabilityFlagsSchema,
|
|
currentModeId: z.string().nullable(),
|
|
availableModes: z.array(AgentModeSchema),
|
|
pendingPermissions: z.array(AgentPermissionRequestPayloadSchema),
|
|
persistence: AgentPersistenceHandleSchema.nullable(),
|
|
runtimeInfo: AgentRuntimeInfoSchema.optional(),
|
|
lastUsage: AgentUsageSchema.optional(),
|
|
lastError: z.string().optional(),
|
|
title: z.string().nullable(),
|
|
labels: z.record(z.string(), z.string()).default({}),
|
|
requiresAttention: z.boolean().optional(),
|
|
attentionReason: z.enum(["finished", "error", "permission"]).nullable().optional(),
|
|
attentionTimestamp: z.string().nullable().optional(),
|
|
archivedAt: z.string().nullable().optional(),
|
|
providerUnavailable: z.boolean().optional(),
|
|
});
|
|
|
|
export type AgentSnapshotPayload = z.infer<typeof AgentSnapshotPayloadSchema>;
|
|
|
|
export const AgentListItemPayloadSchema = z.object({
|
|
id: z.string(),
|
|
shortId: z.string(),
|
|
title: z.string().nullable(),
|
|
provider: AgentProviderSchema,
|
|
model: z.string().nullable(),
|
|
thinkingOptionId: z.string().nullable().optional(),
|
|
effectiveThinkingOptionId: z.string().nullable().optional(),
|
|
status: AgentStatusSchema,
|
|
cwd: z.string(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string(),
|
|
lastUserMessageAt: z.string().nullable(),
|
|
archivedAt: z.string().nullable().optional(),
|
|
requiresAttention: z.boolean().optional(),
|
|
attentionReason: z.enum(["finished", "error", "permission"]).nullable().optional(),
|
|
attentionTimestamp: z.string().nullable().optional(),
|
|
labels: z.record(z.string(), z.string()).default({}),
|
|
providerUnavailable: z.boolean().optional(),
|
|
});
|
|
|
|
export type AgentListItemPayload = z.infer<typeof AgentListItemPayloadSchema>;
|
|
|
|
export type AgentStreamEventPayload = z.infer<typeof AgentStreamEventPayloadSchema>;
|
|
|
|
export const RecentProviderSessionDescriptorPayloadSchema = z.object({
|
|
providerId: z.string(),
|
|
providerLabel: z.string(),
|
|
providerHandleId: z.string(),
|
|
cwd: z.string(),
|
|
title: z.string().nullable(),
|
|
firstPromptPreview: z.string().nullable(),
|
|
lastPromptPreview: z.string().nullable(),
|
|
lastActivityAt: z.string(),
|
|
});
|
|
|
|
export type RecentProviderSessionDescriptorPayload = z.infer<
|
|
typeof RecentProviderSessionDescriptorPayloadSchema
|
|
>;
|
|
|
|
// ============================================================================
|
|
// Session Inbound Messages (Session receives these)
|
|
// ============================================================================
|
|
|
|
export const VoiceAudioChunkMessageSchema = z.object({
|
|
type: z.literal("voice_audio_chunk"),
|
|
audio: z.string(), // base64 encoded
|
|
format: z.string(),
|
|
isLast: z.boolean(),
|
|
});
|
|
|
|
export const AbortRequestMessageSchema = z.object({
|
|
type: z.literal("abort_request"),
|
|
});
|
|
|
|
export const AudioPlayedMessageSchema = z.object({
|
|
type: z.literal("audio_played"),
|
|
id: z.string(),
|
|
});
|
|
|
|
const AgentDirectoryFilterSchema = z.object({
|
|
labels: z.record(z.string(), z.string()).optional(),
|
|
projectKeys: z.array(z.string()).optional(),
|
|
statuses: z.array(AgentStatusSchema).optional(),
|
|
includeArchived: z.boolean().optional(),
|
|
requiresAttention: z.boolean().optional(),
|
|
thinkingOptionId: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const DeleteAgentRequestMessageSchema = z.object({
|
|
type: z.literal("delete_agent_request"),
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ArchiveAgentRequestMessageSchema = z.object({
|
|
type: z.literal("archive_agent_request"),
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CloseItemsRequestMessageSchema = z.object({
|
|
type: z.literal("close_items_request"),
|
|
agentIds: z.array(z.string()).default([]),
|
|
terminalIds: z.array(z.string()).default([]),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const UpdateAgentRequestMessageSchema = z.object({
|
|
type: z.literal("update_agent_request"),
|
|
agentId: z.string(),
|
|
name: z.string().optional(),
|
|
labels: z.record(z.string(), z.string()).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
// The daemon accepts only image bytes chosen or acquired by the client. It must
|
|
// never fetch a user-provided URL on the host's network.
|
|
export const ProjectIconSourceSchema = z.discriminatedUnion("type", [
|
|
z.object({ type: z.literal("automatic") }),
|
|
z.object({ type: z.literal("upload"), data: z.string() }),
|
|
]);
|
|
|
|
export const ProjectRenameRequestSchema = z.object({
|
|
type: z.literal("project.rename.request"),
|
|
projectId: z.string(),
|
|
// Null or empty string clears the override and reverts to the derived name.
|
|
customName: z.string().nullable(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProjectIconSetRequestSchema = z.object({
|
|
type: z.literal("project.icon.set.request"),
|
|
projectId: z.string(),
|
|
source: ProjectIconSourceSchema,
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProjectRemoveRequestSchema = z.object({
|
|
type: z.literal("project.remove.request"),
|
|
projectId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspaceTitleSetRequestSchema = z.object({
|
|
type: z.literal("workspace.title.set.request"),
|
|
workspaceId: z.string(),
|
|
// Null or empty string clears the title and reverts to the derived name.
|
|
title: z.string().nullable(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspacePinSetRequestSchema = z.object({
|
|
type: z.literal("workspace.pin.set.request"),
|
|
workspaceId: z.string(),
|
|
pinned: z.boolean(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspaceLabelColorSchema = z.enum(WORKSPACE_LABEL_COLORS);
|
|
export const WorkspaceLabelDefinitionSchema = z.object({
|
|
name: z.string(),
|
|
color: WorkspaceLabelColorSchema,
|
|
});
|
|
const WorkspaceLabelSyncCursorSchema = z.object({
|
|
generation: z.string(),
|
|
afterSeq: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export const WorkspaceLabelListRequestSchema = z.object({
|
|
type: z.literal("workspace.label.list.request"),
|
|
requestId: z.string(),
|
|
subscribe: z.object({ subscriptionId: z.string() }),
|
|
sync: WorkspaceLabelSyncCursorSchema.optional(),
|
|
});
|
|
export const WorkspaceLabelAssignmentSetRequestSchema = z.object({
|
|
type: z.literal("workspace.label.assignment.set.request"),
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
label: WorkspaceLabelDefinitionSchema,
|
|
assigned: z.boolean(),
|
|
});
|
|
/**
|
|
* Editing a label is one operation. A name and a colour are two fields of one thing, and two
|
|
* RPCs can land half-applied — leaving the catalog in a state the user never asked for and the
|
|
* UI with nothing true to say. Both fields are optional; omitting one leaves it alone.
|
|
*/
|
|
export const WorkspaceLabelUpdateRequestSchema = z.object({
|
|
type: z.literal("workspace.label.update.request"),
|
|
requestId: z.string(),
|
|
name: z.string(),
|
|
newName: z.string().optional(),
|
|
color: WorkspaceLabelColorSchema.optional(),
|
|
});
|
|
export const WorkspaceLabelDeleteRequestSchema = z.object({
|
|
type: z.literal("workspace.label.delete.request"),
|
|
requestId: z.string(),
|
|
name: z.string(),
|
|
});
|
|
export const WorkspaceLabelDeleteInspectRequestSchema = z.object({
|
|
type: z.literal("workspace.label.delete.inspect.request"),
|
|
requestId: z.string(),
|
|
name: z.string(),
|
|
});
|
|
|
|
export const WorkspaceRecoveryInspectRequestSchema = z.object({
|
|
type: z.literal("workspace.recovery.inspect.request"),
|
|
workspaceId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspaceRecoveryRestoreRequestSchema = z.object({
|
|
type: z.literal("workspace.recovery.restore.request"),
|
|
workspaceId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SetVoiceModeMessageSchema = z.object({
|
|
type: z.literal("set_voice_mode"),
|
|
enabled: z.boolean(),
|
|
agentId: z.string().optional(),
|
|
requestId: z.string().optional(),
|
|
});
|
|
|
|
export const GitHubPrAttachmentSchema = z.object({
|
|
type: z.literal("github_pr"),
|
|
mimeType: z.literal("application/github-pr"),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
baseRefName: z.string().nullable().optional(),
|
|
headRefName: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const ForgeChangeRequestAttachmentSchema = z.object({
|
|
type: z.literal("forge_change_request"),
|
|
mimeType: z.literal("application/paseo-forge-change-request"),
|
|
forge: z.string().optional().default("github"),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
projectPath: z.string().optional(),
|
|
baseRefName: z.string().nullable().optional(),
|
|
headRefName: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const GitHubIssueAttachmentSchema = z.object({
|
|
type: z.literal("github_issue"),
|
|
mimeType: z.literal("application/github-issue"),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const ForgeIssueAttachmentSchema = z.object({
|
|
type: z.literal("forge_issue"),
|
|
mimeType: z.literal("application/paseo-forge-issue"),
|
|
forge: z.string().optional().default("github"),
|
|
number: z.number().int().positive(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
body: z.string().nullable().optional(),
|
|
projectPath: z.string().optional(),
|
|
});
|
|
|
|
export const ExternalResourceAttachmentMetadataSchema = z.object({
|
|
provider: z.string(),
|
|
providerLabel: z.string(),
|
|
resourceType: z.string(),
|
|
id: z.string(),
|
|
identifier: z.string(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
});
|
|
|
|
export const TextAttachmentSchema = z
|
|
.object({
|
|
type: z.literal("text"),
|
|
mimeType: z.literal("text/plain"),
|
|
contextKind: z.string().optional(),
|
|
title: z.string().nullable().optional(),
|
|
text: z.string(),
|
|
externalResource: ExternalResourceAttachmentMetadataSchema.optional(),
|
|
})
|
|
.transform(({ contextKind, ...attachment }) => ({
|
|
...attachment,
|
|
...(contextKind === "chat_history" ? { contextKind } : {}),
|
|
}));
|
|
|
|
export const ReviewAttachmentContextLineSchema = z.object({
|
|
oldLineNumber: z.number().int().positive().nullable(),
|
|
newLineNumber: z.number().int().positive().nullable(),
|
|
type: z.enum(["add", "remove", "context"]),
|
|
content: z.string(),
|
|
});
|
|
|
|
export const ReviewAttachmentCommentSchema = z.object({
|
|
filePath: z.string(),
|
|
side: z.enum(["old", "new"]),
|
|
lineNumber: z.number().int().positive(),
|
|
body: z.string(),
|
|
context: z.object({
|
|
hunkHeader: z.string(),
|
|
targetLine: ReviewAttachmentContextLineSchema,
|
|
lines: z.array(ReviewAttachmentContextLineSchema),
|
|
}),
|
|
});
|
|
|
|
export const ReviewAttachmentSchema = z.object({
|
|
type: z.literal("review"),
|
|
mimeType: z.literal("application/paseo-review"),
|
|
cwd: z.string(),
|
|
mode: z.enum(["uncommitted", "base"]),
|
|
baseRef: z.string().nullable().optional(),
|
|
comments: z.array(ReviewAttachmentCommentSchema),
|
|
});
|
|
|
|
export const UploadedFileAttachmentSchema = z.object({
|
|
type: z.literal("uploaded_file"),
|
|
id: z.string(),
|
|
fileName: z.string(),
|
|
mimeType: z.string(),
|
|
size: z.number().int().nonnegative(),
|
|
path: z.string(),
|
|
});
|
|
|
|
export const AgentAttachmentSchema = z.discriminatedUnion("type", [
|
|
ForgeChangeRequestAttachmentSchema,
|
|
ForgeIssueAttachmentSchema,
|
|
GitHubPrAttachmentSchema,
|
|
GitHubIssueAttachmentSchema,
|
|
TextAttachmentSchema,
|
|
ReviewAttachmentSchema,
|
|
UploadedFileAttachmentSchema,
|
|
]);
|
|
|
|
function normalizeAgentAttachments(input: unknown): AgentAttachment[] {
|
|
if (!Array.isArray(input)) {
|
|
return [];
|
|
}
|
|
const normalized: AgentAttachment[] = [];
|
|
for (const item of input) {
|
|
const parsed = AgentAttachmentSchema.safeParse(item);
|
|
if (parsed.success) {
|
|
normalized.push(parsed.data);
|
|
}
|
|
}
|
|
return normalized;
|
|
}
|
|
|
|
const AgentAttachmentsSchema = z.unknown().transform(normalizeAgentAttachments).optional();
|
|
|
|
export const ChangeRequestCheckoutSourceSchema = z.object({
|
|
kind: z.literal("change_request"),
|
|
forge: z.string().optional(),
|
|
number: z.number().int().positive(),
|
|
projectPath: z.string().optional(),
|
|
});
|
|
|
|
const ImageAttachmentSchema = z.object({
|
|
data: z.string(), // base64 encoded image
|
|
mimeType: z.string(), // e.g., "image/jpeg", "image/png"
|
|
});
|
|
|
|
export const ActiveTurnBehaviorSchema = z.enum(["interrupt", "steer"]);
|
|
export type ActiveTurnBehavior = z.infer<typeof ActiveTurnBehaviorSchema>;
|
|
|
|
export const SendAgentMessageSchema = z.object({
|
|
type: z.literal("send_agent_message"),
|
|
agentId: z.string(),
|
|
text: z.string(),
|
|
messageId: z.string().optional(), // Client-provided ID for deduplication
|
|
activeTurnBehavior: ActiveTurnBehaviorSchema.optional(),
|
|
images: z.array(ImageAttachmentSchema).optional(),
|
|
attachments: AgentAttachmentsSchema,
|
|
});
|
|
|
|
// ============================================================================
|
|
// Agent RPCs (requestId-correlated)
|
|
// ============================================================================
|
|
|
|
const DirectorySyncRequestSchema = z.object({
|
|
generation: z.string().optional(),
|
|
afterSeq: z.number().int().nonnegative().optional(),
|
|
});
|
|
|
|
const DirectorySyncRemovalSchema = z.object({
|
|
id: z.string(),
|
|
seq: z.number().int().positive(),
|
|
});
|
|
|
|
const DirectorySyncMetadataSchema = z.object({
|
|
generation: z.string(),
|
|
headSeq: z.number().int().nonnegative(),
|
|
mode: z.enum(["snapshot", "changes"]),
|
|
reason: z
|
|
.enum(["no_cursor", "generation_changed", "cursor_expired", "changes_too_large"])
|
|
.optional(),
|
|
removals: z.array(DirectorySyncRemovalSchema),
|
|
});
|
|
|
|
export const FetchAgentsRequestMessageSchema = z.object({
|
|
type: z.literal("fetch_agents_request"),
|
|
requestId: z.string(),
|
|
scope: z.enum(["active"]).optional(),
|
|
filter: AgentDirectoryFilterSchema.optional(),
|
|
sort: z
|
|
.array(
|
|
z.object({
|
|
key: z.enum(["status_priority", "created_at", "updated_at", "title"]),
|
|
direction: z.enum(["asc", "desc"]),
|
|
}),
|
|
)
|
|
.optional(),
|
|
page: z
|
|
.object({
|
|
limit: z.number().int().positive().max(200),
|
|
cursor: z.string().min(1).optional(),
|
|
})
|
|
.optional(),
|
|
subscribe: z
|
|
.object({
|
|
subscriptionId: z.string().optional(),
|
|
})
|
|
.optional(),
|
|
// COMPAT(directorySync): added in v0.3.x, remove optional after 2027-02-12.
|
|
sync: DirectorySyncRequestSchema.optional(),
|
|
});
|
|
|
|
const WorkspaceStateBucketSchema = z.enum([
|
|
"needs_input",
|
|
"failed",
|
|
"running",
|
|
"attention",
|
|
"done",
|
|
]);
|
|
|
|
export const FetchWorkspacesRequestMessageSchema = z.object({
|
|
type: z.literal("fetch_workspaces_request"),
|
|
requestId: z.string(),
|
|
filter: z
|
|
.object({
|
|
query: z.string().optional(),
|
|
projectId: z.string().optional(),
|
|
// Unused: accepted so older clients still parse, but the server does not filter on it.
|
|
idPrefix: z.string().optional(),
|
|
})
|
|
.optional(),
|
|
sort: z
|
|
.array(
|
|
z.object({
|
|
key: z.enum(["status_priority", "activity_at", "name", "project_id"]),
|
|
direction: z.enum(["asc", "desc"]),
|
|
}),
|
|
)
|
|
.optional(),
|
|
page: z
|
|
.object({
|
|
limit: z.number().int().positive().max(200),
|
|
cursor: z.string().min(1).optional(),
|
|
})
|
|
.optional(),
|
|
subscribe: z
|
|
.object({
|
|
subscriptionId: z.string().optional(),
|
|
})
|
|
.optional(),
|
|
// COMPAT(directorySync): added in v0.3.x, remove optional after 2027-02-12.
|
|
sync: DirectorySyncRequestSchema.optional(),
|
|
});
|
|
|
|
export const ProjectListRequestMessageSchema = z.object({
|
|
type: z.literal("project.list.request"),
|
|
requestId: z.string(),
|
|
// COMPAT(directorySync): added in v0.3.x, remove optional after 2027-02-12.
|
|
sync: DirectorySyncRequestSchema.optional(),
|
|
});
|
|
|
|
export const FetchAgentHistoryRequestMessageSchema = z.object({
|
|
type: z.literal("fetch_agent_history_request"),
|
|
requestId: z.string(),
|
|
filter: AgentDirectoryFilterSchema.optional(),
|
|
// A ranked free-text query over agent title, workspace name, branch, and
|
|
// project name. Present only on history: agent subscriptions filter on
|
|
// structure, not on relevance. Ranking replaces `sort` when it is set.
|
|
search: z.string().optional(),
|
|
sort: z
|
|
.array(
|
|
z.object({
|
|
key: z.enum(["status_priority", "created_at", "updated_at", "title"]),
|
|
direction: z.enum(["asc", "desc"]),
|
|
}),
|
|
)
|
|
.optional(),
|
|
page: z
|
|
.object({
|
|
limit: z.number().int().positive().max(200),
|
|
cursor: z.string().min(1).optional(),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
export const FetchRecentProviderSessionsRequestMessageSchema = z.object({
|
|
type: z.literal("fetch_recent_provider_sessions_request"),
|
|
requestId: z.string(),
|
|
cwd: z.string().optional(),
|
|
providers: z.array(z.string()).optional(),
|
|
since: z.string().optional(),
|
|
limit: z.number().int().positive().max(200).optional(),
|
|
});
|
|
|
|
export const FetchAgentRequestMessageSchema = z.object({
|
|
type: z.literal("fetch_agent_request"),
|
|
requestId: z.string(),
|
|
/** Accepts full ID, unique prefix, or exact full title (server resolves). */
|
|
agentId: z.string(),
|
|
});
|
|
|
|
export const SendAgentMessageRequestSchema = z.object({
|
|
type: z.literal("send_agent_message_request"),
|
|
requestId: z.string(),
|
|
/** Accepts full ID, unique prefix, or exact full title (server resolves). */
|
|
agentId: z.string(),
|
|
text: z.string(),
|
|
messageId: z.string().optional(), // Client-provided ID for deduplication
|
|
activeTurnBehavior: ActiveTurnBehaviorSchema.optional(),
|
|
images: z.array(ImageAttachmentSchema).optional(),
|
|
attachments: AgentAttachmentsSchema,
|
|
});
|
|
|
|
export const WaitForFinishRequestSchema = z.object({
|
|
type: z.literal("wait_for_finish_request"),
|
|
requestId: z.string(),
|
|
/** Accepts full ID, unique prefix, or exact full title (server resolves). */
|
|
agentId: z.string(),
|
|
timeoutMs: z.number().int().positive().optional(),
|
|
});
|
|
|
|
export const DaemonGetStatusRequestSchema = z.object({
|
|
type: z.literal("daemon.get_status.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const DaemonGetPairingOfferRequestSchema = z.object({
|
|
type: z.literal("daemon.get_pairing_offer.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const DaemonConfigReloadRequestSchema = z.object({
|
|
type: z.literal("daemon.config.reload.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const HubManagementDaemonConnectRequestSchema = z.object({
|
|
type: z.literal("hub.management.daemon.connect.request"),
|
|
requestId: z.string(),
|
|
hubUrl: z.string(),
|
|
token: z.string(),
|
|
});
|
|
export const HubManagementDaemonGetStatusRequestSchema = z.object({
|
|
type: z.literal("hub.management.daemon.get_status.request"),
|
|
requestId: z.string(),
|
|
});
|
|
export const HubManagementDaemonDisconnectRequestSchema = z.object({
|
|
type: z.literal("hub.management.daemon.disconnect.request"),
|
|
requestId: z.string(),
|
|
force: z.boolean().optional(),
|
|
});
|
|
|
|
export const DiagnosticsRequestSchema = z.object({
|
|
type: z.literal("diagnostics.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const PluginCatalogGetRequestSchema = z.object({
|
|
type: z.literal("plugin.catalog.get.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const PluginListRequestSchema = z.object({
|
|
type: z.literal("plugin.list.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const PluginLogsGetRequestSchema = z.object({
|
|
type: z.literal("plugin.logs.get.request"),
|
|
requestId: z.string(),
|
|
pluginId: PluginIdSchema,
|
|
});
|
|
|
|
export const PluginDirectoryInstallRequestSchema = z.object({
|
|
type: z.literal("plugin.directory.install.request"),
|
|
requestId: z.string(),
|
|
path: z.string().min(1),
|
|
id: PluginIdSchema.optional(),
|
|
});
|
|
|
|
export const PluginDirectoryInspectRequestSchema = z.object({
|
|
type: z.literal("plugin.directory.inspect.request"),
|
|
requestId: z.string(),
|
|
path: z.string().min(1),
|
|
});
|
|
|
|
function pluginIdRequest<const Type extends string>(type: Type) {
|
|
return z.object({ type: z.literal(type), requestId: z.string(), pluginId: PluginIdSchema });
|
|
}
|
|
|
|
export const PluginReloadRequestSchema = pluginIdRequest("plugin.reload.request");
|
|
export const PluginEnableRequestSchema = pluginIdRequest("plugin.enable.request");
|
|
export const PluginDisableRequestSchema = pluginIdRequest("plugin.disable.request");
|
|
export const PluginRemoveRequestSchema = pluginIdRequest("plugin.remove.request");
|
|
|
|
export const PluginRpcInvokeRequestSchema = z.object({
|
|
type: z.literal("plugin.rpc.invoke.request"),
|
|
requestId: z.string(),
|
|
pluginId: PluginIdSchema,
|
|
method: z.string().min(1),
|
|
input: z.unknown(),
|
|
});
|
|
|
|
export const AgentSkillOperationSchema = z.discriminatedUnion("kind", [
|
|
z.object({ kind: z.literal("add"), name: z.string() }).strict(),
|
|
z.object({ kind: z.literal("update"), name: z.string() }).strict(),
|
|
z.object({ kind: z.literal("delete"), name: z.string() }).strict(),
|
|
]);
|
|
export type AgentSkillOperation = z.infer<typeof AgentSkillOperationSchema>;
|
|
|
|
export const AgentSkillsStatusSchema = z.object({
|
|
state: z.enum(["not-installed", "up-to-date", "drift"]),
|
|
ops: z.array(AgentSkillOperationSchema),
|
|
available: z.array(z.string()),
|
|
installed: z.array(z.string()),
|
|
selection: AgentSkillSelectionSchema,
|
|
});
|
|
export type AgentSkillsStatus = z.infer<typeof AgentSkillsStatusSchema>;
|
|
|
|
export const AgentSkillsConfirmationSchema = z.object({ removals: z.array(z.string()) }).strict();
|
|
export type AgentSkillsConfirmation = z.infer<typeof AgentSkillsConfirmationSchema>;
|
|
|
|
export const AgentSkillsSaveResultSchema = AgentSkillsStatusSchema.extend({
|
|
confirmationRequired: AgentSkillsConfirmationSchema.nullable(),
|
|
});
|
|
export type AgentSkillsSaveResult = z.infer<typeof AgentSkillsSaveResultSchema>;
|
|
|
|
function agentSkillsRequest<const Type extends string>(type: Type) {
|
|
return z.object({ type: z.literal(type), requestId: z.string() }).strict();
|
|
}
|
|
|
|
export const AgentSkillsGetStatusRequestSchema = agentSkillsRequest(
|
|
"agent.skills.get_status.request",
|
|
);
|
|
export const AgentSkillsReconcileRequestSchema = agentSkillsRequest(
|
|
"agent.skills.reconcile.request",
|
|
);
|
|
export const AgentSkillsUninstallRequestSchema = agentSkillsRequest(
|
|
"agent.skills.uninstall.request",
|
|
);
|
|
export const AgentSkillsSaveSelectionRequestSchema = z
|
|
.object({
|
|
type: z.literal("agent.skills.save_selection.request"),
|
|
requestId: z.string(),
|
|
selection: AgentSkillSelectionSchema,
|
|
confirmedRemovals: z.array(z.string()).optional(),
|
|
})
|
|
.strict();
|
|
export const AgentSkillsImportLegacySelectionRequestSchema = z
|
|
.object({
|
|
type: z.literal("agent.skills.import_legacy_selection.request"),
|
|
requestId: z.string(),
|
|
selection: AgentSkillSelectionSchema,
|
|
})
|
|
.strict();
|
|
|
|
export const GetDaemonConfigRequestMessageSchema = z.object({
|
|
type: z.literal("get_daemon_config_request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SetDaemonConfigRequestMessageSchema = z.object({
|
|
type: z.literal("set_daemon_config_request"),
|
|
requestId: z.string(),
|
|
config: MutableDaemonConfigPatchSchema,
|
|
});
|
|
|
|
export const ReadProjectConfigRequestMessageSchema = z.object({
|
|
type: z.literal("read_project_config_request"),
|
|
requestId: z.string(),
|
|
repoRoot: z.string(),
|
|
});
|
|
|
|
export const WriteProjectConfigRequestMessageSchema = z.object({
|
|
type: z.literal("write_project_config_request"),
|
|
requestId: z.string(),
|
|
repoRoot: z.string(),
|
|
config: PaseoConfigRawSchema,
|
|
expectedRevision: PaseoConfigRevisionSchema.nullable(),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Dictation Streaming (lossless, resumable)
|
|
// ============================================================================
|
|
|
|
export const DictationStreamStartMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_start"),
|
|
dictationId: z.string(),
|
|
format: z.string(), // e.g. "audio/pcm;rate=16000;bits=16"
|
|
});
|
|
|
|
export const DictationStreamChunkMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_chunk"),
|
|
dictationId: z.string(),
|
|
seq: z.number().int().nonnegative(),
|
|
audio: z.string(), // base64 encoded chunk
|
|
format: z.string(), // e.g. "audio/pcm;rate=16000;bits=16"
|
|
});
|
|
|
|
export const DictationStreamFinishMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_finish"),
|
|
dictationId: z.string(),
|
|
finalSeq: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export const DictationStreamCancelMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_cancel"),
|
|
dictationId: z.string(),
|
|
});
|
|
|
|
const GitSetupOptionsSchema = z.object({
|
|
baseBranch: z.string().optional(),
|
|
createNewBranch: z.boolean().optional(),
|
|
newBranchName: z.string().optional(),
|
|
createWorktree: z.boolean().optional(),
|
|
worktreeSlug: z.string().optional(),
|
|
refName: z.string().min(1).optional(),
|
|
action: z.enum(["branch-off", "checkout"]).optional(),
|
|
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
|
|
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
|
|
// clients send checkoutSource.
|
|
githubPrNumber: z.number().int().positive().optional(),
|
|
});
|
|
|
|
export type GitSetupOptions = z.infer<typeof GitSetupOptionsSchema>;
|
|
|
|
export const CreateAgentWorktreeTargetSchema = z.discriminatedUnion("mode", [
|
|
z.object({
|
|
mode: z.literal("branch-off"),
|
|
newBranch: z.string().min(1),
|
|
base: z.string().min(1).optional(),
|
|
}),
|
|
z.object({
|
|
mode: z.literal("checkout-branch"),
|
|
branch: z.string().min(1),
|
|
}),
|
|
z.object({
|
|
mode: z.literal("checkout-pr"),
|
|
prNumber: z.number().int().positive(),
|
|
}),
|
|
]);
|
|
|
|
export type CreateAgentWorktreeTarget = z.infer<typeof CreateAgentWorktreeTargetSchema>;
|
|
|
|
export const CreateAgentRequestMessageSchema = z.object({
|
|
type: z.literal("create_agent_request"),
|
|
config: AgentSessionConfigSchema,
|
|
env: z.record(z.string(), z.string()).optional(),
|
|
workspaceId: z.string().optional(),
|
|
// Optional caller context lets managed CLI invocations use the same daemon-owned
|
|
// workspace and parentage policy as agent-scoped MCP creation.
|
|
callerAgentId: z.string().optional(),
|
|
worktreeName: z.string().optional(),
|
|
initialPrompt: z.string().optional(),
|
|
clientMessageId: z.string().optional(),
|
|
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
images: z.array(ImageAttachmentSchema).optional(),
|
|
attachments: AgentAttachmentsSchema,
|
|
git: GitSetupOptionsSchema.optional(),
|
|
worktree: CreateAgentWorktreeTargetSchema.optional(),
|
|
autoArchive: z.boolean().optional(),
|
|
labels: z.record(z.string(), z.string()).default({}),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ListProviderModelsRequestMessageSchema = z.object({
|
|
type: z.literal("list_provider_models_request"),
|
|
provider: AgentProviderSchema,
|
|
cwd: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ListProviderModesRequestMessageSchema = z.object({
|
|
type: z.literal("list_provider_modes_request"),
|
|
provider: AgentProviderSchema,
|
|
cwd: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ListAvailableProvidersRequestMessageSchema = z.object({
|
|
type: z.literal("list_available_providers_request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const GetProvidersSnapshotRequestMessageSchema = z.object({
|
|
type: z.literal("get_providers_snapshot_request"),
|
|
cwd: z.string().optional(),
|
|
// COMPAT(compactProviderSnapshots): old daemons ignore this field and return a full snapshot.
|
|
ifNoneMatch: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const RefreshProvidersSnapshotRequestMessageSchema = z.object({
|
|
type: z.literal("refresh_providers_snapshot_request"),
|
|
cwd: z.string().optional(),
|
|
providers: z.array(AgentProviderSchema).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProviderDiagnosticRequestMessageSchema = z.object({
|
|
type: z.literal("provider_diagnostic_request"),
|
|
provider: AgentProviderSchema,
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProviderUsageListRequestMessageSchema = z.object({
|
|
type: z.literal("provider.usage.list.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ResumeAgentRequestMessageSchema = z.object({
|
|
type: z.literal("resume_agent_request"),
|
|
handle: AgentPersistenceHandleSchema,
|
|
overrides: AgentSessionConfigSchema.partial().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ImportAgentRequestMessageSchema = z.object({
|
|
type: z.literal("import_agent_request"),
|
|
provider: AgentProviderSchema.optional(),
|
|
providerId: z.string().optional(),
|
|
sessionId: z.string().optional(),
|
|
providerHandleId: z.string().optional(),
|
|
cwd: z.string().optional(),
|
|
workspaceId: z.string().optional(),
|
|
labels: z.record(z.string(), z.string()).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const RefreshAgentRequestMessageSchema = z.object({
|
|
type: z.literal("refresh_agent_request"),
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CancelAgentRequestMessageSchema = z.object({
|
|
type: z.literal("cancel_agent_request"),
|
|
agentId: z.string(),
|
|
requestId: z.string().optional(),
|
|
});
|
|
|
|
export const RestartServerRequestMessageSchema = z.object({
|
|
type: z.literal("restart_server_request"),
|
|
reason: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ShutdownServerRequestMessageSchema = z.object({
|
|
type: z.literal("shutdown_server_request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const DaemonUpdateRequestMessageSchema = z.object({
|
|
type: z.literal("daemon.update.request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const AgentTimelineCursorSchema = z.object({
|
|
epoch: z.string(),
|
|
seq: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export const FetchAgentTimelineRequestMessageSchema = z.object({
|
|
type: z.literal("fetch_agent_timeline_request"),
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
direction: z.enum(["tail", "before", "after"]).optional(),
|
|
cursor: AgentTimelineCursorSchema.optional(),
|
|
// 0 means "all matching rows for this query window".
|
|
limit: z.number().int().nonnegative().optional(),
|
|
// Default should be projected for app timeline loading.
|
|
projection: z.enum(["projected", "canonical"]).optional(),
|
|
// Allow the client to merge this bounded page outside its contiguous loaded range.
|
|
mergeWindow: z.boolean().optional(),
|
|
});
|
|
|
|
export const AgentTimelineListPromptsRequestMessageSchema = z.object({
|
|
type: z.literal("agent.timeline.list_prompts.request"),
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProviderSubagentListRequestMessageSchema = z.object({
|
|
type: z.literal("agent.provider_subagents.list.request"),
|
|
parentAgentId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProviderSubagentTimelineRequestMessageSchema = z.object({
|
|
type: z.literal("agent.provider_subagents.timeline.get.request"),
|
|
parentAgentId: z.string(),
|
|
subagentId: z.string(),
|
|
requestId: z.string(),
|
|
direction: z.enum(["tail", "before", "after"]).optional(),
|
|
cursor: AgentTimelineCursorSchema.optional(),
|
|
limit: z.number().int().nonnegative().optional(),
|
|
});
|
|
|
|
export const SetAgentTimelineSubscriptionRequestMessageSchema = z.object({
|
|
type: z.literal("agent.timeline.set_subscription.request"),
|
|
agentIds: z.array(z.string()),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const AgentForkContextRequestMessageSchema = z.object({
|
|
type: z.literal("agent.fork_context.request"),
|
|
agentId: z.string(),
|
|
boundaryCursor: AgentTimelineCursorSchema.optional(),
|
|
boundaryMessageId: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SetAgentModeRequestMessageSchema = z.object({
|
|
type: z.literal("set_agent_mode_request"),
|
|
agentId: z.string(),
|
|
modeId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
const AgentActionResponsePayloadSchema = z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string(),
|
|
accepted: z.boolean(),
|
|
error: z.string().nullable(),
|
|
notice: AgentProviderNoticeSchema.nullable().optional(),
|
|
});
|
|
|
|
export const SetAgentModeResponseMessageSchema = z.object({
|
|
type: z.literal("set_agent_mode_response"),
|
|
payload: AgentActionResponsePayloadSchema,
|
|
});
|
|
|
|
export const SetAgentModelRequestMessageSchema = z.object({
|
|
type: z.literal("set_agent_model_request"),
|
|
agentId: z.string(),
|
|
modelId: z.string().nullable(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SetAgentModelResponseMessageSchema = z.object({
|
|
type: z.literal("set_agent_model_response"),
|
|
payload: AgentActionResponsePayloadSchema,
|
|
});
|
|
|
|
export const SetAgentThinkingRequestMessageSchema = z.object({
|
|
type: z.literal("set_agent_thinking_request"),
|
|
agentId: z.string(),
|
|
thinkingOptionId: z.string().nullable(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SetAgentThinkingResponseMessageSchema = z.object({
|
|
type: z.literal("set_agent_thinking_response"),
|
|
payload: AgentActionResponsePayloadSchema,
|
|
});
|
|
|
|
export const SetAgentFeatureRequestMessageSchema = z.object({
|
|
type: z.literal("set_agent_feature_request"),
|
|
agentId: z.string(),
|
|
featureId: z.string(),
|
|
value: z.unknown(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SetAgentFeatureResponseMessageSchema = z.object({
|
|
type: z.literal("set_agent_feature_response"),
|
|
payload: AgentActionResponsePayloadSchema,
|
|
});
|
|
|
|
/**
|
|
* Every agent-config value a client can change in one shot. Each field is
|
|
* optional and an omitted field is left alone; `null` on model and thinking
|
|
* clears them, matching the single-field RPCs above.
|
|
*/
|
|
export const AgentConfigApplySchema = z.object({
|
|
modelId: z.string().nullable().optional(),
|
|
modeId: z.string().optional(),
|
|
thinkingOptionId: z.string().nullable().optional(),
|
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
|
|
export type AgentConfigApply = z.infer<typeof AgentConfigApplySchema>;
|
|
|
|
/**
|
|
* Applies a whole config bundle to one agent. The four single-field RPCs above
|
|
* stay for individual control edits. One request prevents client interruption
|
|
* and other mutations from interleaving between bundle steps; provider-level
|
|
* rejection can still leave earlier steps applied.
|
|
*/
|
|
export const AgentConfigApplyRequestMessageSchema = z.object({
|
|
type: z.literal("agent.config.apply.request"),
|
|
agentId: z.string(),
|
|
config: AgentConfigApplySchema,
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const AgentConfigApplyResponseMessageSchema = z.object({
|
|
type: z.literal("agent.config.apply.response"),
|
|
payload: AgentActionResponsePayloadSchema,
|
|
});
|
|
|
|
export const AgentDetachRequestMessageSchema = z.object({
|
|
type: z.literal("agent.detach.request"),
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const AgentDetachResponseMessageSchema = z.object({
|
|
type: z.literal("agent.detach.response"),
|
|
payload: AgentActionResponsePayloadSchema,
|
|
});
|
|
|
|
export const AgentRewindModeSchema = z.enum(["conversation", "files", "both"]);
|
|
|
|
export const AgentRewindRequestMessageSchema = z.object({
|
|
type: z.literal("agent.rewind.request"),
|
|
agentId: z.string(),
|
|
messageId: z.string(),
|
|
mode: AgentRewindModeSchema,
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const AgentRewindResponseMessageSchema = z.object({
|
|
type: z.literal("agent.rewind.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string(),
|
|
ok: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const UpdateAgentResponseMessageSchema = z.object({
|
|
type: z.literal("update_agent_response"),
|
|
payload: AgentActionResponsePayloadSchema,
|
|
});
|
|
|
|
export const ProjectRenameResponsePayloadSchema = z.object({
|
|
requestId: z.string(),
|
|
projectId: z.string(),
|
|
accepted: z.boolean(),
|
|
customName: z.string().nullable(),
|
|
error: z.string().nullable(),
|
|
});
|
|
|
|
export const ProjectRenameResponseSchema = z.object({
|
|
type: z.literal("project.rename.response"),
|
|
payload: ProjectRenameResponsePayloadSchema,
|
|
});
|
|
|
|
export const ProjectIconSetResponseSchema = z.object({
|
|
type: z.literal("project.icon.set.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
projectId: z.string(),
|
|
accepted: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const ProjectRemoveResponsePayloadSchema = z.object({
|
|
requestId: z.string(),
|
|
projectId: z.string(),
|
|
accepted: z.boolean(),
|
|
removedWorkspaceIds: z.array(z.string()).default([]),
|
|
error: z.string().nullable(),
|
|
});
|
|
|
|
export const ProjectRemoveResponseSchema = z.object({
|
|
type: z.literal("project.remove.response"),
|
|
payload: ProjectRemoveResponsePayloadSchema,
|
|
});
|
|
|
|
export const WorkspaceTitleSetResponsePayloadSchema = z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
accepted: z.boolean(),
|
|
title: z.string().nullable(),
|
|
error: z.string().nullable(),
|
|
});
|
|
|
|
export const WorkspaceTitleSetResponseSchema = z.object({
|
|
type: z.literal("workspace.title.set.response"),
|
|
payload: WorkspaceTitleSetResponsePayloadSchema,
|
|
});
|
|
|
|
export const WorkspacePinSetResponsePayloadSchema = z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
accepted: z.boolean(),
|
|
pinnedAt: z.string().nullable(),
|
|
error: z.string().nullable(),
|
|
});
|
|
|
|
export const WorkspacePinSetResponseSchema = z.object({
|
|
type: z.literal("workspace.pin.set.response"),
|
|
payload: WorkspacePinSetResponsePayloadSchema,
|
|
});
|
|
|
|
export const WorkspaceRecoveryStateSchema = z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("recoverable"),
|
|
workspaceId: z.string(),
|
|
workspaceName: z.string(),
|
|
action: z.string(),
|
|
branch: z.string().nullable(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("unavailable"),
|
|
workspaceId: z.string(),
|
|
reason: z.string(),
|
|
message: z.string(),
|
|
}),
|
|
]);
|
|
|
|
export const WorkspaceRecoveryInspectResponseSchema = z.object({
|
|
type: z.literal("workspace.recovery.inspect.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
state: WorkspaceRecoveryStateSchema,
|
|
}),
|
|
});
|
|
|
|
export const WorkspaceRecoveryRestoreResponseSchema = z.object({
|
|
type: z.literal("workspace.recovery.restore.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
accepted: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const SetVoiceModeResponseMessageSchema = z.object({
|
|
type: z.literal("set_voice_mode_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
enabled: z.boolean(),
|
|
agentId: z.string().nullable(),
|
|
accepted: z.boolean(),
|
|
error: z.string().nullable(),
|
|
reasonCode: z.string().optional(),
|
|
retryable: z.boolean().optional(),
|
|
missingModelIds: z.array(z.string()).optional(),
|
|
}),
|
|
});
|
|
|
|
export const AgentPermissionResponseMessageSchema = z.object({
|
|
type: z.literal("agent_permission_response"),
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
response: AgentPermissionResponseSchema,
|
|
});
|
|
|
|
const CheckoutErrorCodeSchema = z.enum([
|
|
"NOT_GIT_REPO",
|
|
"NOT_ALLOWED",
|
|
"MERGE_CONFLICT",
|
|
"UNKNOWN",
|
|
]);
|
|
|
|
const CheckoutErrorSchema = z.object({
|
|
code: CheckoutErrorCodeSchema,
|
|
message: z.string(),
|
|
});
|
|
|
|
const CheckoutDiffCompareSchema = z.object({
|
|
mode: z.enum(["uncommitted", "base"]),
|
|
baseRef: z.string().optional(),
|
|
ignoreWhitespace: z.boolean().optional(),
|
|
});
|
|
|
|
export const CheckoutStatusRequestSchema = z.object({
|
|
type: z.literal("checkout_status_request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SubscribeCheckoutDiffRequestSchema = z.object({
|
|
type: z.literal("subscribe_checkout_diff_request"),
|
|
subscriptionId: z.string(),
|
|
cwd: z.string(),
|
|
compare: CheckoutDiffCompareSchema,
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const UnsubscribeCheckoutDiffRequestSchema = z.object({
|
|
type: z.literal("unsubscribe_checkout_diff_request"),
|
|
subscriptionId: z.string(),
|
|
});
|
|
|
|
export const CheckoutCommitRequestSchema = z.object({
|
|
type: z.literal("checkout_commit_request"),
|
|
cwd: z.string(),
|
|
message: z.string().optional(),
|
|
addAll: z.boolean().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutMergeRequestSchema = z.object({
|
|
type: z.literal("checkout_merge_request"),
|
|
cwd: z.string(),
|
|
baseRef: z.string().optional(),
|
|
strategy: z.enum(["merge", "squash"]).optional(),
|
|
requireCleanTarget: z.boolean().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutMergeFromBaseRequestSchema = z.object({
|
|
type: z.literal("checkout_merge_from_base_request"),
|
|
cwd: z.string(),
|
|
baseRef: z.string().optional(),
|
|
requireCleanTarget: z.boolean().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutPullRequestSchema = z.object({
|
|
type: z.literal("checkout_pull_request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutPushRequestSchema = z.object({
|
|
type: z.literal("checkout_push_request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutRefreshRequestSchema = z.object({
|
|
type: z.literal("checkout.refresh.request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutDiscardChangesRequestSchema = z.object({
|
|
type: z.literal("checkout.discard_changes.request"),
|
|
cwd: z.string(),
|
|
paths: z.array(z.string()).min(1),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutPrCreateRequestSchema = z.object({
|
|
type: z.literal("checkout_pr_create_request"),
|
|
cwd: z.string(),
|
|
title: z.string().optional(),
|
|
body: z.string().optional(),
|
|
baseRef: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutPrMergeRequestSchema = z.object({
|
|
type: z.literal("checkout_pr_merge_request"),
|
|
cwd: z.string(),
|
|
mergeMethod: z.enum(["merge", "squash", "rebase"]),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutForgeSetAutoMergeRequestSchema = z.object({
|
|
type: z.literal("checkout.forge.set_auto_merge.request"),
|
|
cwd: z.string(),
|
|
enabled: z.boolean(),
|
|
mergeMethod: z.enum(["merge", "squash", "rebase"]).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
// COMPAT(githubAutoMergeRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
// all supported clients use checkout.forge.set_auto_merge.*.
|
|
export const CheckoutGithubSetAutoMergeRequestSchema = z.object({
|
|
type: z.literal("checkout.github.set_auto_merge.request"),
|
|
cwd: z.string(),
|
|
enabled: z.boolean(),
|
|
mergeMethod: z.enum(["merge", "squash", "rebase"]).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
const CheckoutCommitFileSchema = z.object({
|
|
path: z.string(),
|
|
additions: z.number(),
|
|
deletions: z.number(),
|
|
status: z.enum(["added", "modified", "deleted", "renamed"]).optional(),
|
|
});
|
|
|
|
const CheckoutCommitSchema = z.object({
|
|
sha: z.string(),
|
|
shortSha: z.string(),
|
|
subject: z.string(),
|
|
authorName: z.string(),
|
|
authorDate: z.string(), // ISO 8601
|
|
isOnRemote: z.boolean(), // false = local-only (unpushed)
|
|
// COMPAT(commitBaseClassification): added in v0.2.0, remove optional after 2027-01-23.
|
|
isOnBase: z.boolean().optional(),
|
|
files: z.array(CheckoutCommitFileSchema),
|
|
});
|
|
|
|
export const CheckoutCommitsListRequestSchema = z.object({
|
|
type: z.literal("checkout.commits.list.request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutCommitFileDiffRequestSchema = z.object({
|
|
type: z.literal("checkout.commits.file_diff.request"),
|
|
cwd: z.string(),
|
|
sha: z.string(),
|
|
path: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
const GitHubRepoSegmentSchema = z.string().regex(/^[A-Za-z0-9._-]+$/);
|
|
|
|
const CheckoutCheckDetailsRequestPayloadSchema = z.object({
|
|
cwd: z.string(),
|
|
// GitHub addresses check runs by owner/name. GitLab resolves the project from
|
|
// cwd and omits these GitHub-only single-segment fields.
|
|
repoOwner: GitHubRepoSegmentSchema.optional(),
|
|
repoName: GitHubRepoSegmentSchema.optional(),
|
|
// Permanently optional: a check addressed only by workflowRunId (Gitea
|
|
// Actions runs carry no check-run id) is fetchable. Callers send at least one
|
|
// of checkRunId/workflowRunId; the gated forge RPC only reaches daemons that
|
|
// understand this.
|
|
checkRunId: z.number().int().positive().optional(),
|
|
workflowRunId: z.number().int().positive().optional(),
|
|
// Permanent forge-routing field, optional because only some forges need it:
|
|
// GitLab routes check details to the MR's head pipeline; Gitea-family adapters
|
|
// resolve the PR head SHA by number, including after merge/close. GitHub
|
|
// ignores it.
|
|
changeRequestNumber: z.number().int().positive().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutForgeGetCheckDetailsRequestSchema =
|
|
CheckoutCheckDetailsRequestPayloadSchema.extend({
|
|
type: z.literal("checkout.forge.get_check_details.request"),
|
|
});
|
|
|
|
// COMPAT(githubCheckDetailsRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
// all supported clients use checkout.forge.get_check_details.*.
|
|
export const CheckoutGithubGetCheckDetailsRequestSchema =
|
|
CheckoutCheckDetailsRequestPayloadSchema.extend({
|
|
type: z.literal("checkout.github.get_check_details.request"),
|
|
});
|
|
|
|
export const CheckoutPrStatusRequestSchema = z.object({
|
|
type: z.literal("checkout_pr_status_request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const PullRequestTimelineRequestSchema = z.object({
|
|
type: z.literal("pull_request_timeline_request"),
|
|
cwd: z.string(),
|
|
prNumber: z.number(),
|
|
repoOwner: z.string(),
|
|
repoName: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ValidateBranchRequestSchema = z.object({
|
|
type: z.literal("validate_branch_request"),
|
|
cwd: z.string(),
|
|
branchName: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutSwitchBranchRequestSchema = z.object({
|
|
type: z.literal("checkout_switch_branch_request"),
|
|
cwd: z.string(),
|
|
branch: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CheckoutRenameBranchRequestSchema = z.object({
|
|
type: z.literal("checkout.rename_branch.request"),
|
|
cwd: z.string(),
|
|
branch: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const StashSaveRequestSchema = z.object({
|
|
type: z.literal("stash_save_request"),
|
|
cwd: z.string(),
|
|
/** Branch name to tag the stash with for later identification. */
|
|
branch: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const StashPopRequestSchema = z.object({
|
|
type: z.literal("stash_pop_request"),
|
|
cwd: z.string(),
|
|
/** Zero-based index from stash_list_response. */
|
|
stashIndex: z.number().int().min(0),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const StashListRequestSchema = z.object({
|
|
type: z.literal("stash_list_request"),
|
|
cwd: z.string(),
|
|
/** If true, only return paseo-created stashes. Default true. */
|
|
paseoOnly: z.boolean().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const BranchSuggestionsRequestSchema = z.object({
|
|
type: z.literal("branch_suggestions_request"),
|
|
cwd: z.string(),
|
|
query: z.string().optional(),
|
|
limit: z.number().int().min(1).max(200).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const GitHubSearchItemSchema = z.object({
|
|
kind: z.enum(["issue", "pr"]),
|
|
forge: z.string().optional(),
|
|
number: z.number(),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
state: z.string(),
|
|
body: z.string().nullable(),
|
|
labels: z.array(z.string()),
|
|
projectPath: z.string().optional(),
|
|
baseRefName: z.string().nullable().optional(),
|
|
headRefName: z.string().nullable().optional(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const ForgeSearchItemSchema = GitHubSearchItemSchema.extend({
|
|
kind: z.enum(["issue", "change_request"]),
|
|
});
|
|
|
|
// COMPAT(githubSearchKind): added in v0.1.106, remove with the legacy
|
|
// github_search_request RPC after 2026-12-28.
|
|
export const ForgeSearchKindSchema = z.enum([
|
|
"issue",
|
|
"change_request",
|
|
"github-issue",
|
|
"github-pr",
|
|
"pr",
|
|
]);
|
|
|
|
export const GitHubSearchKindSchema = ForgeSearchKindSchema;
|
|
|
|
export const ForgeSearchRequestSchema = z.object({
|
|
type: z.literal("forge.search.request"),
|
|
cwd: z.string(),
|
|
query: z.string(),
|
|
limit: z.number().int().min(1).max(50).optional(),
|
|
kinds: z.array(ForgeSearchKindSchema).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
// COMPAT(githubSearchRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
// clients use forge.search.*.
|
|
export const GitHubSearchRequestSchema = z.object({
|
|
type: z.literal("github_search_request"),
|
|
cwd: z.string(),
|
|
query: z.string(),
|
|
limit: z.number().int().min(1).max(50).optional(),
|
|
kinds: z.array(GitHubSearchKindSchema).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const DirectorySuggestionsRequestSchema = z.object({
|
|
type: z.literal("directory_suggestions_request"),
|
|
query: z.string(),
|
|
cwd: z.string().optional(),
|
|
includeFiles: z.boolean().optional(),
|
|
includeDirectories: z.boolean().optional(),
|
|
matchMode: z.enum(["fuzzy", "suffix"]).optional(),
|
|
limit: z.number().int().min(1).max(100).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const PaseoWorktreeListRequestSchema = z.object({
|
|
type: z.literal("paseo_worktree_list_request"),
|
|
cwd: z.string().optional(),
|
|
repoRoot: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const PaseoWorktreeArchiveRequestSchema = z.object({
|
|
type: z.literal("paseo_worktree_archive_request"),
|
|
worktreePath: z.string().optional(),
|
|
repoRoot: z.string().optional(),
|
|
branchName: z.string().optional(),
|
|
// COMPAT(worktreeArchiveWorkspaceId): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
|
|
// Explicit workspace record to archive. A directory can back multiple workspaces
|
|
// (Model B), so resolving the target by cwd alone picks the wrong record. When
|
|
// present the daemon archives this exact workspace; when absent it falls back to
|
|
// resolving by worktreePath, preferring the worktree-kind record on a cwd tie.
|
|
workspaceId: z.string().optional(),
|
|
// COMPAT(worktreeArchiveScope): added in v0.1.97, drop the gate when floor >= v0.1.97.
|
|
// Scope of the archive operation. "workspace" archives a single workspace record
|
|
// (today's default UI behavior). "worktree" archives every active workspace whose
|
|
// cwd resolves to the target directory, then removes the directory if it is
|
|
// Paseo-owned. Omitted/unknown values default to "workspace" for old-client safety.
|
|
scope: z.enum(["workspace", "worktree"]).optional().default("workspace"),
|
|
// COMPAT(worktreeDiskDeletion): added in v0.1.97, ignored as of v0.1.97
|
|
// (disk removal derived from scope + last-reference + ownership); field
|
|
// retained for wire parse-compat, drop when floor >= v0.1.97.
|
|
deleteWorktreeFromDisk: z.boolean().optional().default(false),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FirstAgentContextSchema = z.object({
|
|
prompt: z.string().optional(),
|
|
attachments: AgentAttachmentsSchema,
|
|
});
|
|
|
|
export const CreatePaseoWorktreeRequestSchema = z.object({
|
|
type: z.literal("create_paseo_worktree_request"),
|
|
cwd: z.string(),
|
|
projectId: z.string().optional(),
|
|
worktreeSlug: z.string().optional(),
|
|
nameContext: z.string().optional(),
|
|
attachments: AgentAttachmentsSchema.optional(),
|
|
firstAgentContext: FirstAgentContextSchema.optional(),
|
|
refName: z.string().min(1).optional(),
|
|
action: z.enum(["branch-off", "checkout"]).optional(),
|
|
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
|
|
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
|
|
// clients send checkoutSource: { kind: "change_request", forge, number }.
|
|
githubPrNumber: z.number().int().positive().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspaceSetupStatusRequestSchema = z.object({
|
|
type: z.literal("workspace_setup_status_request"),
|
|
workspaceId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
// COMPAT(desktopEditorBridge): added in v0.1.88, remove after 2026-12-03 once old clients no longer call daemon editor RPCs.
|
|
export const LegacyListAvailableEditorsRequestSchema = z.object({
|
|
type: z.literal("list_available_editors_request"),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const LegacyOpenInEditorRequestSchema = z.object({
|
|
type: z.literal("open_in_editor_request"),
|
|
path: z.string(),
|
|
editorId: z.string().trim().min(1),
|
|
mode: z.enum(["open", "reveal"]).optional(),
|
|
cwd: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const OpenProjectRequestSchema = z.object({
|
|
type: z.literal("open_project_request"),
|
|
// Path used only for workspace lookup/creation. Use the returned workspace.id for all subsequent references.
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
// Smallest shorthand repo path is "a/b": owner, slash, repository.
|
|
const MIN_REPOSITORY_PATH_LENGTH = 3;
|
|
|
|
export const ProjectAddRequestSchema = z.object({
|
|
type: z.literal("project.add.request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProjectCreateDirectoryRequestSchema = z.object({
|
|
type: z.literal("project.create_directory.request"),
|
|
parentPath: z.string(),
|
|
name: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const GithubRepositorySchema = z.object({
|
|
id: z.string().min(1),
|
|
name: z.string().min(1),
|
|
nameWithOwner: z.string().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
description: z.string().nullable(),
|
|
visibility: z.enum(["public", "private", "internal"]),
|
|
updatedAt: z.string(),
|
|
cloneUrl: z.string().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
});
|
|
|
|
export const WorkspaceGithubSearchRepositoriesRequestSchema = z.object({
|
|
type: z.literal("workspace.github.search_repositories.request"),
|
|
query: z.string(),
|
|
limit: z.number().int().min(1).max(50).optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProjectGithubCloneProtocolSchema = z.enum(["https", "ssh"]);
|
|
|
|
export const ProjectGithubCloneRequestSchema = z.object({
|
|
type: z.literal("project.github.clone.request"),
|
|
repo: z.string().trim().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
cloneProtocol: ProjectGithubCloneProtocolSchema.optional(),
|
|
targetDirectory: z.string().trim().min(1),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ArchiveWorkspaceRequestSchema = z.object({
|
|
type: z.literal("archive_workspace_request"),
|
|
workspaceId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
// Create a new workspace record. Unlike open_project, this never deduplicates by
|
|
// directory: it always produces a fresh workspace. The source discriminates
|
|
// between an existing local directory and a newly created paseo worktree.
|
|
export const WorkspaceCreateRequestSchema = z.object({
|
|
type: z.literal("workspace.create.request"),
|
|
requestId: z.string(),
|
|
// Optional user-set title applied to the created workspace.
|
|
title: z.string().optional(),
|
|
// Optional prompt context for workspace-level name/branch generation.
|
|
firstAgentContext: FirstAgentContextSchema.optional(),
|
|
source: z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("directory"),
|
|
// Path of the existing checkout/directory to back the workspace.
|
|
path: z.string(),
|
|
projectId: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("worktree"),
|
|
// The project whose repo the worktree is cut from.
|
|
cwd: z.string().optional(),
|
|
projectId: z.string().optional(),
|
|
action: z.enum(["branch-off", "checkout"]).optional(),
|
|
// Target branch for checkout, or base ref for branch-off.
|
|
refName: z.string().min(1).optional(),
|
|
baseBranch: z.string().optional(),
|
|
// New branch name for branch-off. The worktree path may use a different slug.
|
|
branchName: z.string().min(1).optional(),
|
|
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
|
|
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
|
|
// clients send checkoutSource.
|
|
githubPrNumber: z.number().int().positive().optional(),
|
|
worktreeSlug: z.string().optional(),
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const WorkspaceClearAttentionRequestSchema = z.object({
|
|
type: z.literal("workspace.clear_attention.request"),
|
|
workspaceId: z.union([z.string(), z.array(z.string())]),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
// Highlighted diff token schema
|
|
// Note: style can be a compound class name (e.g., "heading meta") from the syntax highlighter
|
|
const HighlightTokenSchema = z.object({
|
|
text: z.string(),
|
|
style: z.string().nullable(),
|
|
});
|
|
|
|
const DiffLineSchema = z.object({
|
|
type: z.enum(["add", "remove", "context", "header"]),
|
|
content: z.string(),
|
|
tokens: z.array(HighlightTokenSchema).optional(),
|
|
});
|
|
|
|
const DiffHunkSchema = z.object({
|
|
oldStart: z.number(),
|
|
oldCount: z.number(),
|
|
newStart: z.number(),
|
|
newCount: z.number(),
|
|
lines: z.array(DiffLineSchema),
|
|
});
|
|
|
|
const ParsedDiffFileSchema = z.object({
|
|
path: z.string(),
|
|
// COMPAT(diffOldPath): added in v0.3.0, remove gate after 2027-02-09.
|
|
oldPath: z.string().optional(),
|
|
isNew: z.boolean(),
|
|
isDeleted: z.boolean(),
|
|
additions: z.number(),
|
|
deletions: z.number(),
|
|
hunks: z.array(DiffHunkSchema),
|
|
status: z.enum(["ok", "too_large", "binary"]).optional(),
|
|
});
|
|
|
|
const FileExplorerEntrySchema = z.object({
|
|
name: z.string(),
|
|
path: z.string(),
|
|
kind: z.enum(["file", "directory"]),
|
|
size: z.number(),
|
|
modifiedAt: z.string(),
|
|
});
|
|
|
|
const FileExplorerFileSchema = z.object({
|
|
path: z.string(),
|
|
kind: z.enum(["text", "image", "binary"]),
|
|
encoding: z.enum(["utf-8", "base64", "none"]),
|
|
content: z.string().optional(),
|
|
mimeType: z.string().optional(),
|
|
size: z.number(),
|
|
modifiedAt: z.string(),
|
|
revision: z.string().optional(),
|
|
});
|
|
|
|
const FileExplorerDirectorySchema = z.object({
|
|
path: z.string(),
|
|
entries: z.array(FileExplorerEntrySchema),
|
|
});
|
|
|
|
export const FileExplorerRequestSchema = z.object({
|
|
type: z.literal("file_explorer_request"),
|
|
cwd: z.string(),
|
|
path: z.string().optional(),
|
|
mode: z.enum(["list", "file"]),
|
|
requestId: z.string(),
|
|
acceptBinary: z.boolean().optional(),
|
|
});
|
|
|
|
export const FileVersionSchema = z.discriminatedUnion("status", [
|
|
z.object({
|
|
status: z.literal("ready"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
size: z.number().int().nonnegative(),
|
|
modifiedAt: z.string(),
|
|
revision: z.string().optional(),
|
|
}),
|
|
z.object({
|
|
status: z.literal("missing"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
}),
|
|
z.object({
|
|
status: z.literal("error"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
error: z.string(),
|
|
}),
|
|
]);
|
|
|
|
export const FileSubscribeRequestSchema = z.object({
|
|
type: z.literal("fs.file.subscribe.request"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
subscriptionId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileUnsubscribeRequestSchema = z.object({
|
|
type: z.literal("fs.file.unsubscribe.request"),
|
|
subscriptionId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileWriteRequestSchema = z.object({
|
|
type: z.literal("fs.file.write.request"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
content: z.string(),
|
|
expectedModifiedAt: z.string(),
|
|
expectedRevision: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileEntryCreateRequestSchema = z.object({
|
|
type: z.literal("fs.entry.create.request"),
|
|
cwd: z.string(),
|
|
parentPath: z.string(),
|
|
name: z.string(),
|
|
kind: z.enum(["file", "directory"]),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileEntryRenameRequestSchema = z.object({
|
|
type: z.literal("fs.entry.rename.request"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
name: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileEntryDuplicateRequestSchema = z.object({
|
|
type: z.literal("fs.entry.duplicate.request"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileEntryDeleteRequestSchema = z.object({
|
|
type: z.literal("fs.entry.delete.request"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProjectIconRequestSchema = z.object({
|
|
type: z.literal("project_icon_request"),
|
|
cwd: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ProjectIconGetRequestSchema = z.object({
|
|
type: z.literal("project.icon.get.request"),
|
|
projectId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileDownloadTokenRequestSchema = z.object({
|
|
type: z.literal("file_download_token_request"),
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const FileUploadRequestSchema = z.object({
|
|
type: z.literal("file.upload.request"),
|
|
fileName: z.string().min(1),
|
|
mimeType: z.string().min(1),
|
|
size: z.number().int().nonnegative(),
|
|
modifiedAt: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ClearAgentAttentionMessageSchema = z.object({
|
|
type: z.literal("clear_agent_attention"),
|
|
agentId: z.union([z.string(), z.array(z.string())]),
|
|
requestId: z.string().optional(),
|
|
});
|
|
|
|
export const ClientHeartbeatMessageSchema = z.object({
|
|
type: z.literal("client_heartbeat"),
|
|
deviceType: z.enum(["web", "mobile"]),
|
|
focusedAgentId: z.string().nullable(),
|
|
// COMPAT(terminalFocusHeartbeat): added in v0.1.97, remove optional default after 2026-12-13 once old clients no longer send heartbeats without terminal focus.
|
|
focusedTerminalId: z.string().nullable().optional().default(null),
|
|
lastActivityAt: z.string(),
|
|
appVisible: z.boolean(),
|
|
appVisibilityChangedAt: z.string().optional(),
|
|
});
|
|
|
|
export const PingMessageSchema = z.object({
|
|
type: z.literal("ping"),
|
|
requestId: z.string(),
|
|
clientSentAt: z.number().int().optional(),
|
|
});
|
|
|
|
const ListCommandsDraftConfigSchema = z.object({
|
|
provider: AgentProviderSchema,
|
|
cwd: z.string(),
|
|
modeId: z.string().optional(),
|
|
model: z.string().optional(),
|
|
thinkingOptionId: z.string().optional(),
|
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
|
|
export const ListProviderFeaturesRequestMessageSchema = z.object({
|
|
type: z.literal("list_provider_features_request"),
|
|
draftConfig: ListCommandsDraftConfigSchema,
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ListCommandsRequestSchema = z.object({
|
|
type: z.literal("list_commands_request"),
|
|
agentId: z.string(),
|
|
draftConfig: ListCommandsDraftConfigSchema.optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const RegisterPushTokenMessageSchema = z.object({
|
|
type: z.literal("register_push_token"),
|
|
token: z.string(),
|
|
});
|
|
|
|
export const PushUnregisterRequestSchema = z.object({
|
|
type: z.literal("push.unregister.request"),
|
|
token: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const PushUnregisterResponseSchema = z.object({
|
|
type: z.literal("push.unregister.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Terminal Messages
|
|
// ============================================================================
|
|
|
|
export const ListTerminalsRequestSchema = z.object({
|
|
type: z.literal("list_terminals_request"),
|
|
cwd: z.string().optional(),
|
|
workspaceId: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SubscribeTerminalsRequestSchema = z.object({
|
|
type: z.literal("subscribe_terminals_request"),
|
|
cwd: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
});
|
|
|
|
export const UnsubscribeTerminalsRequestSchema = z.object({
|
|
type: z.literal("unsubscribe_terminals_request"),
|
|
cwd: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
});
|
|
|
|
export const CreateTerminalRequestSchema = z.object({
|
|
type: z.literal("create_terminal_request"),
|
|
cwd: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
name: z.string().optional(),
|
|
agentId: z.string().optional(),
|
|
command: z.string().optional(),
|
|
args: z.array(z.string()).optional(),
|
|
// Initial PTY size. Added in v0.1.107; the app no longer sends it (the estimate cache that fed
|
|
// it was removed — the pane-focus resize claim sizes the PTY instead). Kept and honored
|
|
// permanently: released v0.1.107 clients still send it, and programmatic callers may pass an
|
|
// exact size. Daemons without it start at 80x24 and the first resize corrects that.
|
|
size: z
|
|
.object({
|
|
rows: z.number().int().positive(),
|
|
cols: z.number().int().positive(),
|
|
})
|
|
.optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const RenameTerminalRequestSchema = z.object({
|
|
type: z.literal("terminal.rename.request"),
|
|
terminalId: z.string(),
|
|
title: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const StartWorkspaceScriptRequestSchema = z.object({
|
|
type: z.literal("start_workspace_script_request"),
|
|
workspaceId: z.string(),
|
|
scriptName: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspaceScriptListRequestSchema = z.object({
|
|
type: z.literal("workspace.script.list.request"),
|
|
workspaceId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspaceScriptStartRequestSchema = z.object({
|
|
type: z.literal("workspace.script.start.request"),
|
|
workspaceId: z.string(),
|
|
scriptName: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const WorkspaceScriptStopRequestSchema = z.object({
|
|
type: z.literal("workspace.script.stop.request"),
|
|
workspaceId: z.string(),
|
|
scriptName: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const SubscribeTerminalRequestSchema = z.object({
|
|
type: z.literal("subscribe_terminal_request"),
|
|
terminalId: z.string(),
|
|
requestId: z.string(),
|
|
restore: z
|
|
.object({
|
|
mode: z.enum(["live", "visible-snapshot", "full-snapshot"]),
|
|
scrollbackLines: z.number().int().nonnegative().optional(),
|
|
size: z
|
|
.object({
|
|
rows: z.number().int().positive(),
|
|
cols: z.number().int().positive(),
|
|
})
|
|
.optional(),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
export const UnsubscribeTerminalRequestSchema = z.object({
|
|
type: z.literal("unsubscribe_terminal_request"),
|
|
terminalId: z.string(),
|
|
});
|
|
|
|
const TerminalClientMessageSchema = z.discriminatedUnion("type", [
|
|
z.object({ type: z.literal("input"), data: z.string() }),
|
|
z.object({
|
|
type: z.literal("resize"),
|
|
rows: z.number(),
|
|
cols: z.number(),
|
|
intent: z.enum(["claim", "update"]).optional(),
|
|
}),
|
|
z.object({
|
|
type: z.literal("mouse"),
|
|
row: z.number(),
|
|
col: z.number(),
|
|
button: z.number(),
|
|
action: z.enum(["down", "up", "move"]),
|
|
}),
|
|
]);
|
|
|
|
export const TerminalInputSchema = z.object({
|
|
type: z.literal("terminal_input"),
|
|
terminalId: z.string(),
|
|
message: TerminalClientMessageSchema,
|
|
});
|
|
|
|
export const KillTerminalRequestSchema = z.object({
|
|
type: z.literal("kill_terminal_request"),
|
|
terminalId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const CaptureTerminalRequestSchema = z.object({
|
|
type: z.literal("capture_terminal_request"),
|
|
terminalId: z.string(),
|
|
start: z.number().int().optional(),
|
|
end: z.number().int().optional(),
|
|
stripAnsi: z.boolean().default(true),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const HubExecutionAgentCreateRequestSchema = z.object({
|
|
type: z.literal("hub.execution.agent.create.request"),
|
|
requestId: z.string(),
|
|
executionId: z.string(),
|
|
provider: z.string(),
|
|
cwd: z.string(),
|
|
prompt: z.string(),
|
|
// COMPAT(hubExecutionWorkspaceSelection): semantics retired in v0.3.1; remove after 2027-08-08 once the Hub floor no longer sends it.
|
|
workspaceId: z.string().optional(),
|
|
model: z.string().optional(),
|
|
modeId: z.string().optional(),
|
|
thinkingOptionId: z.string().optional(),
|
|
featureValues: z.record(z.string(), z.unknown()).optional(),
|
|
providerOptions: ProviderOptionsSchema.optional(),
|
|
toolPolicy: ToolPolicySchema.optional(),
|
|
env: z.record(z.string(), z.string()).optional(),
|
|
mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
|
|
worktree: CreateAgentWorktreeTargetSchema.optional(),
|
|
});
|
|
|
|
export type HubExecutionAgentCreateRequest = z.infer<typeof HubExecutionAgentCreateRequestSchema>;
|
|
|
|
export const HubExecutionAgentValidateRequestSchema = z.object({
|
|
type: z.literal("hub.execution.agent.validate.request"),
|
|
requestId: z.string(),
|
|
provider: z.string(),
|
|
model: z.string().optional(),
|
|
modeId: z.string().optional(),
|
|
thinkingOptionId: z.string().optional(),
|
|
providerOptions: ProviderOptionsSchema.optional(),
|
|
});
|
|
|
|
export type HubExecutionAgentValidateRequest = z.infer<
|
|
typeof HubExecutionAgentValidateRequestSchema
|
|
>;
|
|
|
|
const HubExecutionAgentCreateErrorSchema = z.discriminatedUnion("code", [
|
|
z.object({
|
|
code: z.literal("provider_options_invalid"),
|
|
provider: z.string(),
|
|
issues: z.array(
|
|
z.object({
|
|
path: z.array(z.union([z.string(), z.number()])),
|
|
message: z.string(),
|
|
}),
|
|
),
|
|
message: z.string(),
|
|
}),
|
|
z.object({
|
|
code: z.literal("tool_policy_unsupported"),
|
|
provider: z.string(),
|
|
message: z.string(),
|
|
}),
|
|
z.object({
|
|
code: z.literal("create_failed"),
|
|
message: z.string(),
|
|
}),
|
|
]);
|
|
|
|
export type HubExecutionAgentCreateError = z.infer<typeof HubExecutionAgentCreateErrorSchema>;
|
|
|
|
export const HubExecutionControlActionSchema = z.enum(["interrupt", "archive"]);
|
|
export type HubExecutionControlAction = z.infer<typeof HubExecutionControlActionSchema>;
|
|
|
|
export const HubExecutionControlRequestSchema = z.object({
|
|
type: z.literal("hub.execution.control.request"),
|
|
requestId: z.string(),
|
|
executionId: z.string(),
|
|
action: HubExecutionControlActionSchema,
|
|
});
|
|
|
|
export type HubExecutionControlRequest = z.infer<typeof HubExecutionControlRequestSchema>;
|
|
|
|
export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
HubExecutionAgentCreateRequestSchema,
|
|
HubExecutionAgentValidateRequestSchema,
|
|
HubExecutionControlRequestSchema,
|
|
BrowserAutomationExecuteResponseSchema,
|
|
VoiceAudioChunkMessageSchema,
|
|
AbortRequestMessageSchema,
|
|
AudioPlayedMessageSchema,
|
|
FetchAgentsRequestMessageSchema,
|
|
FetchAgentHistoryRequestMessageSchema,
|
|
FetchRecentProviderSessionsRequestMessageSchema,
|
|
FetchWorkspacesRequestMessageSchema,
|
|
ProjectListRequestMessageSchema,
|
|
FetchAgentRequestMessageSchema,
|
|
DeleteAgentRequestMessageSchema,
|
|
ArchiveAgentRequestMessageSchema,
|
|
CloseItemsRequestMessageSchema,
|
|
UpdateAgentRequestMessageSchema,
|
|
ProjectRenameRequestSchema,
|
|
ProjectIconSetRequestSchema,
|
|
ProjectRemoveRequestSchema,
|
|
WorkspaceTitleSetRequestSchema,
|
|
WorkspacePinSetRequestSchema,
|
|
WorkspaceLabelListRequestSchema,
|
|
WorkspaceLabelAssignmentSetRequestSchema,
|
|
WorkspaceLabelUpdateRequestSchema,
|
|
WorkspaceLabelDeleteRequestSchema,
|
|
WorkspaceLabelDeleteInspectRequestSchema,
|
|
WorkspaceRecoveryInspectRequestSchema,
|
|
WorkspaceRecoveryRestoreRequestSchema,
|
|
SetVoiceModeMessageSchema,
|
|
SendAgentMessageRequestSchema,
|
|
WaitForFinishRequestSchema,
|
|
DaemonGetStatusRequestSchema,
|
|
DaemonGetPairingOfferRequestSchema,
|
|
DaemonConfigReloadRequestSchema,
|
|
HubManagementDaemonConnectRequestSchema,
|
|
HubManagementDaemonGetStatusRequestSchema,
|
|
HubManagementDaemonDisconnectRequestSchema,
|
|
DiagnosticsRequestSchema,
|
|
PluginCatalogGetRequestSchema,
|
|
PluginListRequestSchema,
|
|
PluginLogsGetRequestSchema,
|
|
PluginDirectoryInstallRequestSchema,
|
|
PluginDirectoryInspectRequestSchema,
|
|
PluginReloadRequestSchema,
|
|
PluginEnableRequestSchema,
|
|
PluginDisableRequestSchema,
|
|
PluginRemoveRequestSchema,
|
|
PluginRpcInvokeRequestSchema,
|
|
AgentSkillsGetStatusRequestSchema,
|
|
AgentSkillsReconcileRequestSchema,
|
|
AgentSkillsUninstallRequestSchema,
|
|
AgentSkillsSaveSelectionRequestSchema,
|
|
AgentSkillsImportLegacySelectionRequestSchema,
|
|
GetDaemonConfigRequestMessageSchema,
|
|
SetDaemonConfigRequestMessageSchema,
|
|
ReadProjectConfigRequestMessageSchema,
|
|
WriteProjectConfigRequestMessageSchema,
|
|
DictationStreamStartMessageSchema,
|
|
DictationStreamChunkMessageSchema,
|
|
DictationStreamFinishMessageSchema,
|
|
DictationStreamCancelMessageSchema,
|
|
CreateAgentRequestMessageSchema,
|
|
ListProviderModelsRequestMessageSchema,
|
|
ListProviderModesRequestMessageSchema,
|
|
ListProviderFeaturesRequestMessageSchema,
|
|
ListAvailableProvidersRequestMessageSchema,
|
|
GetProvidersSnapshotRequestMessageSchema,
|
|
RefreshProvidersSnapshotRequestMessageSchema,
|
|
ProviderDiagnosticRequestMessageSchema,
|
|
ProviderUsageListRequestMessageSchema,
|
|
ResumeAgentRequestMessageSchema,
|
|
ImportAgentRequestMessageSchema,
|
|
RefreshAgentRequestMessageSchema,
|
|
CancelAgentRequestMessageSchema,
|
|
ShutdownServerRequestMessageSchema,
|
|
RestartServerRequestMessageSchema,
|
|
DaemonUpdateRequestMessageSchema,
|
|
FetchAgentTimelineRequestMessageSchema,
|
|
AgentTimelineListPromptsRequestMessageSchema,
|
|
ProviderSubagentListRequestMessageSchema,
|
|
ProviderSubagentTimelineRequestMessageSchema,
|
|
SetAgentTimelineSubscriptionRequestMessageSchema,
|
|
AgentForkContextRequestMessageSchema,
|
|
SetAgentModeRequestMessageSchema,
|
|
SetAgentModelRequestMessageSchema,
|
|
SetAgentThinkingRequestMessageSchema,
|
|
SetAgentFeatureRequestMessageSchema,
|
|
AgentConfigApplyRequestMessageSchema,
|
|
AgentDetachRequestMessageSchema,
|
|
AgentRewindRequestMessageSchema,
|
|
AgentPermissionResponseMessageSchema,
|
|
CheckoutStatusRequestSchema,
|
|
SubscribeCheckoutDiffRequestSchema,
|
|
UnsubscribeCheckoutDiffRequestSchema,
|
|
CheckoutCommitRequestSchema,
|
|
CheckoutMergeRequestSchema,
|
|
CheckoutMergeFromBaseRequestSchema,
|
|
CheckoutPullRequestSchema,
|
|
CheckoutPushRequestSchema,
|
|
CheckoutRefreshRequestSchema,
|
|
CheckoutDiscardChangesRequestSchema,
|
|
CheckoutPrCreateRequestSchema,
|
|
CheckoutPrMergeRequestSchema,
|
|
CheckoutForgeSetAutoMergeRequestSchema,
|
|
CheckoutGithubSetAutoMergeRequestSchema,
|
|
CheckoutCommitsListRequestSchema,
|
|
CheckoutCommitFileDiffRequestSchema,
|
|
CheckoutForgeGetCheckDetailsRequestSchema,
|
|
CheckoutGithubGetCheckDetailsRequestSchema,
|
|
CheckoutPrStatusRequestSchema,
|
|
PullRequestTimelineRequestSchema,
|
|
CheckoutSwitchBranchRequestSchema,
|
|
CheckoutRenameBranchRequestSchema,
|
|
StashSaveRequestSchema,
|
|
StashPopRequestSchema,
|
|
StashListRequestSchema,
|
|
ValidateBranchRequestSchema,
|
|
BranchSuggestionsRequestSchema,
|
|
ForgeSearchRequestSchema,
|
|
GitHubSearchRequestSchema,
|
|
DirectorySuggestionsRequestSchema,
|
|
PaseoWorktreeListRequestSchema,
|
|
PaseoWorktreeArchiveRequestSchema,
|
|
CreatePaseoWorktreeRequestSchema,
|
|
WorkspaceSetupStatusRequestSchema,
|
|
LegacyListAvailableEditorsRequestSchema,
|
|
LegacyOpenInEditorRequestSchema,
|
|
OpenProjectRequestSchema,
|
|
ProjectAddRequestSchema,
|
|
ProjectCreateDirectoryRequestSchema,
|
|
WorkspaceGithubSearchRepositoriesRequestSchema,
|
|
ProjectGithubCloneRequestSchema,
|
|
ArchiveWorkspaceRequestSchema,
|
|
WorkspaceCreateRequestSchema,
|
|
WorkspaceClearAttentionRequestSchema,
|
|
FileExplorerRequestSchema,
|
|
FileSubscribeRequestSchema,
|
|
FileUnsubscribeRequestSchema,
|
|
FileWriteRequestSchema,
|
|
FileEntryCreateRequestSchema,
|
|
FileEntryRenameRequestSchema,
|
|
FileEntryDuplicateRequestSchema,
|
|
FileEntryDeleteRequestSchema,
|
|
ProjectIconRequestSchema,
|
|
ProjectIconGetRequestSchema,
|
|
FileDownloadTokenRequestSchema,
|
|
FileUploadRequestSchema,
|
|
ClearAgentAttentionMessageSchema,
|
|
ClientHeartbeatMessageSchema,
|
|
PingMessageSchema,
|
|
ListCommandsRequestSchema,
|
|
RegisterPushTokenMessageSchema,
|
|
PushUnregisterRequestSchema,
|
|
ListTerminalsRequestSchema,
|
|
SubscribeTerminalsRequestSchema,
|
|
UnsubscribeTerminalsRequestSchema,
|
|
CreateTerminalRequestSchema,
|
|
RenameTerminalRequestSchema,
|
|
StartWorkspaceScriptRequestSchema,
|
|
WorkspaceScriptListRequestSchema,
|
|
WorkspaceScriptStartRequestSchema,
|
|
WorkspaceScriptStopRequestSchema,
|
|
SubscribeTerminalRequestSchema,
|
|
UnsubscribeTerminalRequestSchema,
|
|
TerminalInputSchema,
|
|
KillTerminalRequestSchema,
|
|
CaptureTerminalRequestSchema,
|
|
ChatCreateRequestSchema,
|
|
ChatListRequestSchema,
|
|
ChatInspectRequestSchema,
|
|
ChatDeleteRequestSchema,
|
|
ChatPostRequestSchema,
|
|
ChatReadRequestSchema,
|
|
ChatWaitRequestSchema,
|
|
ScheduleCreateRequestSchema,
|
|
ScheduleListRequestSchema,
|
|
ScheduleInspectRequestSchema,
|
|
ScheduleLogsRequestSchema,
|
|
SchedulePauseRequestSchema,
|
|
ScheduleResumeRequestSchema,
|
|
ScheduleDeleteRequestSchema,
|
|
ScheduleRunOnceRequestSchema,
|
|
ScheduleUpdateRequestSchema,
|
|
LoopRunRequestSchema,
|
|
LoopListRequestSchema,
|
|
LoopInspectRequestSchema,
|
|
LoopLogsRequestSchema,
|
|
LoopStopRequestSchema,
|
|
]);
|
|
|
|
export type SessionInboundMessage = z.infer<typeof SessionInboundMessageSchema>;
|
|
|
|
// ============================================================================
|
|
// Session Outbound Messages (Session emits these)
|
|
// ============================================================================
|
|
|
|
export const ActivityLogPayloadSchema = z.object({
|
|
id: z.string(),
|
|
timestamp: z.coerce.date(),
|
|
type: z.enum(["transcript", "assistant", "tool_call", "tool_result", "error", "system"]),
|
|
content: z.string(),
|
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
});
|
|
|
|
export const ActivityLogMessageSchema = z.object({
|
|
type: z.literal("activity_log"),
|
|
payload: ActivityLogPayloadSchema,
|
|
});
|
|
|
|
export const AssistantChunkMessageSchema = z.object({
|
|
type: z.literal("assistant_chunk"),
|
|
payload: z.object({
|
|
chunk: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const AudioOutputMessageSchema = z.object({
|
|
type: z.literal("audio_output"),
|
|
payload: z.object({
|
|
audio: z.string(), // base64 encoded
|
|
format: z.string(),
|
|
id: z.string(),
|
|
isVoiceMode: z.boolean(), // Mode when audio was generated (for drift protection)
|
|
groupId: z.string().optional(), // Logical utterance id
|
|
chunkIndex: z.number().int().nonnegative().optional(),
|
|
isLastChunk: z.boolean().optional(),
|
|
}),
|
|
});
|
|
|
|
export const TranscriptionResultMessageSchema = z.object({
|
|
type: z.literal("transcription_result"),
|
|
payload: z.object({
|
|
text: z.string(),
|
|
language: z.string().optional(),
|
|
duration: z.number().optional(),
|
|
requestId: z.string(), // Echoed back from request for tracking
|
|
avgLogprob: z.number().optional(),
|
|
isLowConfidence: z.boolean().optional(),
|
|
byteLength: z.number().optional(),
|
|
format: z.string().optional(),
|
|
debugRecordingPath: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
export const VoiceInputStateMessageSchema = z.object({
|
|
type: z.literal("voice_input_state"),
|
|
payload: z.object({
|
|
isSpeaking: z.boolean(),
|
|
}),
|
|
});
|
|
|
|
export const DictationStreamAckMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_ack"),
|
|
payload: z.object({
|
|
dictationId: z.string(),
|
|
ackSeq: z.number().int(),
|
|
}),
|
|
});
|
|
|
|
export const DictationStreamFinishAcceptedMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_finish_accepted"),
|
|
payload: z.object({
|
|
dictationId: z.string(),
|
|
timeoutMs: z.number().int().positive(),
|
|
}),
|
|
});
|
|
|
|
export const DictationStreamPartialMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_partial"),
|
|
payload: z.object({
|
|
dictationId: z.string(),
|
|
text: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const DictationStreamFinalMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_final"),
|
|
payload: z.object({
|
|
dictationId: z.string(),
|
|
text: z.string(),
|
|
debugRecordingPath: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
export const DictationStreamErrorMessageSchema = z.object({
|
|
type: z.literal("dictation_stream_error"),
|
|
payload: z.object({
|
|
dictationId: z.string(),
|
|
error: z.string(),
|
|
retryable: z.boolean(),
|
|
reasonCode: z.string().optional(),
|
|
missingModelIds: z.array(z.string()).optional(),
|
|
debugRecordingPath: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
export const ServerCapabilityStateSchema = z.object({
|
|
enabled: z.boolean(),
|
|
reason: z.string(),
|
|
});
|
|
|
|
export const ServerVoiceCapabilitiesSchema = z.object({
|
|
dictation: ServerCapabilityStateSchema,
|
|
voice: ServerCapabilityStateSchema,
|
|
});
|
|
|
|
export const ServerCapabilitiesSchema = z
|
|
.object({
|
|
voice: ServerVoiceCapabilitiesSchema.optional(),
|
|
})
|
|
.passthrough();
|
|
|
|
const ServerInfoHostnameSchema = z.unknown().transform((value): string | null => {
|
|
if (typeof value !== "string") {
|
|
return null;
|
|
}
|
|
const trimmed = value.trim();
|
|
return trimmed.length > 0 ? trimmed : null;
|
|
});
|
|
|
|
const ServerInfoVersionSchema = z.unknown().transform((value): string | null => {
|
|
if (typeof value !== "string") {
|
|
return null;
|
|
}
|
|
const trimmed = value.trim();
|
|
return trimmed.length > 0 ? trimmed : null;
|
|
});
|
|
|
|
const ServerCapabilitiesFromUnknownSchema = z
|
|
.unknown()
|
|
.optional()
|
|
.transform((value): z.infer<typeof ServerCapabilitiesSchema> | undefined => {
|
|
if (value === undefined) {
|
|
return undefined;
|
|
}
|
|
const parsed = ServerCapabilitiesSchema.safeParse(value);
|
|
if (!parsed.success) {
|
|
return undefined;
|
|
}
|
|
return parsed.data;
|
|
});
|
|
|
|
export const ServerInfoStatusPayloadSchema = z
|
|
.object({
|
|
status: z.literal("server_info"),
|
|
serverId: z.string().trim().min(1),
|
|
hostname: ServerInfoHostnameSchema.optional(),
|
|
version: ServerInfoVersionSchema.optional(),
|
|
// COMPAT(desktopManaged): added in v0.1.X, remove optional parsing after 2027-01-16.
|
|
desktopManaged: z.boolean().optional(),
|
|
capabilities: ServerCapabilitiesFromUnknownSchema.optional(),
|
|
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
|
features: z
|
|
.object({
|
|
providersSnapshot: z.boolean().optional(),
|
|
// COMPAT(providersSnapshotCwd): added in v0.3.2, remove gate after 2027-02-10.
|
|
providersSnapshotCwd: z.boolean().optional(),
|
|
// COMPAT(directorySync): added in v0.3.x, remove gate after 2027-02-12.
|
|
directorySync: z.boolean().optional(),
|
|
// COMPAT(workspaceLabels): added in v0.5.0, remove after 2027-08-14.
|
|
workspaceLabels: z.boolean().optional(),
|
|
// COMPAT(checkoutForgeSetAutoMerge): added in v0.1.106, remove old
|
|
// checkoutGithubSetAutoMerge fallback after 2026-12-28.
|
|
checkoutForgeSetAutoMerge: z.boolean().optional(),
|
|
checkoutGithubSetAutoMerge: z.boolean().optional(),
|
|
// COMPAT(githubCheckDetails): added in v0.1.92, remove gate after 2026-12-08.
|
|
githubCheckDetails: z.boolean().optional(),
|
|
// COMPAT(forgeCheckDetails): added in v0.1.106, remove githubCheckDetails fallback after 2026-12-28.
|
|
forgeCheckDetails: z.boolean().optional(),
|
|
// COMPAT(forgeSearch): added in v0.1.106, remove github_search fallback after 2026-12-28.
|
|
forgeSearch: z.boolean().optional(),
|
|
// COMPAT(daemonStatusRpc): added in v0.1.76, remove gate after 2026-11-18.
|
|
daemonStatusRpc: z.boolean().optional(),
|
|
// COMPAT(daemonConfigReload): added in v0.4.0, remove gate after 2027-02-14.
|
|
daemonConfigReload: z.boolean().optional(),
|
|
// COMPAT(relayConfig): added in v0.2.6, remove gate after 2027-01-31.
|
|
relayConfig: z.boolean().optional(),
|
|
// COMPAT(pushTokenRevocation): added in v0.3.2, remove gate after 2027-02-10.
|
|
pushTokenRevocation: z.boolean().optional(),
|
|
// COMPAT(plugins): added in v0.3.0, remove gate after 2027-08-07.
|
|
plugins: z.boolean().optional(),
|
|
// COMPAT(pluginManagement): added in v0.4.0, remove gate after 2027-08-14.
|
|
pluginManagement: z.boolean().optional(),
|
|
// COMPAT(pluginLogs): added in v0.4.0, remove gate after 2027-08-16.
|
|
pluginLogs: z.boolean().optional(),
|
|
// COMPAT(skillManagement): added in v0.4.0, remove gate after 2027-08-16.
|
|
skillManagement: z.boolean().optional(),
|
|
// COMPAT(terminalRestoreModes): added in v0.1.81, remove gate after 2026-11-23.
|
|
"terminal-restore-modes": z.boolean().optional(),
|
|
// COMPAT(terminalInputModeReplay): added in v0.2.6, remove gate after 2027-02-02.
|
|
"terminal-input-mode-replay": z.boolean().optional(),
|
|
// COMPAT(terminalSizeOwnership): added in v0.2.6, remove gate after 2027-02-02.
|
|
"terminal-size-ownership": z.boolean().optional(),
|
|
// COMPAT(rewind): added in v0.1.X, drop the gate when floor >= v0.1.X.
|
|
rewind: z.boolean().optional(),
|
|
// COMPAT(agentTimelinePromptIndex): added in v0.2.X, drop the gate when floor >= v0.2.X.
|
|
agentTimelinePromptIndex: z.boolean().optional(),
|
|
// COMPAT(agentHistorySearch): added in v0.3.0, remove gate after 2027-02-07.
|
|
agentHistorySearch: z.boolean().optional(),
|
|
// COMPAT(checkoutRefresh): added in v0.1.86, remove gate after 2026-11-29.
|
|
checkoutRefresh: z.boolean().optional(),
|
|
// COMPAT(workspaceMultiplicity): added in v0.1.97, drop the gate when floor >= v0.1.97
|
|
workspaceMultiplicity: z.boolean().optional(),
|
|
// COMPAT(projectRemove): added in v0.1.97, drop the gate when floor >= v0.1.97.
|
|
projectRemove: z.boolean().optional(),
|
|
// COMPAT(projectAdd): added in v0.1.97, drop the gate when floor >= v0.1.97.
|
|
projectAdd: z.boolean().optional(),
|
|
// COMPAT(worktreeRestore): added in v0.1.97, drop the gate when floor >= v0.1.97
|
|
worktreeRestore: z.boolean().optional(),
|
|
// COMPAT(workspaceRecovery): added in v0.1.105, remove after 2027-01-11 once daemon floor >= v0.1.105.
|
|
workspaceRecovery: z.boolean().optional(),
|
|
// COMPAT(workspaceFileEditing): added in v0.2.0, remove after 2027-01-18 once daemon floor >= v0.2.0.
|
|
workspaceFileEditing: z.boolean().optional(),
|
|
// COMPAT(providerUsageList): added in v0.1.98, drop the gate when daemon floor >= v0.1.98.
|
|
providerUsageList: z.boolean().optional(),
|
|
// COMPAT(agentDetach): added in v0.1.98, remove gate after 2026-12-19 once daemon floor >= v0.1.98.
|
|
agentDetach: z.boolean().optional(),
|
|
// COMPAT(agentThinkingUpdate): added in v0.2.4, remove gate after 2027-01-28.
|
|
agentThinkingUpdate: z.boolean().optional(),
|
|
// COMPAT(daemonDiagnostics): added in v0.1.100, remove gate after 2026-12-25 once daemon floor >= v0.1.100.
|
|
daemonDiagnostics: z.boolean().optional(),
|
|
// COMPAT(daemonSelfUpdate): added in v0.1.93, remove gate after 2026-12-13.
|
|
daemonSelfUpdate: z.boolean().optional(),
|
|
// COMPAT(agentForkContext): added in v0.1.102, remove gate after 2026-12-28.
|
|
agentForkContext: z.boolean().optional(),
|
|
// COMPAT(agentForkContextCursor): added in v0.1.108, remove gate after 2027-01-14.
|
|
agentForkContextCursor: z.boolean().optional(),
|
|
// COMPAT(providerSubagents): added in v0.1.107, remove gate after 2027-01-12.
|
|
providerSubagents: z.boolean().optional(),
|
|
// COMPAT(workspacePinning): added in v0.1.107, remove gate after 2027-01-12.
|
|
workspacePinning: z.boolean().optional(),
|
|
// COMPAT(hubRelationship): added in v0.1.X, drop the gate when floor >= v0.1.X.
|
|
hubRelationship: z.boolean().optional(),
|
|
// COMPAT(projectGithubClone): added in v0.1.108, remove gate after 2027-01-15.
|
|
projectGithubClone: z.boolean().optional(),
|
|
// COMPAT(workspaceGithubRepositorySearch): added in v0.1.108, remove gate after 2027-01-15.
|
|
workspaceGithubRepositorySearch: z.boolean().optional(),
|
|
// COMPAT(projectCreateDirectory): added in v0.1.108, remove gate after 2027-01-15.
|
|
projectCreateDirectory: z.boolean().optional(),
|
|
// COMPAT(projectList): added in v0.2.4, drop the gate when floor >= v0.2.4.
|
|
projectList: z.boolean().optional(),
|
|
// COMPAT(commitsList): added in v0.1.110, remove gate after 2027-01-16.
|
|
commitsList: z.boolean().optional(),
|
|
// COMPAT(commitBaseClassification): added in v0.2.0, remove gate after 2027-01-23.
|
|
commitBaseClassification: z.boolean().optional(),
|
|
// COMPAT(providerRemoval): added in v0.1.105, drop the gate when floor >= v0.1.105.
|
|
providerRemoval: z.boolean().optional(),
|
|
// COMPAT(importSessionWorkspaceTarget): added in v0.1.110, remove gate after 2027-01-16.
|
|
importSessionWorkspaceTarget: z.boolean().optional(),
|
|
// COMPAT(forgeProviders): added in v0.1.106, drop the gate when daemon floor >= v0.1.106.
|
|
// Daemon advertises pluggable non-GitHub forge support (the forge registry);
|
|
// the client gates non-GitHub setup UI on it.
|
|
forgeProviders: z.boolean().optional(),
|
|
// COMPAT(selectiveAgentTimeline): added in v0.1.106, remove after 2027-01-12.
|
|
selectiveAgentTimeline: z.boolean().optional(),
|
|
// COMPAT(canonicalSubmittedPrompts): added in v0.2.6, remove gate after 2027-01-30.
|
|
canonicalSubmittedPrompts: z.boolean().optional(),
|
|
// COMPAT(agentTurnIdentity): accept peers that observed pre-release v0.2.6 through 2027-01-31.
|
|
agentTurnIdentity: z.boolean().optional(),
|
|
// COMPAT(stableProjectIdentity): added in v0.1.109, remove gate after 2027-01-15.
|
|
stableProjectIdentity: z.boolean().optional(),
|
|
// COMPAT(workspaceScriptManagement): added in v0.1.105, remove gate after 2027-01-10.
|
|
workspaceScriptManagement: z.boolean().optional(),
|
|
// COMPAT(projectCustomIcon): added in v0.2.0, remove after 2027-01-20.
|
|
projectCustomIcon: z.boolean().optional(),
|
|
// COMPAT(fsEntryOps): added in v0.3.0, remove gate after 2027-02-08.
|
|
fsEntryOps: z.boolean().optional(),
|
|
// COMPAT(fsEntryDuplicate): added in v0.3.0, remove gate after 2027-02-09.
|
|
fsEntryDuplicate: z.boolean().optional(),
|
|
// COMPAT(checkoutDiscardChanges): added in v0.3.0, remove gate after 2027-02-08.
|
|
checkoutDiscardChanges: z.boolean().optional(),
|
|
// COMPAT(agentProfiles): added in v0.3.2, remove gate after 2027-02-11.
|
|
// An older daemon parses its persisted config strictly, so writing
|
|
// agentProfiles to one is silently dropped. The client hides the feature
|
|
// rather than letting a save appear to succeed.
|
|
agentProfiles: z.boolean().optional(),
|
|
// COMPAT(agentConfigApply): added in v0.3.2, remove gate after 2027-02-11.
|
|
agentConfigApply: z.boolean().optional(),
|
|
})
|
|
.optional(),
|
|
})
|
|
.passthrough()
|
|
.transform((payload) => ({
|
|
...payload,
|
|
hostname: payload.hostname ?? null,
|
|
version: payload.version ?? null,
|
|
}));
|
|
|
|
export const StatusMessageSchema = z.object({
|
|
type: z.literal("status"),
|
|
payload: z
|
|
.object({
|
|
status: z.string(),
|
|
})
|
|
.passthrough(), // Allow additional fields
|
|
});
|
|
|
|
export const PongMessageSchema = z.object({
|
|
type: z.literal("pong"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
clientSentAt: z.number().int().optional(),
|
|
serverReceivedAt: z.number().int(),
|
|
serverSentAt: z.number().int(),
|
|
}),
|
|
});
|
|
|
|
export const RpcErrorMessageSchema = z.object({
|
|
type: z.literal("rpc_error"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
requestType: z.string().optional(),
|
|
error: z.string(),
|
|
code: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
const AgentStatusWithRequestSchema = z.object({
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
const AgentStatusWithTimelineSchema = AgentStatusWithRequestSchema.extend({
|
|
timelineSize: z.number().optional(),
|
|
});
|
|
|
|
export const AgentCreatedStatusPayloadSchema = z
|
|
.object({
|
|
status: z.literal("agent_created"),
|
|
agent: AgentSnapshotPayloadSchema,
|
|
})
|
|
.extend(AgentStatusWithRequestSchema.shape);
|
|
|
|
export const AgentCreateFailedStatusPayloadSchema = z.object({
|
|
status: z.literal("agent_create_failed"),
|
|
requestId: z.string(),
|
|
error: z.string(),
|
|
errorCode: z.string().optional(),
|
|
});
|
|
|
|
export const AgentResumedStatusPayloadSchema = z
|
|
.object({
|
|
status: z.literal("agent_resumed"),
|
|
agent: AgentSnapshotPayloadSchema,
|
|
})
|
|
.extend(AgentStatusWithTimelineSchema.shape);
|
|
|
|
export const AgentRefreshedStatusPayloadSchema = z
|
|
.object({
|
|
status: z.literal("agent_refreshed"),
|
|
})
|
|
.extend(AgentStatusWithTimelineSchema.shape);
|
|
|
|
export const RestartRequestedStatusPayloadSchema = z.object({
|
|
status: z.literal("restart_requested"),
|
|
clientId: z.string(),
|
|
reason: z.string().optional(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ShutdownRequestedStatusPayloadSchema = z.object({
|
|
status: z.literal("shutdown_requested"),
|
|
clientId: z.string(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const DaemonConfigChangedStatusPayloadSchema = z
|
|
.object({
|
|
status: z.literal("daemon_config_changed"),
|
|
config: MutableDaemonConfigSchema,
|
|
})
|
|
.passthrough();
|
|
|
|
export const PluginCatalogChangedStatusPayloadSchema = z.object({
|
|
status: z.literal("plugin_catalog_changed"),
|
|
pluginId: PluginIdSchema,
|
|
});
|
|
|
|
export const KnownStatusPayloadSchema = z.discriminatedUnion("status", [
|
|
AgentCreatedStatusPayloadSchema,
|
|
AgentCreateFailedStatusPayloadSchema,
|
|
AgentResumedStatusPayloadSchema,
|
|
AgentRefreshedStatusPayloadSchema,
|
|
ShutdownRequestedStatusPayloadSchema,
|
|
RestartRequestedStatusPayloadSchema,
|
|
DaemonConfigChangedStatusPayloadSchema,
|
|
PluginCatalogChangedStatusPayloadSchema,
|
|
]);
|
|
|
|
export type KnownStatusPayload = z.infer<typeof KnownStatusPayloadSchema>;
|
|
|
|
export const ArtifactMessageSchema = z.object({
|
|
type: z.literal("artifact"),
|
|
payload: z.object({
|
|
type: z.enum(["markdown", "diff", "image", "code"]),
|
|
id: z.string(),
|
|
title: z.string(),
|
|
content: z.string(),
|
|
isBase64: z.boolean(),
|
|
}),
|
|
});
|
|
|
|
export const ProjectCheckoutLiteNotGitPayloadSchema = z
|
|
.object({
|
|
cwd: z.string(),
|
|
isGit: z.literal(false),
|
|
currentBranch: z.null(),
|
|
remoteUrl: z.null(),
|
|
worktreeRoot: z.null().optional(),
|
|
isPaseoOwnedWorktree: z.literal(false),
|
|
mainRepoRoot: z.null(),
|
|
})
|
|
.transform((value) => ({
|
|
...value,
|
|
worktreeRoot: null,
|
|
}));
|
|
|
|
export const ProjectCheckoutLiteGitNonPaseoPayloadSchema = z
|
|
.object({
|
|
cwd: z.string(),
|
|
isGit: z.literal(true),
|
|
currentBranch: z.string().nullable(),
|
|
remoteUrl: z.string().nullable(),
|
|
worktreeRoot: z.string().optional(),
|
|
isPaseoOwnedWorktree: z.literal(false),
|
|
mainRepoRoot: z.string().nullable().optional().default(null),
|
|
})
|
|
.transform((value) => ({
|
|
...value,
|
|
worktreeRoot: value.worktreeRoot ?? value.cwd,
|
|
}));
|
|
|
|
export const ProjectCheckoutLiteGitPaseoPayloadSchema = z
|
|
.object({
|
|
cwd: z.string(),
|
|
isGit: z.literal(true),
|
|
currentBranch: z.string().nullable(),
|
|
remoteUrl: z.string().nullable(),
|
|
worktreeRoot: z.string().optional(),
|
|
isPaseoOwnedWorktree: z.literal(true),
|
|
mainRepoRoot: z.string(),
|
|
})
|
|
.transform((value) => ({
|
|
...value,
|
|
worktreeRoot: value.worktreeRoot ?? value.cwd,
|
|
}));
|
|
|
|
export const ProjectCheckoutLitePayloadSchema = z.union([
|
|
ProjectCheckoutLiteNotGitPayloadSchema,
|
|
ProjectCheckoutLiteGitNonPaseoPayloadSchema,
|
|
ProjectCheckoutLiteGitPaseoPayloadSchema,
|
|
]);
|
|
|
|
export const ProjectPlacementPayloadSchema = z.object({
|
|
projectKey: z.string(),
|
|
projectName: z.string(),
|
|
workspaceName: z.string().nullable().optional(),
|
|
checkout: ProjectCheckoutLitePayloadSchema,
|
|
});
|
|
|
|
export const WorkspaceScriptLifecycleSchema = z.enum(["running", "stopped"]);
|
|
export const WorkspaceScriptHealthSchema = z.enum(["healthy", "unhealthy"]);
|
|
|
|
export const WorkspaceScriptPayloadSchema = z.object({
|
|
scriptName: z.string(),
|
|
type: z.enum(["script", "service"]).optional().default("service"),
|
|
hostname: z.string(),
|
|
port: z.number().int().positive().nullable(),
|
|
localProxyUrl: z.string().nullable().optional(),
|
|
publicProxyUrl: z.string().nullable().optional(),
|
|
proxyUrl: z.string().nullable().optional().default(null),
|
|
lifecycle: WorkspaceScriptLifecycleSchema,
|
|
health: WorkspaceScriptHealthSchema.nullable(),
|
|
exitCode: z.number().nullable().optional().default(null),
|
|
terminalId: z.string().nullable().optional().default(null),
|
|
});
|
|
|
|
const WorkspaceGitRuntimePayloadSchema = z
|
|
.object({
|
|
currentBranch: z.string().nullable().optional(),
|
|
remoteUrl: z.string().nullable().optional(),
|
|
isPaseoOwnedWorktree: z.boolean().optional(),
|
|
isDirty: z.boolean().nullable().optional(),
|
|
aheadBehind: z
|
|
.object({
|
|
ahead: z.number(),
|
|
behind: z.number(),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
aheadOfOrigin: z.number().nullable().optional(),
|
|
behindOfOrigin: z.number().nullable().optional(),
|
|
})
|
|
.optional()
|
|
.nullable();
|
|
|
|
export const WorkspaceGitHubRuntimePayloadSchema = z
|
|
.object({
|
|
featuresEnabled: z.boolean().optional(),
|
|
pullRequest: z
|
|
.object({
|
|
number: z.number().optional(),
|
|
url: z.string(),
|
|
title: z.string(),
|
|
state: z.string(),
|
|
baseRefName: z.string(),
|
|
headRefName: z.string(),
|
|
isMerged: z.boolean(),
|
|
isDraft: z.boolean().optional(),
|
|
mergeable: z.enum(["MERGEABLE", "CONFLICTING", "UNKNOWN"]).catch("UNKNOWN").optional(),
|
|
checks: z
|
|
.array(
|
|
z.object({
|
|
name: z.string(),
|
|
status: z.enum(["success", "failure", "pending", "skipped", "cancelled"]),
|
|
url: z.string().nullable(),
|
|
workflow: z.string().optional(),
|
|
duration: z.string().optional(),
|
|
}),
|
|
)
|
|
.optional(),
|
|
checksStatus: z.enum(["none", "pending", "success", "failure"]).optional(),
|
|
reviewDecision: z.enum(["approved", "changes_requested", "pending"]).nullable().optional(),
|
|
repoOwner: z.string().optional(),
|
|
repoName: z.string().optional(),
|
|
github: z.unknown().optional(),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
error: z
|
|
.object({
|
|
message: z.string(),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
refreshedAt: z.string().nullable().optional(),
|
|
})
|
|
.optional()
|
|
.nullable();
|
|
|
|
export const WorkspaceDescriptorPayloadSchema = z
|
|
.object({
|
|
id: z.string(),
|
|
projectId: z.string(),
|
|
projectDisplayName: z.string(),
|
|
// COMPAT(projectCustomName): added in v0.1.76, drop the optional gate when floor >= v0.1.76.
|
|
// When the user has renamed a project, projectDisplayName carries the resolved
|
|
// value (customName) and projectCustomName mirrors the raw override so the
|
|
// settings UI can prefill its input and offer a "reset" action.
|
|
projectCustomName: z.string().nullable().optional(),
|
|
// Identifies the project's stored custom icon; null means automatic.
|
|
// COMPAT(projectCustomIcon): added in v0.2.0, remove after 2027-01-20.
|
|
projectCustomIconRevision: z.string().nullable().optional(),
|
|
projectRootPath: z.string(),
|
|
workspaceDirectory: z.string().optional(),
|
|
// COMPAT(worktreeSlug): added in v0.2.6, remove optional after 2027-01-31.
|
|
// Present only for Paseo-owned worktrees; this is the basename of their root directory.
|
|
worktreeSlug: z.string().optional(),
|
|
projectKind: z.enum(["git", "non_git", "directory"]),
|
|
// COMPAT(workspaces): keep legacy directory workspace kind parseable.
|
|
workspaceKind: z.enum(["directory", "local_checkout", "checkout", "worktree"]),
|
|
name: z.string(),
|
|
// COMPAT(workspaceTitles): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
|
|
// When the user has titled a workspace, `name` carries the resolved value
|
|
// (title) and `title` mirrors the raw override so the rename UI can prefill
|
|
// its input and offer a "reset to branch name" action. Null means the name
|
|
// is derived from the branch/directory.
|
|
title: z.string().nullable().optional(),
|
|
// COMPAT(workspacePinning): added in v0.1.107, remove optional after 2027-01-12.
|
|
pinnedAt: z.string().nullable().optional(),
|
|
// COMPAT(workspaceLabels): added in v0.5.0, remove optional after 2027-08-14.
|
|
labels: z.array(z.string()).optional(),
|
|
archivingAt: z.string().nullable().optional().default(null),
|
|
status: WorkspaceStateBucketSchema,
|
|
// Best-effort workspace status entry timestamp. Old daemons omit the
|
|
// field; old clients treat missing and null equivalently. The transform
|
|
// coerces a missing field to `null` so downstream code never has to
|
|
// handle `undefined`.
|
|
statusEnteredAt: z
|
|
.string()
|
|
.nullish()
|
|
.transform((value) => value ?? null),
|
|
activityAt: z.string().nullable(),
|
|
diffStat: z
|
|
.object({
|
|
additions: z.number(),
|
|
deletions: z.number(),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
scripts: z.array(WorkspaceScriptPayloadSchema).default([]),
|
|
gitRuntime: WorkspaceGitRuntimePayloadSchema,
|
|
githubRuntime: WorkspaceGitHubRuntimePayloadSchema,
|
|
// COMPAT(forge): added in v0.1.106, remove after 2026-12-27. The forge resolved
|
|
// for this workspace, so the sidebar/hover-card render the right brand mark.
|
|
// Old daemons omit it; absent means the client falls back to GitHub.
|
|
forge: z.string().optional(),
|
|
project: ProjectPlacementPayloadSchema.optional(),
|
|
// COMPAT(directorySync): sequence of this latest directory projection.
|
|
syncSeq: z.number().int().positive().optional(),
|
|
})
|
|
.transform((workspace) => ({
|
|
...workspace,
|
|
workspaceDirectory: workspace.workspaceDirectory ?? workspace.projectRootPath,
|
|
}));
|
|
|
|
export const AgentUpdateMessageSchema = z.object({
|
|
type: z.literal("agent_update"),
|
|
payload: z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("upsert"),
|
|
agent: AgentSnapshotPayloadSchema,
|
|
project: ProjectPlacementPayloadSchema.nullable().optional(),
|
|
generation: z.string().optional(),
|
|
seq: z.number().int().positive().optional(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("remove"),
|
|
agentId: z.string(),
|
|
generation: z.string().optional(),
|
|
seq: z.number().int().positive().optional(),
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const AgentStreamMessageSchema = z.object({
|
|
type: z.literal("agent_stream"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
event: AgentStreamEventPayloadSchema,
|
|
timestamp: z.string(),
|
|
// Present for timeline events. Maps 1:1 to canonical in-memory timeline rows.
|
|
seq: z.number().int().nonnegative().optional(),
|
|
epoch: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
export const AgentStatusMessageSchema = z.object({
|
|
type: z.literal("agent_status"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
status: z.string(),
|
|
info: AgentSnapshotPayloadSchema,
|
|
}),
|
|
});
|
|
|
|
export const AgentListMessageSchema = z.object({
|
|
type: z.literal("agent_list"),
|
|
payload: z.object({
|
|
agents: z.array(AgentSnapshotPayloadSchema),
|
|
}),
|
|
});
|
|
|
|
export const AgentSearchMatchFieldSchema = z.enum(["workspace", "title", "branch", "project"]);
|
|
|
|
export const AgentSearchMatchSchema = z.object({
|
|
field: AgentSearchMatchFieldSchema,
|
|
ranges: z.array(
|
|
z.object({
|
|
start: z.number().int().nonnegative(),
|
|
length: z.number().int().positive(),
|
|
}),
|
|
),
|
|
});
|
|
|
|
export type AgentSearchMatch = z.infer<typeof AgentSearchMatchSchema>;
|
|
|
|
const AgentDirectoryResponseEntrySchema = z.object({
|
|
agent: AgentSnapshotPayloadSchema,
|
|
project: ProjectPlacementPayloadSchema,
|
|
// Relevance of this entry to the request's `search`, lower being better.
|
|
// Set only when the request carried a query; a client merging results from
|
|
// several hosts needs it to interleave their separately ranked pages.
|
|
searchScore: z.number().optional(),
|
|
// Where the query matched, so the row can mark it. The ranker computes this
|
|
// anyway; sending it keeps the client from re-deriving a second opinion that
|
|
// could disagree with the ranking it is explaining.
|
|
searchMatches: z.array(AgentSearchMatchSchema).optional(),
|
|
// COMPAT(directorySync): sequence of this latest directory projection.
|
|
syncSeq: z.number().int().positive().optional(),
|
|
});
|
|
|
|
const AgentDirectoryPageInfoSchema = z.object({
|
|
nextCursor: z.string().nullable(),
|
|
prevCursor: z.string().nullable(),
|
|
hasMore: z.boolean(),
|
|
});
|
|
|
|
export const FetchAgentsResponseMessageSchema = z.object({
|
|
type: z.literal("fetch_agents_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
subscriptionId: z.string().nullable().optional(),
|
|
entries: z.array(AgentDirectoryResponseEntrySchema),
|
|
pageInfo: AgentDirectoryPageInfoSchema,
|
|
sync: DirectorySyncMetadataSchema.optional(),
|
|
}),
|
|
});
|
|
|
|
export const FetchAgentHistoryResponseMessageSchema = z.object({
|
|
type: z.literal("fetch_agent_history_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
entries: z.array(AgentDirectoryResponseEntrySchema),
|
|
pageInfo: AgentDirectoryPageInfoSchema,
|
|
// More sessions matched the request's `search` than the page could hold.
|
|
// Distinct from `pageInfo.hasMore`, which promises a fetchable next page —
|
|
// a ranked result set has none, and the way on is a narrower query.
|
|
searchTruncated: z.boolean().optional(),
|
|
}),
|
|
});
|
|
|
|
export const FetchRecentProviderSessionsResponseMessageSchema = z.object({
|
|
type: z.literal("fetch_recent_provider_sessions_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
entries: z.array(RecentProviderSessionDescriptorPayloadSchema),
|
|
filteredAlreadyImportedCount: z.number().int().nonnegative().optional(),
|
|
}),
|
|
});
|
|
|
|
// COMPAT(workspaceProjects): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
|
|
// A project parent that has zero active workspaces. The sidebar renders the
|
|
// project row with a new-workspace child so projects persist after their last
|
|
// workspace is archived.
|
|
export const WorkspaceProjectDescriptorPayloadSchema = z.object({
|
|
projectId: z.string(),
|
|
// COMPAT(projectKey): added in v0.2.4 on 2026-07-28; remove optional after 2027-01-28.
|
|
projectKey: z.string().optional(),
|
|
projectDisplayName: z.string(),
|
|
projectCustomName: z.string().nullable().optional(),
|
|
// COMPAT(projectCustomIcon): added in v0.2.0, remove after 2027-01-20.
|
|
projectCustomIconRevision: z.string().nullable().optional(),
|
|
// Fingerprints the effective icon, including automatic discovery and the
|
|
// absence of an icon. Clients may persist icon results against this value.
|
|
// COMPAT(projectIconCache): added in v0.2.7, remove optional after 2027-02-12.
|
|
projectIconRevision: z.string().optional(),
|
|
projectRootPath: z.string(),
|
|
projectKind: z.enum(["git", "non_git", "directory"]),
|
|
// COMPAT(directorySync): sequence of this latest directory projection.
|
|
syncSeq: z.number().int().positive().optional(),
|
|
});
|
|
|
|
export const FetchWorkspacesResponseMessageSchema = z.object({
|
|
type: z.literal("fetch_workspaces_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
subscriptionId: z.string().nullable().optional(),
|
|
entries: z.array(WorkspaceDescriptorPayloadSchema),
|
|
// COMPAT(workspaceProjects): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
|
|
// Project parents with no active workspaces. Old daemons omit it; old clients
|
|
// ignore it. Only populated on the first page (no cursor).
|
|
emptyProjects: z.array(WorkspaceProjectDescriptorPayloadSchema).optional().default([]),
|
|
pageInfo: z.object({
|
|
nextCursor: z.string().nullable(),
|
|
prevCursor: z.string().nullable(),
|
|
hasMore: z.boolean(),
|
|
}),
|
|
sync: DirectorySyncMetadataSchema.optional(),
|
|
}),
|
|
});
|
|
|
|
export const WorkspaceUpdateMessageSchema = z.object({
|
|
type: z.literal("workspace_update"),
|
|
payload: z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("upsert"),
|
|
workspace: WorkspaceDescriptorPayloadSchema,
|
|
generation: z.string().optional(),
|
|
seq: z.number().int().positive().optional(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("remove"),
|
|
id: z.string(),
|
|
// COMPAT(workspaceProjects): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
|
|
// When archiving this workspace leaves its project with no active
|
|
// workspaces, the daemon includes the project parent so the sidebar keeps
|
|
// rendering it without waiting for a full re-hydration. Old daemons omit
|
|
// it; old clients ignore it and surface the project on their next
|
|
// workspace fetch instead.
|
|
emptyProject: WorkspaceProjectDescriptorPayloadSchema.optional(),
|
|
// Project removal is represented on the existing workspace update channel
|
|
// so old clients can still parse the message and ignore the extra field.
|
|
removedProjectId: z.string().optional(),
|
|
generation: z.string().optional(),
|
|
seq: z.number().int().positive().optional(),
|
|
}),
|
|
]),
|
|
});
|
|
|
|
const WorkspaceLabelSyncMetadataSchema = z.object({
|
|
mode: z.enum(["snapshot", "changes"]),
|
|
generation: z.string(),
|
|
headSeq: z.number().int().nonnegative(),
|
|
removals: z.array(z.object({ name: z.string(), seq: z.number().int().positive() })),
|
|
});
|
|
export const WorkspaceLabelListResponseSchema = z.object({
|
|
type: z.literal("workspace.label.list.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
labels: z.array(WorkspaceLabelDefinitionSchema),
|
|
sync: WorkspaceLabelSyncMetadataSchema,
|
|
}),
|
|
});
|
|
export const WorkspaceLabelUpdateSchema = z.object({
|
|
type: z.literal("workspace.label.update"),
|
|
payload: z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("upsert"),
|
|
label: WorkspaceLabelDefinitionSchema,
|
|
previousName: z.string().optional(),
|
|
generation: z.string(),
|
|
seq: z.number().int().positive(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("remove"),
|
|
name: z.string(),
|
|
generation: z.string(),
|
|
seq: z.number().int().positive(),
|
|
}),
|
|
]),
|
|
});
|
|
export const WorkspaceLabelAssignmentSetResponseSchema = z.object({
|
|
type: z.literal("workspace.label.assignment.set.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
label: WorkspaceLabelDefinitionSchema,
|
|
workspaceLabels: z.array(z.string()),
|
|
}),
|
|
});
|
|
export const WorkspaceLabelUpdateResponseSchema = z.object({
|
|
type: z.literal("workspace.label.update.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
label: WorkspaceLabelDefinitionSchema,
|
|
affectedWorkspaceCount: z.number().int().nonnegative(),
|
|
}),
|
|
});
|
|
export const WorkspaceLabelDeleteResponseSchema = z.object({
|
|
type: z.literal("workspace.label.delete.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
affectedWorkspaceCount: z.number().int().nonnegative(),
|
|
}),
|
|
});
|
|
export const WorkspaceLabelDeleteInspectResponseSchema = z.object({
|
|
type: z.literal("workspace.label.delete.inspect.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
affectedWorkspaceCount: z.number().int().nonnegative(),
|
|
}),
|
|
});
|
|
|
|
export const ProjectUpdateMessageSchema = z.object({
|
|
type: z.literal("project.update"),
|
|
payload: z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("upsert"),
|
|
project: WorkspaceProjectDescriptorPayloadSchema,
|
|
generation: z.string().optional(),
|
|
seq: z.number().int().positive().optional(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("remove"),
|
|
projectId: z.string(),
|
|
generation: z.string().optional(),
|
|
seq: z.number().int().positive().optional(),
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const ProjectListResponseMessageSchema = z.object({
|
|
type: z.literal("project.list.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
projects: z.array(WorkspaceProjectDescriptorPayloadSchema),
|
|
sync: DirectorySyncMetadataSchema.optional(),
|
|
}),
|
|
});
|
|
|
|
export const ScriptStatusUpdateMessageSchema = z.object({
|
|
type: z.literal("script_status_update"),
|
|
payload: z.object({
|
|
workspaceId: z.string(),
|
|
scripts: z.array(WorkspaceScriptPayloadSchema),
|
|
}),
|
|
});
|
|
|
|
export const WorkspaceSetupProgressMessageSchema = z.object({
|
|
type: z.literal("workspace_setup_progress"),
|
|
payload: z.object({
|
|
workspaceId: z.string(),
|
|
status: z.enum(["running", "completed", "failed"]),
|
|
detail: WorktreeSetupDetailPayloadSchema,
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const WorkspaceSetupSnapshotSchema = z.object({
|
|
status: z.enum(["running", "completed", "failed"]),
|
|
detail: WorktreeSetupDetailPayloadSchema,
|
|
error: z.string().nullable(),
|
|
});
|
|
|
|
export const WorkspaceSetupStatusResponseMessageSchema = z.object({
|
|
type: z.literal("workspace_setup_status_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
snapshot: WorkspaceSetupSnapshotSchema.nullable(),
|
|
}),
|
|
});
|
|
|
|
export const OpenProjectResponseMessageSchema = z.object({
|
|
type: z.literal("open_project_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
workspace: WorkspaceDescriptorPayloadSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
// Unknown codes from newer daemons degrade to null; clients fall back to `error`.
|
|
errorCode: z.enum(["directory_not_found"]).nullish().catch(null),
|
|
}),
|
|
});
|
|
|
|
export const ProjectAddResponseSchema = z.object({
|
|
type: z.literal("project.add.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
errorCode: z.enum(["directory_not_found"]).nullish().catch(null),
|
|
}),
|
|
});
|
|
|
|
export const ProjectCreateDirectoryErrorCodeSchema = z.enum([
|
|
"invalid_name",
|
|
"parent_directory_not_found",
|
|
"directory_exists",
|
|
"permission_denied",
|
|
"registration_failed",
|
|
"filesystem_error",
|
|
]);
|
|
|
|
export const ProjectCreateDirectoryResponseSchema = z.object({
|
|
type: z.literal("project.create_directory.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
directoryPath: z.string().nullable(),
|
|
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
// Error codes are open-ended on the wire so older clients can still parse
|
|
// responses after a newer daemon learns another failure reason.
|
|
errorCode: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const WorkspaceGithubSearchRepositoriesResponseSchema = z.object({
|
|
type: z.literal("workspace.github.search_repositories.response"),
|
|
payload: z.discriminatedUnion("status", [
|
|
z.object({
|
|
status: z.literal("success"),
|
|
requestId: z.string(),
|
|
repositories: z.array(GithubRepositorySchema),
|
|
available: z.literal(true),
|
|
error: z.null(),
|
|
}),
|
|
z.object({
|
|
status: z.literal("unavailable"),
|
|
requestId: z.string(),
|
|
repositories: z.array(GithubRepositorySchema),
|
|
reason: z.literal("gh_missing"),
|
|
available: z.literal(false),
|
|
error: z.string(),
|
|
}),
|
|
z.object({
|
|
status: z.literal("unauthenticated"),
|
|
requestId: z.string(),
|
|
repositories: z.array(GithubRepositorySchema),
|
|
available: z.literal(false),
|
|
error: z.string(),
|
|
}),
|
|
z.object({
|
|
status: z.literal("error"),
|
|
requestId: z.string(),
|
|
repositories: z.array(GithubRepositorySchema),
|
|
available: z.literal(true),
|
|
error: z.string(),
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const ProjectGithubCloneResponseSchema = z.object({
|
|
type: z.literal("project.github.clone.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
repo: z.string().trim().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
checkoutPath: z.string().nullable(),
|
|
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const StartWorkspaceScriptResponseMessageSchema = z.object({
|
|
type: z.literal("start_workspace_script_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
scriptName: z.string(),
|
|
terminalId: z.string().nullable(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
const WorkspaceScriptOperationPayloadSchema = z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
scriptName: z.string().optional(),
|
|
script: WorkspaceScriptPayloadSchema.nullable().optional(),
|
|
scripts: z.array(WorkspaceScriptPayloadSchema).optional(),
|
|
error: z.string().nullable(),
|
|
});
|
|
|
|
export const WorkspaceScriptListResponseMessageSchema = z.object({
|
|
type: z.literal("workspace.script.list.response"),
|
|
payload: WorkspaceScriptOperationPayloadSchema,
|
|
});
|
|
|
|
export const WorkspaceScriptStartResponseMessageSchema = z.object({
|
|
type: z.literal("workspace.script.start.response"),
|
|
payload: WorkspaceScriptOperationPayloadSchema,
|
|
});
|
|
|
|
export const WorkspaceScriptStopResponseMessageSchema = z.object({
|
|
type: z.literal("workspace.script.stop.response"),
|
|
payload: WorkspaceScriptOperationPayloadSchema,
|
|
});
|
|
|
|
// COMPAT(desktopEditorBridge): added in v0.1.88, remove after 2026-12-03 once old clients no longer parse daemon editor RPC responses.
|
|
export const LegacyListAvailableEditorsResponseMessageSchema = z.object({
|
|
type: z.literal("list_available_editors_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
editors: z.array(
|
|
z.object({
|
|
id: z.string().trim().min(1),
|
|
label: z.string(),
|
|
}),
|
|
),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const LegacyOpenInEditorResponseMessageSchema = z.object({
|
|
type: z.literal("open_in_editor_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const ArchiveWorkspaceResponseMessageSchema = z.object({
|
|
type: z.literal("archive_workspace_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.string(),
|
|
archivedAt: z.string().nullable(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const FetchAgentResponseMessageSchema = z.object({
|
|
type: z.literal("fetch_agent_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agent: AgentSnapshotPayloadSchema.nullable(),
|
|
project: ProjectPlacementPayloadSchema.nullable().optional(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
const AgentTimelineSeqRangeSchema = z.object({
|
|
startSeq: z.number().int().nonnegative(),
|
|
endSeq: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export const AgentTimelineEntryPayloadSchema = z.object({
|
|
provider: AgentProviderSchema,
|
|
item: AgentTimelineItemPayloadSchema,
|
|
turnId: z.string().optional(),
|
|
timestamp: z.string(),
|
|
seqStart: z.number().int().nonnegative(),
|
|
seqEnd: z.number().int().nonnegative(),
|
|
sourceSeqRanges: z.array(AgentTimelineSeqRangeSchema),
|
|
collapsed: z.array(z.enum(["assistant_merge", "reasoning_merge", "tool_lifecycle"])),
|
|
});
|
|
|
|
export const FetchAgentTimelineResponseMessageSchema = z.object({
|
|
type: z.literal("fetch_agent_timeline_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string(),
|
|
agent: AgentSnapshotPayloadSchema.nullable(),
|
|
direction: z.enum(["tail", "before", "after"]),
|
|
projection: z.enum(["projected", "canonical"]),
|
|
epoch: z.string(),
|
|
reset: z.boolean(),
|
|
staleCursor: z.boolean(),
|
|
gap: z.boolean(),
|
|
window: z.object({
|
|
minSeq: z.number().int().nonnegative(),
|
|
maxSeq: z.number().int().nonnegative(),
|
|
nextSeq: z.number().int().nonnegative(),
|
|
}),
|
|
startCursor: AgentTimelineCursorSchema.nullable(),
|
|
endCursor: AgentTimelineCursorSchema.nullable(),
|
|
hasOlder: z.boolean(),
|
|
hasNewer: z.boolean(),
|
|
mergeWindow: z.boolean().optional(),
|
|
entries: z.array(AgentTimelineEntryPayloadSchema),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const AgentTimelineListPromptsResponseMessageSchema = z.object({
|
|
type: z.literal("agent.timeline.list_prompts.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string(),
|
|
epoch: z.string(),
|
|
prompts: z.array(
|
|
z.object({
|
|
seq: z.number().int().nonnegative(),
|
|
timestamp: z.string(),
|
|
preview: z.string(),
|
|
}),
|
|
),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const ProviderSubagentDescriptorPayloadSchema = z.object({
|
|
id: z.string(),
|
|
parentAgentId: z.string(),
|
|
provider: AgentProviderSchema,
|
|
title: z.string().nullable(),
|
|
description: z.string().nullable(),
|
|
status: z.enum(["running", "completed", "failed", "canceled"]),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string(),
|
|
toolCallId: z.string().nullable(),
|
|
cwd: z.string().nullable().optional(),
|
|
// Compact provider-owned context for the shared track. Providers choose what belongs here and
|
|
// format it for display; clients must not parse provider-specific facts out of this string.
|
|
subtitle: z.string().nullable().optional(),
|
|
});
|
|
|
|
export type ProviderSubagentDescriptorPayload = z.infer<
|
|
typeof ProviderSubagentDescriptorPayloadSchema
|
|
>;
|
|
|
|
export const ProviderSubagentListResponseMessageSchema = z.object({
|
|
type: z.literal("agent.provider_subagents.list.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
parentAgentId: z.string(),
|
|
subagents: z.array(ProviderSubagentDescriptorPayloadSchema),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const ProviderSubagentTimelineResponseMessageSchema = z.object({
|
|
type: z.literal("agent.provider_subagents.timeline.get.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
parentAgentId: z.string(),
|
|
subagentId: z.string(),
|
|
provider: AgentProviderSchema.nullable(),
|
|
direction: z.enum(["tail", "before", "after"]),
|
|
epoch: z.string(),
|
|
reset: z.boolean(),
|
|
staleCursor: z.boolean(),
|
|
gap: z.boolean(),
|
|
window: z.object({
|
|
minSeq: z.number().int().nonnegative(),
|
|
maxSeq: z.number().int().nonnegative(),
|
|
nextSeq: z.number().int().nonnegative(),
|
|
}),
|
|
hasOlder: z.boolean(),
|
|
hasNewer: z.boolean(),
|
|
rows: z.array(
|
|
z.object({
|
|
item: AgentTimelineItemPayloadSchema,
|
|
timestamp: z.string(),
|
|
seq: z.number().int().nonnegative(),
|
|
}),
|
|
),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const ProviderSubagentUpdateMessageSchema = z.object({
|
|
type: z.literal("agent.provider_subagents.update"),
|
|
payload: z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("upsert"),
|
|
subagent: ProviderSubagentDescriptorPayloadSchema,
|
|
}),
|
|
z.object({
|
|
kind: z.literal("timeline"),
|
|
parentAgentId: z.string(),
|
|
subagentId: z.string(),
|
|
provider: AgentProviderSchema,
|
|
item: AgentTimelineItemPayloadSchema,
|
|
timestamp: z.string(),
|
|
seq: z.number().int().nonnegative(),
|
|
epoch: z.string(),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("remove"),
|
|
parentAgentId: z.string(),
|
|
subagentId: z.string(),
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const SetAgentTimelineSubscriptionResponseMessageSchema = z.object({
|
|
type: z.literal("agent.timeline.set_subscription.response"),
|
|
payload: z.object({
|
|
agentIds: z.array(z.string()),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const AgentAttentionRequiredMessageSchema = z.object({
|
|
type: z.literal("agent_attention_required"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
reason: z.enum(["finished", "error", "permission"]),
|
|
timestamp: z.string(),
|
|
shouldNotify: z.boolean(),
|
|
notification: z
|
|
.object({
|
|
title: z.string(),
|
|
body: z.string(),
|
|
data: z.object({
|
|
serverId: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
agentId: z.string(),
|
|
reason: z.enum(["finished", "error", "permission"]),
|
|
}),
|
|
})
|
|
.optional(),
|
|
}),
|
|
});
|
|
|
|
export const AgentForkContextResponseMessageSchema = z.object({
|
|
type: z.literal("agent.fork_context.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string(),
|
|
attachment: TextAttachmentSchema.nullable(),
|
|
itemCount: z.number().int().nonnegative(),
|
|
boundaryMessageId: z.string().nullable(),
|
|
boundaryCursor: AgentTimelineCursorSchema.nullable().optional(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const CancelAgentResponseMessageSchema = z.object({
|
|
type: z.literal("cancel_agent_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string(),
|
|
agent: AgentSnapshotPayloadSchema.nullable(),
|
|
error: z.string().nullable().optional(),
|
|
}),
|
|
});
|
|
|
|
export const ClearAgentAttentionResponseMessageSchema = z.object({
|
|
type: z.literal("clear_agent_attention_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string().or(z.array(z.string())),
|
|
agents: z.array(AgentSnapshotPayloadSchema),
|
|
}),
|
|
});
|
|
|
|
export const WorkspaceCreateResponseSchema = z.object({
|
|
type: z.literal("workspace.create.response"),
|
|
payload: z.object({
|
|
workspace: WorkspaceDescriptorPayloadSchema.nullable(),
|
|
setupTerminalId: z.string().nullable(),
|
|
error: z.string().nullable(),
|
|
errorCode: z.string().optional(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const WorkspaceClearAttentionResponseSchema = z.object({
|
|
type: z.literal("workspace.clear_attention.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
workspaceId: z.union([z.string(), z.array(z.string())]),
|
|
clearedAgentIds: z.array(z.string()),
|
|
results: z.array(
|
|
z.object({
|
|
workspaceId: z.string(),
|
|
clearedAgentIds: z.array(z.string()),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const SendAgentMessageResponseMessageSchema = z.object({
|
|
type: z.literal("send_agent_message_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
agentId: z.string(),
|
|
accepted: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const WaitForFinishResponseMessageSchema = z.object({
|
|
type: z.literal("wait_for_finish_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
status: z.enum(["idle", "error", "permission", "timeout"]),
|
|
final: AgentSnapshotPayloadSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
lastMessage: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const GetDaemonConfigResponseMessageSchema = z.object({
|
|
type: z.literal("get_daemon_config_response"),
|
|
payload: z
|
|
.object({
|
|
requestId: z.string(),
|
|
config: MutableDaemonConfigSchema,
|
|
})
|
|
.passthrough(),
|
|
});
|
|
|
|
export const DaemonGetStatusResponseSchema = z.object({
|
|
type: z.literal("daemon.get_status.response"),
|
|
payload: z
|
|
.object({
|
|
requestId: z.string(),
|
|
serverId: z.string(),
|
|
version: z.string().nullable().optional(),
|
|
pid: z.number(),
|
|
nodePath: z.string(),
|
|
startedAt: z.string().nullable().optional(),
|
|
listen: z.string().nullable(),
|
|
relay: z
|
|
.object({
|
|
enabled: z.boolean(),
|
|
endpoint: z.string(),
|
|
publicEndpoint: z.string(),
|
|
useTls: z.boolean(),
|
|
publicUseTls: z.boolean(),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
providers: z.array(
|
|
z.object({
|
|
provider: z.string(),
|
|
available: z.boolean(),
|
|
error: z.string().nullable().optional(),
|
|
}),
|
|
),
|
|
})
|
|
.passthrough(),
|
|
});
|
|
|
|
export const HubRelationshipStatusSchema = z.object({
|
|
state: z.enum([
|
|
"not_connected",
|
|
"connecting",
|
|
"connected",
|
|
"reconnecting",
|
|
"disconnecting",
|
|
"revoked",
|
|
]),
|
|
daemonId: z.string().nullable(),
|
|
hubOrigin: z.string().nullable(),
|
|
scopes: z.array(z.string()),
|
|
connectedAt: z.string().nullable(),
|
|
lastError: z.string().nullable(),
|
|
});
|
|
export const HubManagementDaemonConnectResponseSchema = z.object({
|
|
type: z.literal("hub.management.daemon.connect.response"),
|
|
payload: z.object({ requestId: z.string(), status: HubRelationshipStatusSchema }),
|
|
});
|
|
export const HubManagementDaemonGetStatusResponseSchema = z.object({
|
|
type: z.literal("hub.management.daemon.get_status.response"),
|
|
payload: z.object({ requestId: z.string(), status: HubRelationshipStatusSchema }),
|
|
});
|
|
export const HubManagementDaemonDisconnectResponseSchema = z.object({
|
|
type: z.literal("hub.management.daemon.disconnect.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
status: HubRelationshipStatusSchema,
|
|
warning: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
export const DaemonGetPairingOfferResponseSchema = z.object({
|
|
type: z.literal("daemon.get_pairing_offer.response"),
|
|
payload: z
|
|
.object({
|
|
requestId: z.string(),
|
|
url: z.string(),
|
|
qr: z.string().nullable().optional(),
|
|
relayEnabled: z.boolean(),
|
|
})
|
|
.passthrough(),
|
|
});
|
|
|
|
export const DaemonConfigReloadResponseSchema = z.object({
|
|
type: z.literal("daemon.config.reload.response"),
|
|
payload: z
|
|
.object({
|
|
requestId: z.string(),
|
|
appliedPaths: z.array(z.string()),
|
|
restartRequiredPaths: z.array(z.string()),
|
|
overrideControlledPaths: z.array(z.string()),
|
|
})
|
|
.passthrough(),
|
|
});
|
|
|
|
export const DiagnosticsResponseSchema = z.object({
|
|
type: z.literal("diagnostics.response"),
|
|
payload: z
|
|
.object({
|
|
requestId: z.string(),
|
|
diagnostic: z.string(),
|
|
})
|
|
.passthrough(),
|
|
});
|
|
|
|
export const SetDaemonConfigResponseMessageSchema = z.object({
|
|
type: z.literal("set_daemon_config_response"),
|
|
payload: z
|
|
.object({
|
|
requestId: z.string(),
|
|
config: MutableDaemonConfigSchema,
|
|
})
|
|
.passthrough(),
|
|
});
|
|
|
|
export const ReadProjectConfigResponseMessageSchema = z.object({
|
|
type: z.literal("read_project_config_response"),
|
|
// zod-aot 0.2.0 miscompiles boolean discriminators as string options
|
|
// (`"true"`/`"false"`), so keep this sequential until upstream fixes it.
|
|
payload: z.union([
|
|
z.object({
|
|
requestId: z.string(),
|
|
repoRoot: z.string(),
|
|
ok: z.literal(true),
|
|
config: PaseoConfigRawSchema.nullable(),
|
|
revision: PaseoConfigRevisionSchema.nullable(),
|
|
hasUncommittedWorktreeSetupChanges: z.boolean().optional(),
|
|
}),
|
|
z.object({
|
|
requestId: z.string(),
|
|
repoRoot: z.string(),
|
|
ok: z.literal(false),
|
|
error: ProjectConfigRpcErrorSchema,
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const WriteProjectConfigResponseMessageSchema = z.object({
|
|
type: z.literal("write_project_config_response"),
|
|
// zod-aot 0.2.0 miscompiles boolean discriminators as string options
|
|
// (`"true"`/`"false"`), so keep this sequential until upstream fixes it.
|
|
payload: z.union([
|
|
z.object({
|
|
requestId: z.string(),
|
|
repoRoot: z.string(),
|
|
ok: z.literal(true),
|
|
config: PaseoConfigRawSchema,
|
|
revision: PaseoConfigRevisionSchema,
|
|
hasUncommittedWorktreeSetupChanges: z.boolean().optional(),
|
|
}),
|
|
z.object({
|
|
requestId: z.string(),
|
|
repoRoot: z.string(),
|
|
ok: z.literal(false),
|
|
error: ProjectConfigRpcErrorSchema,
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const AgentPermissionRequestMessageSchema = z.object({
|
|
type: z.literal("agent_permission_request"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
request: AgentPermissionRequestPayloadSchema,
|
|
}),
|
|
});
|
|
|
|
export const AgentPermissionResolvedMessageSchema = z.object({
|
|
type: z.literal("agent_permission_resolved"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
resolution: AgentPermissionResponseSchema,
|
|
}),
|
|
});
|
|
|
|
export const AgentDeletedMessageSchema = z.object({
|
|
type: z.literal("agent_deleted"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const AgentArchivedMessageSchema = z.object({
|
|
type: z.literal("agent_archived"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
archivedAt: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
const CloseItemsAgentResultSchema = z.object({
|
|
agentId: z.string(),
|
|
archivedAt: z.string(),
|
|
});
|
|
|
|
const CloseItemsTerminalResultSchema = z.object({
|
|
terminalId: z.string(),
|
|
success: z.boolean(),
|
|
});
|
|
|
|
export const CloseItemsResponseSchema = z.object({
|
|
type: z.literal("close_items_response"),
|
|
payload: z.object({
|
|
agents: z.array(CloseItemsAgentResultSchema),
|
|
terminals: z.array(CloseItemsTerminalResultSchema),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
const AheadBehindSchema = z.object({
|
|
ahead: z.number(),
|
|
behind: z.number(),
|
|
});
|
|
|
|
const CheckoutStatusCommonSchema = z.object({
|
|
cwd: z.string(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
// The full ref currentBranch tracks, as git resolves `<branch>@{upstream}`:
|
|
// "refs/remotes/origin/main", "refs/remotes/upstream/main" on a fork, or a
|
|
// "refs/heads/..." ref for a branch tracking a local branch. Null when there is no
|
|
// upstream. Clients use it verbatim — the remote is not necessarily origin and the
|
|
// upstream branch name is not necessarily currentBranch, so composing one is wrong.
|
|
// aheadOfOrigin/behindOfOrigin are measured against exactly this ref.
|
|
upstreamRef: z.string().nullable().optional(),
|
|
});
|
|
|
|
const CheckoutStatusNotGitSchema = CheckoutStatusCommonSchema.extend({
|
|
isGit: z.literal(false),
|
|
isPaseoOwnedWorktree: z.literal(false),
|
|
repoRoot: z.null(),
|
|
currentBranch: z.null(),
|
|
isDirty: z.null(),
|
|
baseRef: z.null(),
|
|
aheadBehind: z.null(),
|
|
aheadOfOrigin: z.null(),
|
|
behindOfOrigin: z.null(),
|
|
hasRemote: z.boolean(),
|
|
remoteUrl: z.null(),
|
|
});
|
|
|
|
const CheckoutStatusGitNonPaseoSchema = CheckoutStatusCommonSchema.extend({
|
|
isGit: z.literal(true),
|
|
isPaseoOwnedWorktree: z.literal(false),
|
|
repoRoot: z.string(),
|
|
mainRepoRoot: z.string().nullable().optional().default(null),
|
|
currentBranch: z.string().nullable(),
|
|
isDirty: z.boolean(),
|
|
baseRef: z.string().nullable(),
|
|
aheadBehind: AheadBehindSchema.nullable(),
|
|
aheadOfOrigin: z.number().nullable(),
|
|
behindOfOrigin: z.number().nullable(),
|
|
hasRemote: z.boolean(),
|
|
remoteUrl: z.string().nullable(),
|
|
});
|
|
|
|
const CheckoutStatusGitPaseoSchema = CheckoutStatusCommonSchema.extend({
|
|
isGit: z.literal(true),
|
|
isPaseoOwnedWorktree: z.literal(true),
|
|
repoRoot: z.string(),
|
|
mainRepoRoot: z.string(),
|
|
currentBranch: z.string().nullable(),
|
|
isDirty: z.boolean(),
|
|
baseRef: z.string(),
|
|
aheadBehind: AheadBehindSchema.nullable(),
|
|
aheadOfOrigin: z.number().nullable(),
|
|
behindOfOrigin: z.number().nullable(),
|
|
hasRemote: z.boolean(),
|
|
remoteUrl: z.string().nullable(),
|
|
});
|
|
|
|
export const CheckoutStatusResponseSchema = z.object({
|
|
type: z.literal("checkout_status_response"),
|
|
payload: z.union([
|
|
CheckoutStatusNotGitSchema,
|
|
CheckoutStatusGitNonPaseoSchema,
|
|
CheckoutStatusGitPaseoSchema,
|
|
]),
|
|
});
|
|
|
|
const CheckoutPrGithubAutoMergeRequestSchema = z
|
|
.object({
|
|
enabledAt: z.string().nullable().optional().default(null),
|
|
mergeMethod: z.string().nullable().optional().default(null),
|
|
enabledBy: z.string().nullable().optional().default(null),
|
|
})
|
|
.nullable()
|
|
.optional()
|
|
.default(null);
|
|
|
|
const CheckoutPrGithubRepositoryPolicySchema = z
|
|
.object({
|
|
autoMergeAllowed: z.boolean().optional().default(false),
|
|
mergeCommitAllowed: z.boolean().optional().default(false),
|
|
squashMergeAllowed: z.boolean().optional().default(false),
|
|
rebaseMergeAllowed: z.boolean().optional().default(false),
|
|
viewerDefaultMergeMethod: z.string().nullable().optional().default(null),
|
|
})
|
|
.optional()
|
|
.default({
|
|
autoMergeAllowed: false,
|
|
mergeCommitAllowed: false,
|
|
squashMergeAllowed: false,
|
|
rebaseMergeAllowed: false,
|
|
viewerDefaultMergeMethod: null,
|
|
});
|
|
|
|
const CheckoutPrGithubStatusObjectSchema = z.object({
|
|
mergeStateStatus: z.string().nullable().optional().default(null),
|
|
autoMergeRequest: CheckoutPrGithubAutoMergeRequestSchema,
|
|
viewerCanEnableAutoMerge: z.boolean().optional().default(false),
|
|
viewerCanDisableAutoMerge: z.boolean().optional().default(false),
|
|
viewerCanMergeAsAdmin: z.boolean().optional().default(false),
|
|
viewerCanUpdateBranch: z.boolean().optional().default(false),
|
|
repository: CheckoutPrGithubRepositoryPolicySchema,
|
|
isMergeQueueEnabled: z.boolean().optional().default(false),
|
|
isInMergeQueue: z.boolean().optional().default(false),
|
|
});
|
|
|
|
const CheckoutPrGithubStatusSchema = CheckoutPrGithubStatusObjectSchema.optional();
|
|
|
|
// The open facts envelope for forge-specific PR facts. Permanent — non-GitHub
|
|
// forges deliver their native facts through it. The transitional piece is the
|
|
// `github` mirror above, which stays populated for clients predating this
|
|
// envelope; see COMPAT(forgeSpecific) in status-projection.ts for the shim.
|
|
//
|
|
// NOTE: `forgeSpecific.forge` is a FACTS-FAMILY tag, not the workspace brand id.
|
|
// The whole Gitea family (gitea, forgejo, codeberg) emits `forge: "gitea"` here
|
|
// because they share one facts shape, while the top-level `forge` above carries
|
|
// the specific brand. Validation of family-specific payloads happens at runtime
|
|
// in the consumer that knows that forge family.
|
|
const CheckoutPrForgeSpecificSchema = z.unknown().optional();
|
|
|
|
export const CheckoutPrStatusSchema = z.object({
|
|
// COMPAT(forge): added in v0.1.106, remove the default after 2026-12-27 once daemon floor >= v0.1.106.
|
|
forge: z.string().optional().default("github"),
|
|
projectPath: z.string().optional(),
|
|
number: z.number().optional(),
|
|
url: z.string(),
|
|
title: z.string(),
|
|
state: z.string(),
|
|
baseRefName: z.string(),
|
|
headRefName: z.string(),
|
|
isMerged: z.boolean(),
|
|
isDraft: z.boolean().optional().default(false),
|
|
mergeable: z
|
|
.enum(["MERGEABLE", "CONFLICTING", "UNKNOWN"])
|
|
.catch("UNKNOWN")
|
|
.optional()
|
|
.default("UNKNOWN"),
|
|
checks: z
|
|
.array(
|
|
z.object({
|
|
name: z.string(),
|
|
status: z.string(),
|
|
url: z.string().nullable(),
|
|
workflow: z.string().optional(),
|
|
/**
|
|
* Formatted by the forge adapter: how long a finished check took, or how long a
|
|
* running one has been going. Raw timestamps stay off the wire.
|
|
*/
|
|
duration: z.string().optional(),
|
|
checkRunId: z.number().optional(),
|
|
workflowRunId: z.number().optional(),
|
|
}),
|
|
)
|
|
.optional()
|
|
.default([]),
|
|
checksStatus: z.string().optional(),
|
|
reviewDecision: z.string().nullable().optional(),
|
|
repoOwner: z.string().optional(),
|
|
repoName: z.string().optional(),
|
|
github: CheckoutPrGithubStatusSchema,
|
|
forgeSpecific: CheckoutPrForgeSpecificSchema,
|
|
});
|
|
|
|
// Why a forge's PR/MR features are (un)available, so the client can offer the
|
|
// precise next step instead of a generic dead-end. Kept open on the wire so
|
|
// feature consumers can ignore values introduced by newer daemons.
|
|
export type ForgeAuthState =
|
|
| "authenticated"
|
|
| "unauthenticated"
|
|
| "cli_missing"
|
|
| "no_remote"
|
|
| "error";
|
|
|
|
export const ForgeAuthStateSchema = z.unknown().optional();
|
|
|
|
const CheckoutPrStatusPayloadSchema = z.object({
|
|
cwd: z.string(),
|
|
status: CheckoutPrStatusSchema.nullable(),
|
|
githubFeaturesEnabled: z.boolean(),
|
|
// COMPAT(forgeAuthState): added in v0.1.106, remove after 2026-12-27. Optional richer
|
|
// signal that supersedes githubFeaturesEnabled. The legacy boolean stays for old clients
|
|
// and may remain true for non-auth error payloads so old clients still show the error.
|
|
// Drop the boolean once the daemon floor >= v0.1.106.
|
|
authState: ForgeAuthStateSchema,
|
|
// COMPAT(forge): added in v0.1.106, remove the default after 2026-12-27 once daemon floor >= v0.1.106.
|
|
forge: z.string().optional().default("github"),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
const CheckoutStatusUpdateMetadataSchema = z.object({
|
|
prStatus: CheckoutPrStatusPayloadSchema.optional(),
|
|
});
|
|
|
|
export const CheckoutStatusUpdateSchema = z.object({
|
|
type: z.literal("checkout_status_update"),
|
|
payload: z
|
|
.union([
|
|
CheckoutStatusNotGitSchema,
|
|
CheckoutStatusGitNonPaseoSchema,
|
|
CheckoutStatusGitPaseoSchema,
|
|
])
|
|
.and(CheckoutStatusUpdateMetadataSchema),
|
|
});
|
|
|
|
const CheckoutDiffSubscriptionPayloadSchema = z.object({
|
|
subscriptionId: z.string(),
|
|
cwd: z.string(),
|
|
files: z.array(ParsedDiffFileSchema),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
// COMPAT(diffTooLarge): added in v0.2.4, keep optional until the daemon floor is v0.2.4.
|
|
diffTooLarge: z.boolean().optional(),
|
|
});
|
|
|
|
export const SubscribeCheckoutDiffResponseSchema = z.object({
|
|
type: z.literal("subscribe_checkout_diff_response"),
|
|
payload: CheckoutDiffSubscriptionPayloadSchema.extend({
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutDiffUpdateSchema = z.object({
|
|
type: z.literal("checkout_diff_update"),
|
|
payload: CheckoutDiffSubscriptionPayloadSchema,
|
|
});
|
|
|
|
export const CheckoutCommitResponseSchema = z.object({
|
|
type: z.literal("checkout_commit_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutMergeResponseSchema = z.object({
|
|
type: z.literal("checkout_merge_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutMergeFromBaseResponseSchema = z.object({
|
|
type: z.literal("checkout_merge_from_base_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutPullResponseSchema = z.object({
|
|
type: z.literal("checkout_pull_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutPushResponseSchema = z.object({
|
|
type: z.literal("checkout_push_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutRefreshResponseSchema = z.object({
|
|
type: z.literal("checkout.refresh.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutPrCreateResponseSchema = z.object({
|
|
type: z.literal("checkout_pr_create_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
url: z.string().nullable(),
|
|
number: z.number().nullable(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutPrMergeResponseSchema = z.object({
|
|
type: z.literal("checkout_pr_merge_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutForgeSetAutoMergeResponseSchema = z.object({
|
|
type: z.literal("checkout.forge.set_auto_merge.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
enabled: z.boolean(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
// COMPAT(githubAutoMergeRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
// all supported clients use checkout.forge.set_auto_merge.*.
|
|
export const CheckoutGithubSetAutoMergeResponseSchema = z.object({
|
|
type: z.literal("checkout.github.set_auto_merge.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
enabled: z.boolean(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutDiscardChangesResponseSchema = z.object({
|
|
type: z.literal("checkout.discard_changes.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutCommitsListResponseSchema = z.object({
|
|
type: z.literal("checkout.commits.list.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
baseRef: z.string().nullable(),
|
|
commits: z.array(CheckoutCommitSchema),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutCommitFileDiffResponseSchema = z.object({
|
|
type: z.literal("checkout.commits.file_diff.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
sha: z.string(),
|
|
path: z.string(),
|
|
// null when the file is absent from the commit or carries no textual diff
|
|
// (e.g. binary-only changes).
|
|
file: ParsedDiffFileSchema.nullable(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
const CheckoutGithubCheckAnnotationSchema = z.object({
|
|
path: z.string().optional(),
|
|
startLine: z.number().optional(),
|
|
endLine: z.number().optional(),
|
|
annotationLevel: z.string().optional(),
|
|
message: z.string().optional(),
|
|
title: z.string().optional(),
|
|
rawDetails: z.string().optional(),
|
|
});
|
|
|
|
const CheckoutGithubCheckJobSchema = z.object({
|
|
jobId: z.number(),
|
|
name: z.string(),
|
|
status: z.string().nullable().optional(),
|
|
conclusion: z.string().nullable().optional(),
|
|
url: z.string().nullable().optional(),
|
|
logTail: z.string().optional(),
|
|
logTruncated: z.boolean().optional(),
|
|
});
|
|
|
|
// Statuses stay open strings so future forge values cannot break parsing.
|
|
const CheckoutPipelineJobSchema = z.object({
|
|
id: z.number(),
|
|
name: z.string(),
|
|
stage: z.string(),
|
|
status: z.string(),
|
|
rawStatus: z.string(),
|
|
url: z.string().nullable().optional().default(null),
|
|
allowFailure: z.boolean().optional().default(false),
|
|
durationSeconds: z.number().nullable().optional().default(null),
|
|
});
|
|
|
|
const CheckoutPipelineStageSchema = z.object({
|
|
name: z.string(),
|
|
status: z.string(),
|
|
jobs: z.array(CheckoutPipelineJobSchema).optional().default([]),
|
|
});
|
|
|
|
const CheckoutPipelineSchema = z.object({
|
|
id: z.number(),
|
|
status: z.string(),
|
|
rawStatus: z.string(),
|
|
url: z.string().nullable().optional().default(null),
|
|
ref: z.string().nullable().optional().default(null),
|
|
sha: z.string().nullable().optional().default(null),
|
|
stages: z.array(CheckoutPipelineStageSchema).optional().default([]),
|
|
});
|
|
|
|
export const CheckoutGithubCheckDetailsSchema = z.object({
|
|
checkRunId: z.number(),
|
|
workflowRunId: z.number().nullable().optional(),
|
|
name: z.string(),
|
|
status: z.string().nullable().optional(),
|
|
conclusion: z.string().nullable().optional(),
|
|
url: z.string().nullable().optional(),
|
|
detailsUrl: z.string().nullable().optional(),
|
|
output: z
|
|
.object({
|
|
title: z.string().nullable().optional(),
|
|
summary: z.string().nullable().optional(),
|
|
text: z.string().nullable().optional(),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
annotations: z.array(CheckoutGithubCheckAnnotationSchema).optional().default([]),
|
|
failedJobs: z.array(CheckoutGithubCheckJobSchema).optional().default([]),
|
|
truncated: z.boolean().optional().default(false),
|
|
// No default: server CheckDetails keeps this optional and GitHub leaves it absent.
|
|
pipeline: CheckoutPipelineSchema.nullable().optional(),
|
|
});
|
|
|
|
export const CheckoutCheckDetailsSchema = CheckoutGithubCheckDetailsSchema;
|
|
|
|
export const CheckoutForgeGetCheckDetailsResponseSchema = z.object({
|
|
type: z.literal("checkout.forge.get_check_details.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
details: CheckoutCheckDetailsSchema.nullable().optional().default(null),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
// COMPAT(githubCheckDetailsRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
// all supported clients use checkout.forge.get_check_details.*.
|
|
export const CheckoutGithubGetCheckDetailsResponseSchema = z.object({
|
|
type: z.literal("checkout.github.get_check_details.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
details: CheckoutCheckDetailsSchema.nullable().optional().default(null),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutPrStatusResponseSchema = z.object({
|
|
type: z.literal("checkout_pr_status_response"),
|
|
payload: CheckoutPrStatusPayloadSchema,
|
|
});
|
|
|
|
const PullRequestTimelineKnownErrorSchema = z.discriminatedUnion("kind", [
|
|
z.object({
|
|
kind: z.literal("not_found"),
|
|
message: z.string().optional().default(""),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("forbidden"),
|
|
message: z.string().optional().default(""),
|
|
}),
|
|
z.object({
|
|
kind: z.literal("unknown"),
|
|
message: z.string().optional().default(""),
|
|
}),
|
|
]);
|
|
|
|
const PullRequestTimelineErrorSchema = z.preprocess((value) => {
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
return { kind: "unknown", message: "" };
|
|
}
|
|
const error = value as Record<string, unknown>;
|
|
if (error.kind === "not_found" || error.kind === "forbidden" || error.kind === "unknown") {
|
|
return error;
|
|
}
|
|
return { ...error, kind: "unknown" };
|
|
}, PullRequestTimelineKnownErrorSchema);
|
|
|
|
const PullRequestTimelineReviewItemSchema = z.object({
|
|
id: z.string().optional().default(""),
|
|
kind: z.literal("review"),
|
|
author: z.string().optional().default("unknown"),
|
|
authorUrl: z.string().nullable().optional(),
|
|
avatarUrl: z.string().nullable().optional(),
|
|
body: z.string().optional().default(""),
|
|
createdAt: z.number().optional().default(0),
|
|
url: z.string().optional().default(""),
|
|
reviewState: z
|
|
.enum(["approved", "changes_requested", "commented"])
|
|
.optional()
|
|
.default("commented"),
|
|
});
|
|
|
|
const PullRequestTimelineCommentItemSchema = z.object({
|
|
id: z.string().optional().default(""),
|
|
kind: z.literal("comment"),
|
|
author: z.string().optional().default("unknown"),
|
|
authorUrl: z.string().nullable().optional(),
|
|
avatarUrl: z.string().nullable().optional(),
|
|
body: z.string().optional().default(""),
|
|
createdAt: z.number().optional().default(0),
|
|
url: z.string().optional().default(""),
|
|
// GitHub review id this inline comment belongs to; lets clients nest review
|
|
// threads under their parent review. Absent on issue comments and on
|
|
// timelines from daemons that predate the field.
|
|
reviewId: z.string().optional(),
|
|
// Forge-neutral discussion/thread id this comment belongs to, independent of a
|
|
// file position. GitLab maps its discussion id here so general (non-file)
|
|
// reply chains group into one thread; file-position threads also carry it.
|
|
// Absent on standalone comments and on timelines from daemons that predate it.
|
|
threadId: z.string().optional(),
|
|
// Forge-neutral resolution state for a thread that has no file position, e.g. a
|
|
// GitLab general (non-file) discussion that is resolvable. File-position threads
|
|
// carry their resolution under `location.isResolved` instead. Absent on ordinary
|
|
// comments, on forges that expose no thread resolution, and on older timelines.
|
|
threadIsResolved: z.boolean().optional(),
|
|
location: z
|
|
.object({
|
|
path: z.string(),
|
|
line: z.number().optional(),
|
|
startLine: z.number().optional(),
|
|
threadId: z.string().optional(),
|
|
isResolved: z.boolean().optional(),
|
|
isOutdated: z.boolean().optional(),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
export const PullRequestTimelineItemSchema = z.preprocess(
|
|
(value) => {
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
return value;
|
|
}
|
|
const item = value as Record<string, unknown>;
|
|
if (item.kind === "review" || item.kind === "comment") {
|
|
return item;
|
|
}
|
|
return { ...item, kind: "comment" };
|
|
},
|
|
z.discriminatedUnion("kind", [
|
|
PullRequestTimelineReviewItemSchema,
|
|
PullRequestTimelineCommentItemSchema,
|
|
]),
|
|
);
|
|
|
|
export const PullRequestTimelineResponseSchema = z.object({
|
|
type: z.literal("pull_request_timeline_response"),
|
|
payload: z
|
|
.object({
|
|
cwd: z.string().optional().default(""),
|
|
prNumber: z.number().nullable().optional().default(null),
|
|
items: z.array(PullRequestTimelineItemSchema).optional().default([]),
|
|
truncated: z.boolean().optional().default(false),
|
|
error: PullRequestTimelineErrorSchema.nullable().optional().default(null),
|
|
requestId: z.string().optional().default(""),
|
|
githubFeaturesEnabled: z.boolean().optional().default(true),
|
|
// COMPAT(forgeAuthState): added in v0.1.106, remove after 2026-12-27. Optional richer
|
|
// signal that supersedes githubFeaturesEnabled, mirroring CheckoutPrStatusPayloadSchema.
|
|
// Drop the boolean once the daemon floor >= v0.1.106.
|
|
authState: ForgeAuthStateSchema,
|
|
})
|
|
.optional()
|
|
.prefault({}),
|
|
});
|
|
|
|
export const CheckoutSwitchBranchResponseSchema = z.object({
|
|
type: z.literal("checkout_switch_branch_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
branch: z.string(),
|
|
source: z.enum(["local", "remote"]).optional(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CheckoutRenameBranchResponseSchema = z.object({
|
|
type: z.literal("checkout.rename_branch.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
success: z.boolean(),
|
|
cwd: z.string(),
|
|
currentBranch: z.string().nullable(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
}),
|
|
});
|
|
|
|
const StashEntrySchema = z.object({
|
|
index: z.number().int().min(0),
|
|
message: z.string(),
|
|
branch: z.string().nullable(),
|
|
isPaseo: z.boolean(),
|
|
});
|
|
|
|
export const StashSaveResponseSchema = z.object({
|
|
type: z.literal("stash_save_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const StashPopResponseSchema = z.object({
|
|
type: z.literal("stash_pop_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
success: z.boolean(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const StashListResponseSchema = z.object({
|
|
type: z.literal("stash_list_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
entries: z.array(StashEntrySchema),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const ValidateBranchResponseSchema = z.object({
|
|
type: z.literal("validate_branch_response"),
|
|
payload: z.object({
|
|
exists: z.boolean(),
|
|
resolvedRef: z.string().nullable(),
|
|
isRemote: z.boolean(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const BranchSuggestionsResponseSchema = z.object({
|
|
type: z.literal("branch_suggestions_response"),
|
|
payload: z.object({
|
|
branches: z.array(z.string()),
|
|
branchDetails: z
|
|
.array(
|
|
z.object({
|
|
name: z.string(),
|
|
committerDate: z.number(),
|
|
hasLocal: z.boolean().optional(),
|
|
hasRemote: z.boolean().optional(),
|
|
localAhead: z.number().int().nonnegative().optional(),
|
|
localBehind: z.number().int().nonnegative().optional(),
|
|
}),
|
|
)
|
|
.optional(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
const ForgeSearchResponsePayloadSchema = z.object({
|
|
items: z.array(z.unknown()),
|
|
authState: z.unknown().optional(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
const GitHubSearchResponsePayloadSchema = z.object({
|
|
items: z.array(z.unknown()),
|
|
featuresEnabled: z.boolean().optional(),
|
|
authState: z.unknown().optional(),
|
|
githubFeaturesEnabled: z.boolean().optional(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
});
|
|
|
|
export const ForgeSearchResponseSchema = z.object({
|
|
type: z.literal("forge.search.response"),
|
|
payload: ForgeSearchResponsePayloadSchema,
|
|
});
|
|
|
|
// COMPAT(githubSearchRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
// clients use forge.search.*.
|
|
export const GitHubSearchResponseSchema = z.object({
|
|
type: z.literal("github_search_response"),
|
|
payload: GitHubSearchResponsePayloadSchema,
|
|
});
|
|
|
|
export const DirectorySuggestionsResponseSchema = z.object({
|
|
type: z.literal("directory_suggestions_response"),
|
|
payload: z.object({
|
|
directories: z.array(z.string()),
|
|
entries: z
|
|
.array(
|
|
z.object({
|
|
path: z.string(),
|
|
kind: z.enum(["file", "directory"]),
|
|
}),
|
|
)
|
|
.optional()
|
|
.default([]),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
const PaseoWorktreeSchema = z.object({
|
|
worktreePath: z.string(),
|
|
createdAt: z.string(),
|
|
branchName: z.string().nullable().optional(),
|
|
head: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const PaseoWorktreeListResponseSchema = z.object({
|
|
type: z.literal("paseo_worktree_list_response"),
|
|
payload: z.object({
|
|
worktrees: z.array(PaseoWorktreeSchema),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const PaseoWorktreeArchiveResponseSchema = z.object({
|
|
type: z.literal("paseo_worktree_archive_response"),
|
|
payload: z.object({
|
|
success: z.boolean(),
|
|
removedAgents: z.array(z.string()).optional(),
|
|
error: CheckoutErrorSchema.nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CreatePaseoWorktreeResponseSchema = z.object({
|
|
type: z.literal("create_paseo_worktree_response"),
|
|
payload: z.object({
|
|
workspace: WorkspaceDescriptorPayloadSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
errorCode: z.string().optional(),
|
|
setupTerminalId: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileExplorerResponseSchema = z.object({
|
|
type: z.literal("file_explorer_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
mode: z.enum(["list", "file"]),
|
|
directory: FileExplorerDirectorySchema.nullable(),
|
|
file: FileExplorerFileSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileSubscribeResponseSchema = z.object({
|
|
type: z.literal("fs.file.subscribe.response"),
|
|
payload: z.object({
|
|
subscriptionId: z.string(),
|
|
initial: FileVersionSchema,
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileUnsubscribeResponseSchema = z.object({
|
|
type: z.literal("fs.file.unsubscribe.response"),
|
|
payload: z.object({
|
|
subscriptionId: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileWriteResultSchema = z.discriminatedUnion("status", [
|
|
z.object({
|
|
status: z.literal("written"),
|
|
modifiedAt: z.string(),
|
|
size: z.number(),
|
|
revision: z.string().optional(),
|
|
}),
|
|
z.object({ status: z.literal("conflict"), version: FileVersionSchema }),
|
|
z.object({ status: z.literal("error"), error: z.string() }),
|
|
]);
|
|
|
|
export const FileWriteResponseSchema = z.object({
|
|
type: z.literal("fs.file.write.response"),
|
|
payload: z.object({
|
|
result: FileWriteResultSchema,
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileEntryCreateResponseSchema = z.object({
|
|
type: z.literal("fs.entry.create.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
parentPath: z.string(),
|
|
path: z.string().nullable(),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileEntryRenameResponseSchema = z.object({
|
|
type: z.literal("fs.entry.rename.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
renamedPath: z.string().nullable(),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileEntryDuplicateResponseSchema = z.object({
|
|
type: z.literal("fs.entry.duplicate.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
duplicatedPath: z.string().nullable(),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileEntryDeleteResponseSchema = z.object({
|
|
type: z.literal("fs.entry.delete.response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileUpdateSchema = z.object({
|
|
type: z.literal("fs.file.update"),
|
|
payload: z.object({
|
|
subscriptionId: z.string(),
|
|
version: FileVersionSchema,
|
|
}),
|
|
});
|
|
|
|
const ProjectIconSchema = z.object({
|
|
data: z.string(),
|
|
mimeType: z.string(),
|
|
});
|
|
|
|
export const ProjectIconResponseSchema = z.object({
|
|
type: z.literal("project_icon_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
icon: ProjectIconSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const ProjectIconGetResponseSchema = z.object({
|
|
type: z.literal("project.icon.get.response"),
|
|
payload: z.object({
|
|
projectId: z.string(),
|
|
icon: ProjectIconSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileDownloadTokenResponseSchema = z.object({
|
|
type: z.literal("file_download_token_response"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
path: z.string(),
|
|
token: z.string().nullable(),
|
|
fileName: z.string().nullable(),
|
|
mimeType: z.string().nullable(),
|
|
size: z.number().nullable(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const FileUploadResponseSchema = z.object({
|
|
type: z.literal("file.upload.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
file: UploadedFileAttachmentSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const ListProviderModelsResponseMessageSchema = z.object({
|
|
type: z.literal("list_provider_models_response"),
|
|
payload: z.object({
|
|
provider: AgentProviderSchema,
|
|
models: z.array(AgentModelDefinitionSchema).optional(),
|
|
error: z.string().nullable().optional(),
|
|
fetchedAt: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const ListProviderModesResponseMessageSchema = z.object({
|
|
type: z.literal("list_provider_modes_response"),
|
|
payload: z.object({
|
|
provider: AgentProviderSchema,
|
|
modes: z.array(AgentModeSchema).optional(),
|
|
error: z.string().nullable().optional(),
|
|
fetchedAt: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const ListProviderFeaturesResponseMessageSchema = z.object({
|
|
type: z.literal("list_provider_features_response"),
|
|
payload: z.object({
|
|
provider: AgentProviderSchema,
|
|
features: z.array(AgentFeatureSchema).optional(),
|
|
error: z.string().nullable().optional(),
|
|
fetchedAt: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
const ProviderAvailabilitySchema = z.object({
|
|
provider: AgentProviderSchema,
|
|
available: z.boolean(),
|
|
error: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const ListAvailableProvidersResponseSchema = z.object({
|
|
type: z.literal("list_available_providers_response"),
|
|
payload: z.object({
|
|
providers: z.array(ProviderAvailabilitySchema),
|
|
error: z.string().nullable().optional(),
|
|
fetchedAt: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
|
export const GetProvidersSnapshotResponseMessageSchema = z.object({
|
|
type: z.literal("get_providers_snapshot_response"),
|
|
payload: z.object({
|
|
cwd: z.string().optional(),
|
|
entries: z.array(ProviderSnapshotEntrySchema),
|
|
compactSnapshot: CompactProviderSnapshotSchema.optional(),
|
|
snapshotHash: z.string().optional(),
|
|
notModified: z.boolean().optional(),
|
|
generatedAt: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
|
export const ProvidersSnapshotUpdateMessageSchema = z.object({
|
|
type: z.literal("providers_snapshot_update"),
|
|
payload: z.object({
|
|
cwd: z.string().optional(),
|
|
entries: z.array(ProviderSnapshotEntrySchema),
|
|
compactSnapshot: CompactProviderSnapshotSchema.optional(),
|
|
snapshotHash: z.string().optional(),
|
|
generatedAt: z.string(),
|
|
}),
|
|
});
|
|
|
|
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
|
export const RefreshProvidersSnapshotResponseMessageSchema = z.object({
|
|
type: z.literal("refresh_providers_snapshot_response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
acknowledged: z.boolean(),
|
|
}),
|
|
});
|
|
|
|
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
|
export const ProviderDiagnosticResponseMessageSchema = z.object({
|
|
type: z.literal("provider_diagnostic_response"),
|
|
payload: z.object({
|
|
provider: AgentProviderSchema,
|
|
diagnostic: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const ProviderUsageToneSchema = z.enum(["default", "ok", "warning", "danger"]);
|
|
export const ProviderUsageStatusSchema = z.enum(["available", "unavailable", "error"]);
|
|
|
|
export const ProviderUsageWindowSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
usedPct: z.number().nullable().optional(),
|
|
remainingPct: z.number().nullable().optional(),
|
|
resetsAt: z.string().nullable().optional(),
|
|
runsOutAt: z.string().nullable().optional(),
|
|
shortfallPct: z.number().nullable().optional(),
|
|
tone: ProviderUsageToneSchema.optional(),
|
|
});
|
|
|
|
export const ProviderUsageBalanceSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
used: z.number().nullable().optional(),
|
|
remaining: z.number().nullable().optional(),
|
|
limit: z.number().nullable().optional(),
|
|
unit: z.enum(["usd", "credits", "requests", "tokens"]),
|
|
resetsAt: z.string().nullable().optional(),
|
|
tone: ProviderUsageToneSchema.optional(),
|
|
});
|
|
|
|
export const ProviderUsageDetailSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
value: z.string(),
|
|
tone: ProviderUsageToneSchema.optional(),
|
|
});
|
|
|
|
export const ProviderUsageSchema = z.object({
|
|
providerId: z.string(),
|
|
displayName: z.string(),
|
|
status: ProviderUsageStatusSchema,
|
|
planLabel: z.string().nullable(),
|
|
sourceLabel: z.string().nullable().optional(),
|
|
fetchedAt: z.string().nullable().optional(),
|
|
nextRefreshAt: z.string().nullable().optional(),
|
|
windows: z.array(ProviderUsageWindowSchema),
|
|
balances: z.array(ProviderUsageBalanceSchema).optional(),
|
|
details: z.array(ProviderUsageDetailSchema).optional(),
|
|
error: z.string().nullable().optional(),
|
|
});
|
|
|
|
export const ProviderUsageListResponseMessageSchema = z.object({
|
|
type: z.literal("provider.usage.list.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
fetchedAt: z.string(),
|
|
providers: z.array(ProviderUsageSchema),
|
|
}),
|
|
});
|
|
|
|
const AgentSlashCommandSchema = z.object({
|
|
name: z.string(),
|
|
description: z.string(),
|
|
argumentHint: z.string(),
|
|
kind: z.enum(["command", "skill"]).optional().catch("command"),
|
|
});
|
|
|
|
export const ListCommandsResponseSchema = z.object({
|
|
type: z.literal("list_commands_response"),
|
|
payload: z.object({
|
|
agentId: z.string(),
|
|
commands: z.array(AgentSlashCommandSchema),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
// ============================================================================
|
|
// Terminal Outbound Messages
|
|
// ============================================================================
|
|
|
|
const TerminalInfoSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
cwd: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
title: z.string().optional(),
|
|
activity: TerminalActivitySchema.nullable().optional(),
|
|
});
|
|
|
|
export const TerminalCellSchema = z.object({
|
|
char: z.string(),
|
|
fg: z.number().optional(),
|
|
bg: z.number().optional(),
|
|
fgMode: z.number().optional(),
|
|
bgMode: z.number().optional(),
|
|
bold: z.boolean().optional(),
|
|
italic: z.boolean().optional(),
|
|
underline: z.boolean().optional(),
|
|
dim: z.boolean().optional(),
|
|
inverse: z.boolean().optional(),
|
|
strikethrough: z.boolean().optional(),
|
|
});
|
|
|
|
export const TerminalCursorStyleSchema = z.enum(["block", "underline", "bar"]);
|
|
|
|
export const TerminalCursorSchema = z.object({
|
|
row: z.number(),
|
|
col: z.number(),
|
|
hidden: z.boolean().optional(),
|
|
style: TerminalCursorStyleSchema.optional(),
|
|
blink: z.boolean().optional(),
|
|
});
|
|
|
|
export const TerminalStateSchema = z.object({
|
|
rows: z.number(),
|
|
cols: z.number(),
|
|
grid: z.array(z.array(TerminalCellSchema)),
|
|
scrollback: z.array(z.array(TerminalCellSchema)),
|
|
cursor: TerminalCursorSchema,
|
|
title: z.string().optional(),
|
|
// Per-row soft-wrap flags aligned 1:1 with `grid` / `scrollback`. `true` means
|
|
// the row continued onto the next row (xterm's GRID_LINE_WRAPPED equivalent),
|
|
// so the client can re-wrap the logical line on resize instead of freezing it
|
|
// at the snapshot width. Optional: only sent to clients that advertise the
|
|
// `terminalReflowableSnapshot` capability, so old daemons/clients are unaffected.
|
|
gridWrapped: z.array(z.boolean()).optional(),
|
|
scrollbackWrapped: z.array(z.boolean()).optional(),
|
|
});
|
|
|
|
export const ListTerminalsResponseSchema = z.object({
|
|
type: z.literal("list_terminals_response"),
|
|
payload: z.object({
|
|
cwd: z.string().optional(),
|
|
terminals: z.array(TerminalInfoSchema.omit({ cwd: true })),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const TerminalsChangedSchema = z.object({
|
|
type: z.literal("terminals_changed"),
|
|
payload: z.object({
|
|
cwd: z.string(),
|
|
terminals: z.array(TerminalInfoSchema.omit({ cwd: true })),
|
|
}),
|
|
});
|
|
|
|
export const CreateTerminalResponseSchema = z.object({
|
|
type: z.literal("create_terminal_response"),
|
|
payload: z.object({
|
|
terminal: TerminalInfoSchema.nullable(),
|
|
error: z.string().nullable(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const RenameTerminalResponseSchema = z.object({
|
|
type: z.literal("terminal.rename.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const SubscribeTerminalResponseSchema = z.object({
|
|
type: z.literal("subscribe_terminal_response"),
|
|
payload: z.union([
|
|
z.object({
|
|
terminalId: z.string(),
|
|
slot: z.number().int().min(0).max(255),
|
|
error: z.null(),
|
|
requestId: z.string(),
|
|
}),
|
|
z.object({
|
|
terminalId: z.string(),
|
|
error: z.string(),
|
|
requestId: z.string(),
|
|
}),
|
|
]),
|
|
});
|
|
|
|
export const KillTerminalResponseSchema = z.object({
|
|
type: z.literal("kill_terminal_response"),
|
|
payload: z.object({
|
|
terminalId: z.string(),
|
|
success: z.boolean(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const CaptureTerminalResponseSchema = z.object({
|
|
type: z.literal("capture_terminal_response"),
|
|
payload: z.object({
|
|
terminalId: z.string(),
|
|
lines: z.array(z.string()),
|
|
totalLines: z.number().int().nonnegative(),
|
|
requestId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const TerminalStreamExitSchema = z.object({
|
|
type: z.literal("terminal_stream_exit"),
|
|
payload: z.object({
|
|
terminalId: z.string(),
|
|
}),
|
|
});
|
|
|
|
export const TerminalAttentionRequiredSchema = z.object({
|
|
type: z.literal("terminal_attention_required"),
|
|
payload: z.object({
|
|
serverId: z.string().optional(),
|
|
terminalId: z.string(),
|
|
cwd: z.string(),
|
|
workspaceId: z.string().optional(),
|
|
reason: z.enum(["finished", "needs_input"]),
|
|
title: z.string(),
|
|
body: z.string(),
|
|
shouldNotify: z.boolean(),
|
|
}),
|
|
});
|
|
|
|
export const DaemonUpdateResponseSchema = z.object({
|
|
type: z.literal("daemon.update.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
previousVersion: z.string().nullable(),
|
|
newVersion: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export type DaemonUpdateResponse = z.infer<typeof DaemonUpdateResponseSchema>;
|
|
|
|
export const DaemonUpdateProgressMessageSchema = z.object({
|
|
type: z.literal("daemon.update.progress"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
phase: z.enum(["starting", "downloading", "installing", "complete"]),
|
|
}),
|
|
});
|
|
|
|
export const HubExecutionAgentCreateResponseSchema = z.object({
|
|
type: z.literal("hub.execution.agent.create.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
executionId: z.string(),
|
|
agentId: z.string().nullable(),
|
|
agent: AgentSnapshotPayloadSchema.nullable(),
|
|
success: z.boolean(),
|
|
toolPolicyApplied: z.literal(true).optional(),
|
|
error: HubExecutionAgentCreateErrorSchema.nullable(),
|
|
}),
|
|
});
|
|
|
|
export const HubExecutionAgentValidationIssueSchema = z.object({
|
|
path: z.array(z.union([z.string(), z.number()])),
|
|
message: z.string(),
|
|
});
|
|
|
|
export type HubExecutionAgentValidationIssue = z.infer<
|
|
typeof HubExecutionAgentValidationIssueSchema
|
|
>;
|
|
|
|
export const HubExecutionAgentValidateResponseSchema = z.object({
|
|
type: z.literal("hub.execution.agent.validate.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
valid: z.boolean(),
|
|
issues: z.array(HubExecutionAgentValidationIssueSchema),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const HubExecutionControlResponseSchema = z.object({
|
|
type: z.literal("hub.execution.control.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
executionId: z.string(),
|
|
action: HubExecutionControlActionSchema,
|
|
success: z.boolean(),
|
|
error: z.string().nullable(),
|
|
}),
|
|
});
|
|
|
|
export const HubExecutionAgentUpdateSchema = z.object({
|
|
type: z.literal("hub.execution.agent.update"),
|
|
payload: z.object({
|
|
executionId: z.string(),
|
|
agentId: z.string(),
|
|
agent: AgentSnapshotPayloadSchema,
|
|
}),
|
|
});
|
|
|
|
export const HubExecutionAgentStreamSchema = z.object({
|
|
type: z.literal("hub.execution.agent.stream"),
|
|
payload: z.object({
|
|
executionId: z.string(),
|
|
agentId: z.string(),
|
|
event: AgentStreamEventPayloadSchema,
|
|
}),
|
|
});
|
|
|
|
export type HubExecutionAgentCreateResponse = z.infer<typeof HubExecutionAgentCreateResponseSchema>;
|
|
export type HubExecutionAgentValidateResponse = z.infer<
|
|
typeof HubExecutionAgentValidateResponseSchema
|
|
>;
|
|
export type HubExecutionControlResponse = z.infer<typeof HubExecutionControlResponseSchema>;
|
|
export type HubExecutionAgentUpdate = z.infer<typeof HubExecutionAgentUpdateSchema>;
|
|
export type HubExecutionAgentStream = z.infer<typeof HubExecutionAgentStreamSchema>;
|
|
|
|
export const HubExecutionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
HubExecutionAgentCreateResponseSchema,
|
|
HubExecutionAgentValidateResponseSchema,
|
|
HubExecutionControlResponseSchema,
|
|
HubExecutionAgentUpdateSchema,
|
|
HubExecutionAgentStreamSchema,
|
|
]);
|
|
|
|
export type HubExecutionOutboundMessage = z.infer<typeof HubExecutionOutboundMessageSchema>;
|
|
|
|
export class HubMessageCorrelationError extends Error {
|
|
constructor(messageType: HubExecutionOutboundMessage["type"]) {
|
|
super(`Hub message ${messageType} has mismatched agent correlation`);
|
|
this.name = "HubMessageCorrelationError";
|
|
}
|
|
}
|
|
|
|
export function parseHubExecutionOutboundMessage(value: unknown): HubExecutionOutboundMessage {
|
|
const message = HubExecutionOutboundMessageSchema.parse(value);
|
|
const payload = message.payload;
|
|
if (
|
|
"agent" in payload &&
|
|
payload.agent !== null &&
|
|
"agentId" in payload &&
|
|
payload.agentId !== null &&
|
|
payload.agent.id !== payload.agentId
|
|
) {
|
|
throw new HubMessageCorrelationError(message.type);
|
|
}
|
|
return message;
|
|
}
|
|
|
|
export type DaemonUpdateProgressMessage = z.infer<typeof DaemonUpdateProgressMessageSchema>;
|
|
|
|
export const PluginCatalogGetResponseSchema = z.object({
|
|
type: z.literal("plugin.catalog.get.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
plugins: z.array(
|
|
z.object({
|
|
id: PluginIdSchema,
|
|
clientBundle: z.string(),
|
|
}),
|
|
),
|
|
}),
|
|
});
|
|
|
|
export const PluginStatusSchema = z.enum(["running", "disabled", "failed"]);
|
|
export type PluginStatus = z.infer<typeof PluginStatusSchema>;
|
|
|
|
export const PluginListItemSchema = z.object({
|
|
id: PluginIdSchema,
|
|
path: z.string(),
|
|
enabled: z.boolean(),
|
|
status: PluginStatusSchema,
|
|
error: z.string().optional(),
|
|
});
|
|
export type PluginListItem = z.infer<typeof PluginListItemSchema>;
|
|
|
|
export const PluginLogEntrySchema = z.object({
|
|
sequence: z.number().int().nonnegative(),
|
|
timestamp: z.string().datetime(),
|
|
stream: z.enum(["stdout", "stderr"]),
|
|
message: z.string(),
|
|
});
|
|
export type PluginLogEntry = z.infer<typeof PluginLogEntrySchema>;
|
|
|
|
export const PluginListResponseSchema = z.object({
|
|
type: z.literal("plugin.list.response"),
|
|
payload: z.object({ requestId: z.string(), plugins: z.array(PluginListItemSchema) }),
|
|
});
|
|
|
|
export const PluginLogsGetResponseSchema = z.object({
|
|
type: z.literal("plugin.logs.get.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
pluginId: PluginIdSchema,
|
|
entries: z.array(PluginLogEntrySchema),
|
|
}),
|
|
});
|
|
|
|
export const PluginDirectoryInstallResponseSchema = z.object({
|
|
type: z.literal("plugin.directory.install.response"),
|
|
payload: z.object({ requestId: z.string(), plugin: PluginListItemSchema }),
|
|
});
|
|
|
|
export const PluginDirectoryInspectResponseSchema = z.object({
|
|
type: z.literal("plugin.directory.inspect.response"),
|
|
payload: z.object({ requestId: z.string(), id: PluginIdSchema }),
|
|
});
|
|
|
|
function pluginActionResponse<const Type extends string>(type: Type) {
|
|
return z.object({
|
|
type: z.literal(type),
|
|
payload: z.object({ requestId: z.string(), plugin: PluginListItemSchema }),
|
|
});
|
|
}
|
|
|
|
export const PluginReloadResponseSchema = pluginActionResponse("plugin.reload.response");
|
|
export const PluginEnableResponseSchema = pluginActionResponse("plugin.enable.response");
|
|
export const PluginDisableResponseSchema = pluginActionResponse("plugin.disable.response");
|
|
export const PluginRemoveResponseSchema = z.object({
|
|
type: z.literal("plugin.remove.response"),
|
|
payload: z.object({ requestId: z.string() }).strict(),
|
|
});
|
|
|
|
export const PluginRpcInvokeResponseSchema = z.object({
|
|
type: z.literal("plugin.rpc.invoke.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
output: z.unknown(),
|
|
}),
|
|
});
|
|
|
|
function agentSkillsStatusResponse<const Type extends string>(type: Type) {
|
|
return z.object({
|
|
type: z.literal(type),
|
|
payload: AgentSkillsStatusSchema.extend({ requestId: z.string() }),
|
|
});
|
|
}
|
|
|
|
export const AgentSkillsGetStatusResponseSchema = agentSkillsStatusResponse(
|
|
"agent.skills.get_status.response",
|
|
);
|
|
export const AgentSkillsReconcileResponseSchema = agentSkillsStatusResponse(
|
|
"agent.skills.reconcile.response",
|
|
);
|
|
export const AgentSkillsUninstallResponseSchema = agentSkillsStatusResponse(
|
|
"agent.skills.uninstall.response",
|
|
);
|
|
export const AgentSkillsSaveSelectionResponseSchema = z.object({
|
|
type: z.literal("agent.skills.save_selection.response"),
|
|
payload: AgentSkillsSaveResultSchema.extend({ requestId: z.string() }),
|
|
});
|
|
export const AgentSkillsImportLegacySelectionResponseSchema = z.object({
|
|
type: z.literal("agent.skills.import_legacy_selection.response"),
|
|
payload: z.object({
|
|
requestId: z.string(),
|
|
imported: z.boolean(),
|
|
selection: AgentSkillSelectionSchema,
|
|
}),
|
|
});
|
|
|
|
export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
HubExecutionAgentCreateResponseSchema,
|
|
HubExecutionAgentValidateResponseSchema,
|
|
HubExecutionControlResponseSchema,
|
|
HubExecutionAgentUpdateSchema,
|
|
HubExecutionAgentStreamSchema,
|
|
BrowserAutomationExecuteRequestSchema,
|
|
PluginCatalogGetResponseSchema,
|
|
PluginListResponseSchema,
|
|
PluginLogsGetResponseSchema,
|
|
PluginDirectoryInstallResponseSchema,
|
|
PluginDirectoryInspectResponseSchema,
|
|
PluginReloadResponseSchema,
|
|
PluginEnableResponseSchema,
|
|
PluginDisableResponseSchema,
|
|
PluginRemoveResponseSchema,
|
|
PluginRpcInvokeResponseSchema,
|
|
AgentSkillsGetStatusResponseSchema,
|
|
AgentSkillsReconcileResponseSchema,
|
|
AgentSkillsUninstallResponseSchema,
|
|
AgentSkillsSaveSelectionResponseSchema,
|
|
AgentSkillsImportLegacySelectionResponseSchema,
|
|
ActivityLogMessageSchema,
|
|
AssistantChunkMessageSchema,
|
|
AudioOutputMessageSchema,
|
|
TranscriptionResultMessageSchema,
|
|
VoiceInputStateMessageSchema,
|
|
DictationStreamAckMessageSchema,
|
|
DictationStreamFinishAcceptedMessageSchema,
|
|
DictationStreamPartialMessageSchema,
|
|
DictationStreamFinalMessageSchema,
|
|
DictationStreamErrorMessageSchema,
|
|
StatusMessageSchema,
|
|
PongMessageSchema,
|
|
PushUnregisterResponseSchema,
|
|
RpcErrorMessageSchema,
|
|
ArtifactMessageSchema,
|
|
AgentUpdateMessageSchema,
|
|
WorkspaceUpdateMessageSchema,
|
|
WorkspaceLabelListResponseSchema,
|
|
WorkspaceLabelUpdateSchema,
|
|
WorkspaceLabelAssignmentSetResponseSchema,
|
|
WorkspaceLabelUpdateResponseSchema,
|
|
WorkspaceLabelDeleteResponseSchema,
|
|
WorkspaceLabelDeleteInspectResponseSchema,
|
|
ProjectUpdateMessageSchema,
|
|
ProjectListResponseMessageSchema,
|
|
ScriptStatusUpdateMessageSchema,
|
|
WorkspaceSetupProgressMessageSchema,
|
|
WorkspaceSetupStatusResponseMessageSchema,
|
|
AgentStreamMessageSchema,
|
|
AgentStatusMessageSchema,
|
|
FetchAgentsResponseMessageSchema,
|
|
FetchAgentHistoryResponseMessageSchema,
|
|
FetchRecentProviderSessionsResponseMessageSchema,
|
|
FetchWorkspacesResponseMessageSchema,
|
|
ProjectAddResponseSchema,
|
|
ProjectCreateDirectoryResponseSchema,
|
|
OpenProjectResponseMessageSchema,
|
|
WorkspaceGithubSearchRepositoriesResponseSchema,
|
|
ProjectGithubCloneResponseSchema,
|
|
StartWorkspaceScriptResponseMessageSchema,
|
|
WorkspaceScriptListResponseMessageSchema,
|
|
WorkspaceScriptStartResponseMessageSchema,
|
|
WorkspaceScriptStopResponseMessageSchema,
|
|
LegacyListAvailableEditorsResponseMessageSchema,
|
|
LegacyOpenInEditorResponseMessageSchema,
|
|
ArchiveWorkspaceResponseMessageSchema,
|
|
FetchAgentResponseMessageSchema,
|
|
FetchAgentTimelineResponseMessageSchema,
|
|
AgentTimelineListPromptsResponseMessageSchema,
|
|
ProviderSubagentListResponseMessageSchema,
|
|
ProviderSubagentTimelineResponseMessageSchema,
|
|
ProviderSubagentUpdateMessageSchema,
|
|
SetAgentTimelineSubscriptionResponseMessageSchema,
|
|
AgentAttentionRequiredMessageSchema,
|
|
AgentForkContextResponseMessageSchema,
|
|
CancelAgentResponseMessageSchema,
|
|
ClearAgentAttentionResponseMessageSchema,
|
|
WorkspaceCreateResponseSchema,
|
|
WorkspaceClearAttentionResponseSchema,
|
|
SendAgentMessageResponseMessageSchema,
|
|
SetVoiceModeResponseMessageSchema,
|
|
DaemonGetStatusResponseSchema,
|
|
DaemonGetPairingOfferResponseSchema,
|
|
DaemonConfigReloadResponseSchema,
|
|
HubManagementDaemonConnectResponseSchema,
|
|
HubManagementDaemonGetStatusResponseSchema,
|
|
HubManagementDaemonDisconnectResponseSchema,
|
|
DiagnosticsResponseSchema,
|
|
GetDaemonConfigResponseMessageSchema,
|
|
SetDaemonConfigResponseMessageSchema,
|
|
ReadProjectConfigResponseMessageSchema,
|
|
WriteProjectConfigResponseMessageSchema,
|
|
SetAgentModeResponseMessageSchema,
|
|
SetAgentModelResponseMessageSchema,
|
|
SetAgentThinkingResponseMessageSchema,
|
|
SetAgentFeatureResponseMessageSchema,
|
|
AgentConfigApplyResponseMessageSchema,
|
|
AgentDetachResponseMessageSchema,
|
|
AgentRewindResponseMessageSchema,
|
|
UpdateAgentResponseMessageSchema,
|
|
ProjectRenameResponseSchema,
|
|
ProjectIconSetResponseSchema,
|
|
ProjectRemoveResponseSchema,
|
|
WorkspaceTitleSetResponseSchema,
|
|
WorkspacePinSetResponseSchema,
|
|
WorkspaceRecoveryInspectResponseSchema,
|
|
WorkspaceRecoveryRestoreResponseSchema,
|
|
WaitForFinishResponseMessageSchema,
|
|
AgentPermissionRequestMessageSchema,
|
|
AgentPermissionResolvedMessageSchema,
|
|
AgentDeletedMessageSchema,
|
|
AgentArchivedMessageSchema,
|
|
CloseItemsResponseSchema,
|
|
CheckoutStatusResponseSchema,
|
|
CheckoutStatusUpdateSchema,
|
|
SubscribeCheckoutDiffResponseSchema,
|
|
CheckoutDiffUpdateSchema,
|
|
CheckoutCommitResponseSchema,
|
|
CheckoutMergeResponseSchema,
|
|
CheckoutMergeFromBaseResponseSchema,
|
|
CheckoutPullResponseSchema,
|
|
CheckoutPushResponseSchema,
|
|
CheckoutRefreshResponseSchema,
|
|
CheckoutDiscardChangesResponseSchema,
|
|
CheckoutPrCreateResponseSchema,
|
|
CheckoutPrMergeResponseSchema,
|
|
CheckoutForgeSetAutoMergeResponseSchema,
|
|
CheckoutGithubSetAutoMergeResponseSchema,
|
|
CheckoutCommitsListResponseSchema,
|
|
CheckoutCommitFileDiffResponseSchema,
|
|
CheckoutForgeGetCheckDetailsResponseSchema,
|
|
CheckoutGithubGetCheckDetailsResponseSchema,
|
|
CheckoutPrStatusResponseSchema,
|
|
PullRequestTimelineResponseSchema,
|
|
CheckoutSwitchBranchResponseSchema,
|
|
CheckoutRenameBranchResponseSchema,
|
|
StashSaveResponseSchema,
|
|
StashPopResponseSchema,
|
|
StashListResponseSchema,
|
|
ValidateBranchResponseSchema,
|
|
BranchSuggestionsResponseSchema,
|
|
ForgeSearchResponseSchema,
|
|
GitHubSearchResponseSchema,
|
|
DirectorySuggestionsResponseSchema,
|
|
PaseoWorktreeListResponseSchema,
|
|
PaseoWorktreeArchiveResponseSchema,
|
|
CreatePaseoWorktreeResponseSchema,
|
|
FileExplorerResponseSchema,
|
|
FileSubscribeResponseSchema,
|
|
FileUnsubscribeResponseSchema,
|
|
FileWriteResponseSchema,
|
|
FileEntryCreateResponseSchema,
|
|
FileEntryRenameResponseSchema,
|
|
FileEntryDuplicateResponseSchema,
|
|
FileEntryDeleteResponseSchema,
|
|
FileUpdateSchema,
|
|
ProjectIconResponseSchema,
|
|
ProjectIconGetResponseSchema,
|
|
FileDownloadTokenResponseSchema,
|
|
FileUploadResponseSchema,
|
|
ListProviderModelsResponseMessageSchema,
|
|
ListProviderModesResponseMessageSchema,
|
|
ListProviderFeaturesResponseMessageSchema,
|
|
ListAvailableProvidersResponseSchema,
|
|
GetProvidersSnapshotResponseMessageSchema,
|
|
ProvidersSnapshotUpdateMessageSchema,
|
|
RefreshProvidersSnapshotResponseMessageSchema,
|
|
ProviderDiagnosticResponseMessageSchema,
|
|
ProviderUsageListResponseMessageSchema,
|
|
ListCommandsResponseSchema,
|
|
ListTerminalsResponseSchema,
|
|
TerminalsChangedSchema,
|
|
CreateTerminalResponseSchema,
|
|
RenameTerminalResponseSchema,
|
|
SubscribeTerminalResponseSchema,
|
|
KillTerminalResponseSchema,
|
|
CaptureTerminalResponseSchema,
|
|
TerminalStreamExitSchema,
|
|
TerminalAttentionRequiredSchema,
|
|
ChatCreateResponseSchema,
|
|
ChatListResponseSchema,
|
|
ChatInspectResponseSchema,
|
|
ChatDeleteResponseSchema,
|
|
ChatPostResponseSchema,
|
|
ChatReadResponseSchema,
|
|
ChatWaitResponseSchema,
|
|
ScheduleCreateResponseSchema,
|
|
ScheduleListResponseSchema,
|
|
ScheduleInspectResponseSchema,
|
|
ScheduleLogsResponseSchema,
|
|
SchedulePauseResponseSchema,
|
|
ScheduleResumeResponseSchema,
|
|
ScheduleDeleteResponseSchema,
|
|
ScheduleRunOnceResponseSchema,
|
|
ScheduleUpdateResponseSchema,
|
|
LoopRunResponseSchema,
|
|
LoopListResponseSchema,
|
|
LoopInspectResponseSchema,
|
|
LoopLogsResponseSchema,
|
|
LoopStopResponseSchema,
|
|
DaemonUpdateProgressMessageSchema,
|
|
DaemonUpdateResponseSchema,
|
|
]);
|
|
|
|
export type SessionOutboundMessage = z.infer<typeof SessionOutboundMessageSchema>;
|
|
|
|
// Type exports for individual message types
|
|
export type ActivityLogMessage = z.infer<typeof ActivityLogMessageSchema>;
|
|
export type AssistantChunkMessage = z.infer<typeof AssistantChunkMessageSchema>;
|
|
export type AudioOutputMessage = z.infer<typeof AudioOutputMessageSchema>;
|
|
export type TranscriptionResultMessage = z.infer<typeof TranscriptionResultMessageSchema>;
|
|
export type StatusMessage = z.infer<typeof StatusMessageSchema>;
|
|
export type ServerCapabilityState = z.infer<typeof ServerCapabilityStateSchema>;
|
|
export type ServerVoiceCapabilities = z.infer<typeof ServerVoiceCapabilitiesSchema>;
|
|
export type ServerCapabilities = z.infer<typeof ServerCapabilitiesSchema>;
|
|
export type ServerInfoStatusPayload = z.infer<typeof ServerInfoStatusPayloadSchema>;
|
|
export type RpcErrorMessage = z.infer<typeof RpcErrorMessageSchema>;
|
|
export type ArtifactMessage = z.infer<typeof ArtifactMessageSchema>;
|
|
export type AgentUpdateMessage = z.infer<typeof AgentUpdateMessageSchema>;
|
|
export type WorkspaceSetupProgressMessage = z.infer<typeof WorkspaceSetupProgressMessageSchema>;
|
|
export type WorkspaceSetupSnapshot = z.infer<typeof WorkspaceSetupSnapshotSchema>;
|
|
export type WorkspaceSetupStatusResponseMessage = z.infer<
|
|
typeof WorkspaceSetupStatusResponseMessageSchema
|
|
>;
|
|
export type AgentStreamMessage = z.infer<typeof AgentStreamMessageSchema>;
|
|
export type AgentStatusMessage = z.infer<typeof AgentStatusMessageSchema>;
|
|
export type ProjectCheckoutLitePayload = z.infer<typeof ProjectCheckoutLitePayloadSchema>;
|
|
export type ProjectPlacementPayload = z.infer<typeof ProjectPlacementPayloadSchema>;
|
|
export type WorkspaceStateBucket = z.infer<typeof WorkspaceStateBucketSchema>;
|
|
export type WorkspaceDescriptorPayload = z.infer<typeof WorkspaceDescriptorPayloadSchema>;
|
|
export type WorkspaceProjectDescriptorPayload = z.infer<
|
|
typeof WorkspaceProjectDescriptorPayloadSchema
|
|
>;
|
|
export type ProjectListResponseMessage = z.infer<typeof ProjectListResponseMessageSchema>;
|
|
export type WorkspaceScriptLifecycle = z.infer<typeof WorkspaceScriptLifecycleSchema>;
|
|
export type WorkspaceScriptHealth = z.infer<typeof WorkspaceScriptHealthSchema>;
|
|
export type WorkspaceScriptPayload = z.infer<typeof WorkspaceScriptPayloadSchema>;
|
|
export type FetchAgentsResponseMessage = z.infer<typeof FetchAgentsResponseMessageSchema>;
|
|
export type FetchAgentHistoryResponseMessage = z.infer<
|
|
typeof FetchAgentHistoryResponseMessageSchema
|
|
>;
|
|
export type FetchRecentProviderSessionsResponseMessage = z.infer<
|
|
typeof FetchRecentProviderSessionsResponseMessageSchema
|
|
>;
|
|
export type FetchWorkspacesResponseMessage = z.infer<typeof FetchWorkspacesResponseMessageSchema>;
|
|
export type ProjectAddResponse = z.infer<typeof ProjectAddResponseSchema>;
|
|
export type ProjectCreateDirectoryResponse = z.infer<typeof ProjectCreateDirectoryResponseSchema>;
|
|
export type ScriptStatusUpdateMessage = z.infer<typeof ScriptStatusUpdateMessageSchema>;
|
|
export type OpenProjectResponseMessage = z.infer<typeof OpenProjectResponseMessageSchema>;
|
|
export type WorkspaceGithubSearchRepositoriesResponse = z.infer<
|
|
typeof WorkspaceGithubSearchRepositoriesResponseSchema
|
|
>;
|
|
export type GithubRepository = z.infer<typeof GithubRepositorySchema>;
|
|
export type ProjectGithubCloneResponse = z.infer<typeof ProjectGithubCloneResponseSchema>;
|
|
export type StartWorkspaceScriptResponseMessage = z.infer<
|
|
typeof StartWorkspaceScriptResponseMessageSchema
|
|
>;
|
|
export type WorkspaceScriptListRequest = z.infer<typeof WorkspaceScriptListRequestSchema>;
|
|
export type WorkspaceScriptStartRequest = z.infer<typeof WorkspaceScriptStartRequestSchema>;
|
|
export type WorkspaceScriptStopRequest = z.infer<typeof WorkspaceScriptStopRequestSchema>;
|
|
export type WorkspaceScriptListResponseMessage = z.infer<
|
|
typeof WorkspaceScriptListResponseMessageSchema
|
|
>;
|
|
export type WorkspaceScriptStartResponseMessage = z.infer<
|
|
typeof WorkspaceScriptStartResponseMessageSchema
|
|
>;
|
|
export type WorkspaceScriptStopResponseMessage = z.infer<
|
|
typeof WorkspaceScriptStopResponseMessageSchema
|
|
>;
|
|
export type LegacyListAvailableEditorsResponseMessage = z.infer<
|
|
typeof LegacyListAvailableEditorsResponseMessageSchema
|
|
>;
|
|
export type LegacyOpenInEditorResponseMessage = z.infer<
|
|
typeof LegacyOpenInEditorResponseMessageSchema
|
|
>;
|
|
export type ArchiveWorkspaceResponseMessage = z.infer<typeof ArchiveWorkspaceResponseMessageSchema>;
|
|
export type FetchAgentResponseMessage = z.infer<typeof FetchAgentResponseMessageSchema>;
|
|
export type FetchAgentTimelineResponseMessage = z.infer<
|
|
typeof FetchAgentTimelineResponseMessageSchema
|
|
>;
|
|
export type AgentTimelineListPromptsResponseMessage = z.infer<
|
|
typeof AgentTimelineListPromptsResponseMessageSchema
|
|
>;
|
|
export type AgentForkContextResponseMessage = z.infer<typeof AgentForkContextResponseMessageSchema>;
|
|
export type CancelAgentResponseMessage = z.infer<typeof CancelAgentResponseMessageSchema>;
|
|
export type SendAgentMessageResponseMessage = z.infer<typeof SendAgentMessageResponseMessageSchema>;
|
|
export type SetVoiceModeResponseMessage = z.infer<typeof SetVoiceModeResponseMessageSchema>;
|
|
export type SetAgentModeResponseMessage = z.infer<typeof SetAgentModeResponseMessageSchema>;
|
|
export type SetAgentModelResponseMessage = z.infer<typeof SetAgentModelResponseMessageSchema>;
|
|
export type SetAgentThinkingResponseMessage = z.infer<typeof SetAgentThinkingResponseMessageSchema>;
|
|
export type SetAgentFeatureResponseMessage = z.infer<typeof SetAgentFeatureResponseMessageSchema>;
|
|
export type AgentConfigApplyResponseMessage = z.infer<typeof AgentConfigApplyResponseMessageSchema>;
|
|
export type AgentDetachResponseMessage = z.infer<typeof AgentDetachResponseMessageSchema>;
|
|
export type AgentRewindResponseMessage = z.infer<typeof AgentRewindResponseMessageSchema>;
|
|
export type UpdateAgentResponseMessage = z.infer<typeof UpdateAgentResponseMessageSchema>;
|
|
export type ProjectRenameResponse = z.infer<typeof ProjectRenameResponseSchema>;
|
|
export type ProjectIconSetResponse = z.infer<typeof ProjectIconSetResponseSchema>;
|
|
export type ProjectRemoveResponse = z.infer<typeof ProjectRemoveResponseSchema>;
|
|
export type WorkspaceTitleSetResponse = z.infer<typeof WorkspaceTitleSetResponseSchema>;
|
|
export type WorkspaceTitleSetResponsePayload = z.infer<
|
|
typeof WorkspaceTitleSetResponsePayloadSchema
|
|
>;
|
|
export type WorkspacePinSetResponse = z.infer<typeof WorkspacePinSetResponseSchema>;
|
|
export type WorkspacePinSetResponsePayload = z.infer<typeof WorkspacePinSetResponsePayloadSchema>;
|
|
export type WorkspaceRecoveryState = z.infer<typeof WorkspaceRecoveryStateSchema>;
|
|
export type WorkspaceRecoveryInspectResponse = z.infer<
|
|
typeof WorkspaceRecoveryInspectResponseSchema
|
|
>;
|
|
export type WorkspaceRecoveryRestoreResponse = z.infer<
|
|
typeof WorkspaceRecoveryRestoreResponseSchema
|
|
>;
|
|
export type WorkspaceCreateRequest = z.infer<typeof WorkspaceCreateRequestSchema>;
|
|
export type WorkspaceCreateResponse = z.infer<typeof WorkspaceCreateResponseSchema>;
|
|
export type ProjectRenameResponsePayload = z.infer<typeof ProjectRenameResponsePayloadSchema>;
|
|
export type ProjectRemoveResponsePayload = z.infer<typeof ProjectRemoveResponsePayloadSchema>;
|
|
export type WaitForFinishResponseMessage = z.infer<typeof WaitForFinishResponseMessageSchema>;
|
|
export type AgentPermissionRequestMessage = z.infer<typeof AgentPermissionRequestMessageSchema>;
|
|
export type AgentPermissionResolvedMessage = z.infer<typeof AgentPermissionResolvedMessageSchema>;
|
|
export type AgentDeletedMessage = z.infer<typeof AgentDeletedMessageSchema>;
|
|
export type ListProviderModelsResponseMessage = z.infer<
|
|
typeof ListProviderModelsResponseMessageSchema
|
|
>;
|
|
export type ListProviderModesResponseMessage = z.infer<
|
|
typeof ListProviderModesResponseMessageSchema
|
|
>;
|
|
export type ListProviderFeaturesResponseMessage = z.infer<
|
|
typeof ListProviderFeaturesResponseMessageSchema
|
|
>;
|
|
export type ListAvailableProvidersResponse = z.infer<typeof ListAvailableProvidersResponseSchema>;
|
|
export type DaemonGetStatusResponse = z.infer<typeof DaemonGetStatusResponseSchema>;
|
|
export type DaemonGetPairingOfferResponse = z.infer<typeof DaemonGetPairingOfferResponseSchema>;
|
|
export type DaemonConfigReloadResponse = z.infer<typeof DaemonConfigReloadResponseSchema>;
|
|
export type DiagnosticsResponse = z.infer<typeof DiagnosticsResponseSchema>;
|
|
export type GetProvidersSnapshotResponseMessage = z.infer<
|
|
typeof GetProvidersSnapshotResponseMessageSchema
|
|
>;
|
|
export type ProvidersSnapshotUpdateMessage = z.infer<typeof ProvidersSnapshotUpdateMessageSchema>;
|
|
export type RefreshProvidersSnapshotResponseMessage = z.infer<
|
|
typeof RefreshProvidersSnapshotResponseMessageSchema
|
|
>;
|
|
export type ProviderDiagnosticResponseMessage = z.infer<
|
|
typeof ProviderDiagnosticResponseMessageSchema
|
|
>;
|
|
export type ProviderUsageTone = z.infer<typeof ProviderUsageToneSchema>;
|
|
export type ProviderUsageStatus = z.infer<typeof ProviderUsageStatusSchema>;
|
|
export type ProviderUsage = z.infer<typeof ProviderUsageSchema>;
|
|
export type ProviderUsageWindow = z.infer<typeof ProviderUsageWindowSchema>;
|
|
export type ProviderUsageBalance = z.infer<typeof ProviderUsageBalanceSchema>;
|
|
export type ProviderUsageDetail = z.infer<typeof ProviderUsageDetailSchema>;
|
|
export type ProviderUsageListResponseMessage = z.infer<
|
|
typeof ProviderUsageListResponseMessageSchema
|
|
>;
|
|
export type ChatCreateResponse = z.infer<typeof ChatCreateResponseSchema>;
|
|
export type ChatListResponse = z.infer<typeof ChatListResponseSchema>;
|
|
export type ChatInspectResponse = z.infer<typeof ChatInspectResponseSchema>;
|
|
export type ChatDeleteResponse = z.infer<typeof ChatDeleteResponseSchema>;
|
|
export type ChatPostResponse = z.infer<typeof ChatPostResponseSchema>;
|
|
export type ChatReadResponse = z.infer<typeof ChatReadResponseSchema>;
|
|
export type ChatWaitResponse = z.infer<typeof ChatWaitResponseSchema>;
|
|
export type ScheduleCreateResponse = z.infer<typeof ScheduleCreateResponseSchema>;
|
|
export type ScheduleListResponse = z.infer<typeof ScheduleListResponseSchema>;
|
|
export type ScheduleInspectResponse = z.infer<typeof ScheduleInspectResponseSchema>;
|
|
export type ScheduleLogsResponse = z.infer<typeof ScheduleLogsResponseSchema>;
|
|
export type SchedulePauseResponse = z.infer<typeof SchedulePauseResponseSchema>;
|
|
export type ScheduleResumeResponse = z.infer<typeof ScheduleResumeResponseSchema>;
|
|
export type ScheduleDeleteResponse = z.infer<typeof ScheduleDeleteResponseSchema>;
|
|
export type ScheduleRunOnceResponse = z.infer<typeof ScheduleRunOnceResponseSchema>;
|
|
export type ScheduleUpdateResponse = z.infer<typeof ScheduleUpdateResponseSchema>;
|
|
export type LoopRunResponse = z.infer<typeof LoopRunResponseSchema>;
|
|
export type LoopListResponse = z.infer<typeof LoopListResponseSchema>;
|
|
export type LoopInspectResponse = z.infer<typeof LoopInspectResponseSchema>;
|
|
export type LoopLogsResponse = z.infer<typeof LoopLogsResponseSchema>;
|
|
export type LoopStopResponse = z.infer<typeof LoopStopResponseSchema>;
|
|
|
|
// Type exports for payload types
|
|
export type ActivityLogPayload = z.infer<typeof ActivityLogPayloadSchema>;
|
|
|
|
// Type exports for inbound message types
|
|
export type VoiceAudioChunkMessage = z.infer<typeof VoiceAudioChunkMessageSchema>;
|
|
export type FetchAgentsRequestMessage = z.infer<typeof FetchAgentsRequestMessageSchema>;
|
|
export type FetchAgentHistoryRequestMessage = z.infer<typeof FetchAgentHistoryRequestMessageSchema>;
|
|
export type FetchRecentProviderSessionsRequestMessage = z.infer<
|
|
typeof FetchRecentProviderSessionsRequestMessageSchema
|
|
>;
|
|
export type FetchWorkspacesRequestMessage = z.infer<typeof FetchWorkspacesRequestMessageSchema>;
|
|
export type ProjectListRequestMessage = z.infer<typeof ProjectListRequestMessageSchema>;
|
|
export type FetchAgentRequestMessage = z.infer<typeof FetchAgentRequestMessageSchema>;
|
|
export type AgentForkContextRequestMessage = z.infer<typeof AgentForkContextRequestMessageSchema>;
|
|
export type SendAgentMessageRequest = z.infer<typeof SendAgentMessageRequestSchema>;
|
|
export type WaitForFinishRequest = z.infer<typeof WaitForFinishRequestSchema>;
|
|
export type DictationStreamStartMessage = z.infer<typeof DictationStreamStartMessageSchema>;
|
|
export type DictationStreamChunkMessage = z.infer<typeof DictationStreamChunkMessageSchema>;
|
|
export type DictationStreamFinishMessage = z.infer<typeof DictationStreamFinishMessageSchema>;
|
|
export type DictationStreamCancelMessage = z.infer<typeof DictationStreamCancelMessageSchema>;
|
|
export type CreateAgentRequestMessage = z.infer<typeof CreateAgentRequestMessageSchema>;
|
|
export type AgentAttachment = z.infer<typeof AgentAttachmentSchema>;
|
|
export type ForgeChangeRequestAttachment = z.infer<typeof ForgeChangeRequestAttachmentSchema>;
|
|
export type ForgeIssueAttachment = z.infer<typeof ForgeIssueAttachmentSchema>;
|
|
export type UploadedFileAttachment = z.infer<typeof UploadedFileAttachmentSchema>;
|
|
export type FirstAgentContext = z.infer<typeof FirstAgentContextSchema>;
|
|
export type ReviewAttachment = z.infer<typeof ReviewAttachmentSchema>;
|
|
export type ListProviderModelsRequestMessage = z.infer<
|
|
typeof ListProviderModelsRequestMessageSchema
|
|
>;
|
|
export type ListProviderModesRequestMessage = z.infer<typeof ListProviderModesRequestMessageSchema>;
|
|
export type ListProviderFeaturesRequestMessage = z.infer<
|
|
typeof ListProviderFeaturesRequestMessageSchema
|
|
>;
|
|
export type ListAvailableProvidersRequestMessage = z.infer<
|
|
typeof ListAvailableProvidersRequestMessageSchema
|
|
>;
|
|
export type GetProvidersSnapshotRequestMessage = z.infer<
|
|
typeof GetProvidersSnapshotRequestMessageSchema
|
|
>;
|
|
export type RefreshProvidersSnapshotRequestMessage = z.infer<
|
|
typeof RefreshProvidersSnapshotRequestMessageSchema
|
|
>;
|
|
export type ProviderDiagnosticRequestMessage = z.infer<
|
|
typeof ProviderDiagnosticRequestMessageSchema
|
|
>;
|
|
export type ChatCreateRequest = z.infer<typeof ChatCreateRequestSchema>;
|
|
export type ChatListRequest = z.infer<typeof ChatListRequestSchema>;
|
|
export type ChatInspectRequest = z.infer<typeof ChatInspectRequestSchema>;
|
|
export type ChatDeleteRequest = z.infer<typeof ChatDeleteRequestSchema>;
|
|
export type ChatPostRequest = z.infer<typeof ChatPostRequestSchema>;
|
|
export type ChatReadRequest = z.infer<typeof ChatReadRequestSchema>;
|
|
export type ChatWaitRequest = z.infer<typeof ChatWaitRequestSchema>;
|
|
export type ScheduleCreateRequest = z.infer<typeof ScheduleCreateRequestSchema>;
|
|
export type ScheduleListRequest = z.infer<typeof ScheduleListRequestSchema>;
|
|
export type ScheduleInspectRequest = z.infer<typeof ScheduleInspectRequestSchema>;
|
|
export type ScheduleLogsRequest = z.infer<typeof ScheduleLogsRequestSchema>;
|
|
export type SchedulePauseRequest = z.infer<typeof SchedulePauseRequestSchema>;
|
|
export type ScheduleResumeRequest = z.infer<typeof ScheduleResumeRequestSchema>;
|
|
export type ScheduleDeleteRequest = z.infer<typeof ScheduleDeleteRequestSchema>;
|
|
export type ScheduleRunOnceRequest = z.infer<typeof ScheduleRunOnceRequestSchema>;
|
|
export type ScheduleUpdateRequest = z.infer<typeof ScheduleUpdateRequestSchema>;
|
|
export type LoopRunRequest = z.infer<typeof LoopRunRequestSchema>;
|
|
export type LoopListRequest = z.infer<typeof LoopListRequestSchema>;
|
|
export type LoopInspectRequest = z.infer<typeof LoopInspectRequestSchema>;
|
|
export type LoopLogsRequest = z.infer<typeof LoopLogsRequestSchema>;
|
|
export type LoopStopRequest = z.infer<typeof LoopStopRequestSchema>;
|
|
export type ResumeAgentRequestMessage = z.infer<typeof ResumeAgentRequestMessageSchema>;
|
|
export type DeleteAgentRequestMessage = z.infer<typeof DeleteAgentRequestMessageSchema>;
|
|
export type UpdateAgentRequestMessage = z.infer<typeof UpdateAgentRequestMessageSchema>;
|
|
export type ProjectIconSource = z.infer<typeof ProjectIconSourceSchema>;
|
|
export type ProjectRenameRequest = z.infer<typeof ProjectRenameRequestSchema>;
|
|
export type ProjectIconSetRequest = z.infer<typeof ProjectIconSetRequestSchema>;
|
|
export type ProjectRemoveRequest = z.infer<typeof ProjectRemoveRequestSchema>;
|
|
export type WorkspaceTitleSetRequest = z.infer<typeof WorkspaceTitleSetRequestSchema>;
|
|
export type WorkspacePinSetRequest = z.infer<typeof WorkspacePinSetRequestSchema>;
|
|
export type WorkspaceRecoveryInspectRequest = z.infer<typeof WorkspaceRecoveryInspectRequestSchema>;
|
|
export type WorkspaceRecoveryRestoreRequest = z.infer<typeof WorkspaceRecoveryRestoreRequestSchema>;
|
|
export type SetAgentModeRequestMessage = z.infer<typeof SetAgentModeRequestMessageSchema>;
|
|
export type SetAgentModelRequestMessage = z.infer<typeof SetAgentModelRequestMessageSchema>;
|
|
export type SetAgentThinkingRequestMessage = z.infer<typeof SetAgentThinkingRequestMessageSchema>;
|
|
export type SetAgentFeatureRequestMessage = z.infer<typeof SetAgentFeatureRequestMessageSchema>;
|
|
export type AgentConfigApplyRequestMessage = z.infer<typeof AgentConfigApplyRequestMessageSchema>;
|
|
export type AgentDetachRequestMessage = z.infer<typeof AgentDetachRequestMessageSchema>;
|
|
export type AgentPermissionResponseMessage = z.infer<typeof AgentPermissionResponseMessageSchema>;
|
|
export type CheckoutStatusRequest = z.infer<typeof CheckoutStatusRequestSchema>;
|
|
export type CheckoutStatusResponse = z.infer<typeof CheckoutStatusResponseSchema>;
|
|
export type CheckoutStatusUpdate = z.infer<typeof CheckoutStatusUpdateSchema>;
|
|
export type SubscribeCheckoutDiffRequest = z.infer<typeof SubscribeCheckoutDiffRequestSchema>;
|
|
export type UnsubscribeCheckoutDiffRequest = z.infer<typeof UnsubscribeCheckoutDiffRequestSchema>;
|
|
export type SubscribeCheckoutDiffResponse = z.infer<typeof SubscribeCheckoutDiffResponseSchema>;
|
|
export type CheckoutDiffUpdate = z.infer<typeof CheckoutDiffUpdateSchema>;
|
|
export type CheckoutCommitRequest = z.infer<typeof CheckoutCommitRequestSchema>;
|
|
export type CheckoutCommitResponse = z.infer<typeof CheckoutCommitResponseSchema>;
|
|
export type CheckoutMergeRequest = z.infer<typeof CheckoutMergeRequestSchema>;
|
|
export type CheckoutMergeResponse = z.infer<typeof CheckoutMergeResponseSchema>;
|
|
export type CheckoutMergeFromBaseRequest = z.infer<typeof CheckoutMergeFromBaseRequestSchema>;
|
|
export type CheckoutMergeFromBaseResponse = z.infer<typeof CheckoutMergeFromBaseResponseSchema>;
|
|
export type CheckoutPullRequest = z.infer<typeof CheckoutPullRequestSchema>;
|
|
export type CheckoutPullResponse = z.infer<typeof CheckoutPullResponseSchema>;
|
|
export type CheckoutPushRequest = z.infer<typeof CheckoutPushRequestSchema>;
|
|
export type CheckoutPushResponse = z.infer<typeof CheckoutPushResponseSchema>;
|
|
export type CheckoutRefreshRequest = z.infer<typeof CheckoutRefreshRequestSchema>;
|
|
export type CheckoutRefreshResponse = z.infer<typeof CheckoutRefreshResponseSchema>;
|
|
export type CheckoutDiscardChangesRequest = z.infer<typeof CheckoutDiscardChangesRequestSchema>;
|
|
export type CheckoutDiscardChangesResponse = z.infer<typeof CheckoutDiscardChangesResponseSchema>;
|
|
export type CheckoutCommitFile = z.infer<typeof CheckoutCommitFileSchema>;
|
|
export type CheckoutCommit = z.infer<typeof CheckoutCommitSchema>;
|
|
export type CheckoutCommitsListRequest = z.infer<typeof CheckoutCommitsListRequestSchema>;
|
|
export type CheckoutCommitsListResponse = z.infer<typeof CheckoutCommitsListResponseSchema>;
|
|
export type CheckoutCommitFileDiffRequest = z.infer<typeof CheckoutCommitFileDiffRequestSchema>;
|
|
export type CheckoutCommitFileDiffResponse = z.infer<typeof CheckoutCommitFileDiffResponseSchema>;
|
|
export type ParsedDiffFile = z.infer<typeof ParsedDiffFileSchema>;
|
|
export type CheckoutPrCreateRequest = z.infer<typeof CheckoutPrCreateRequestSchema>;
|
|
export type CheckoutPrCreateResponse = z.infer<typeof CheckoutPrCreateResponseSchema>;
|
|
export type CheckoutPrMergeRequest = z.infer<typeof CheckoutPrMergeRequestSchema>;
|
|
export type CheckoutPrMergeResponse = z.infer<typeof CheckoutPrMergeResponseSchema>;
|
|
export type CheckoutPrMergeMethod = z.infer<typeof CheckoutPrMergeRequestSchema>["mergeMethod"];
|
|
export type CheckoutForgeSetAutoMergeRequest = z.infer<
|
|
typeof CheckoutForgeSetAutoMergeRequestSchema
|
|
>;
|
|
export type CheckoutForgeSetAutoMergeResponse = z.infer<
|
|
typeof CheckoutForgeSetAutoMergeResponseSchema
|
|
>;
|
|
export type CheckoutGithubSetAutoMergeRequest = z.infer<
|
|
typeof CheckoutGithubSetAutoMergeRequestSchema
|
|
>;
|
|
export type CheckoutGithubSetAutoMergeResponse = z.infer<
|
|
typeof CheckoutGithubSetAutoMergeResponseSchema
|
|
>;
|
|
export type CheckoutForgeGetCheckDetailsRequest = z.infer<
|
|
typeof CheckoutForgeGetCheckDetailsRequestSchema
|
|
>;
|
|
export type CheckoutGithubGetCheckDetailsRequest = z.infer<
|
|
typeof CheckoutGithubGetCheckDetailsRequestSchema
|
|
>;
|
|
export type CheckoutCheckDetails = z.infer<typeof CheckoutCheckDetailsSchema>;
|
|
export type CheckoutGithubCheckDetails = z.infer<typeof CheckoutGithubCheckDetailsSchema>;
|
|
export type CheckoutPipeline = z.infer<typeof CheckoutPipelineSchema>;
|
|
export type CheckoutPipelineStage = z.infer<typeof CheckoutPipelineStageSchema>;
|
|
export type CheckoutPipelineJob = z.infer<typeof CheckoutPipelineJobSchema>;
|
|
export type CheckoutForgeGetCheckDetailsResponse = z.infer<
|
|
typeof CheckoutForgeGetCheckDetailsResponseSchema
|
|
>;
|
|
export type CheckoutGithubGetCheckDetailsResponse = z.infer<
|
|
typeof CheckoutGithubGetCheckDetailsResponseSchema
|
|
>;
|
|
export type PullRequestMergeable = z.infer<typeof CheckoutPrStatusSchema>["mergeable"];
|
|
export type CheckoutPrStatusRequest = z.infer<typeof CheckoutPrStatusRequestSchema>;
|
|
export type CheckoutPrStatusResponse = z.infer<typeof CheckoutPrStatusResponseSchema>;
|
|
export type PullRequestTimelineRequest = z.infer<typeof PullRequestTimelineRequestSchema>;
|
|
export type PullRequestTimelineItem = z.infer<typeof PullRequestTimelineItemSchema>;
|
|
export type PullRequestTimelineResponse = z.infer<typeof PullRequestTimelineResponseSchema>;
|
|
export type CheckoutSwitchBranchRequest = z.infer<typeof CheckoutSwitchBranchRequestSchema>;
|
|
export type CheckoutSwitchBranchResponse = z.infer<typeof CheckoutSwitchBranchResponseSchema>;
|
|
export type CheckoutRenameBranchRequest = z.infer<typeof CheckoutRenameBranchRequestSchema>;
|
|
export type CheckoutRenameBranchResponse = z.infer<typeof CheckoutRenameBranchResponseSchema>;
|
|
export type StashSaveRequest = z.infer<typeof StashSaveRequestSchema>;
|
|
export type StashSaveResponse = z.infer<typeof StashSaveResponseSchema>;
|
|
export type StashPopRequest = z.infer<typeof StashPopRequestSchema>;
|
|
export type StashPopResponse = z.infer<typeof StashPopResponseSchema>;
|
|
export type StashListRequest = z.infer<typeof StashListRequestSchema>;
|
|
export type StashListResponse = z.infer<typeof StashListResponseSchema>;
|
|
export type StashEntry = z.infer<typeof StashEntrySchema>;
|
|
export type ValidateBranchRequest = z.infer<typeof ValidateBranchRequestSchema>;
|
|
export type ValidateBranchResponse = z.infer<typeof ValidateBranchResponseSchema>;
|
|
export type BranchSuggestionsRequest = z.infer<typeof BranchSuggestionsRequestSchema>;
|
|
export type BranchSuggestionsResponse = z.infer<typeof BranchSuggestionsResponseSchema>;
|
|
export type ForgeSearchItem = z.infer<typeof ForgeSearchItemSchema>;
|
|
export type ForgeSearchKind = "issue" | "change_request";
|
|
export type ForgeSearchRequest = z.infer<typeof ForgeSearchRequestSchema>;
|
|
export type ForgeSearchResponse = z.infer<typeof ForgeSearchResponseSchema>;
|
|
export type GitHubSearchItem = z.infer<typeof GitHubSearchItemSchema>;
|
|
export type GitHubSearchKind = z.infer<typeof GitHubSearchKindSchema>;
|
|
export type GitHubSearchRequest = z.infer<typeof GitHubSearchRequestSchema>;
|
|
export type GitHubSearchResponse = z.infer<typeof GitHubSearchResponseSchema>;
|
|
export type ChangeRequestCheckoutSource = z.infer<typeof ChangeRequestCheckoutSourceSchema>;
|
|
export type CreatePaseoWorktreeRequest = z.infer<typeof CreatePaseoWorktreeRequestSchema>;
|
|
export type DirectorySuggestionsRequest = z.infer<typeof DirectorySuggestionsRequestSchema>;
|
|
export type DirectorySuggestionsResponse = z.infer<typeof DirectorySuggestionsResponseSchema>;
|
|
export type PaseoWorktreeListRequest = z.infer<typeof PaseoWorktreeListRequestSchema>;
|
|
export type PaseoWorktreeListResponse = z.infer<typeof PaseoWorktreeListResponseSchema>;
|
|
export type PaseoWorktreeArchiveRequest = z.infer<typeof PaseoWorktreeArchiveRequestSchema>;
|
|
export type PaseoWorktreeArchiveResponse = z.infer<typeof PaseoWorktreeArchiveResponseSchema>;
|
|
export type WorkspaceSetupStatusRequest = z.infer<typeof WorkspaceSetupStatusRequestSchema>;
|
|
export type LegacyListAvailableEditorsRequest = z.infer<
|
|
typeof LegacyListAvailableEditorsRequestSchema
|
|
>;
|
|
export type LegacyOpenInEditorRequest = z.infer<typeof LegacyOpenInEditorRequestSchema>;
|
|
export type OpenProjectRequest = z.infer<typeof OpenProjectRequestSchema>;
|
|
export type ProjectAddRequest = z.infer<typeof ProjectAddRequestSchema>;
|
|
export type ProjectCreateDirectoryRequest = z.infer<typeof ProjectCreateDirectoryRequestSchema>;
|
|
export type ProjectCreateDirectoryErrorCode = z.infer<typeof ProjectCreateDirectoryErrorCodeSchema>;
|
|
export type WorkspaceGithubSearchRepositoriesRequest = z.infer<
|
|
typeof WorkspaceGithubSearchRepositoriesRequestSchema
|
|
>;
|
|
export type ProjectGithubCloneRequest = z.infer<typeof ProjectGithubCloneRequestSchema>;
|
|
export type ProjectGithubCloneProtocol = z.infer<typeof ProjectGithubCloneProtocolSchema>;
|
|
export type ArchiveWorkspaceRequest = z.infer<typeof ArchiveWorkspaceRequestSchema>;
|
|
export type WorkspaceClearAttentionRequest = z.infer<typeof WorkspaceClearAttentionRequestSchema>;
|
|
export type FileExplorerRequest = z.infer<typeof FileExplorerRequestSchema>;
|
|
export type FileExplorerResponse = z.infer<typeof FileExplorerResponseSchema>;
|
|
export type FileVersion = z.infer<typeof FileVersionSchema>;
|
|
export type FileSubscribeRequest = z.infer<typeof FileSubscribeRequestSchema>;
|
|
export type FileSubscribeResponse = z.infer<typeof FileSubscribeResponseSchema>;
|
|
export type FileUnsubscribeRequest = z.infer<typeof FileUnsubscribeRequestSchema>;
|
|
export type FileUnsubscribeResponse = z.infer<typeof FileUnsubscribeResponseSchema>;
|
|
export type FileWriteRequest = z.infer<typeof FileWriteRequestSchema>;
|
|
export type FileWriteResponse = z.infer<typeof FileWriteResponseSchema>;
|
|
export type FileEntryCreateRequest = z.infer<typeof FileEntryCreateRequestSchema>;
|
|
export type FileEntryCreateResponse = z.infer<typeof FileEntryCreateResponseSchema>;
|
|
export type FileEntryRenameRequest = z.infer<typeof FileEntryRenameRequestSchema>;
|
|
export type FileEntryRenameResponse = z.infer<typeof FileEntryRenameResponseSchema>;
|
|
export type FileEntryDuplicateRequest = z.infer<typeof FileEntryDuplicateRequestSchema>;
|
|
export type FileEntryDuplicateResponse = z.infer<typeof FileEntryDuplicateResponseSchema>;
|
|
export type FileEntryDeleteRequest = z.infer<typeof FileEntryDeleteRequestSchema>;
|
|
export type FileEntryDeleteResponse = z.infer<typeof FileEntryDeleteResponseSchema>;
|
|
export type FileWriteResult = z.infer<typeof FileWriteResultSchema>;
|
|
export type FileUpdate = z.infer<typeof FileUpdateSchema>;
|
|
export type ProjectIconRequest = z.infer<typeof ProjectIconRequestSchema>;
|
|
export type ProjectIconResponse = z.infer<typeof ProjectIconResponseSchema>;
|
|
export type ProjectIconGetRequest = z.infer<typeof ProjectIconGetRequestSchema>;
|
|
export type ProjectIconGetResponse = z.infer<typeof ProjectIconGetResponseSchema>;
|
|
export type ProjectIcon = z.infer<typeof ProjectIconSchema>;
|
|
export type FileDownloadTokenRequest = z.infer<typeof FileDownloadTokenRequestSchema>;
|
|
export type FileDownloadTokenResponse = z.infer<typeof FileDownloadTokenResponseSchema>;
|
|
export type FileUploadRequest = z.infer<typeof FileUploadRequestSchema>;
|
|
export type FileUploadResponse = z.infer<typeof FileUploadResponseSchema>;
|
|
export type RestartServerRequestMessage = z.infer<typeof RestartServerRequestMessageSchema>;
|
|
export type ShutdownServerRequestMessage = z.infer<typeof ShutdownServerRequestMessageSchema>;
|
|
export type ClearAgentAttentionMessage = z.infer<typeof ClearAgentAttentionMessageSchema>;
|
|
export type ClearAgentAttentionResponseMessage = z.infer<
|
|
typeof ClearAgentAttentionResponseMessageSchema
|
|
>;
|
|
export type ClientHeartbeatMessage = z.infer<typeof ClientHeartbeatMessageSchema>;
|
|
export type ListCommandsRequest = z.infer<typeof ListCommandsRequestSchema>;
|
|
export type ListCommandsResponse = z.infer<typeof ListCommandsResponseSchema>;
|
|
export type RegisterPushTokenMessage = z.infer<typeof RegisterPushTokenMessageSchema>;
|
|
export type PushUnregisterRequest = z.infer<typeof PushUnregisterRequestSchema>;
|
|
export type PushUnregisterResponse = z.infer<typeof PushUnregisterResponseSchema>;
|
|
|
|
// Terminal message types
|
|
export type ListTerminalsRequest = z.infer<typeof ListTerminalsRequestSchema>;
|
|
export type ListTerminalsResponse = z.infer<typeof ListTerminalsResponseSchema>;
|
|
export type SubscribeTerminalsRequest = z.infer<typeof SubscribeTerminalsRequestSchema>;
|
|
export type UnsubscribeTerminalsRequest = z.infer<typeof UnsubscribeTerminalsRequestSchema>;
|
|
export type TerminalsChanged = z.infer<typeof TerminalsChangedSchema>;
|
|
export type CreateTerminalRequest = z.infer<typeof CreateTerminalRequestSchema>;
|
|
export type CreateTerminalResponse = z.infer<typeof CreateTerminalResponseSchema>;
|
|
export type RenameTerminalRequest = z.infer<typeof RenameTerminalRequestSchema>;
|
|
export type RenameTerminalResponse = z.infer<typeof RenameTerminalResponseSchema>;
|
|
export type StartWorkspaceScriptRequest = z.infer<typeof StartWorkspaceScriptRequestSchema>;
|
|
export type StartWorkspaceScriptResponse = z.infer<
|
|
typeof StartWorkspaceScriptResponseMessageSchema
|
|
>;
|
|
export type SubscribeTerminalRequest = z.infer<typeof SubscribeTerminalRequestSchema>;
|
|
export type SubscribeTerminalResponse = z.infer<typeof SubscribeTerminalResponseSchema>;
|
|
export type UnsubscribeTerminalRequest = z.infer<typeof UnsubscribeTerminalRequestSchema>;
|
|
export type TerminalInput = z.infer<typeof TerminalInputSchema>;
|
|
export type TerminalCell = z.infer<typeof TerminalCellSchema>;
|
|
export type TerminalCursorStyle = z.infer<typeof TerminalCursorStyleSchema>;
|
|
export type TerminalCursor = z.infer<typeof TerminalCursorSchema>;
|
|
export type TerminalState = z.infer<typeof TerminalStateSchema>;
|
|
export type CloseItemsRequest = z.infer<typeof CloseItemsRequestMessageSchema>;
|
|
export type CloseItemsResponse = z.infer<typeof CloseItemsResponseSchema>;
|
|
export type KillTerminalRequest = z.infer<typeof KillTerminalRequestSchema>;
|
|
export type KillTerminalResponse = z.infer<typeof KillTerminalResponseSchema>;
|
|
export type CaptureTerminalRequest = z.infer<typeof CaptureTerminalRequestSchema>;
|
|
export type CaptureTerminalResponse = z.infer<typeof CaptureTerminalResponseSchema>;
|
|
export type TerminalStreamExit = z.infer<typeof TerminalStreamExitSchema>;
|
|
|
|
// ============================================================================
|
|
// WebSocket Level Messages (wraps session messages)
|
|
// ============================================================================
|
|
|
|
// WebSocket-only messages (not session messages)
|
|
export const WSPingMessageSchema = z.object({
|
|
type: z.literal("ping"),
|
|
});
|
|
|
|
export const WSPongMessageSchema = z.object({
|
|
type: z.literal("pong"),
|
|
});
|
|
|
|
export const WSHelloMessageSchema = z.object({
|
|
type: z.literal("hello"),
|
|
clientId: z.string().min(1),
|
|
clientType: z.enum(["mobile", "browser", "cli", "mcp"]),
|
|
protocolVersion: z.number().int(),
|
|
appVersion: z.string().optional(),
|
|
capabilities: z
|
|
.object({
|
|
voice: z.boolean().optional(),
|
|
pushNotifications: z.boolean().optional(),
|
|
[CLIENT_CAPS.reasoningMergeEnum]: z.boolean().optional(),
|
|
[CLIENT_CAPS.selectiveAgentTimeline]: z.boolean().optional(),
|
|
[CLIENT_CAPS.customModeIcons]: z.boolean().optional(),
|
|
[CLIENT_CAPS.terminalReflowableSnapshot]: z.boolean().optional(),
|
|
[CLIENT_CAPS.providerSubagents]: z.boolean().optional(),
|
|
[CLIENT_CAPS.projectUpdates]: z.boolean().optional(),
|
|
[CLIENT_CAPS.compactProviderSnapshots]: z.boolean().optional(),
|
|
[CLIENT_CAPS.browserHost]: BrowserAutomationHostCapabilitySchema.optional(),
|
|
})
|
|
.passthrough()
|
|
.optional(),
|
|
});
|
|
|
|
export const WSRecordingStateMessageSchema = z.object({
|
|
type: z.literal("recording_state"),
|
|
isRecording: z.boolean(),
|
|
});
|
|
|
|
// Wrapped session message
|
|
export const WSSessionInboundSchema = z.object({
|
|
type: z.literal("session"),
|
|
message: SessionInboundMessageSchema,
|
|
});
|
|
|
|
export const WSSessionOutboundSchema = z.object({
|
|
type: z.literal("session"),
|
|
message: SessionOutboundMessageSchema,
|
|
});
|
|
|
|
// Complete WebSocket message schemas
|
|
export const WSInboundMessageSchema = z.discriminatedUnion("type", [
|
|
WSPingMessageSchema,
|
|
WSHelloMessageSchema,
|
|
WSRecordingStateMessageSchema,
|
|
WSSessionInboundSchema,
|
|
]);
|
|
|
|
export const WSOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
WSPongMessageSchema,
|
|
WSSessionOutboundSchema,
|
|
]);
|
|
|
|
export type WSInboundMessage = z.infer<typeof WSInboundMessageSchema>;
|
|
export type WSOutboundMessage = z.infer<typeof WSOutboundMessageSchema>;
|
|
export type WSHelloMessage = z.infer<typeof WSHelloMessageSchema>;
|
|
|
|
// ============================================================================
|
|
// Helper functions for message conversion
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Extract session message from WebSocket message
|
|
* Returns null if message should be handled at WS level only
|
|
*/
|
|
export function extractSessionMessage(wsMsg: WSInboundMessage): SessionInboundMessage | null {
|
|
if (wsMsg.type === "session") {
|
|
return wsMsg.message;
|
|
}
|
|
// Ping and recording_state are WS-level only
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Wrap session message in WebSocket envelope
|
|
*/
|
|
export function wrapSessionMessage(sessionMsg: SessionOutboundMessage): WSOutboundMessage {
|
|
return {
|
|
type: "session",
|
|
message: sessionMsg,
|
|
};
|
|
}
|
|
|
|
export function parseServerInfoStatusPayload(payload: unknown): ServerInfoStatusPayload | null {
|
|
const parsed = ServerInfoStatusPayloadSchema.safeParse(payload);
|
|
if (!parsed.success) {
|
|
return null;
|
|
}
|
|
return parsed.data;
|
|
}
|