@agentorg/computer 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sdk.js CHANGED
@@ -24573,6 +24573,18 @@ function removeTrailingSlash(url2) {
24573
24573
  return url2;
24574
24574
  }
24575
24575
 
24576
+ // src/text.ts
24577
+ var MAX_TEXT = 1e4;
24578
+ function* pieces(text, most = MAX_TEXT) {
24579
+ for (let from = 0; from < text.length; ) {
24580
+ let to = Math.min(from + most, text.length);
24581
+ const last = text.charCodeAt(to - 1);
24582
+ if (to < text.length && last >= 55296 && last <= 56319) to -= 1;
24583
+ yield text.slice(from, to);
24584
+ from = to;
24585
+ }
24586
+ }
24587
+
24576
24588
  // src/sdk.ts
24577
24589
  var ComputerError = class extends Error {
24578
24590
  code;
@@ -24657,32 +24669,30 @@ async function openLive(session, onMessage) {
24657
24669
  ws.addEventListener("message", (event) => onMessage(event.data));
24658
24670
  return { ws, closed };
24659
24671
  }
24660
- var INPUT = 48;
24661
- var RESIZE = 49;
24662
- var Pty = class {
24672
+ var Terminals = class {
24663
24673
  #open;
24664
24674
  constructor(open2) {
24665
24675
  this.#open = open2;
24666
24676
  }
24667
- /** Attach to its shell, starting one if none is running. Every attachment shares it. */
24677
+ /**
24678
+ * Each terminal as it starts, writes and exits: those already there first, each with the end of
24679
+ * what it wrote. Operating, the default, can also open a shell and act on any of them.
24680
+ */
24668
24681
  async connect(opts) {
24669
- const mode = opts.mode ?? "operate";
24670
- const decoder = new TextDecoder();
24671
- const { ws, closed } = await openLive(await this.#open("terminal", mode), (data) => {
24672
- if (typeof data === "string") return;
24673
- const frame = new Uint8Array(data);
24674
- if (frame[0] === INPUT) opts.onData(decoder.decode(frame.subarray(1), { stream: true }));
24675
- });
24676
- const send = (type, text) => {
24677
- const body = new TextEncoder().encode(text);
24678
- const frame = new Uint8Array(body.length + 1);
24679
- frame[0] = type;
24680
- frame.set(body, 1);
24681
- ws.send(frame);
24682
- };
24682
+ const { ws, closed } = await openLive(
24683
+ await this.#open("terminal", opts.mode ?? "operate"),
24684
+ (data) => {
24685
+ if (typeof data === "string") opts.onEvent(JSON.parse(data));
24686
+ }
24687
+ );
24688
+ const send = (input) => ws.send(JSON.stringify(input));
24683
24689
  return {
24684
- sendInput: (data) => send(INPUT, data),
24685
- resize: (columns, rows) => send(RESIZE, JSON.stringify({ columns, rows })),
24690
+ openShell: (columns, rows) => send({ type: "open", columns, rows }),
24691
+ sendInput: (id, text) => {
24692
+ for (const piece of pieces(text)) send({ type: "input", id, text: piece });
24693
+ },
24694
+ resize: (id, columns, rows) => send({ type: "resize", id, columns, rows }),
24695
+ stop: (id) => send({ type: "stop", id }),
24686
24696
  close: () => ws.close(),
24687
24697
  closed
24688
24698
  };
@@ -24690,17 +24700,8 @@ var Pty = class {
24690
24700
  };
24691
24701
  var Commands = class {
24692
24702
  #endpoint;
24693
- #open;
24694
- constructor(endpoint, open2) {
24703
+ constructor(endpoint) {
24695
24704
  this.#endpoint = endpoint;
24696
- this.#open = open2;
24697
- }
24698
- /** Each of the agent's commands as it runs: the ones already heard first, then as they come. */
24699
- async watch(onEvent) {
24700
- const { ws, closed } = await openLive(await this.#open("commands", "watch"), (data) => {
24701
- if (typeof data === "string") onEvent(JSON.parse(data));
24702
- });
24703
- return { close: () => ws.close(), closed };
24704
24705
  }
24705
24706
  async run(cmd, opts = {}) {
24706
24707
  let answer = await this.#endpoint.command("exec_command", {
@@ -24777,7 +24778,7 @@ var Computer = class _Computer {
24777
24778
  computerID;
24778
24779
  commands;
24779
24780
  files;
24780
- pty;
24781
+ terminals;
24781
24782
  #connection;
24782
24783
  #token;
24783
24784
  #computer;
@@ -24788,9 +24789,8 @@ var Computer = class _Computer {
24788
24789
  this.#token = token;
24789
24790
  this.#urls = info.endpoints;
24790
24791
  this.#computer = new Endpoint(info.endpoints.computer, token);
24791
- const open2 = (surface, mode) => this.liveSession(surface, mode);
24792
- this.commands = new Commands(this.#computer, open2);
24793
- this.pty = new Pty(open2);
24792
+ this.commands = new Commands(this.#computer);
24793
+ this.terminals = new Terminals((surface, mode) => this.liveSession(surface, mode));
24794
24794
  this.files = new Files(this.#computer);
24795
24795
  }
24796
24796
  static async create(opts) {
@@ -146,7 +146,7 @@ export interface paths {
146
146
  };
147
147
  get?: never;
148
148
  put?: never;
149
- /** A one-time ticket to watch or operate one of its surfaces live: the agent's commands as they run, a shell of your own, its files, or its browser. Open its url as a WebSocket within 60 seconds. */
149
+ /** A one-time ticket to watch or operate one of its surfaces live: its terminals, its files, or its browser. Open its url as a WebSocket within 60 seconds. */
150
150
  post: operations["createLiveSession"];
151
151
  delete?: never;
152
152
  options?: never;
@@ -182,7 +182,7 @@ export interface components {
182
182
  message: string;
183
183
  };
184
184
  /**
185
- * @description How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command and write_stdin. Below terminal, the browser's code-running tool is hidden.
185
+ * @description How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden.
186
186
  * @enum {string}
187
187
  */
188
188
  Access: "none" | "read" | "files" | "terminal";
@@ -248,10 +248,10 @@ export interface components {
248
248
  };
249
249
  };
250
250
  /**
251
- * @description commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes.
251
+ * @description terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes.
252
252
  * @enum {string}
253
253
  */
254
- Surface: "commands" | "terminal" | "files" | "browser";
254
+ Surface: "terminal" | "files" | "browser";
255
255
  /**
256
256
  * @description In watch you see and don't act: what you send is dropped, except that a files socket may still ask to list, to read and for what changed.
257
257
  * @enum {string}
@@ -371,6 +371,68 @@ export interface components {
371
371
  /** @description A URL, or back, forward or reload. */
372
372
  to: string;
373
373
  };
374
+ /** @description What the service sends on a terminal@1 socket, as JSON text, no message over 65,536 bytes. A terminal is a command the agent started or a shell a person opened; its id is the session id the agent's tools use. A new socket is first sent, for each terminal already there, the oldest first, its start, the end of what it wrote (its last 65,536 characters), and its exit if it has ended; then each event as it happens, with nothing to mark where the first ends. The last 64 that ended are among those already there, and one that leaves that list is not told. A character here is a UTF-16 unit. A socket with more than 4 MiB still to be sent to it is closed, with no close frame (1006): one that has stopped reading, or one that is reading while a terminal writes tens of megabytes at once. It isn't an error. Opened again, it is sent every terminal afresh, with the last 65,536 characters each wrote, in place of whatever it held. */
375
+ TerminalEvent: {
376
+ /** @constant */
377
+ type: "start";
378
+ id: string;
379
+ /**
380
+ * @description The way in it came: agent through a tool, person through this surface.
381
+ * @enum {string}
382
+ */
383
+ by: "agent" | "person";
384
+ /** @description Its command, the first 8,000 characters of it. */
385
+ cmd: string;
386
+ /** @description Its folder, the first 2,000 characters of it. */
387
+ workdir: string;
388
+ /** @description Whether it is on a terminal device, as a person's shell is. One that isn't, as the agent's commands aren't, echoes nothing typed into it and wants a line feed for Enter. Nothing tells the size of one that is. */
389
+ tty: boolean;
390
+ /** Format: date-time */
391
+ at: string;
392
+ } | {
393
+ /** @constant */
394
+ type: "output";
395
+ id: string;
396
+ /**
397
+ * @description Left out for one on a terminal device, which has one stream, and in what a new socket is first sent, where the two are one text.
398
+ * @enum {string}
399
+ */
400
+ stream?: "stdout" | "stderr";
401
+ text: string;
402
+ } | {
403
+ /** @constant */
404
+ type: "exit";
405
+ id: string;
406
+ exitCode: number;
407
+ /** Format: date-time */
408
+ at: string;
409
+ } | {
410
+ /** @constant */
411
+ type: "refused";
412
+ message: string;
413
+ };
414
+ /** @description What an operate socket sends on terminal@1, as JSON text. One that can't be done, or that is none of these, is answered with refused. What a watch socket sends is dropped. A message over 65,536 bytes closes the socket, so a long text goes as several inputs. */
415
+ TerminalInput: {
416
+ /** @constant */
417
+ type: "open";
418
+ columns: number;
419
+ rows: number;
420
+ } | {
421
+ /** @constant */
422
+ type: "input";
423
+ id: string;
424
+ text: string;
425
+ } | {
426
+ /** @constant */
427
+ type: "resize";
428
+ id: string;
429
+ columns: number;
430
+ rows: number;
431
+ } | {
432
+ /** @constant */
433
+ type: "stop";
434
+ id: string;
435
+ };
374
436
  /** @description What a socket sends on files@1, as JSON text. Each has an id of its own choosing, which the answer repeats; answers come as they are ready, in any order, and ids aren't checked for repeats. A request still unanswered when the socket closes gets no answer. A path is from the workspace, with / between its parts, or absolute inside it, and nothing outside the workspace is reached. A binary message that follows no write closes the socket, and so does any message over 1,048,576 bytes. */
375
437
  FilesRequest: {
376
438
  /** @constant */
@@ -7,24 +7,11 @@ export type ComputerLog = Schemas["ComputerLogs"]["logs"][number];
7
7
  export type LiveSurface = Schemas["Surface"];
8
8
  export type LiveMode = Schemas["LiveMode"];
9
9
  export type LiveSession = Schemas["LiveSession"];
10
- /** What happens to one of the agent's commands, as it happens. */
11
- export type CommandEvent = {
12
- type: "start";
13
- id: string;
14
- cmd: string;
15
- workdir: string;
16
- at: string;
17
- } | {
18
- type: "output";
19
- id: string;
20
- stream: "stdout" | "stderr";
21
- text: string;
22
- } | {
23
- type: "exit";
24
- id: string;
25
- exitCode: number;
26
- at: string;
27
- };
10
+ /**
11
+ * What happens to a terminal, as it happens: the agent's command or a person's shell. And
12
+ * `refused`, with why, when what this connection asked wasn't done.
13
+ */
14
+ export type TerminalEvent = Schemas["TerminalEvent"];
28
15
  export interface LiveHandle {
29
16
  close(): void;
30
17
  /** Resolves when the socket closes, with why. */
@@ -33,9 +20,14 @@ export interface LiveHandle {
33
20
  reason: string;
34
21
  }>;
35
22
  }
36
- export interface PtyHandle extends LiveHandle {
37
- sendInput(data: string): void;
38
- resize(columns: number, rows: number): void;
23
+ /** What an operating connection can do. What can't be done comes back as a `refused` event. */
24
+ export interface TerminalsHandle extends LiveHandle {
25
+ /** Start a shell of your own. It arrives as a `start` event, which carries its id. */
26
+ openShell(columns: number, rows: number): void;
27
+ /** Type into a running terminal, the agent's included: a long text as several messages. */
28
+ sendInput(id: string, text: string): void;
29
+ resize(id: string, columns: number, rows: number): void;
30
+ stop(id: string): void;
39
31
  }
40
32
  export interface ConnectionOpts {
41
33
  /** The control token; `AGENTCOMPUTER_API_KEY` by default. */
@@ -82,22 +74,23 @@ declare class Endpoint {
82
74
  close(): Promise<void>;
83
75
  }
84
76
  type Opener = (surface: LiveSurface, mode: LiveMode) => Promise<LiveSession>;
85
- /** A shell of your own on the computer, beside the agent's commands. */
86
- declare class Pty {
77
+ /** Every terminal on the computer: the agent's commands and a person's shells alike. */
78
+ declare class Terminals {
87
79
  #private;
88
80
  constructor(open: Opener);
89
- /** Attach to its shell, starting one if none is running. Every attachment shares it. */
81
+ /**
82
+ * Each terminal as it starts, writes and exits: those already there first, each with the end of
83
+ * what it wrote. Operating, the default, can also open a shell and act on any of them.
84
+ */
90
85
  connect(opts: {
91
- onData: (data: string) => void;
86
+ onEvent: (event: TerminalEvent) => void;
92
87
  mode?: LiveMode;
93
- }): Promise<PtyHandle>;
88
+ }): Promise<TerminalsHandle>;
94
89
  }
95
90
  /** Commands on a computer with the terminal level. */
96
91
  declare class Commands {
97
92
  #private;
98
- constructor(endpoint: Endpoint, open: Opener);
99
- /** Each of the agent's commands as it runs: the ones already heard first, then as they come. */
100
- watch(onEvent: (event: CommandEvent) => void): Promise<LiveHandle>;
93
+ constructor(endpoint: Endpoint);
101
94
  /** Run a command to its end. */
102
95
  run(cmd: string, opts?: {
103
96
  cwd?: string;
@@ -144,7 +137,7 @@ export declare class Computer {
144
137
  readonly computerID: string;
145
138
  readonly commands: Commands;
146
139
  readonly files: Files;
147
- readonly pty: Pty;
140
+ readonly terminals: Terminals;
148
141
  private constructor();
149
142
  static create(opts: CreateOpts): Promise<Computer>;
150
143
  /** A computer made earlier. Its token was shown when it was made, and only then. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentorg/computer",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "Computers for agents, as a service: a terminal, files and a browser over MCP",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  "playwright-core": "1.65.0-alpha-2026-10-30"
32
32
  },
33
33
  "devDependencies": {
34
- "@agentorg/exec": "0.0.4",
34
+ "@agentorg/exec": "0.0.5",
35
35
  "@biomejs/biome": "2.6.5",
36
36
  "@modelcontextprotocol/client": "2.4.0",
37
37
  "@modelcontextprotocol/node": "2.1.2",