Skip to content

Console API

client.console opens a real shell on the connected host and streams its bytes. It is the same capability the Terminal app uses, not a "run one command" helper: you write input, you read output, and you own the session until you close it.

Availability

Requires the system.console permission and a connected workspace whose provider offers the terminal capability. Without both, open fails with denied or unavailable.

ts
const env = await client.environment.get();
const canOpen = env.connection === "connected" && env.capabilities.includes("terminal");

Interface

ts
interface RemoteConsole {
  readonly binding: string;
  readonly resizable: boolean;
  read(signal?: AbortSignal): Promise<Uint8Array | null>;   // null means end of stream
  write(bytes: Uint8Array | string, signal?: AbortSignal): Promise<void>;  // strings are sent as UTF-8
  resize(cols: number, rows: number, signal?: AbortSignal): Promise<void>;
  close(): Promise<void>;
}

interface AppConsoleAPI {
  open(options: { binding: string; cols?: number; rows?: number }, signal?: AbortSignal): Promise<RemoteConsole>;
}

Defaults are 80 columns by 24 rows. Dimensions must be 2–500 columns and 2–300 rows. resizable reports whether the provider accepts resize at all — a fixed-size console rejects it with unavailable.

Examples

Open a shell, echo its output and send a command:

ts
const console_ = await client.console.open({ binding, cols: 100, rows: 30 });
const decoder = new TextDecoder();

const pump = (async () => {
  for (;;) {
    const chunk = await console_.read();
    if (chunk === null) break;              // the shell ended
    append(decoder.decode(chunk, { stream: true }));
  }
})();

await console_.write("uptime\n");

Always release it, and stop reading when your window goes away:

ts
try {
  await pump;
} finally {
  await console_.close();
}

Follow the size of your own view:

ts
if (console_.resizable) await console_.resize(cols, rows);

Output arrives as raw bytes, including escape sequences. Decode with TextDecoder and { stream: true } so multi-byte characters split across chunks survive, and render with a terminal emulator if you need cursor control.

Errors

CodeMessageMeaning
deniedThe extension does not hold the required permission.system.console is not granted.
unavailableThis console has fixed dimensions.resize on a non-resizable console.
invalidConsole dimensions must be 2–500 columns and 2–300 rows.Out-of-range size.
invalidSupply at most 64 KiB of bytes.A single write was too large; the SDK already chunks strings for you.
busyClose an existing console before opening another.More than 16 consoles in one window.
busyOnly one read may wait on a console.Two concurrent read() calls.
busyWait for the current console write.Two concurrent writes.
closedConsole is closed.Used after close().
closedConsole is closed or belongs to a previous connection.The connection changed.
closedConsole retired during writing; some bytes may have been delivered.Genuinely uncertain: do not blindly resend.
abortedConsole read canceled; the console was closed.A read's signal fired, which also closes the console.
failedConsole provider violated output flow control or returned an invalid byte chunk.A provider bug; the console is retired.

Lifecycle and permissions

A console is owned by the window that opened it, up to 16 per window including pending opens. Cancelling any single operation closes the whole console, because a half-cancelled shell has no useful state — pass a signal only when you mean to end the session.

Output is backpressured: the host holds chunks of at most 64 KiB until your read() consumes them, so a chatty process cannot flood your window. Writes above 64 KiB are rejected, and the SDK splits long strings into chunks for you.

Losing the connection, or the terminal capability, retires every console: pending reads and writes reject with closed. Open a new one after the workspace reconnects — shells do not resume. A console is a real shell with the permissions of the account the workspace signed in as.

ShellCanvas documentation