Follow Discord
Sweep 25 Sep 2026 · 19:33Z Build v2.1.283 504 read Stable v2.1.274 Latest v2.1.283 Next v2.1.283 Feeds RSS JSON llms.txt llms-full.txt Unofficial
Mods API · 03 of 03

Types

Every declaration in the file, verbatim, with the doc comment above it.

Declarations570over 12 pages
Mined from2.1.283the shipped binary

Every named declaration in the file, 570 of them, verbatim and in the order Claude Code wrote them, 50 to a page. This is the page to land on from a signature: a verb that returns ToolCallResult links here, at whichever page it is on, and what you get is the declaration itself rather than a description of it.

The source is 13,820 lines of TypeScript mined from build 2.1.283. Anything longer than 12 lines is folded; click the line count to open it. To find a name on another page, search every symbol.

Names on this page, 101 to 150 of 570

ElicitationHookInput type # line 3482

Added in 2.1.265

Hook input for the Elicitation event. Fired when an MCP server requests user input. Hooks can auto-respond (accept/decline) instead of showing the dialog.

  type ElicitationHookInput = BaseHookInput & {
      hook_event_name: 'Elicitation';
      mcp_server_name: string;
      message: string;
      mode?: 'form' | 'url';
      url?: string;
      elicitation_id?: string;
      requested_schema?: Record<string, unknown>;
  };

ElicitationResultHookInput type # line 3495

Added in 2.1.265

Hook input for the ElicitationResult event. Fired after the user responds to an MCP elicitation. Hooks can observe or override the response before it is sent to the server.

  type ElicitationResultHookInput = BaseHookInput & {
      hook_event_name: 'ElicitationResult';
      mcp_server_name: string;
      elicitation_id?: string;
      mode?: 'form' | 'url';
      action: 'accept' | 'decline' | 'cancel';
      content?: Record<string, unknown>;
  };

EngineCreateInput type # line 3512

In the first published surface (2.1.259)

The input of engine.create: the fold that builds $, once per load, core innermost.

A hook is written in post-order: const built = await next(e) is $ as built so far; return { ...built, voice: { say } } adds this plugin's noun. See EngineEventOf's engine.create for what a step may and may not do.

  export type EngineCreateInput = {
      /**
       * The modules this fold builds, in list order, first outermost (managed
       * plugins first, so an org plugin's withholding wins).
       *
       * The whole set at a load, this plugin alone at its reload, the ones added
       * or changed at a refresh that keeps the rest: a module added later that
       * does not hook this event is built against the table as it stands.
       */
      plugins: readonly string[];
  };

EngineCreateResult type # line 3531

In the first published surface (2.1.259)

What an engine.create hook returns: $ as built so far with this plugin's nouns added, less any it withheld.

Every declared noun is optional here. Between hooks it crosses the chain as interface descriptors; a hook sees objects (EngineInterfaceBuilt).

  export type EngineCreateResult = Partial<EngineInterface> & {
      readonly [noun: string]: unknown;
  };

EngineEventOf type # line 3543

In the first published surface (2.1.259)

The events the engine raises at its call sites, and engine.create; the classic settings hooks' events are ClassicEventOf.

At every one, a hook that fails (throws, overruns its budget: HookBudget, answers a wrong shape) is skipped: the hooks beneath and core run in its place, or its last next result stands; the failure is reported by name.

