Skip to main content

WIT

Constant WIT 

Source
pub const WIT: &str = "// The Standard Code plugin contract, version 2 (docs/plugin-runtime.md).\n//\n// Every plugin is a wasm component against this package. A UI plugin targets\n// `ui-plugin` and paints through shared buffers in its own linear memory that\n// the viewer samples on its paced frame cadence. A daemon plugin targets\n// `daemon-plugin` inside `standardd` and never renders.\n//\n// Every interface of a world is linked at instantiation. Grants are checked\n// per call: a call the plugin\'s approved grants do not cover returns\n// `call-error::grant-denied` naming the missing grant, and the host counts the\n// denial. Imports outside the world fail at instantiation, before any call.\npackage standard:plugin@2.0.0;\n\n/// Types shared by every interface.\ninterface types {\n    /// A JSON document as text. Values, configuration, events, live messages\n    /// and call payloads are all JSON.\n    type json = string;\n\n    /// Why a host call did not run.\n    variant call-error {\n        /// The manifest does not carry the grant the call needs. The payload\n        /// names the grant (`values.read:git.*`, `account.read`, ...).\n        grant-denied(string),\n        /// The per-plugin rate limit for this call kind was reached.\n        rate-limited,\n        /// The backing service is not reachable right now.\n        unavailable(string),\n        /// The arguments were malformed (an unknown surface id, an oversized\n        /// value, a key outside the plugin\'s namespace).\n        invalid(string),\n    }\n\n    /// Where an event or call is delivered.\n    variant target {\n        /// Every listener on the account.\n        all,\n        /// Every viewer.\n        viewers,\n        /// Every daemon.\n        daemons,\n        /// The daemon on one machine, by machine id.\n        machine(string),\n        /// The singleton daemon of the plugin.\n        singleton,\n    }\n}\n\n/// Durable key-value state on the account, namespaced by plugin id.\n/// Grants: `values.read:<prefix>` and `values.write:<prefix>`; the plugin\'s\n/// own id is the default prefix.\ninterface values {\n    use types.{json, call-error};\n\n    get: func(key: string) -> result<option<json>, call-error>;\n    set: func(key: string, value: json) -> result<_, call-error>;\n    delete: func(key: string) -> result<_, call-error>;\n    keys: func(prefix: string) -> result<list<string>, call-error>;\n    /// Ask for `event::value-changed` for keys under the prefix.\n    watch: func(prefix: string) -> result<_, call-error>;\n}\n\n/// The unstored latest-value channel. Grants: `live.publish:<prefix>` and\n/// `live.subscribe:<prefix>`. Deliveries arrive as `event::live`.\ninterface live {\n    use types.{json, call-error};\n\n    publish: func(key: string, payload: json) -> result<_, call-error>;\n    /// Withdraws the latest value of `key`: subscribers hear\n    /// `event::live-deleted`, and a later subscriber sees nothing for it.\n    /// Grant: the same `live.publish:<prefix>` as publishing it.\n    delete: func(key: string) -> result<_, call-error>;\n    subscribe: func(prefix: string) -> result<_, call-error>;\n    unsubscribe: func(prefix: string) -> result<_, call-error>;\n}\n\n/// Named, unstored messages between plugins. The plugin\'s own namespace\n/// (`<id>.*`) needs no grant; `global.*`, another plugin\'s namespace and\n/// `system.*` need `events.emit:<ns>` or `events.on:<ns>`. Deliveries arrive\n/// as `event::plugin-event`.\n///\n/// The host delivers one system event to a daemon plugin unasked:\n/// `system.plugin.interest` with `{ \"surfaces\": [<surface id>, ...] }`,\n/// the plugin\'s UI surfaces some viewer on the account shows now (the union\n/// over every viewer; an instance counts as its surface), once when the\n/// plugin starts and again whenever it changes. A daemon half reads outside\n/// sources for its UI only while it names something.\ninterface events {\n    use types.{json, call-error, target};\n\n    emit: func(name: string, payload: json, to: target) -> result<_, call-error>;\n    on: func(pattern: string) -> result<_, call-error>;\n    off: func(pattern: string) -> result<_, call-error>;\n}\n\n/// Request/response to a companion plugin. Grant: `call:<companion>`\n/// (implied for companions).\n///\n/// A UI plugin prefers `send` and `call-async`: neither blocks its thread,\n/// so `event` and `frame` stay within their budgets while the companion\n/// works. At most 32 `send`s and `call-async`s of one plugin are in flight\n/// at once; past that they answer `rate-limited`.\ninterface calls {\n    use types.{json, call-error, target};\n\n    /// Calls `method` and waits for the answer: at most `timeout-ms` (10 s\n    /// when none, 30 s at most), then `unavailable(\"call_timeout\")`. Blocks\n    /// the plugin\'s thread meanwhile (never the viewer\'s); in a browser\n    /// without JSPI it answers `unavailable`.\n    call: func(method: string, payload: json, to: target, timeout-ms: option<u32>) -> result<json, call-error>;\n\n    /// Sends `method` and returns at once: nothing answers. For commands\n    /// whose outcome arrives another way (a value, a live message).\n    send: func(method: string, payload: json, to: target) -> result<_, call-error>;\n\n    /// Starts a call and returns its id at once; the answer (or its error,\n    /// a timeout included) arrives later as `event::call-result` with that\n    /// id. Ids are unique for the life of the plugin, restarts included.\n    call-async: func(method: string, payload: json, to: target, timeout-ms: option<u32>) -> result<u64, call-error>;\n}\n\n/// The plugin\'s configuration document, as the account stores it. No grant.\ninterface config {\n    use types.{json};\n\n    get: func() -> json;\n}\n\n/// The plugin\'s own report of how it is doing, shown beside its runtime\n/// state in the Plugins view (a UI plugin\'s, per viewer) and by\n/// `standard plugin health` (a daemon plugin\'s, per machine). Each call\n/// replaces the last report; a plugin that never calls is `ok`. No grant.\ninterface health {\n    enum health-state {\n        ok,\n        /// Working, with a problem the user may want to know about (a\n        /// provider unreachable, a watch that stopped).\n        degraded,\n        /// Not doing its job until something changes.\n        failed,\n    }\n\n    /// Reports `state` with a short message for the user (at most 200\n    /// characters are kept; empty for `ok`).\n    set: func(state: health-state, message: string);\n}\n\n/// Named secrets the user entered for this plugin. Grant: `secret:<NAME>`.\ninterface secrets {\n    use types.{call-error};\n\n    get: func(name: string) -> result<option<string>, call-error>;\n}\n\n/// Read-only account state. Grant: `account.read`. Never what is inside a\n/// pane: no screen, scrollback, input or output exists in this world.\ninterface account {\n    use types.{call-error};\n\n    record machine {\n        id: string,\n        name: string,\n        online: bool,\n    }\n\n    record project {\n        id: string,\n        name: string,\n        machine: string,\n        path: string,\n    }\n\n    enum agent-status {\n        none,\n        working,\n        idle,\n        waiting-for-input,\n    }\n\n    record pane {\n        id: string,\n        /// The pane\'s generation: 1 at creation, advanced by every restart\n        /// and restore. A pane id with its generation names one run of the\n        /// pane (`<id>@<generation>`); 0 while unknown.\n        generation: u64,\n        machine: string,\n        project: option<string>,\n        title: string,\n        /// The pane\'s current directory when the host knows it, else its\n        /// project root. A daemon learns it when an event already fires\n        /// for the pane (its creation, a new foreground program, an agent\n        /// hook), and a new directory arrives as a `changed` pane.\n        cwd: string,\n        cols: u32,\n        rows: u32,\n        /// The foreground program name, when known.\n        program: option<string>,\n        /// The agent the pane runs, when one is detected.\n        agent: option<string>,\n        agent-status: agent-status,\n    }\n\n    record account-state {\n        machines: list<machine>,\n        projects: list<project>,\n        panes: list<pane>,\n    }\n\n    state: func() -> result<account-state, call-error>;\n    /// Ask for `event::account-changed` on every change.\n    watch: func() -> result<_, call-error>;\n}\n\n/// Exactly-once effects across the runtimes of one plugin. Every viewer on\n/// the account runs its own instance of a UI plugin, and a fleet daemon\n/// plugin runs on every daemon; an effect that must happen once (a\n/// notification, a write another instance would repeat) is claimed first,\n/// and only the instance whose claim succeeded performs it. A singleton\'s\n/// claims carry its lease epoch like every other write. Keys live in the\n/// plugin\'s own namespace. No grant.\ninterface claims {\n    use types.{call-error};\n\n    /// Claims `key` for `ttl-ms`. `true`: this instance holds the claim and\n    /// performs the effect. `false`: another instance holds it. A claim\n    /// held by this instance is renewed.\n    claim: func(key: string, ttl-ms: u32) -> result<bool, call-error>;\n    /// Gives up a claim this instance holds; nothing when it holds none.\n    release: func(key: string) -> result<_, call-error>;\n}\n\n/// Where a UI plugin paints. UI world only.\n///\n/// A surface is one region of the plugin\'s own linear memory, laid out as the\n/// host describes (`layout`), double-buffered with a sequence number so a\n/// half-written slot is never sampled. The plugin allocates the region at the\n/// size the host reports, attaches it, paints one slot, and commits with the\n/// dirty rectangles. The viewer samples committed slots only when a frame is\n/// due and the surface is visible, and reads only the dirty rectangles.\ninterface surface {\n    use types.{call-error};\n\n    enum model {\n        /// Graphemes, colours and attributes per cell.\n        cells,\n        /// RGBA8 pixels, the surface\'s size in cells times the cell pixel size.\n        pixels,\n    }\n\n    /// The size a surface currently has. `cols` and `rows` are cells;\n    /// `px-w`/`px-h` are the pixel size of the pixels model (zero while the\n    /// viewer has no pixel geometry); `cell-px-w`/`cell-px-h` the pixel size\n    /// of one cell.\n    record geometry {\n        cols: u32,\n        rows: u32,\n        px-w: u32,\n        px-h: u32,\n        cell-px-w: u32,\n        cell-px-h: u32,\n    }\n\n    /// How the region must be laid out, in bytes.\n    record region-layout {\n        /// Total length of the region: `header-len + 2 * slot-len`.\n        len: u32,\n        /// The header at offset zero: eight little-endian u32 words\n        /// `seq, model, cols, rows, px-w, px-h, cell-px-w, cell-px-h`.\n        header-len: u32,\n        /// Bytes per slot. Cells: `cols * rows * 16`\n        /// (`grapheme: u32, fg: u32, bg: u32, attrs: u16, pad: u16`).\n        /// Pixels: `px-w * px-h * 4` RGBA8.\n        slot-len: u32,\n        model: model,\n        geometry: geometry,\n    }\n\n    record rect {\n        x: u32,\n        y: u32,\n        w: u32,\n        h: u32,\n    }\n\n    /// The layout the named surface needs right now. `invalid` for an id the\n    /// manifest does not declare.\n    layout: func(id: string) -> result<region-layout, call-error>;\n\n    /// Bind a region of the plugin\'s memory as the surface\'s buffer. The\n    /// region must be at least `region-layout.len` bytes and carry the header for\n    /// the current geometry. Attaching again after `event::resize` rebinds\n    /// the surface to a new region; the host keeps sampling the old region\n    /// until the first commit at the new size and never reads it after that\n    /// commit, so the plugin may free it once that commit returns.\n    attach: func(id: string, region: list<u8>) -> result<_, call-error>;\n\n    /// Publish the slot the plugin just painted. `slot` is 0 or 1; `dirty`\n    /// lists the changed rectangles in cells (cells model) or pixels (pixels\n    /// model). An empty list changes nothing and requests no frame. The\n    /// first commit after a resize is treated as fully dirty.\n    commit: func(id: string, slot: u8, dirty: list<rect>) -> result<_, call-error>;\n\n    detach: func(id: string) -> result<_, call-error>;\n\n    /// Opens a surface the viewer shows only on request: a `stage` or a\n    /// `panel.popover`. Allowed only while the plugin handles a user\n    /// gesture (a `key`, `paste` or pointer `down` on one of its surfaces,\n    /// or one of its `command`s); `invalid` otherwise, and for any other\n    /// anchor. The surface receives `visibility` and `focus` once the\n    /// viewer shows it.\n    open: func(id: string) -> result<_, call-error>;\n\n    /// Closes a surface `open` opened; nothing when it is not open. Needs no\n    /// gesture. The user closes it too (Escape, or a click outside it); the\n    /// plugin sees `focus(id, false)` and `visibility(id, false)` either way.\n    close: func(id: string) -> result<_, call-error>;\n\n    /// Asks for a size instead of the manifest\'s `height`/`width`: `cols`\n    /// and `rows` in cells, 0 for \"the viewer\'s choice\" in that dimension,\n    /// except the rows of a `machine.after` or `project.after` instance,\n    /// where 0 is no rows: the instance is not drawn, takes no space and is\n    /// hidden until it asks for rows again. The viewer clamps it to what\n    /// the anchor allows where it places the surface (a card\'s width is\n    /// the sidebar\'s; a popover fits the modal area) and answers with a\n    /// `resize` when the size changes. Stays in force until asked again;\n    /// `invalid` for an unknown surface. An instance id\n    /// (`<surface>@<owner>`) may be asked before the viewer has sized it.\n    request-size: func(id: string, cols: u32, rows: u32) -> result<_, call-error>;\n\n    /// Sets a short label the viewer shows at the right end of the\n    /// surface\'s chrome title: a boxed `sidebar.card`\'s top border, a\n    /// `pane`\'s header, a `column`\'s title row. `none` removes it. At most\n    /// 48 characters with no control characters; `invalid` otherwise, and\n    /// for an unknown surface. Stays until set again.\n    set-label: func(id: string, label: option<string>) -> result<_, call-error>;\n\n    /// A cell of a surface, from its top left.\n    record caret {\n        col: u32,\n        row: u32,\n    }\n\n    /// Places the viewer\'s own text cursor at `caret` in the surface while\n    /// the surface takes keys (an open `stage`, `panel.popover` or\n    /// `pane.overlay`, or the surface a click or `open` gave input focus),\n    /// so a text field draws no cursor of its own: the viewer paints its\n    /// cursor there, and the cursor trail moves to it as it moves between\n    /// panes. `none` removes it; a caret outside the surface is not drawn.\n    /// `invalid` for an unknown surface. Stays until set again.\n    set-caret: func(id: string, caret: option<caret>) -> result<_, call-error>;\n}\n\n/// Viewer-local state and capabilities. UI world only. No grant.\ninterface view {\n    use types.{call-error};\n\n    /// Whether this viewer is the one the user is controlling.\n    is-driving: func() -> bool;\n\n    /// The viewer\'s theme colours as 0xRRGGBB.\n    record theme-colours {\n        fg: u32,\n        bg: u32,\n        /// `fg` receded toward `bg`: \"grayed out\" (never a fixed gray).\n        recede-fg: u32,\n        recede-bg: u32,\n        accent: u32,\n        /// The terminal\'s 16 ANSI colours, 0 to 15, as the viewer resolved\n        /// them (the xterm defaults where the terminal did not say).\n        palette: list<u32>,\n    }\n\n    theme: func() -> theme-colours;\n\n    record viewer-capabilities {\n        /// Whether the pixels model paints as real graphics here.\n        graphics: bool,\n        /// The pixel size of one cell of this plugin\'s pixels surfaces.\n        cell-px-w: u32,\n        cell-px-h: u32,\n        /// The frame rate this plugin gets right now: the viewer\'s paced\n        /// rate, lowered by what the terminal link sustains and by the\n        /// slow-plugin policy.\n        fps: u32,\n        /// Device pixels per surface pixel: 1, or 2 while the slow-plugin\n        /// policy has halved this plugin\'s pixel resolution (the viewer\n        /// scales the image up).\n        pixel-scale: u32,\n    }\n\n    capabilities: func() -> viewer-capabilities;\n\n    /// The focused pane\'s id, when one is focused.\n    focused-pane: func() -> option<string>;\n\n    /// Shows the pane with id `pane` in this viewer\'s workspace and gives\n    /// it focus, as a click on its sidebar row does. Allowed only while the\n    /// plugin handles a user gesture (a `key`, `paste` or pointer `down` on\n    /// one of its surfaces, or one of its `command`s); `invalid` otherwise.\n    /// A pane the viewer does not know is ignored.\n    focus-pane: func(pane: string) -> result<_, call-error>;\n\n    /// A pane and its generation (`account.pane`\'s `id` and `generation`).\n    record pane-ref {\n        id: string,\n        /// 0 while the viewer does not know it.\n        generation: u64,\n    }\n\n    /// The pane an instance surface belongs to, with its generation now. A\n    /// `pane.footer` or `pane.header` surface has one instance per pane\n    /// the viewer shows, named `<surface-id>@<pane-id>`; it arrives as\n    /// `resize` and `visibility` for that id, and the plugin creates a\n    /// surface by it. None for any other id.\n    surface-pane: func(surface: string) -> option<pane-ref>;\n\n    /// The machine an instance surface belongs to: a `machine.after`\n    /// surface has one instance per machine the viewer shows, named\n    /// `<surface-id>@<machine-id>`. None for any other id.\n    surface-machine: func(surface: string) -> option<string>;\n\n    /// The project an instance surface belongs to: a `project.after`\n    /// surface has one instance per project the viewer shows, named\n    /// `<surface-id>@<project-id>`. None for any other id.\n    surface-project: func(surface: string) -> option<string>;\n\n    /// The identity tint (0xRRGGBB) of what an instance surface belongs\n    /// to: a `machine.after` instance\'s machine, a `project.after`\n    /// instance\'s project, a pane instance\'s project (else its machine).\n    /// None without one, or for any other id.\n    surface-tint: func(surface: string) -> option<u32>;\n\n    /// The identity tint of a machine or project, by id, as the viewer\n    /// paints it; none when it has none.\n    identity-tint: func(id: string) -> option<u32>;\n\n    /// Asks for a `frame()` on the next paced frame, from any export\n    /// (an `event` included). Without a request, a commit made in `event`\n    /// is sampled on the next frame something else causes.\n    request-frame: func();\n\n    /// Asks for a `frame()` at `at-ms` on the viewer\'s clock (the clock\n    /// `frame` receives as `now-ms`). The earliest request wins.\n    wake-at: func(at-ms: u64);\n\n    /// The machine this viewer runs on, by the account\'s machine id; none\n    /// for a viewer that is not an enrolled machine (a browser).\n    machine-id: func() -> option<string>;\n\n    /// This viewer instance: the same for every plugin of one running\n    /// viewer, different in every other viewer (another terminal on the\n    /// same machine included) and after a restart.\n    instance-id: func() -> string;\n\n    /// The wall clock where the viewer runs: milliseconds since the Unix\n    /// epoch. For dates and countdowns; frames keep to `now-ms`.\n    wall-ms: func() -> u64;\n\n    /// The viewer\'s local time zone\'s offset from UTC right now, in\n    /// minutes, east positive (UTC+2 is 120). Follows daylight saving.\n    utc-offset-minutes: func() -> s32;\n\n    /// The viewer\'s IANA time zone name (`Europe/Berlin`), when known.\n    time-zone: func() -> option<string>;\n}\n\n/// Opens web pages in the user\'s browser. UI world only. Grant:\n/// `url.open:<host>` (`url.open:*.example.com` for its subdomains too,\n/// `url.open:*` for any host).\ninterface url {\n    use types.{call-error};\n\n    /// Opens `url` in the user\'s browser: on the machine the viewer runs on\n    /// (the system opener natively, a new tab in a browser viewer). Only\n    /// `https://` URLs, and only as a direct result of user input: while\n    /// the plugin handles a key, paste, pointer press or command on its\n    /// surfaces, or within one second after one was delivered, and once\n    /// per input. `invalid` otherwise, or for a URL that is not https, has\n    /// no host, or carries whitespace or control characters;\n    /// `grant-denied(url.open:<host>)` for a host no grant names.\n    open: func(url: string) -> result<_, call-error>;\n}\n\n/// What a plugin is told, beyond its frame callback.\ninterface event-types {\n    use surface.{geometry};\n    use types.{json, call-error};\n\n    /// The answer to `calls.call-async`.\n    record call-result {\n        /// The id `call-async` returned.\n        id: u64,\n        outcome: result<json, call-error>,\n    }\n\n    /// Modifier bits of `key.modifiers` and `pointer.modifiers`:\n    /// 1 shift, 2 ctrl, 4 alt (option), 8 super (command).\n\n    enum key-phase {\n        press,\n        /// The key is held and repeats.\n        repeat,\n        /// Only where the viewer\'s terminal reports releases.\n        release,\n    }\n\n    /// A key on the surface with input focus.\n    record key {\n        surface: string,\n        /// A character key is the character it types (`a`, `A`, `1`, `?`,\n        /// `\u{e9}`); a named key is one of `enter`, `tab`, `backtab`,\n        /// `backspace`, `delete`, `insert`, `space`, `left`, `right`, `up`,\n        /// `down`, `home`, `end`, `pageup`, `pagedown`, `f1` to `f12`.\n        /// Escape never arrives: it closes an open surface.\n        code: string,\n        /// The text the key types, when it types text.\n        text: option<string>,\n        modifiers: u32,\n        phase: key-phase,\n    }\n\n    enum pointer-kind {\n        down,\n        up,\n        /// Motion with no button held.\n        move,\n        /// Motion with a button held.\n        drag,\n        /// One wheel step; `button` says which way.\n        wheel,\n        /// The pointer moved onto the surface (before its first `move`).\n        enter,\n        /// The pointer left the surface: moved elsewhere, or the surface\n        /// was hidden under it. `x`/`y`, `col`/`row` are the last position\n        /// on it.\n        leave,\n    }\n\n    /// The pointer over one of the plugin\'s surfaces.\n    record pointer {\n        surface: string,\n        /// The position in the surface\'s own units: cells in the cells\n        /// model, surface pixels in the pixels model (sub-cell where the\n        /// viewer knows the pointer\'s pixel position, else the cell\'s\n        /// centre).\n        x: u32,\n        y: u32,\n        /// The cell under the pointer.\n        col: u32,\n        row: u32,\n        /// 0 none, 1 left, 2 middle, 3 right; for `wheel`: 4 up, 5 down,\n        /// 6 left, 7 right.\n        button: u8,\n        kind: pointer-kind,\n        modifiers: u32,\n    }\n\n    variant event {\n        /// A surface changed size or model; call `surface.layout`,\n        /// allocate, attach.\n        resize(tuple<string, geometry>),\n        /// A surface became visible or hidden.\n        visibility(tuple<string, bool>),\n        /// Graphics support, cell pixel size, frame rate or pixel scale\n        /// changed (`view.capabilities`).\n        capabilities-changed,\n        /// `view.is-driving` changed.\n        driving(bool),\n        /// A watched value changed (`values.watch`).\n        value-changed(tuple<string, option<json>>),\n        /// A live message (`live.subscribe`).\n        live(tuple<string, json>),\n        /// A plugin event (`events.on`).\n        plugin-event(tuple<string, json>),\n        /// The account snapshot changed (`account.watch`).\n        account-changed,\n        key(key),\n        /// Text pasted into the surface with input focus: surface, text.\n        paste(tuple<string, string>),\n        pointer(pointer),\n        /// The viewer\'s theme changed; read `view.theme`.\n        theme-changed,\n        /// A surface gained or lost input focus: surface, focused.\n        focus(tuple<string, bool>),\n        /// The user ran one of the manifest\'s `commands`, by id.\n        command(string),\n        /// A `calls.call-async` finished.\n        call-result(call-result),\n        /// A live key was withdrawn (`live.delete`).\n        live-deleted(string),\n    }\n\n    enum power {\n        mains,\n        save-power,\n    }\n}\n\n/// A UI plugin: runs in every viewer, paints into its surfaces, never has\n/// side effects on the account beyond what its grants allow.\nworld ui-plugin {\n    import types;\n    import values;\n    import live;\n    import events;\n    import calls;\n    import config;\n    import secrets;\n    import account;\n    import health;\n    import surface;\n    import view;\n    import event-types;\n    import claims;\n    import url;\n\n    use event-types.{event, power};\n\n    /// Called once after instantiation with the configuration document.\n    export activate: func(config: string);\n\n    /// Called when a paced frame is due and at least one of the plugin\'s\n    /// surfaces is visible. `now-ms` is the viewer\'s monotonic clock,\n    /// `interval-ms` the paced frame interval. Returns the `now-ms` at which\n    /// the plugin next wants a frame callback (`now-ms` for the next frame,\n    /// a later instant for a clock, none to wait for an event). Nothing wakes\n    /// an idle viewer otherwise.\n    export frame: func(now-ms: u64, interval-ms: u32, power: power) -> option<u64>;\n\n    export event: func(e: event);\n\n    export deactivate: func();\n}\n\n/// A daemon plugin: runs inside `standardd`, never renders. Every interface\n/// of the world is linked, and the system interfaces check the plugin\'s\n/// grants per call. `standardd` also links WASI 0.2 beside them (a plugin\n/// built with the SDK\'s `wasi` feature imports it): `wasi:filesystem` with\n/// exactly the directories the `fs.read:<path>` and `fs.write:<path>` grants\n/// name preopened (`/` under `machine.full`), `wasi:http/outgoing-handler`\n/// to the hosts `fetch:<host>` grants name, `wasi:sockets` only under\n/// `network.full` or `machine.full`, clocks, random, and stdout/stderr into\n/// the daemon\'s log prefixed with the plugin id.\nworld daemon-plugin {\n    import types;\n    import values;\n    import live;\n    import events;\n    import calls;\n    import config;\n    import secrets;\n    import account;\n    import health;\n    import claims;\n    import daemon-context;\n    import daemon-process;\n    import daemon-watch;\n    import daemon-panes;\n    import daemon-net;\n\n    use event-types.{event};\n\n    export activate: func(config: string);\n    export event: func(e: event);\n\n    /// What happened on the daemon\'s machine: watched files changed, a\n    /// child wrote output or exited, a pane changed.\n    export daemon-events;\n\n    /// Answers `calls.call` from the UI plugin with the same id.\n    export companion;\n\n    /// Drives the plugin\'s pending work: called after `activate`, after\n    /// every `event`, `handle-event` and `handle-call`, and at the instant\n    /// the previous call asked for. `now-ms` is the daemon\'s monotonic\n    /// clock. Returns the `now-ms` at which the plugin next wants a call\n    /// (none: only on an event). (Not named `poll`: a daemon plugin may\n    /// link wasi-libc, which defines a `poll` symbol.)\n    export drive: func(now-ms: u64) -> option<u64>;\n\n    export deactivate: func();\n}\n\n/// What a daemon plugin answers: `calls.call` from the UI plugin with the\n/// same id (its companion). An exported interface rather than a world-level\n/// function, so the world needs no `use` of `types` and the UI world a\n/// shared SDK links beside it carries none either.\ninterface companion {\n    use types.{json, call-error};\n\n    /// Who made a call, as the account routed it.\n    record caller {\n        /// The machine the calling runtime runs on.\n        machine-id: string,\n        plugin-id: string,\n        /// `ui` or `daemon`.\n        kind: string,\n        /// The caller\'s lease epoch, when a singleton daemon called.\n        epoch: option<u64>,\n        /// The account controller lease when the call was made: the machine\n        /// the user controls from and its fencing token. A plugin acting for\n        /// the user compares it with the caller\'s machine.\n        controller-machine-id: option<string>,\n        controller-fencing-token: option<string>,\n    }\n\n    /// Answers one call. `invalid` for a method the plugin does not know.\n    handle-call: func(method: string, payload: json, %from: caller) -> result<json, call-error>;\n}\n\n/// Spawn programs on the daemon\'s machine. Grant: `process.exec:<program>`\n/// (the program exactly as spawned; `process.exec:*` for any), or\n/// `machine.full`. Children run in their own process group; the host kills\n/// every group a plugin started when the plugin stops.\ninterface daemon-process {\n    use types.{call-error};\n\n    record spawned {\n        pid: u32,\n    }\n\n    /// Where a child\'s standard stream goes.\n    enum stdio {\n        /// Nowhere (`/dev/null`).\n        null,\n        /// To the plugin: output arrives as `daemon-event::process-output`,\n        /// input goes through `write`.\n        piped,\n        /// The daemon\'s log, each line prefixed with the plugin id (output\n        /// streams only; stdin reads nothing).\n        log,\n    }\n\n    record command {\n        program: string,\n        args: list<string>,\n        /// Variables set on top of the plugin\'s environment\n        /// (`daemon-context.environment`), after `env-remove`.\n        env: list<tuple<string, string>>,\n        /// Variables removed from the plugin\'s environment before `env` is\n        /// applied (`GIT_DIR`, say).\n        env-remove: list<string>,\n        /// Start from an empty environment: only `env`.\n        clear-env: bool,\n        cwd: option<string>,\n        stdin: stdio,\n        stdout: stdio,\n        stderr: stdio,\n    }\n\n    /// Spawns `program` with `args` in the plugin\'s environment: stdin\n    /// empty, output to the log. `cwd` defaults to the user\'s home.\n    spawn: func(program: string, args: list<string>, cwd: option<string>) -> result<spawned, call-error>;\n    /// Spawns a command with its environment and streams.\n    run: func(command: command) -> result<spawned, call-error>;\n    /// Writes to a piped stdin.\n    write: func(pid: u32, bytes: list<u8>) -> result<_, call-error>;\n    /// Closes a piped stdin (the child reads end of file).\n    close-stdin: func(pid: u32) -> result<_, call-error>;\n    /// The exit status once the child has exited (a signal is its negated\n    /// number); none while it runs.\n    try-wait: func(pid: u32) -> result<option<s32>, call-error>;\n    /// Blocks the plugin until the child exits. Prefer awaiting\n    /// `daemon-event::process-exited`.\n    wait: func(pid: u32) -> result<s32, call-error>;\n    /// Blocks the plugin until the child exits or `timeout-ms` passes:\n    /// its exit status, or none when it still runs.\n    wait-timeout: func(pid: u32, timeout-ms: u32) -> result<option<s32>, call-error>;\n    /// Kills the child\'s process group.\n    kill: func(pid: u32) -> result<_, call-error>;\n}\n\n/// Where a daemon plugin runs and the environment it runs with. Daemon\n/// world only; no grant.\n///\n/// The environment is the daemon user\'s login environment reduced to a\n/// safe set: `HOME`, `USER`, `LOGNAME`, `PATH` (the login shell\'s, with its\n/// version managers), `LANG`, every `LC_*`, `TMPDIR` and `SHELL`. Under\n/// `machine.full` it is the whole login environment. WASI sees the same\n/// variables (and `PWD`, the home directory); children inherit them.\ninterface daemon-context {\n    /// The machine this daemon runs on, by the account\'s machine id.\n    machine-id: func() -> string;\n    /// The account this daemon is enrolled in, once the daemon has read it.\n    account-id: func() -> option<string>;\n    /// The plugin\'s environment, sorted by name.\n    environment: func() -> list<tuple<string, string>>;\n    /// The lease epoch this instance runs under: a singleton\'s, which\n    /// every write of its account session carries (a later epoch means the\n    /// lease moved and this instance is stopping). None for a fleet plugin.\n    lease-epoch: func() -> option<u64>;\n\n    /// The Standard Code build this daemon runs.\n    record release-info {\n        /// The channel it came from: `branch:<name>` for a branch build,\n        /// else the published channel\'s name (`team`, `canary`,\n        /// `production`).\n        channel: string,\n        version: string,\n        /// The commit it was built from.\n        git-sha: string,\n    }\n\n    /// The build this daemon runs; none where it is not known (a local\n    /// development daemon).\n    release: func() -> option<release-info>;\n}\n\n/// WebSockets the host holds for the plugin, to servers a\n/// `socket.connect:<host>:<port>` grant names (`wss://` only). The host\n/// connects, answers and sends pings, and delivers what happens as the\n/// plugin event `system.net.websocket` with a JSON payload\n/// `{\"socket\": <handle>, \"kind\": \"open\" | \"message\" | \"closed\",\n/// \"text\": <frame>, \"reason\": <why>}`, so a plugin waiting for frames is\n/// never woken for nothing. Frames are text, 64 KiB at most; eight sockets\n/// per instance; they close when the instance ends.\ninterface daemon-net {\n    use types.{call-error};\n\n    /// Starts connecting to `url` with extra request `headers` (none that\n    /// the handshake owns: `Host`, `Upgrade`, `Connection`, `Sec-*`). The\n    /// handle\'s `open` or `closed` event follows.\n    websocket-open: func(url: string, headers: list<tuple<string, string>>) -> result<u32, call-error>;\n    /// Sends one text frame.\n    websocket-send: func(socket: u32, text: string) -> result<_, call-error>;\n    /// Closes the socket; its `closed` event follows.\n    websocket-close: func(socket: u32);\n}\n\n/// File and directory change events, debounced by the host and delivered\n/// as `daemon-event::file-changed`. Grant: `fs.read:<path>` covering the\n/// path, or `machine.full`. The host never polls: a watcher that fails is\n/// reported as `daemon-event::watch-failed`. A plugin holds at most 256\n/// watches at once (`rate-limited` past that).\ninterface daemon-watch {\n    use types.{call-error};\n\n    record watch-options {\n        /// A directory and everything under it (true), or its own entries\n        /// only. Ignored for a file.\n        recursive: bool,\n        /// Globs relative to the watched path whose changes are dropped\n        /// before they reach the plugin: `*` within a component, `?` one\n        /// character, `**` any number of components. A glob without `/`\n        /// matches a component at any depth (`target`, `*.log`); one with\n        /// `/` is anchored at the watched path (`.git/objects`), and a\n        /// leading `/` anchors a single name there, as in `.gitignore`\n        /// (`/target`). Excluding a directory excludes everything in it. At\n        /// most 64.\n        exclude: list<string>,\n    }\n\n    /// Watches a file or a directory.\n    watch: func(path: string, options: watch-options) -> result<u32, call-error>;\n    unwatch: func(handle: u32) -> result<_, call-error>;\n}\n\n/// Panes on the daemon\'s machine. Grants: `panes.read` to list, subscribe\n/// and wait; `panes.write` to create, type into and close. Writes follow the\n/// daemon\'s own controller rules: a pane is created and typed into only\n/// while this machine holds the account\'s controller lease.\ninterface daemon-panes {\n    use types.{call-error};\n    use account.{pane};\n\n    /// A pane `create` opened: its id and generation (`account.pane`\'s),\n    /// together naming this run of it (`<id>@<generation>`).\n    record created-pane {\n        id: string,\n        generation: u64,\n    }\n\n    panes: func() -> result<list<pane>, call-error>;\n    /// Asks for `daemon-event::pane-changed` for this machine\'s panes.\n    subscribe: func() -> result<_, call-error>;\n    unsubscribe: func() -> result<_, call-error>;\n    /// Opens a pane in `cwd`: a project root of this machine or a directory\n    /// inside one (by whole components, after symlinks), which names the\n    /// project the pane belongs to. It runs `command` through the user\'s\n    /// login shell, or the shell itself when none, with `env` set on top of\n    /// its login environment (at most 64 variables; a name is not empty\n    /// and has no `=`, neither side a NUL). `invalid` for a directory\n    /// outside every project root.\n    create: func(cwd: string, command: option<string>, env: list<tuple<string, string>>) -> result<created-pane, call-error>;\n\n    /// What `create-with` opens: `create`\'s arguments and the pane\'s title.\n    record new-pane {\n        cwd: string,\n        command: option<string>,\n        env: list<tuple<string, string>>,\n        /// The pane\'s title (at most 128 characters, no control\n        /// characters); the plugin\'s id when none.\n        title: option<string>,\n    }\n\n    /// `create`, with a title.\n    create-with: func(pane: new-pane) -> result<created-pane, call-error>;\n    input: func(pane: string, bytes: list<u8>) -> result<_, call-error>;\n    close: func(pane: string) -> result<_, call-error>;\n    /// Blocks until the pane exits or closes, for at most `timeout-ms`\n    /// (capped at 30 s). Whether it did.\n    wait: func(pane: string, timeout-ms: u32) -> result<bool, call-error>;\n}\n\n/// What happens on the daemon\'s machine. An exported interface, like\n/// `companion`, so a UI component built with the same SDK never imports\n/// these types.\ninterface daemon-events {\n    use account.{pane};\n\n    record process-output {\n        pid: u32,\n        /// Standard error rather than standard output.\n        stderr: bool,\n        bytes: list<u8>,\n    }\n\n    record file-change {\n        /// The handle `daemon-watch.watch` returned.\n        watch: u32,\n        /// Every path that changed since the previous delivery.\n        paths: list<string>,\n    }\n\n    enum pane-change-kind {\n        created,\n        /// Title, size or agent state changed.\n        changed,\n        exited,\n        closed,\n    }\n\n    record pane-change {\n        kind: pane-change-kind,\n        pane: pane,\n    }\n\n    variant daemon-event {\n        file-changed(file-change),\n        /// A watch stopped delivering: its handle and the watcher\'s error.\n        watch-failed(tuple<u32, string>),\n        /// Output from a piped stream; at most 64 KiB per event.\n        process-output(process-output),\n        /// A child exited: its pid and status (a signal is negated). Sent\n        /// after the last of its output.\n        process-exited(tuple<u32, s32>),\n        pane-changed(pane-change),\n    }\n\n    /// Called with each event, in order; the plugin is driven afterwards.\n    handle-event: func(e: daemon-event);\n}\n";
Expand description

The WIT package standard:plugin@2.0.0 (wit/plugin.wit): the one copy the SDK bindings, the viewer and daemon hosts and the CLI use.