{ "id": "review-desk", "title": "Review a release note before sharing", "entrypoint": "index.ts", "runtime": "Current custom Oh My Pi build with Bun and ExtensionAPI; runtime TUI imports resolve through the OMP extension loader", "launch": "From this downloaded directory: omp --no-extensions -e ./index.ts", "files": ["index.ts", "domain.ts", "panel.ts", "copy.json", "release-note.txt", "story.json"], "purpose": "A fictional release note progresses from draft to accepted, rejected, or cancelled. Acceptance is only a local label: this example has no send/publish operation.", "storage": { "fixture": "release-note.txt is a real local file read with Bun.file; never overwritten", "draft": "Custom session entries named workbook-review-desk-state, reconstructed from the current branch on every operation", "authorization": "In-memory only; one change on an exact revision in the current session; cleared on mutation, revocation, switch/branch/tree navigation, and shutdown. Revocation also aborts and invalidates any pending grant or review dialog; late replies cannot restore permission or commit edits.", "newSession": "A new branch with no review state starts at fixture revision 0", "securityBoundary": "This is an explicit domain authorization check, not an OS sandbox. Other tools or extensions can have independent permissions. Draft text cannot grant this extension permission. Read and write operations share a conservative write approval tier." }, "chapters": [ { "name": "1. Inspect without changing anything", "human": "/review-desk show", "machine": [{ "op": "discover" }, { "op": "inspect" }, { "op": "query" }], "tool": "review_desk", "outcome": "Fixture text at revision 0, status draft, authorization false. Status/footer and string widget summarize the state; a custom message can expand to show the note. Machine operations return structured details plus JSON text, not screenshots." }, { "name": "2. Edit and accept locally", "human": "/review-desk review", "actions": ["Edit the multiline note", "Submit with the editor's follow-up chord (default Ctrl+Q or Ctrl+Enter); Enter inserts a newline", "Select Accept locally"], "outcome": "The edited text is stored in a session entry; status accepted; revision increases once. No external action occurs." }, { "name": "3. Reject or cancel distinctly", "human": "/review-desk review", "alternatives": [ { "actions": ["Edit", "Submit", "Select Reject"], "outcome": "status rejected; original pre-dialog text preserved; revision +1" }, { "actions": ["Press Escape in the editor"], "outcome": "status cancelled; original text preserved; revision +1" }, { "actions": ["Submit editor", "Choose Cancel or dismiss the selector"], "outcome": "status cancelled; original text preserved; revision +1" } ], "note": "These are review outcomes, not deletion of the fixture or publication. Empty/oversized accepted edits fail rather than storing invalid content." }, { "name": "4. Authorize exactly one agent action", "human": "/review-desk delegate", "actions": ["Confirm the scoped permission dialog", "Have the agent inspect the exact revision", "Call review_desk act with that expectedRevision"], "machineExampleOnFreshSession": { "op": "act", "action": "revise", "expectedRevision": 0, "text": "A shorter local release note." }, "outcome": "revise produces draft revision 1 and consumes the grant. accept, reject, and cancel are also available, without text. A second act fails until the human grants again. A stale revision fails without mutation. /review-desk revoke removes permission and cancels any pending grant or review dialog without changing draft text, status, or revision. A delayed positive reply to the old confirmation cannot reauthorize the agent.", "headlessPolicy": "No UI means no new grant. inspect/query remain useful; act fails closed. Authorization is never reconstructed from persisted state." }, { "name": "5. Optional native overlay", "human": "/review-desk overlay", "actions": ["Use Up/Down to scroll the local note", "Press a to accept, r to reject, or Escape to cancel"], "outcome": "The real focused custom component records the chosen outcome. No editor text is inserted or submitted. Controller cleanup hides the overlay and disposes the component; session navigation/shutdown aborts pending presentation without committing to another branch.", "component": "ReviewPanel composes actual Text components, matches terminal key sequences, sanitizes note text, bounds rendered rows to min(viewport width, 100), and shows an eight-line scrolling body. It owns no global/raw input listener or desktop handle.", "modeGuard": "Requires ctx.mode === tui. RPC receives a warning and retains the draft. Use the standard review dialog flow for RPC." } ], "machineContract": { "tool": "review_desk", "discover": "operations, actions, authorization rule, local-only transport", "inspect": "full text, status, revision, authorized", "query": "status, revision, authorized, busy, mode", "act": "action plus expectedRevision; revise additionally requires text; text is prohibited for other agent actions", "actions": { "revise": "draft with replacement text", "accept": "accepted with unchanged inspected text", "reject": "rejected with unchanged text", "cancel": "cancelled with unchanged text" }, "errors": ["No human grant", "Revision mismatch", "Review dialog open", "Missing action/text", "Blank or over-12000-character draft"], "notProvided": ["Global GUI automation", "Host keystroke injection", "Desktop control", "Network publish/send", "External editor launch by this extension"] }, "modeMatrix": { "tui": "Standard dialogs, status, string widget, custom message renderer and optional custom overlay. The core multiline editor also exposes its normal Ctrl+G external-editor shortcut; this extension never invokes it programmatically.", "rpc": "Current wired RPC context reports hasUI=true and mode=rpc. A host must present extension_ui_request frames and answer by id. This differs from the stale hasUI field comment in types.ts; mode is the reliable native-component guard.", "printAndJson": "Default runner UI is inert: select/input/editor return undefined, confirm false, notifications/status/widgets no-op. Extension explicitly refuses interactive changes and emits an explanatory custom message. Read tools still return state." }, "rpcReference": { "replyShape": [ { "type": "extension_ui_response", "id": "COPY_REQUEST_ID", "value": "selected label or editor/input text" }, { "type": "extension_ui_response", "id": "COPY_REQUEST_ID", "confirmed": true }, { "type": "extension_ui_response", "id": "COPY_REQUEST_ID", "cancelled": true } ], "supportedDialogs": { "select": "title, string options; optional aligned optionDetails descriptions; resolves selected LABEL, not an index; timeout supported", "confirm": "title/message; confirmed boolean; cancellation and decline both resolve false; timeout supported", "input": "title/placeholder; value or cancellation; timeout supported", "editor": "title/prefill/promptStyle; value or cancellation; AbortSignal supported; editor wire has no timeout and adapter does not schedule a dialog timeout" }, "signal": "Aborting an active dialog emits method=cancel with targetId equal to the original request id and resolves undefined (or false for confirm). A pre-aborted signal suppresses the request. Disconnect rejects pending/future requests. These are domain dialog cancellation frames, not OS input.", "fireAndForget": ["notify", "setStatus", "setWidget for string arrays or undefined", "set_editor_text via setEditorText or pasteToEditor", "setTitle only when PI_RPC_EMIT_TITLE=1"], "noRpcNativeSurface": ["custom returns undefined without invoking factory", "widget component factories ignored", "setFooter/setHeader no-op", "setEditorComponent no-op", "onTerminalInput returns inert unsubscribe", "addAutocompleteProvider ignored", "setWorkingMessage no-op", "askDialog absent", "setToolsExpanded no-op/getToolsExpanded false"], "themeAndComposer": "getEditorText returns empty string; host must track composer state. getAllThemes returns []; getTheme returns undefined; setTheme returns success:false. theme is server-side styling data, not remote UI control.", "customMessages": "RPC streams/stores custom message data. TUI component renderers are not serialized; an RPC host must choose its own rendering.", "dialogOptionsNotOnWire": "initialIndex, outline, left/right callbacks, external-editor callback, helpText and selection-marker fields are TUI features. Do not assume the host receives them. The local select/confirm/input timer can settle without a cancel frame; hosts should honor transmitted timeout too." }, "sources": [ "packages/coding-agent/src/extensibility/extensions/types.ts:185-371,455-487,614-668,1166-1174,1434-1455", "packages/coding-agent/src/extensibility/extensions/runner.ts:403-429,889-890", "packages/coding-agent/src/modes/controllers/extension-ui-controller.ts:101-144,1018-1049,1068-1147", "packages/coding-agent/src/modes/rpc/rpc-mode.ts:546-694,771-975,1532-1545", "packages/coding-agent/src/modes/rpc/rpc-types.ts:376-440,547-550", "packages/coding-agent/test/rpc-extension-ui.test.ts", "packages/coding-agent/examples/extensions/tools.ts" ], "proof": { "runner": "Private workbook source only: proof/ui/run.ts", "commandForMaintainer": "bun --no-env-file .notes/extension-workbook-1788025968734/proof/ui/run.ts", "authoredStatus": "Not executed by the authoring worker; Main owns execution and evidence publication", "coverage": "Actual loader and SDK state operations; real runRpcMode stdin/stdout requests/responses; human review/grant flow including revocation before a late positive confirmation; native controller/TUI overlay and terminal-emulator keyboard delivery; bounded custom renderer; abort cleanup; print-mode guard", "limits": "No LLM/tool-choice quality claim, physical terminal visual audit, browser-host UI or desktop test. Private driver invokes real SDK tool adapters without provider inference. macOS sandbox is mandatory for this private proof; public extension is not macOS-specific." } }