422 lines
  export type EngineEventOf = {
      /**
       * Fires when the engine is about to run a tool. `next(e)` runs the hooks
       * beneath, then core (the permission prompt, the tool itself).
       *
       * Return `{ deny: reason }` to refuse or `{ result }` to answer yourself; a
       * hook that returns while its `next` is pending aborts what runs beneath.
       * The managed-settings hooks run first: their deny is the call's result.
       */
      'tool.call': ToolCallInput;
      /**
       * Fires when the engine decides whether a tool call may run, after the
       * `tool.call` and PreToolUse hooks and before the mode settles an ask.
       *
       * `next(e)` resolves to the engine's verdict (rules, mode, the tool's own
       * check, PreToolUse's decision); return any `{ decision }`. `$.tool.check`
       * runs the same chain and executes nothing.
       *
       * @example
       * on("tool.check", { tool: "Read" }, () => ({ decision: "allow" }))
       */
      'tool.check': ToolCheckInput;
      /**
       * Fires when the engine is about to draw a component: once per input value
       * (props, viewport width), plugin load or `$.ui.invalidate("ui.render")`.
       *
       * A repaint reuses the answer; a clock invalidates. `next(e)` resolves to the
       * drawing: return it, wrap it, draw your own, or rewrite `props`. A tree that
       * does not validate draws the engine's own; `--plugin-dir` is told why.
       */
      'ui.render': RenderInput;
      /**
       * Fires when the plugins load (not per draw), once per surface, component
       * and plugin: `e` names the surface and component, never the props.
       *
       * `next(e)` resolves to the surface's table, which `$.ui.resolve(e)` then
       * reads. Return it, one with an element restyled for every other plugin,
       * or one with a key left out (a fragment there); own table: hook skipped.
       */
      'ui.resolve': ResolveInput;
      /**
       * Fires when a `Button` a render hook drew is pressed on a surface; `e` is
       * `{ plugin, element, component, surface }`, `element` the button's `key`.
       *
       * `next(e)` runs the hooks beneath, then core: the element's own `onPress`
       * closure, in its plugin's environment, resolving to `{ element }`. Return
       * `next(e)` to let the press through, or `{ element }` to take it.
       */
      'ui.press': UiPressArgument;
      /**
       * Fires when an `Input` a render hook drew changes or is submitted; `e` is
       * `{ plugin, element, component, surface, kind, value }`.
       *
       * `next(e)` runs the hooks beneath, then the element's own `onInput` or
       * `onSubmit` with `e.value` as the chain left it, resolving to `{ element,
       * value }`; `next({ ...e, value })` rewrites the typing, an answer takes it.
       */
      'ui.input': UiInputArgument;
      /**
       * Fires when a `Select` a render hook drew is picked from; `e` is
       * `{ plugin, element, component, surface, value }`.
       *
       * `next(e)` runs the hooks beneath, then the element's own `onSelect` with
       * `e.value` as the chain left it, resolving to `{ element, value }`;
       * `next({ ...e, value })` rewrites the pick, an answer takes it.
       */
      'ui.select': UiSelectArgument;
      /**
       * Fires when a `Client` THIS plugin drew posts from its surface module
       * (`surface.post(data)`); only this plugin's hooks see it.
       *
       * `next.origin` names `client`: `data` came from code. Core answers `{}`;
       * `next({ ...e, data })` rewrites the data; `{ props }` hands the posting
       * instance its next props without a redraw. One per instance per frame.
       */
      'ui.message': UiMessageArgument;
      /**
       * Fires before a site's window moves: the person's wheel or scroll keys on
       * a `Pane` body or the `AbovePrompt` band, at its edges too; `$.ui.scroll`.
       *
       * `next(e)` moves it to `e.offset` and draws: `{}`; `next({ ...e, offset
       * })` elsewhere; no `next` (`{}` or `{ deny }`) leaves it undrawn, so a hook
       * drawing its own rows under a header moves them by `e.by` and invalidates.
       *
       * @example
       * on("ui.scroll", { requestId: "log" }, ($, e) => (scrollOwnRows(e.by), {}))
       */
      'ui.scroll': UiScrollInput;
      /**
       * Fires before a site's focus ring moves: the person's Tab, arrows or click
       * in a `Pane` or the band; an `autoFocus` element taking it; `$.ui.focus`.
       *
       * `next(e)` lands it on `e.element` (absent: one of the engine's stops) and
       * draws: `{}`; `next({ ...e, element })` on another of `e.plugin`'s; no
       * `next` (`{}` or `{ deny }`) keeps it where it was, drawn as it was.
       *
       * @example
       * on("ui.focus", { requestId: "list" }, ($, e, next) => (mark(e), next(e)))
       */
      'ui.focus': UiFocusInput;
      /**
       * Fires when the engine offers an agent type to the model, in the agent
       * listing and again at dispatch; `next(e)` resolves to `{ isOffered: true }`.
       *
       * Return `{ isOffered: false }` to keep the type out of the listing and
       * refuse its dispatch. A hook that fails passes it through.
       *
       * @example
       * on("agent.offer", { agent: "Plan" }, () => ({ isOffered: false }))
       */
      'agent.offer': AgentOfferInput;
      /**
       * Fires when the Agent tool is about to start a subagent, everything
       * decided and its model not yet resolved.
       *
       * `next(e)` resolves to `{ model }`. Return it, `next({ ...e, model })`,
       * `{ model }` of your own (an alias resolves like the tool's parameter), or
       * `{ deny: reason }`.
       */
      'agent.spawn': AgentSpawnInput;
      /**
       * Fires when a prompt is submitted, before the turn starts. `next(e)` runs
       * the hooks beneath and the UserPromptSubmit settings hooks.
       *
       * Rewrite with `next({ ...e, text })` (the user message on screen follows)
       * or stop it with `{ drop: reason }`; a broken plugin never blocks a prompt.
       * A prompt typed while a turn ran fires at Enter, with that turn's id.
       */
      'prompt.submit': PromptSubmitInput;
      /**
       * Fires when a text is about to be put in the prompt box as the person's
       * draft (a plugin's `$.prompt.fill`); `next(e)` writes it by `e.mode`.
       *
       * `replace` over the draft, `append` after it, `insert` at the cursor;
       * rewrite `text` or `mode` going down, or answer `{ isFilled: false }`
       * without `next` to keep it out, as core does under a dialog or headless.
       *
       * @example
       * on("prompt.fill", ($, e, next) => next({ ...e, text: e.text.trim() }))
       */
      'prompt.fill': PromptFillInput;
      /**
       * Fires when a text is proposed as the prompt box's dim suggestion, Tab to
       * take: the engine's guess after a turn, or a plugin's `$.prompt.suggest`.
       *
       * `next(e)` shows it: `{ isShown }`. Rewrite with `next({ ...e, text })`,
       * or answer `{ isShown: false }` without `next` to drop it; core answers
       * that too while the box holds text or a turn runs.
       *
       * @example
       * on("prompt.suggest", { origin: { kind: "suggestion" } }, hide)
       */
      'prompt.suggest': PromptSuggestInput;
      /**
       * Fires when the person edits the main prompt box: a key the editor took as
       * an edit, or a paste; `next(e)` resolves the box the editor shows.
       *
       * `e` is the draft before and the splice (`start`, `end`, `inputText`); a
       * burst of keys is one edit. Rewrite `inputText` going down or the box
       * coming up; `{ text: e.text, cursor: e.cursor }` without `next` consumes.
       *
       * @example
       * on("prompt.edit", ($, e, next) => next({ ...e, inputText: up(e) }))
       */
      'prompt.edit': PromptEditInput;
      /**
       * Fires once per named section of the system prompt, when the engine
       * assembles it; `next(e)` resolves to `{ text }` as core computed it.
       *
       * Sections are cached by name for the session until
       * `$.ui.invalidate("prompt.section")`: an unstable answer spends the
       * model's prompt cache on every call. A hook that fails passes it through.
       *
       * @example
       * on("prompt.section", { name: "memory" }, () => ({ text: null }))
       */
      'prompt.section': PromptSectionInput;
      /**
       * Fires once per conversation, when the engine computes the context blocks
       * its first user message carries; `next(e)` resolves to `{ blocks }`.
       *
       * Append, drop, reorder or rewrite with `next({ ...e, blocks })`; the
       * engine renders what comes back, in order, until
       * `$.ui.invalidate("prompt.context")` or a re-read (compaction, `/clear`).
       *
       * @example
       * on("prompt.context", () => ({ blocks: [] }))
       */
      'prompt.context': PromptContextInput;
      /**
       * Fires once per message the engine injects for the model on its own (a
       * reminder, a mode transition, a mentioned file), as a request carries it.
       *
       * `next(e)` resolves to `{ text }`; `{ text: null }` leaves it out. The
       * answer holds per attachment for the process (asked again on resume or
       * `$.ui.invalidate`); the transcript keeps the engine's record.
       *
       * @example
       * on("prompt.attachment", { type: "todo_reminder" }, () => ({ text: null }))
       */
      'prompt.attachment': PromptAttachmentInput;
      /**
       * Fires once per tool, when the engine first renders the tool's schema in
       * a session; `next(e)` resolves to `{ description, isDeferred? }`.
       *
       * Cached for the session until `$.ui.invalidate("tool.describe")`: an
       * unstable answer spends the model's prompt cache. An explicit `isDeferred`
       * moves the tool behind ToolSearch (true) or into the prompt's list (false).
       *
       * @example
       * on("tool.describe", { tool: "Bash" }, ($, e) => ({ ...e, description }))
       * @example
       * on("tool.describe", { tool: "Monitor" }, pin) // {...e, isDeferred: false}
       */
      'tool.describe': ToolDescribeInput;
      /**
       * Fires when a slash command is about to run (`/name args` typed, or a
       * plugin's `$.command.run`); `next(e)` resolves to `{ text }`, its output.
       *
       * Core is the engine's command (a registered one has none). Rewrite `args`
       * with `next`, or return `{ text }` without it to answer in its place; one
       * after `next` replaces a printed output, not a panel or prompt it opened.
       *
       * @example
       * on("command.run", { command: "hello" }, () => ({ text: "hello" }))
       */
      'command.run': CommandRunInput;
      /**
       * Fires once per command, when the engine lists it for the typeahead and
       * `/help`; `next(e)` resolves to `{ description, argumentHint, isHidden }`.
       *
       * Listed answers are cached for the session until
       * `$.ui.invalidate("command.describe")`. A hook that fails passes it
       * through.
       *
       * @example
       * on("command.describe", ($, e, next) => next({ ...e, isHidden: true }))
       */
      'command.describe': CommandDescribeInput;
      /**
       * Fires when a `/config` row is about to change, from the menu or a
       * plugin's `$.config.set`; `next(e)` resolves to `{ value }` once written.
       *
       * Return `{ deny: reason }` to leave the row as it is (the menu says why),
       * or `next({ ...e, value })` to clamp it; a value of the wrong kind for
       * the row is refused. A row a trusted source owns is core's to refuse.
       *
       * @example
       * on("config.set", { key: "theme" }, () => ({ deny: "the theme stays" }))
       */
      'config.set': ConfigSetInput;
      /**
       * Fires once per `/config` row, when the menu lists it and for
       * `$.config.list`; `next(e)` resolves to `{ label, description, isHidden }`.
       *
       * Relabel, re-describe or hide with `next({ ...e, isHidden: true })`; the
       * answers are cached until `$.ui.invalidate("config.describe")` or the
       * loaded plugins change. A hook that fails passes the row through.
       *
       * @example
       * on("config.describe", { key: "tips" }, hide) // answers isHidden: true
       */
      'config.describe': ConfigDescribeInput;
      /**
       * Fires when the engine expands a skill's prompt for the model (`/name`,
       * the Skill tool, a preload); `next(e)` resolves to `{ text }` as computed.
       *
       * Return `{ text }` with the text the model reads instead. A hook that
       * fails passes it through.
       *
       * @example
       * on("skill.prompt", { skill: "commit" }, () => ({ text: "A haiku." }))
       */
      'skill.prompt': SkillPromptInput;
      /**
       * Fires when the engine composes a git text the model is to write (`kind`:
       * `commit`, `pr`, `exemption`, `remedy`); `next(e)` resolves to `{ text }`.
       *
       * Return `{ text }` with the text the model reads instead. A hook that
       * fails passes it through.
       *
       * @example
       * on("attribution.text", { kind: "commit" }, () => ({ text: "" }))
       */
      'attribution.text': AttributionTextInput;
      /**
       * Fires once per process for each loaded plugin, before the first prompt,
       * then once per fresh load of one (never `/clear`); `next(e)` is `{ cwd }`.
       *
       * Observe. The first is awaited: a `$.tool.register` is listed by turn one.
       * A later one runs its hooks alone: an enable, a worker respawn, or a reload
       * (changed modules only; all if one hooks `engine.create`/`plugin.register`).
       *
       * @example
       * on("session.start", ($, e, next) => $.tool.register(t).then(() => next(e)))
       */
      'session.start': SessionStartInput;
      /**
       * Fires when a delivery reaches the session (a relay's event, a peer's
       * message, a Remote Control prompt), before it is queued; `{ text }`.
       *
       * Rewrite with `next({ ...e, text })`, or return `{ consumed: reason }` to
       * take it: nothing is queued, shown or read by the model. `origin`,
       * `event` and `agentId` pass on as received; `session.send` is its dual.
       *
       * @example
       * on("session.receive", { origin: "peer" }, () => ({ consumed: "muted" }))
       */
      'session.receive': SessionReceiveInput;
      /**
       * Fires when a plain-text message is about to leave this conversation for
       * another agent or session (the SendMessage tool, or `$.session.send`).
       *
       * `e.origin` says who sends, `e.agentId` which loop. Rewrite `text` or
       * readdress `to` with `next` (a new `to` is judged again); `{ isDelivered:
       * false, reason }` without `next` refuses it. `next(e)` resolves queued.
       *
       * @example
       * on("session.send", ($, e, next) => next({ ...e, text: redact(e.text) }))
       */
      'session.send': SessionSendInput;
      /**
       * Fires when the conversation is about to be compacted (`/compact`, the
       * threshold, a plugin, or ahead of time); `next(e)` resolves `{ messages }`.
       *
       * Rewrite `instructions` or `messages` on the way down, the messages on
       * the way up, or answer `{ messages }` of your own; `{ skip: reason }`
       * leaves the conversation as it is. `trigger` passes on as received.
       *
       * @example
       * on("session.compact", { trigger: "precompute" }, () => ({ skip: "off" }))
       */
      'session.compact': SessionCompactInput;
      /**
       * Fires when a remote client joins the session's roster of attached
       * surfaces: it said so (ui_attach), or it first asked to draw.
       *
       * Observe (a phone joined: draw the lobby); `next(e)` resolves to
       * `{ clientId }`, a different return changes nothing. `$.session.surfaces()`
       * reads the roster; a render hook still reads `e.surface` per ask.
       *
       * @example
       * on("session.attach", { surface: "mobile" }, ($, e, next) => next(e))
       */
      'session.attach': SessionAttachInput;
      /**
       * Fires when a client leaves the roster: it detached, or the session ended
       * with it attached (`e.reason`). Observe; `next(e)` echoes `{ clientId }`.
       *
       * With reason `end` it runs inside `session.end`'s one short bound: there
       * `next.budget` reads that bound and `next.signal` aborts at it.
       */
      'session.detach': SessionDetachInput;
      /**
       * Fires when the engine measures the session and a unit moved: after each
       * main-thread turn, and when a rate-limit window moves a whole point.
       *
       * Observe; `next(e)` echoes `{ changed }`. `$.session.usage()`'s figures,
       * pushed, not polled: compare them with your own threshold here, call the
       * op for the breakdown. One at a time, a burst folding into one more.
       *
       * @example
       * on("session.measure", ($, e, next) => (toastPast90(e.rateLimits), next(e)))
       */
      'session.measure': SessionMeasureInput;
      /**
       * Fires once when the session ends (exit, /clear, resume, logout, signal, a
       * `-p` run done), after its SessionEnd settings hooks; `e.reason` says which.
       *
       * `next(e)` runs the engine's end step, `{ sessionId }`; `e.resume.id` is
       * `--resume`'s. Exits stay fast whatever is loaded: the whole chain shares
       * one short wall-clock bound, which `next.budget` reads (SessionEndInput).
       *
       * @example
       * on("session.end", async ($, e, next) => (await save(next.budget), next(e)))
       */
      'session.end': SessionEndInput;
      /**
       * Fires once per hooks module about to join the chain, at load (the set
       * folded and built, nothing swapped in) and at reload; core allows.
       *
       * Return `{ refuse: reason }` and it never joins: no hook, no noun, no tool
       * of it; the transcript names who refused. Its judges, `$` whole, are the
       * plugins admitted before it and the binary's; judge by `tier` and `uses`.
       *
       * @example
       * on("plugin.register", { tier: "user" }, () => ({ refuse: "managed only" }))
       */
      'plugin.register': PluginRegisterInput;
      /**
       * Fires when a model turn begins, before its first model call; `next(e)`
       * resolves to `{ turnId }`. Observe: a different return changes nothing.
       */
      'turn.start': TurnStartInput;
      /**
       * Fires when the engine is about to send a model request of a turn, main's
       * or a subagent's (`e.agentId`); `next(e)` resolves to the whole response.
       *
       * `next({ ...e, model })` or `effort` sends another; the turn, the index and
       * the message count are pinned. An answer without `next` sends no request.
       * It streams (StreamNext): the hook's budget counts its own code alone.
       */
      'turn.step': TurnStepInput;
      /**
       * Fires when a model turn has ended, at the point its duration is reported;
       * `next(e)` resolves to `{ text }`, the answer. `e.reason` says why.
       *
       * Return `{ text }` with a different text to show it beneath the answer (a
       * synopsis, a TL;DR line); the transcript's record is never rewritten. A
       * hook that fails leaves the answer as it was.
       */
      'turn.complete': TurnCompleteInput;
      /**
       * Runs while `$` is being built, once per load or reload of this plugin
       * and before any other hook of it; `next(e)` resolves to `$` built so far.
       *
       * A step may ADD nouns and WITHHOLD nouns (leave one out, or return without
       * `next`); it may NOT REPLACE one another step added: the step fails, named
       * with both plugins. A step that fails unloads its plugin; `$` is rebuilt.
       */
      'engine.create': EngineCreateInput;
  };

EngineInterface interface # line 3977

In the first published surface (2.1.259)

$, the first parameter of every hook. Frozen; core's interface plus every noun the plugins' engine.create steps added.

Flat, <noun>.<event>; it does not carry on, since registration happens before $ exists. An interface so a plugin types the noun it provides by declaration merging, the way a jQuery plugin types $.fn.

declare module "claude-code" { interface EngineInterface { voice: Voice } }
  export interface EngineInterface extends CoreEngineInterface {
  }

EngineInterfaceBuilt type # line 3988

In the first published surface (2.1.259)

What next(e) resolves to at engine.create: $ as the steps beneath built it, typed as $ is, open to nouns no declaration names yet.

A withheld noun is on it as a stub (a step inside withheld it, or the last fold did and this is a reload), and the host refuses an op on one a step outside withholds later; a typed module bootstraps at load on it.

  export type EngineInterfaceBuilt = EngineInterface & {
      readonly [noun: string]: unknown;
  };

EngineResultOf type # line 3995

In the first published surface (2.1.259)

The engine's events' results.

162 lines
  export type EngineResultOf = {
      /**
       * `{ result, context? }`, `{ deny }`, or core's `{ ref, result }`.
       */
      'tool.call': ToolCallResult;
      /**
       * `{ decision, reason?, rule? }`.
       */
      'tool.check': ToolCheckResult;
      /**
       * The tree to draw; `{ type: "engine", ref }` is core's own drawing.
       */
      'ui.render': RenderElement;
      /**
       * The surface's element table (Elements[e.surface]): constructors from props
       * to a RenderElement.
       */
      'ui.resolve': ElementTable;
      /**
       * `{ element }`: the element whose handler the press reached.
       */
      'ui.press': UiPressResult;
      /**
       * `{ element, value }`: the field whose handler the input reached, and
       * the text it received.
       */
      'ui.input': UiInputResult;
      /**
       * `{ element, value }`: the picker whose handler the pick reached, and
       * the value it received.
       */
      'ui.select': UiSelectResult;
      /**
       * `{ props? }`: the posting instance's next props, when a hook hands some.
       */
      'ui.message': UiMessageResult;
      /**
       * `{}` once the window moved, or `{ deny }`.
       */
      'ui.scroll': UiScrollResult;
      /**
       * `{}` once the ring moved, or `{ deny }`.
       */
      'ui.focus': UiFocusResult;
      /**
       * `{ isOffered }`.
       */
      'agent.offer': AgentOfferResult;
      /**
       * `{ model }` or `{ deny }`.
       */
      'agent.spawn': AgentSpawnResult;
      /**
       * `{ text, context? }` or `{ drop }`.
       */
      'prompt.submit': PromptSubmitResult;
      /**
       * `{ isFilled }`.
       */
      'prompt.fill': PromptFillResult;
      /**
       * `{ isShown }`.
       */
      'prompt.suggest': PromptSuggestResult;
      /**
       * `{ text, cursor }`, the box the editor shows next.
       */
      'prompt.edit': PromptEditResult;
      /**
       * `{ text }` (null leaves the section out).
       */
      'prompt.section': PromptSectionResult;
      /**
       * `{ blocks }` (a block left out is not sent).
       */
      'prompt.context': PromptContextResult;
      /**
       * `{ text }` (null leaves the attachment out).
       */
      'prompt.attachment': PromptAttachmentResult;
      /**
       * `{ description, isDeferred? }`.
       */
      'tool.describe': ToolDescribeResult;
      /**
       * `{ text }` (the command's output, when it printed one).
       */
      'command.run': CommandRunResult;
      /**
       * `{ description, argumentHint, isHidden }`.
       */
      'command.describe': CommandDescribeResult;
      /**
       * `{ value }` once written, or `{ deny }`.
       */
      'config.set': ConfigSetResult;
      /**
       * `{ label, description, isHidden }`.
       */
      'config.describe': ConfigDescribeResult;
      /**
       * `{ text }`.
       */
      'skill.prompt': SkillPromptResult;
      /**
       * `{ text }`.
       */
      'attribution.text': AttributionTextResult;
      /**
       * `{ cwd }`.
       */
      'session.start': SessionStartResult;
      /**
       * `{ text }`, or `{ consumed }`.
       */
      'session.receive': SessionReceiveResult;
      /**
       * `{ isDelivered: true }`, or `{ isDelivered: false, reason }`.
       */
      'session.send': SessionSendResult;
      /**
       * `{ messages, tokensBefore?, tokensAfter? }`, or `{ skip }`.
       */
      'session.compact': SessionCompactResult;
      /**
       * `{ clientId }`.
       */
      'session.attach': SessionAttachResult;
      /**
       * `{ clientId }`.
       */
      'session.detach': SessionDetachResult;
      /**
       * `{ changed }`.
       */
      'session.measure': SessionMeasureResult;
      /**
       * `{ sessionId }`.
       */
      'session.end': SessionEndResult;
      /**
       * `{ allow: true }`, or `{ refuse }`.
       */
      'plugin.register': PluginRegisterResult;
      /**
       * `{ turnId }`.
       */
      'turn.start': TurnStartResult;
      /**
       * The response: `{ turnId, index, answer, toolUses, stopReason, usage }`.
       */
      'turn.step': TurnStepResult;
      /**
       * `{ text }`.
       */
      'turn.complete': TurnCompleteResult;
      /**
       * `$` as built so far, with this plugin's interface added and any it
       * withheld left out; `next(e)` resolves to EngineInterfaceBuilt.
       */
      'engine.create': EngineCreateResult;
  };

EventCalls type # line 4166

In the first published surface (2.1.259) · changed in 2.1.260, 2.1.265, 2.1.267, 2.1.268, 2.1.269, 2.1.271, 2.1.275, 2.1.277, 2.1.280

The engine's own events as calls on $, one signature each: $.<noun>.<event>(input) resolves to its result, or to its stream.

The engine raises its events through these same calls; a plugin's call runs the same chain with the calling hook alone skipped. input may leave out what the engine fills (tool_use_id, the parent agent).

54 lines
  export type EventCalls = {
      tool: {
          call: ToolCallOverloads;
          check: (input: ToolCheckArgs) => Promise<ToolCheckResult>;
          describe: (input: ToolDescribeInput) => Promise<ToolDescribeResult>;
      };
      command: {
          run: (input: CommandRunArgs) => Promise<CommandRunResult>;
          describe: (input: CommandDescribeInput) => Promise<CommandDescribeResult>;
      };
      config: {
          set: (input: ConfigSetArgs) => Promise<ConfigSetResult>;
          describe: (input: ConfigDescribeInput) => Promise<ConfigDescribeResult>;
      };
      prompt: {
          submit: (input: PromptSubmitArgs) => Promise<PromptSubmitResult>;
          fill: (input: PromptFillArgs) => Promise<PromptFillResult>;
          suggest: (input: PromptSuggestArgs) => Promise<PromptSuggestResult>;
          section: (input: PromptSectionInput) => Promise<PromptSectionResult>;
          context: (input: PromptContextInput) => Promise<PromptContextResult>;
          attachment: (input: PromptAttachmentInput) => Promise<PromptAttachmentResult>;
      };
      skill: {
          prompt: (input: SkillPromptInput) => Promise<SkillPromptResult>;
      };
      attribution: {
          text: (input: AttributionTextInput) => Promise<AttributionTextResult>;
      };
      agent: {
          offer: (input: AgentOfferInput) => Promise<AgentOfferResult>;
          spawn: (input: AgentSpawnArgs) => Promise<AgentSpawnResult>;
      };
      session: {
          start: (input: SessionStartInput) => Promise<SessionStartResult>;
          receive: (input: SessionReceiveInput) => Promise<SessionReceiveResult>;
          send: (input: SessionSendArgs) => Promise<SessionSendResult>;
          compact: (input?: SessionCompactArgs) => Promise<SessionCompactResult>;
          attach: (input: SessionAttachInput) => Promise<SessionAttachResult>;
          detach: (input: SessionDetachInput) => Promise<SessionDetachResult>;
          measure: (input: SessionMeasureInput) => Promise<SessionMeasureResult>;
          end: (input: SessionEndInput) => Promise<SessionEndResult>;
      };
      turn: {
          start: (input: TurnStartInput) => Promise<TurnStartResult>;
          step: (input: TurnStepInput) => HookStream<TurnStepChunk, TurnStepResult>;
          complete: (input: TurnCompleteInput) => Promise<TurnCompleteResult>;
      };
      ui: {
          render: <C extends RenderComponent>(input: RenderInput<C>) => Promise<RenderElement>;
          resolve: <E extends ResolveInput>(e: E) => Elements[E['surface']];
          scroll: (input: UiScrollArgs) => Promise<UiScrollResult>;
          focus: (input: UiFocusArgs) => Promise<UiFocusResult>;
      };
  };

EventName type # line 4225

In the first published surface (2.1.259)

The name of an event: a key of EventOf, the engine's own (CoreEventName) and the declared plugin nouns' (NounEventName).

  export type EventName = keyof EventOf;

EventOf type # line 4235

In the first published surface (2.1.259) · changed in 2.1.265

The argument of each event, by event name: what a hook receives as e and what the call on $ takes. Plain data, frozen to every depth.

The engine's own events (CoreEventOf: a plugin's $.fs.write(...) is a dispatch the hooks above it see) and the methods of the plugin nouns declared on EngineInterface (NounEventOf).

  export type EventOf = CoreEventOf & NounEventOf;

EventResult type # line 4241

In the first published surface (2.1.259)

The result of event N: what its hooks return and what their next(e) resolves to.

  export type EventResult<N extends EventName = EventName> = ResultOf[N];

Events type # line 4258

In the first published surface (2.1.259) · changed in 2.1.268, 2.1.269

The hook signature of each event, ($, e, next), as one mapped type over EventOf; a streaming event's is the generator form (StreamHook).

With one handler type per event, Events[E] for a generic E would be a union; as one mapped type it stays a single function type the engine calls without a cast (TS 4.6 correlated unions).

$
the engine interface, frozen, the same object at every invocation; at engine.create the empty table, since $ exists after the fold
e
the event's argument, frozen to every depth (e.command = "ls" is a type error and throws); a rewrite is a copy passed to next
next
the rest of the chain; a chain a hook raises through $ skips this hook and runs every other, its plugin's others too
  export type Events = {
      [E in keyof EventOf]: E extends StreamingEventName ? StreamHook<E> : ($: E extends 'engine.create' ? NoEngineInterface : EngineInterface, e: Frozen<Args<E>>, next: Next<E>) => EventResult<E> | Promise<EventResult<E>>;
  };

ExitReason type # line 4262

Added in 2.1.265

  type ExitReason = 'clear' | 'resume' | 'logout' | 'prompt_input_exit' | 'other';

FileChangedHookInput type # line 4264

Added in 2.1.265

  type FileChangedHookInput = BaseHookInput & {
      hook_event_name: 'FileChanged';
      file_path: string;
      event: 'change' | 'add' | 'unlink';
  };

Frozen type # line 4276

Added in 2.1.268

T with every property read-only to every depth, arrays and tuples kept as declared: how a hook's e is typed.

e.command = 'x' is a type error; next({ ...e, command: 'x' }) compiles.

  export type Frozen<T> = T extends (...args: never[]) => unknown ? T : T extends readonly unknown[] ? {
      [K in keyof T]: Frozen<T[K]>;
  } : T extends object ? {
      readonly [K in keyof T]: Frozen<T[K]>;
  } : T;

FsAncestor type # line 4286

In the first published surface (2.1.259) · changed in 2.1.275

One file $.fs.ancestors found: the directory it stands in, the name it was asked for by, and its text as the engine's memory loader reads it.

19 lines
  export type FsAncestor = {
      /**
       * The directory the file stands in, absolute.
       */
      dir: string;
      /**
       * The spelling the caller asked for it by.
       */
      name: string;
      /**
       * The file's text, with what its `@include`s bring after it.
       */
      content: string;
      /**
       * The file and then each file its `@` imports brought, in load order,
       * path and text apiece; `content` is these texts joined.
       */
      parts: readonly FsAncestorPart[];
  };

FsAncestorPart type # line 4309

Added in 2.1.275

One file of an ancestor entry: the file itself or one it imported.

  export type FsAncestorPart = {
      /**
       * The file's path, absolute.
       */
      path: string;
      /**
       * Its text as the engine's memory loader reads it.
       */
      content: string;
  };

FsAncestorsRequest type # line 4324

In the first published surface (2.1.259) · changed in 2.1.277

The argument of $.fs.ancestors: the file names to look for in each directory, the file to walk down to, and the directory to walk beneath.

20 lines
  export type FsAncestorsRequest = {
      /**
       * Relative `.md` file names, each looked for in every directory.
       */
      names: readonly string[];
      /**
       * The file the walk goes on down to the directory of, relative to the
       * working directory or absolute; absent, it ends at the working directory.
       */
      of?: string;
      /**
       * The directory the walk starts beneath, relative to the working directory
       * or absolute; absent, the walk starts at the filesystem root.
       *
       * Only directories strictly inside it are read, so with `of` a file under
       * the project root the walk reads the directories between the two, as the
       * engine reads a nested CLAUDE.md; a file not inside it finds nothing.
       */
      below?: string;
  };

FsBytes type # line 4349

Added in 2.1.277

What $.fs.read(path, { as: "bytes" }) resolves with: the file's bytes, base64, since only plain data crosses into a plugin's environment.

  export type FsBytes = {
      /**
       * The file's content, standard padded base64;
       * `Uint8Array.fromBase64(base64)` gives the bytes back.
       */
      base64: string;
  };

FsEntry type # line 4360

In the first published surface (2.1.259) · changed in 2.1.277

One entry of $.fs.list: the entry itself, a link not followed.

19 lines
  export type FsEntry = {
      /**
       * The entry's name (no directory part).
       */
      name: string;
      /**
       * `file`, `dir`, or `other`, of the entry itself: a symbolic link is
       * `other` (`$.fs.stat` says what it leads to, and with `resolve` where).
       */
      kind: 'file' | 'dir' | 'other';
      /**
       * Bytes, for a file.
       */
      size: number;
      /**
       * True when the entry is a symbolic link.
       */
      isLink: boolean;
  };

FsReadAs type # line 4383

Added in 2.1.277

How $.fs.read answers: text (UTF-8, the default) or bytes (base64).

  export type FsReadAs = 'text' | 'bytes';

FsReadBytesOptions type # line 4389

Added in 2.1.277

The options of $.fs.read that ask for the bytes: the call answers { base64 }.

  export type FsReadBytesOptions = {
      /**
       * `bytes`.
       */
      as: 'bytes';
  };

FsReadCall type # line 4400

Added in 2.1.277

$.fs.read: the file's text, or with { as: "bytes" } its bytes as { base64 }.

  export type FsReadCall = {
      (path: string): Promise<string>;
      (path: string, options: FsReadBytesOptions): Promise<FsBytes>;
      (path: string, options: FsReadOptions): Promise<string | FsBytes>;
  };

FsReadOptions type # line 4409

Added in 2.1.277

The options of $.fs.read.

  export type FsReadOptions = {
      /**
       * `bytes` answers `{ base64 }` for a binary file; `text` (the default) the
       * file's text.
       */
      as: FsReadAs;
  };

FsStat type # line 4421

In the first published surface (2.1.259) · changed in 2.1.277

What $.fs.stat resolves with: what the path leads to, whether the path itself is a symbolic link, and where it lands when asked.

32 lines
  export type FsStat = {
      /**
       * `file`, `dir`, or `other`, of what the path leads to: a link is
       * followed, and one that leads nowhere is `other`.
       */
      kind: 'file' | 'dir' | 'other';
      /**
       * Bytes, for a file.
       */
      size: number;
      /**
       * Last modification, milliseconds since the epoch.
       */
      mtimeMs: number;
      /**
       * True when the path itself is a symbolic link; `kind`, `size` and
       * `mtimeMs` then describe what it points at, or the link when that is gone.
       */
      isLink: boolean;
      /**
       * Where the path landed when asked with `{ resolve: true }`: absolute,
       * every symbolic link followed, `.` and `..` folded; else absent.
       *
       * Absent too when the path leads nowhere or a hook above withheld it, so
       * a guard denies without it; and a hard link, a volume or file-id spelling
       * (macOS `/.vol/`) or a case alias keeps its own spelling, `isLink` false.
       *
       * @remarks a deny-list on spellings is thus best effort; an allow-list on
       *          `realPath` under a root resolved the same way is the robust guard.
       */
      realPath?: string;
  };

FsStatOptions type # line 4457

Added in 2.1.277

The options of $.fs.stat.

  export type FsStatOptions = {
      /**
       * True to resolve where the path lands as well.
       *
       * The answer then carries `realPath` when the path leads somewhere, at
       * the cost of one more file system call: where it landed then, not a hold
       * on what a tool opens afterwards.
       */
      resolve: boolean;
  };

Glob type # line 4472

Added in 2.1.265

Every event (*), or every event under a namespace (classic.*: each one whose name starts with classic.).

  export type Glob = '*' | `${Namespace}.*`;

GlobHook type # line 4482

Added in 2.1.265 · changed in 2.1.268

The hook on(pattern, hook) takes for a glob or a negation: one function placed on every selected event, e and the result typed as their union.

next.event says which event a run is; next.is(pattern, e) narrows e to one of them. At engine.create (a negation may select it) $ is the empty table and the hook observes the fold, as a * hook does.

  export type GlobHook<P extends Pattern, N extends EventName = Selected<P>> = ($: EngineInterface, e: Frozen<Args<N>>, next: GlobNext<P>) => EventResult<N> | Promise<EventResult<N>>;

GlobNext type # line 4491

Added in 2.1.265 · changed in 2.1.267, 2.1.268, 2.1.275

next in a hook on a glob or a negation: an overload per selected event, then one over their union for an e not yet narrowed.

is narrows e to the selected events its pattern names; event is one of the selected names.

14 lines
  export type GlobNext<P extends Pattern, N extends EventName = Selected<P>> = OrderedOverloads<N> & {
      (e: Args<N>): Promise<GlobNextResult<N>>;
      /**
       * Continues this dispatch at a tier, as Next's `to` (a managed hook's),
       * over the selected events' union for an `e` not yet narrowed.
       */
      readonly to: (e: Args<N>, tier: TargetTier) => Promise<GlobNextResult<N>>;
      readonly signal: AbortSignal;
      readonly is: <M extends PatternOver<N>>(pattern: M, e: unknown) => e is Frozen<Args<Extract<N, Selected<M>>>>;
      readonly event: N;
      readonly origin: Origin;
      readonly trace: readonly TraceEntry<N, Args<N>, GlobNextResult<N>>[];
      readonly budget: NextBudget;
  };

GlobNextResult type # line 4510

Added in 2.1.265

What next(e) resolves to in a glob hook before e is narrowed: the NextResult of each selected event, as a union.

  type GlobNextResult<N extends EventName> = {
      [K in N]: NextResult<K>;
  }[N];

Hook type # line 4517

In the first published surface (2.1.259)

One hook, ($, e, next), on event E.

  export type Hook<E extends EventName = EventName> = Events[E];

HookBudget type # line 4530

Added in 2.1.275

The time bounds every hook runs under, in milliseconds: the engine's own constants are typed by these members, and next.budget reads the live one.

Each bounds the hook's OWN time: the clock stops while a next(e) call or any $ call of the hook's is in flight (a $.clock wait excepted), so a slow chain beneath or a minute-long $.model.complete costs it nothing.

await $.model.complete(ask) // a minute; next.budget.remainingMs unmoved
27 lines
  export type HookBudget = {
      /**
       * A hook's budget per dispatch, from its call to its return; past it the
       * hook is absent (its `.catch` asked, else `next(e)` run on its behalf).
       *
       * A streaming hook's (an async generator) counts only while its own code
       * runs, never at a `yield` or while it reads beneath: on `turn.step` the
       * sum over the response; on `process.spawn` per piece, anew at each pull.
       */
      readonly ms: 10_000;
      /**
       * A `.catch` handler's grace: a fresh budget from the moment it is called,
       * on the same clock (its `next` replay and its `$` calls are free).
       *
       * Past it the hook is absent as if it had no handler; `next.error.budget`
       * and `next.budget.ms` both read it there. `engine.create` has no budget.
       */
      readonly catchMs: 1_000;
      /**
       * How long a hook may keep running after `next.signal` aborted (the person
       * interrupted, a hook above settled first, its own budget ran out).
       *
       * Past it the hook is reported as lingering; the dispatch had already gone
       * on without it when the signal aborted.
       */
      readonly lingerMs: 5_000;
  };

HookFailure type # line 4566

Added in 2.1.267

Why a hook failed, as its .catch handler reads it on next.error: plain frozen data.

throw: the hook threw, or returned what the site refuses, message saying what; timeout: it outran its budget, message then what its last next() rejected with, if it did. budget is the handler's own grace.

13 lines
  export type HookFailure = {
      readonly kind: 'throw' | 'timeout';
      /**
       * The thrown error's message, or for a timeout what the hook's last
       * `next()` rejected with; absent for a timeout with nothing rejected.
       */
      readonly message?: string;
      /**
       * The grace the handler runs under, in milliseconds; past it, the hook is
       * absent as if it had no handler.
       */
      readonly budget: number;
  };

HookFor type # line 4588

In the first published surface (2.1.259) · changed in 2.1.265

The hook type per pattern: an event's own (Events), *'s (AnyEventHook), or a glob's over the events it selects (GlobHook), as one conditional type.

One type, so the two-argument on stays ONE generic signature: as an overload set the language service offers no tool-name completions inside e.tool === "; as an index into a table TS intersects every argument.

  export type HookFor<P extends Pattern> = P extends '*' ? AnyEventHook : P extends EventName ? Events[P] : GlobHook<P>;

HookOf type # line 4596

Added in 2.1.269

The hook event E takes: an async generator over its chunks for a streaming event (StreamingEventName), ($, e, next) => result otherwise.

  export type HookOf<E extends EventName> = Events[E];

HooksModule type # line 4602

In the first published surface (2.1.259)

What a hooks module exports: register, and nothing the loader reads besides.

  export type HooksModule = {
      register: Register;
  };

HookStream type # line 4614

Added in 2.1.269

What next(e) returns on a streaming event: the stream of everything beneath, chunk by chunk, whose return value is the result from beneath.

yield* next(e) forwards the chunks and evaluates to that result; a transforming hook reads for await (const chunk of stream) and then await stream.result. Each call runs what is beneath afresh.

  export type HookStream<C, R> = AsyncGenerator<C, R> & {
      /**
       * Settles with what beneath returned once the stream has been read to
       * its end; rejects if the stream is closed before that.
       */
      readonly result: Promise<R>;
  };

HttpInit type # line 4625

In the first published surface (2.1.259) · changed in 2.1.268, 2.1.277

Options of $.http.fetch.

31 lines
  export type HttpInit = {
      /**
       * `GET` (default), `POST`, ...
       */
      method?: string;
      /**
       * Request headers.
       */
      headers?: Record<string, string>;
      /**
       * The request body, as text.
       */
      body?: string;
      /**
       * The handle `$.session.authorize()` answered: the engine sets the
       * session's credential header itself, only for a first-party host.
       */
      auth?: string;
      /**
       * The absolute path of a Unix domain socket the request goes over instead
       * of TCP (near 100 B at most): one per session, in a private directory.
       *
       * The URL still gives path, query and Host; redirects stay on it; no proxy;
       * `https:` is TLS verified against the URL's host (always, once `auth`
       * rides), so a credential reaches only its host. No relative path, no NUL.
       *
       * @example
       * await $.http.fetch(url, { socketPath: `${runDirectory}/bridge.sock` })
       */
      socketPath?: string;
  };

HttpResponse type # line 4660

In the first published surface (2.1.259)

What $.http.fetch resolves with.

18 lines
  export type HttpResponse = {
      /**
       * The HTTP status code.
       */
      status: number;
      /**
       * True for a 2xx status.
       */
      ok: boolean;
      /**
       * Response headers, lower-cased names.
       */
      headers: Record<string, string>;
      /**
       * The body, as text.
       */
      text: string;
  };

ImageBlitArgs type # line 4690

Added in 2.1.277

A $.ui.blit argument swapping one of the caller's mounted keyed Images to its next picture; every call sends it, so a stream needs no generation.

The surface writes them with its frames, some sixty a second: byte and file sources fold to the last per frame; every shm source reaches the terminal (it unlinks each), and is denied while frames are not written.

await $.ui.blit({ requestId: 'browser', key: 'view',
  source: { shm: '/tb-4', format: 'rgb', width: 1280, height: 720 } })
23 lines
  export type ImageBlitArgs = {
      /**
       * The site the Image is drawn in, by the `requestId` this plugin draws it
       * under.
       */
      requestId: string;
      /**
       * The Image's `key` in that drawing.
       */
      key: string;
      /**
       * The next picture (ImageSource): bytes, or a name the terminal reads.
       */
      source: ImageSource;
      /**
       * Refused unless it is the mounted Image's width in cells. Absent, that.
       */
      columns?: number;
      /**
       * Refused unless it is the mounted Image's height in cells. Absent, that.
       */
      rows?: number;
  };

ImageProps type # line 4727

Added in 2.1.275 · changed in 2.1.277

The props of Image, the terminal surface's picture leaf: pixels over a box of cells where the terminal can (kitty, Ghostty), the alt elsewhere.

A leaf: no children, hover or onPress; the cells are text, so the picture scrolls and clips as a word does. Drawn again with another source it is replaced in place; keyed, $.ui.blit swaps it at the frame rate.

const { bytes } = await $.fs.read('chart.png', { as: 'bytes' })
<Image source={{ png: bytes.toBase64() }} columns={40} rows={12} alt="p95" />
<Image key="view" source={{ shm: '/tb-7', format: 'rgb', width: 960,
  height: 600 }} columns={80} rows={25} alt="the page" />
25 lines
  export type ImageProps = {
      /**
       * The element's address within the drawing: what `$.ui.blit` names to swap.
       *
       * Unique among the Images of one tree; absent, only a redraw changes it.
       */
      key?: string;
      /**
       * The picture (ImageSource): `{ png }` or `{ rgba, width, height }` bytes,
       * or `{ file, format }` / `{ shm, format, width, height }` read here.
       */
      source: ImageSource;
      /** How many terminal columns wide, 1 to 255; the picture is scaled to fill
       * the box and the site clips what its body cannot show. */
      columns: number;
      /**
       * How many terminal rows tall, 1 to 255.
       */
      rows: number;
      /**
       * What the picture says, drawn dim in its place where the picture cannot
       * be (and read by a screen reader); required, may be a single space.
       */
      alt: string;
  };

ImageSource type # line 4770

Added in 2.1.275 · changed in 2.1.277

The picture an Image shows: base64 bytes the plugin holds (at most 2 MiB decoded), or the name of a file or POSIX shared-memory object it does not.

A name is one another process on this machine wrote; the terminal, running as the person, opens, reads and decodes it itself, so no pixel crosses $ and the engine never touches it. One it will not read (not a regular file, under /proc, /sys or /dev, gone, across ssh) draws a blank box, its words in the debug log; it unlinks a shared-memory object once read, so each frame is a fresh one. A source equal to the last drawn sends nothing; generation makes new content under an unchanged name a new source.

{ rgba: pixels.toBase64(), width: 64, height: 32 }
{ file: '/dev/shm/frame-3.rgba', format: 'rgba', width: 640,
  height: 400 }
{ shm: '/tb-view-2', format: 'rgb', width: 1280, height: 720 }
85 lines
  export type ImageSource = {
      /**
       * A whole PNG file, base64.
       */
      png: string;
  } | {
      /**
       * `width * height` RGBA pixels, 4 bytes each, base64.
       */
      rgba: string;
      /**
       * Pixels per row, 1 to 2048.
       */
      width: number;
      /**
       * Rows of pixels, 1 to 2048.
       */
      height: number;
  } | {
      /**
       * The absolute path of a regular file holding a whole PNG, at most
       * 3072 bytes of path; read by the terminal, left in place.
       */
      file: string;
      /**
       * The file is a whole PNG; the terminal decodes it and sizes it itself.
       */
      format: 'png';
      /**
       * A whole number that changes when the file's content does under the
       * same path, so a redraw reads it again; absent, the path alone tells.
       */
      generation?: number;
  } | {
      /**
       * The absolute path of a regular file of `width * height` raw pixels, at
       * most 3072 bytes of path; read by the terminal, left in place.
       *
       * On Linux a file under `/dev/shm` is memory.
       */
      file: string;
      /**
       * `rgba`, 4 bytes a pixel, or `rgb`, 3.
       */
      format: 'rgba' | 'rgb';
      /**
       * Pixels per row, 1 to 4096.
       */
      width: number;
      /**
       * Rows of pixels, 1 to 4096.
       */
      height: number;
      /**
       * A whole number that changes when the file's content does under the
       * same path, so a redraw reads it again; absent, the path alone tells.
       */
      generation?: number;
  } | {
      /**
       * The name of a POSIX shared-memory object of `width * height` raw
       * pixels: `/` then up to 254 of `A-Z a-z 0-9 . _ -` (macOS takes 30).
       *
       * The terminal unlinks it after reading, so a name feeds one Image
       * drawn once and is never sent again on a redraw; POSIX terminals only.
       */
      shm: string;
      /**
       * `rgba`, 4 bytes a pixel, or `rgb`, 3.
       */
      format: 'rgba' | 'rgb';
      /**
       * Pixels per row, 1 to 4096.
       */
      width: number;
      /**
       * Rows of pixels, 1 to 4096.
       */
      height: number;
      /**
       * A whole number that changes when a fresh object reuses a name, so a
       * redraw reads it again; absent, the name alone tells.
       */
      generation?: number;
  };

ImpossibleKeys type # line 4863

In the first published surface (2.1.259)

The keys of object pattern P that object member E cannot satisfy, D levels down; never when there is none, which is what keeps the member.

A key E does not have (an open record has every string key), or one whose value P narrows to nothing.

  type ImpossibleKeys<E, P, D extends readonly unknown[]> = {
      [K in keyof P]-?: K extends keyof E ? [NarrowedValue<Exclude<E[K], undefined>, P[K], D>] extends [never] ? K : never : K;
  }[keyof P];

InputProps type # line 4875

Added in 2.1.260 · changed in 2.1.271

The props of Input, every surface's one-line text field: an address, optional texts, and the closures a change and a submit run. A leaf.

Focused through the same ring as Button (abovePrompt:focus); while it has focus every printable key reaches it alone and Esc returns them; a change and Enter raise ui.input, whose bottom is onInput / onSubmit.

43 lines
  export type InputProps = {
      /**
       * The element's address: `e.element` at `ui.input`, what a matcher names.
       */
      key: string;
      /**
       * Text drawn before the field.
       */
      label?: string;
      /**
       * Text drawn dim in an empty field.
       */
      placeholder?: string;
      /**
       * The text the field holds when drawn; the person's typing replaces it
       * until the hook draws another.
       */
      value?: string;
      /**
       * What Enter does, in a word or two, drawn beside the field while it has
       * focus (`send`). Defaults to `submit`.
       */
      submitLabel?: string;
      /**
       * The site's focus ring starts here when the site takes the keyboard,
       * instead of on nothing, as the DOM's `autofocus`: Enter acts on it at once.
       *
       * A pane opened with `focus`, or the person's focus chord or click, is the
       * take. Of several in one site the first drawn wins; it raises `ui.focus`,
       * origin this plugin. A ring the person has moved stays where it was put.
       */
      autoFocus?: true;
      /**
       * Runs on every change of the text, in the plugin's own environment: the
       * bottom of a `ui.input` chain of kind `change`.
       */
      onInput?: (value: string, e: UiInputArgument) => void;
      /**
       * Runs on Enter with the text, in the plugin's own environment: the bottom
       * of a `ui.input` chain of kind `submit`. No model turn unless it asks one.
       */
      onSubmit: (value: string, e: UiInputArgument) => void;
  };

INSTRUCTION_FILE_KINDS const # line 4923

Added in 2.1.275

Every tier an instruction file can belong to, for checking a hook's answer; the kind type is derived from this list.

  const INSTRUCTION_FILE_KINDS: readonly ["managed", "user", "project", "local", "memory"];

InstructionFile type # line 4929

Added in 2.1.275

One instruction file behind the claudeMd block: where it was read, its tier, its text as loaded, and the file that @-imported it if one did.

18 lines
  export type InstructionFile = {
      /**
       * The file's path, absolute.
       */
      path: string;
      /**
       * Its tier.
       */
      kind: InstructionFileKind;
      /**
       * The text as loaded (comments and frontmatter already stripped).
       */
      content: string;
      /**
       * The path of the file whose `@` import brought this one, when one did.
       */
      parent?: string;
  };

InstructionFileKind type # line 4952

Added in 2.1.275

What tier an instruction file belongs to: the organization's managed policy, the person's own, the project's checked-in or private ones, memory.

  export type InstructionFileKind = (typeof INSTRUCTION_FILE_KINDS)[number];

InstructionsLoadedHookInput type # line 4954

Added in 2.1.265

  type InstructionsLoadedHookInput = BaseHookInput & {
      hook_event_name: 'InstructionsLoaded';
      file_path: string;
      memory_type: 'User' | 'Project' | 'Local' | 'Managed';
      load_reason: 'session_start' | 'nested_traversal' | 'path_glob_match' | 'include' | 'compact';
      globs?: string[];
      trigger_file_path?: string;
      parent_file_path?: string;
  };
Feedback