@agentorg/computer 0.0.8 → 0.0.10
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/README.md +25 -12
- package/dist/THIRD_PARTY_LICENSES.txt +1 -1
- package/dist/agentcomputer.js +931 -383
- package/dist/sdk.js +34 -34
- package/dist/types/generated/schema.d.ts +86 -4
- package/dist/types/sdk.d.ts +23 -30
- package/package.json +2 -2
package/dist/agentcomputer.js
CHANGED
|
@@ -3753,7 +3753,7 @@ var require_websocket_server = __commonJS({
|
|
|
3753
3753
|
// src/main.ts
|
|
3754
3754
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
3755
3755
|
import { homedir as homedir2 } from "node:os";
|
|
3756
|
-
import { isAbsolute as isAbsolute2, join as
|
|
3756
|
+
import { isAbsolute as isAbsolute2, join as join11, resolve as resolve5 } from "node:path";
|
|
3757
3757
|
import { parseArgs } from "node:util";
|
|
3758
3758
|
import { isMainThread as isMainThread2 } from "node:worker_threads";
|
|
3759
3759
|
|
|
@@ -3772,9 +3772,9 @@ var playwright = () => {
|
|
|
3772
3772
|
// src/browser-host.ts
|
|
3773
3773
|
var sandboxFor = (options) => options.sandbox ?? (process.platform !== "linux" || !options.executable && !["chromium", "chrome-for-testing"].includes(options.channel ?? "chrome"));
|
|
3774
3774
|
async function hostBrowser(options) {
|
|
3775
|
-
const
|
|
3776
|
-
process.env.XDG_RUNTIME_DIR =
|
|
3777
|
-
process.env.TMPDIR =
|
|
3775
|
+
const run3 = mkdtempSync(join("/tmp", "agentcomputer-"));
|
|
3776
|
+
process.env.XDG_RUNTIME_DIR = run3;
|
|
3777
|
+
process.env.TMPDIR = run3;
|
|
3778
3778
|
const context = await playwright().chromium.launchPersistentContext(options.profile, {
|
|
3779
3779
|
headless: true,
|
|
3780
3780
|
chromiumSandbox: sandboxFor(options),
|
|
@@ -3783,7 +3783,7 @@ async function hostBrowser(options) {
|
|
|
3783
3783
|
const browser = context.browser();
|
|
3784
3784
|
if (!browser) throw new Error("The browser can't be shared.");
|
|
3785
3785
|
const { endpoint } = await browser.bind("agentcomputer");
|
|
3786
|
-
if (!endpoint.startsWith(
|
|
3786
|
+
if (!endpoint.startsWith(run3 + sep)) {
|
|
3787
3787
|
await context.close();
|
|
3788
3788
|
throw new Error(`The browser's socket isn't in its own folder: ${endpoint}`);
|
|
3789
3789
|
}
|
|
@@ -3797,7 +3797,7 @@ async function hostBrowser(options) {
|
|
|
3797
3797
|
});
|
|
3798
3798
|
await context.close().catch(() => {
|
|
3799
3799
|
});
|
|
3800
|
-
rmSync(
|
|
3800
|
+
rmSync(run3, { recursive: true, force: true });
|
|
3801
3801
|
process.exit(0);
|
|
3802
3802
|
};
|
|
3803
3803
|
for (const signal of ["SIGINT", "SIGTERM"]) process.once(signal, () => void stop());
|
|
@@ -3846,13 +3846,13 @@ async function serveBrowserMcp(options) {
|
|
|
3846
3846
|
}
|
|
3847
3847
|
|
|
3848
3848
|
// src/container.ts
|
|
3849
|
-
import { execFile, spawn as spawn3 } from "node:child_process";
|
|
3849
|
+
import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
|
|
3850
3850
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
3851
3851
|
import { connect } from "node:net";
|
|
3852
|
-
import { join as
|
|
3852
|
+
import { join as join8 } from "node:path";
|
|
3853
3853
|
import { createInterface as createInterface2 } from "node:readline";
|
|
3854
3854
|
import { Readable as Readable3 } from "node:stream";
|
|
3855
|
-
import { promisify } from "node:util";
|
|
3855
|
+
import { promisify as promisify2 } from "node:util";
|
|
3856
3856
|
|
|
3857
3857
|
// src/browser.ts
|
|
3858
3858
|
import { spawn } from "node:child_process";
|
|
@@ -6616,10 +6616,10 @@ var $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
|
|
|
6616
6616
|
}
|
|
6617
6617
|
return void 0;
|
|
6618
6618
|
});
|
|
6619
|
-
const
|
|
6619
|
+
const first2 = def.options.length === 1 ? def.options[0]._zod.run : null;
|
|
6620
6620
|
inst._zod.parse = (payload, ctx) => {
|
|
6621
|
-
if (
|
|
6622
|
-
return
|
|
6621
|
+
if (first2) {
|
|
6622
|
+
return first2(payload, ctx);
|
|
6623
6623
|
}
|
|
6624
6624
|
let async = false;
|
|
6625
6625
|
const results = [];
|
|
@@ -9017,9 +9017,9 @@ var numberProcessor = (schema, ctx, _json, params) => {
|
|
|
9017
9017
|
else
|
|
9018
9018
|
handleUnrepresentable(schema, ctx, json4, params, `A multipleOf divisor of ${divisor} cannot be represented in JSON Schema`);
|
|
9019
9019
|
}
|
|
9020
|
-
const [
|
|
9021
|
-
if (
|
|
9022
|
-
json4.multipleOf =
|
|
9020
|
+
const [first2, ...rest] = divisors;
|
|
9021
|
+
if (first2 !== void 0)
|
|
9022
|
+
json4.multipleOf = first2;
|
|
9023
9023
|
if (rest.length)
|
|
9024
9024
|
json4.allOf = [...json4.allOf ?? [], ...rest.map((m) => ({ multipleOf: m }))];
|
|
9025
9025
|
}
|
|
@@ -19229,8 +19229,8 @@ var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
19229
19229
|
}
|
|
19230
19230
|
if (bestLength < 2) return hextets.join(":");
|
|
19231
19231
|
const head = hextets.slice(0, bestStart).join(":");
|
|
19232
|
-
const
|
|
19233
|
-
return head + "::" +
|
|
19232
|
+
const tail2 = hextets.slice(bestStart + bestLength).join(":");
|
|
19233
|
+
return head + "::" + tail2;
|
|
19234
19234
|
}
|
|
19235
19235
|
function normalizeIPv6Address(input2) {
|
|
19236
19236
|
const compression = input2.indexOf("::");
|
|
@@ -28153,10 +28153,12 @@ var Browser = class {
|
|
|
28153
28153
|
// src/inside.ts
|
|
28154
28154
|
import { createServer as createServer3 } from "node:http";
|
|
28155
28155
|
import { homedir } from "node:os";
|
|
28156
|
-
import { join as
|
|
28156
|
+
import { join as join7 } from "node:path";
|
|
28157
28157
|
|
|
28158
28158
|
// src/runtime.ts
|
|
28159
|
-
import {
|
|
28159
|
+
import { chmodSync as chmodSync2, existsSync, statSync as statSync2 } from "node:fs";
|
|
28160
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
28161
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
28160
28162
|
|
|
28161
28163
|
// node_modules/@agentorg/exec/dist/lib.js
|
|
28162
28164
|
import { realpathSync } from "node:fs";
|
|
@@ -28411,7 +28413,7 @@ var require_ignore = __commonJS2({
|
|
|
28411
28413
|
// ever starts again inside it -- `(\\+?) ` did, which made a long run
|
|
28412
28414
|
// quadratic.
|
|
28413
28415
|
/(\\+)( ?)/g,
|
|
28414
|
-
(_,
|
|
28416
|
+
(_, run3, space) => space ? run3.slice(0, run3.length - run3.length % 2) + SPACE2 : run3,
|
|
28415
28417
|
ESCAPE + SPACE2
|
|
28416
28418
|
],
|
|
28417
28419
|
// git's wildmatch() reads a run of two or more asterisks as one globstar
|
|
@@ -28597,10 +28599,10 @@ var require_ignore = __commonJS2({
|
|
|
28597
28599
|
var REGEX_REPLACE_TRAILING_DOUBLESTAR = /\uE001$/;
|
|
28598
28600
|
var replaceTrailingDoublestar = () => ".+(?=$|\\/$)";
|
|
28599
28601
|
var WILDCARD2 = "[^\\/]*";
|
|
28600
|
-
var separatorAfter = (
|
|
28602
|
+
var separatorAfter = (run3, at) => {
|
|
28601
28603
|
let separator = EMPTY;
|
|
28602
|
-
for (let index = at + 1; index <
|
|
28603
|
-
separator +=
|
|
28604
|
+
for (let index = at + 1; index < run3.length && !run3[index].wildcard; index++) {
|
|
28605
|
+
separator += run3[index].single;
|
|
28604
28606
|
}
|
|
28605
28607
|
return separator;
|
|
28606
28608
|
};
|
|
@@ -28660,26 +28662,26 @@ var require_ignore = __commonJS2({
|
|
|
28660
28662
|
}
|
|
28661
28663
|
}
|
|
28662
28664
|
let out = EMPTY;
|
|
28663
|
-
let
|
|
28665
|
+
let run3 = [];
|
|
28664
28666
|
const flush = () => {
|
|
28665
28667
|
let lastWildcard;
|
|
28666
|
-
|
|
28668
|
+
run3.forEach((token, at) => {
|
|
28667
28669
|
if (token.wildcard) {
|
|
28668
28670
|
lastWildcard = at;
|
|
28669
28671
|
}
|
|
28670
28672
|
});
|
|
28671
|
-
|
|
28673
|
+
run3.forEach((token, at) => {
|
|
28672
28674
|
if (!token.wildcard) {
|
|
28673
28675
|
out += token.single;
|
|
28674
28676
|
return;
|
|
28675
28677
|
}
|
|
28676
|
-
out += at === lastWildcard ? WILDCARD2 : `(?:(?!${separatorAfter(
|
|
28678
|
+
out += at === lastWildcard ? WILDCARD2 : `(?:(?!${separatorAfter(run3, at)})[^\\/])*`;
|
|
28677
28679
|
});
|
|
28678
|
-
|
|
28680
|
+
run3 = [];
|
|
28679
28681
|
};
|
|
28680
28682
|
tokens.forEach((token) => {
|
|
28681
28683
|
if (token.boundary === void 0) {
|
|
28682
|
-
|
|
28684
|
+
run3.push(token);
|
|
28683
28685
|
return;
|
|
28684
28686
|
}
|
|
28685
28687
|
flush();
|
|
@@ -28959,11 +28961,11 @@ var require_ignore = __commonJS2({
|
|
|
28959
28961
|
return true;
|
|
28960
28962
|
};
|
|
28961
28963
|
var isNotRelative = (path) => {
|
|
28962
|
-
const
|
|
28963
|
-
if (
|
|
28964
|
+
const first2 = path.charCodeAt(0);
|
|
28965
|
+
if (first2 === SLASH_CODE) {
|
|
28964
28966
|
return true;
|
|
28965
28967
|
}
|
|
28966
|
-
if (
|
|
28968
|
+
if (first2 !== DOT_CODE) {
|
|
28967
28969
|
return false;
|
|
28968
28970
|
}
|
|
28969
28971
|
if (path.length === 1) {
|
|
@@ -32872,10 +32874,10 @@ var $ZodUnion2 = /* @__PURE__ */ $constructor2("$ZodUnion", (inst, def) => {
|
|
|
32872
32874
|
}
|
|
32873
32875
|
return void 0;
|
|
32874
32876
|
});
|
|
32875
|
-
const
|
|
32877
|
+
const first2 = def.options.length === 1 ? def.options[0]._zod.run : null;
|
|
32876
32878
|
inst._zod.parse = (payload, ctx) => {
|
|
32877
|
-
if (
|
|
32878
|
-
return
|
|
32879
|
+
if (first2) {
|
|
32880
|
+
return first2(payload, ctx);
|
|
32879
32881
|
}
|
|
32880
32882
|
let async = false;
|
|
32881
32883
|
const results = [];
|
|
@@ -32932,10 +32934,10 @@ function handleExclusiveUnionResults(results, final, inst, ctx) {
|
|
|
32932
32934
|
var $ZodXor2 = /* @__PURE__ */ $constructor2("$ZodXor", (inst, def) => {
|
|
32933
32935
|
$ZodUnion2.init(inst, def);
|
|
32934
32936
|
def.inclusive = false;
|
|
32935
|
-
const
|
|
32937
|
+
const first2 = def.options.length === 1 ? def.options[0]._zod.run : null;
|
|
32936
32938
|
inst._zod.parse = (payload, ctx) => {
|
|
32937
|
-
if (
|
|
32938
|
-
return
|
|
32939
|
+
if (first2) {
|
|
32940
|
+
return first2(payload, ctx);
|
|
32939
32941
|
}
|
|
32940
32942
|
let async = false;
|
|
32941
32943
|
const results = [];
|
|
@@ -45270,9 +45272,9 @@ var numberProcessor2 = (schema, ctx, _json, params) => {
|
|
|
45270
45272
|
else
|
|
45271
45273
|
handleUnrepresentable2(schema, ctx, json32, params, `A multipleOf divisor of ${divisor} cannot be represented in JSON Schema`);
|
|
45272
45274
|
}
|
|
45273
|
-
const [
|
|
45274
|
-
if (
|
|
45275
|
-
json32.multipleOf =
|
|
45275
|
+
const [first2, ...rest] = divisors;
|
|
45276
|
+
if (first2 !== void 0)
|
|
45277
|
+
json32.multipleOf = first2;
|
|
45276
45278
|
if (rest.length)
|
|
45277
45279
|
json32.allOf = [...json32.allOf ?? [], ...rest.map((m) => ({ multipleOf: m }))];
|
|
45278
45280
|
}
|
|
@@ -47956,14 +47958,14 @@ function checkArrayGuards(arraySchema, guards) {
|
|
|
47956
47958
|
const key = canonicalKey(items[i], /* @__PURE__ */ new Set());
|
|
47957
47959
|
if (key === null)
|
|
47958
47960
|
continue;
|
|
47959
|
-
const
|
|
47960
|
-
if (
|
|
47961
|
+
const first2 = firstSeen.get(key);
|
|
47962
|
+
if (first2 === void 0) {
|
|
47961
47963
|
firstSeen.set(key, i);
|
|
47962
47964
|
continue;
|
|
47963
47965
|
}
|
|
47964
47966
|
payload.issues.push({
|
|
47965
47967
|
code: "custom",
|
|
47966
|
-
message: `Array items must be unique: element at index ${i} duplicates the one at index ${
|
|
47968
|
+
message: `Array items must be unique: element at index ${i} duplicates the one at index ${first2}`,
|
|
47967
47969
|
input: items,
|
|
47968
47970
|
path: [i],
|
|
47969
47971
|
continue: true
|
|
@@ -48441,7 +48443,7 @@ function visit(schema, fnOrHandlers) {
|
|
|
48441
48443
|
return h ? h(node22, rewritten) : node22;
|
|
48442
48444
|
};
|
|
48443
48445
|
const cache = /* @__PURE__ */ new Map();
|
|
48444
|
-
function
|
|
48446
|
+
function run3(s) {
|
|
48445
48447
|
const cached22 = cache.get(s);
|
|
48446
48448
|
if (cached22 === RESOLVING) {
|
|
48447
48449
|
return new $ZodLazy2({
|
|
@@ -48467,21 +48469,21 @@ function visit(schema, fnOrHandlers) {
|
|
|
48467
48469
|
let changed2 = false;
|
|
48468
48470
|
const newShape = {};
|
|
48469
48471
|
for (const k of keys) {
|
|
48470
|
-
const mapped =
|
|
48472
|
+
const mapped = run3(oldShape[k]);
|
|
48471
48473
|
if (mapped !== oldShape[k])
|
|
48472
48474
|
changed2 = true;
|
|
48473
48475
|
newShape[k] = mapped;
|
|
48474
48476
|
}
|
|
48475
48477
|
let newCatchall = def.catchall;
|
|
48476
48478
|
if (def.catchall) {
|
|
48477
|
-
newCatchall =
|
|
48479
|
+
newCatchall = run3(def.catchall);
|
|
48478
48480
|
if (newCatchall !== def.catchall)
|
|
48479
48481
|
changed2 = true;
|
|
48480
48482
|
}
|
|
48481
48483
|
return changed2 ? clone2(s, { ...def, shape: newShape, catchall: newCatchall }) : s;
|
|
48482
48484
|
}
|
|
48483
48485
|
case "array": {
|
|
48484
|
-
const mapped =
|
|
48486
|
+
const mapped = run3(def.element);
|
|
48485
48487
|
return mapped === def.element ? s : clone2(s, { ...def, element: mapped });
|
|
48486
48488
|
}
|
|
48487
48489
|
case "tuple": {
|
|
@@ -48489,14 +48491,14 @@ function visit(schema, fnOrHandlers) {
|
|
|
48489
48491
|
let changed2 = false;
|
|
48490
48492
|
const newItems = [];
|
|
48491
48493
|
for (const item of oldItems) {
|
|
48492
|
-
const mapped =
|
|
48494
|
+
const mapped = run3(item);
|
|
48493
48495
|
if (mapped !== item)
|
|
48494
48496
|
changed2 = true;
|
|
48495
48497
|
newItems.push(mapped);
|
|
48496
48498
|
}
|
|
48497
48499
|
let newRest = def.rest;
|
|
48498
48500
|
if (def.rest) {
|
|
48499
|
-
newRest =
|
|
48501
|
+
newRest = run3(def.rest);
|
|
48500
48502
|
if (newRest !== def.rest)
|
|
48501
48503
|
changed2 = true;
|
|
48502
48504
|
}
|
|
@@ -48504,12 +48506,12 @@ function visit(schema, fnOrHandlers) {
|
|
|
48504
48506
|
}
|
|
48505
48507
|
case "record":
|
|
48506
48508
|
case "map": {
|
|
48507
|
-
const newKey =
|
|
48508
|
-
const newVal =
|
|
48509
|
+
const newKey = run3(def.keyType);
|
|
48510
|
+
const newVal = run3(def.valueType);
|
|
48509
48511
|
return newKey === def.keyType && newVal === def.valueType ? s : clone2(s, { ...def, keyType: newKey, valueType: newVal });
|
|
48510
48512
|
}
|
|
48511
48513
|
case "set": {
|
|
48512
|
-
const newVal =
|
|
48514
|
+
const newVal = run3(def.valueType);
|
|
48513
48515
|
return newVal === def.valueType ? s : clone2(s, { ...def, valueType: newVal });
|
|
48514
48516
|
}
|
|
48515
48517
|
case "union": {
|
|
@@ -48517,7 +48519,7 @@ function visit(schema, fnOrHandlers) {
|
|
|
48517
48519
|
let changed2 = false;
|
|
48518
48520
|
const newOptions = [];
|
|
48519
48521
|
for (const opt of oldOptions) {
|
|
48520
|
-
const mapped =
|
|
48522
|
+
const mapped = run3(opt);
|
|
48521
48523
|
if (mapped !== opt)
|
|
48522
48524
|
changed2 = true;
|
|
48523
48525
|
newOptions.push(mapped);
|
|
@@ -48525,8 +48527,8 @@ function visit(schema, fnOrHandlers) {
|
|
|
48525
48527
|
return changed2 ? clone2(s, { ...def, options: newOptions }) : s;
|
|
48526
48528
|
}
|
|
48527
48529
|
case "intersection": {
|
|
48528
|
-
const newLeft =
|
|
48529
|
-
const newRight =
|
|
48530
|
+
const newLeft = run3(def.left);
|
|
48531
|
+
const newRight = run3(def.right);
|
|
48530
48532
|
return newLeft === def.left && newRight === def.right ? s : clone2(s, { ...def, left: newLeft, right: newRight });
|
|
48531
48533
|
}
|
|
48532
48534
|
case "optional":
|
|
@@ -48538,23 +48540,23 @@ function visit(schema, fnOrHandlers) {
|
|
|
48538
48540
|
case "nonoptional":
|
|
48539
48541
|
case "promise":
|
|
48540
48542
|
case "success": {
|
|
48541
|
-
const newInner =
|
|
48543
|
+
const newInner = run3(def.innerType);
|
|
48542
48544
|
return newInner === def.innerType ? s : clone2(s, { ...def, innerType: newInner });
|
|
48543
48545
|
}
|
|
48544
48546
|
case "pipe": {
|
|
48545
|
-
const newIn =
|
|
48546
|
-
const newOut =
|
|
48547
|
+
const newIn = run3(def.in);
|
|
48548
|
+
const newOut = run3(def.out);
|
|
48547
48549
|
return newIn === def.in && newOut === def.out ? s : clone2(s, { ...def, in: newIn, out: newOut });
|
|
48548
48550
|
}
|
|
48549
48551
|
case "function": {
|
|
48550
|
-
const newInput =
|
|
48551
|
-
const newOutput =
|
|
48552
|
+
const newInput = run3(def.input);
|
|
48553
|
+
const newOutput = run3(def.output);
|
|
48552
48554
|
return newInput === def.input && newOutput === def.output ? s : clone2(s, { ...def, input: newInput, output: newOutput });
|
|
48553
48555
|
}
|
|
48554
48556
|
case "lazy": {
|
|
48555
48557
|
const original = def.getter;
|
|
48556
48558
|
const { _cachedInner, ...rest } = def;
|
|
48557
|
-
return clone2(s, { ...rest, getter: () =>
|
|
48559
|
+
return clone2(s, { ...rest, getter: () => run3(original()) });
|
|
48558
48560
|
}
|
|
48559
48561
|
// A leaf by choice: `parts` are regex fragments, not data positions.
|
|
48560
48562
|
case "template_literal":
|
|
@@ -48585,7 +48587,7 @@ function visit(schema, fnOrHandlers) {
|
|
|
48585
48587
|
}
|
|
48586
48588
|
}
|
|
48587
48589
|
}
|
|
48588
|
-
return
|
|
48590
|
+
return run3(schema);
|
|
48589
48591
|
}
|
|
48590
48592
|
function deepPartial(schema) {
|
|
48591
48593
|
return visit(schema, {
|
|
@@ -56945,8 +56947,8 @@ var require_utils2 = /* @__PURE__ */ __commonJSMin2(((exports, module) => {
|
|
|
56945
56947
|
}
|
|
56946
56948
|
if (bestLength < 2) return hextets.join(":");
|
|
56947
56949
|
const head = hextets.slice(0, bestStart).join(":");
|
|
56948
|
-
const
|
|
56949
|
-
return head + "::" +
|
|
56950
|
+
const tail2 = hextets.slice(bestStart + bestLength).join(":");
|
|
56951
|
+
return head + "::" + tail2;
|
|
56950
56952
|
}
|
|
56951
56953
|
function normalizeIPv6Address(input2) {
|
|
56952
56954
|
const compression = input2.indexOf("::");
|
|
@@ -63419,9 +63421,9 @@ var WebStandardStreamableHTTPServerTransport = class {
|
|
|
63419
63421
|
}
|
|
63420
63422
|
});
|
|
63421
63423
|
}
|
|
63422
|
-
async _checkScopeChallenge(
|
|
63424
|
+
async _checkScopeChallenge(messages2, authInfo) {
|
|
63423
63425
|
if (!this._scopeChallengeResolver) return;
|
|
63424
|
-
const challenge = await findScopeChallenge(
|
|
63426
|
+
const challenge = await findScopeChallenge(messages2.filter((message) => isJSONRPCRequest2(message)), authInfo, this._scopeChallengeResolver);
|
|
63425
63427
|
return challenge === void 0 ? void 0 : createScopeChallengeResponse(challenge, scopeChallengeResourceMetadataUrl(authInfo));
|
|
63426
63428
|
}
|
|
63427
63429
|
/**
|
|
@@ -63719,21 +63721,21 @@ data:
|
|
|
63719
63721
|
this.onerror?.(/* @__PURE__ */ new Error(`Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE} messages`));
|
|
63720
63722
|
return this.createJsonErrorResponse(400, -32600, `Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE} messages`);
|
|
63721
63723
|
}
|
|
63722
|
-
let
|
|
63724
|
+
let messages2;
|
|
63723
63725
|
try {
|
|
63724
|
-
|
|
63726
|
+
messages2 = Array.isArray(rawMessage) ? rawMessage.map((msg) => JSONRPCMessageSchema2.parse(msg)) : [JSONRPCMessageSchema2.parse(rawMessage)];
|
|
63725
63727
|
} catch (error62) {
|
|
63726
63728
|
this.onerror?.(error62);
|
|
63727
63729
|
return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON-RPC message");
|
|
63728
63730
|
}
|
|
63729
63731
|
if (this._closed) return this.createJsonErrorResponse(404, -32001, "Session not found");
|
|
63730
|
-
const isInitializationRequest =
|
|
63732
|
+
const isInitializationRequest = messages2.some((element) => isInitializeRequest2(element));
|
|
63731
63733
|
if (isInitializationRequest) {
|
|
63732
63734
|
if (this._initialized && this.sessionId !== void 0) {
|
|
63733
63735
|
this.onerror?.(/* @__PURE__ */ new Error("Invalid Request: Server already initialized"));
|
|
63734
63736
|
return this.createJsonErrorResponse(400, -32600, "Invalid Request: Server already initialized");
|
|
63735
63737
|
}
|
|
63736
|
-
if (
|
|
63738
|
+
if (messages2.length > 1) {
|
|
63737
63739
|
this.onerror?.(/* @__PURE__ */ new Error("Invalid Request: Only one initialization request is allowed"));
|
|
63738
63740
|
return this.createJsonErrorResponse(400, -32600, "Invalid Request: Only one initialization request is allowed");
|
|
63739
63741
|
}
|
|
@@ -63750,21 +63752,21 @@ data:
|
|
|
63750
63752
|
if (this._closed) return this.createJsonErrorResponse(404, -32001, "Session not found");
|
|
63751
63753
|
let scopeChallengeResponse;
|
|
63752
63754
|
try {
|
|
63753
|
-
scopeChallengeResponse = await this._checkScopeChallenge(
|
|
63755
|
+
scopeChallengeResponse = await this._checkScopeChallenge(messages2, options?.authInfo);
|
|
63754
63756
|
} catch (error62) {
|
|
63755
63757
|
this.onerror?.(error62);
|
|
63756
63758
|
return this.createJsonErrorResponse(500, -32603, "Internal server error");
|
|
63757
63759
|
}
|
|
63758
63760
|
if (scopeChallengeResponse) return scopeChallengeResponse;
|
|
63759
|
-
if (!
|
|
63760
|
-
for (const message of
|
|
63761
|
+
if (!messages2.some((element) => isJSONRPCRequest2(element))) {
|
|
63762
|
+
for (const message of messages2) this.onmessage?.(message, {
|
|
63761
63763
|
authInfo: options?.authInfo,
|
|
63762
63764
|
request
|
|
63763
63765
|
});
|
|
63764
63766
|
return new Response(null, { status: 202 });
|
|
63765
63767
|
}
|
|
63766
63768
|
const streamId = crypto.randomUUID();
|
|
63767
|
-
const initRequest =
|
|
63769
|
+
const initRequest = messages2.find((m) => isInitializeRequest2(m));
|
|
63768
63770
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION2;
|
|
63769
63771
|
if (this._enableJsonResponse) return new Promise((resolve42) => {
|
|
63770
63772
|
this._streamMapping.set(streamId, {
|
|
@@ -63773,8 +63775,8 @@ data:
|
|
|
63773
63775
|
this._streamMapping.delete(streamId);
|
|
63774
63776
|
}
|
|
63775
63777
|
});
|
|
63776
|
-
for (const message of
|
|
63777
|
-
for (const message of
|
|
63778
|
+
for (const message of messages2) if (isJSONRPCRequest2(message)) this._requestToStreamMapping.set(message.id, streamId);
|
|
63779
|
+
for (const message of messages2) this.onmessage?.(message, {
|
|
63778
63780
|
authInfo: options?.authInfo,
|
|
63779
63781
|
request
|
|
63780
63782
|
});
|
|
@@ -63798,7 +63800,7 @@ data:
|
|
|
63798
63800
|
"X-Accel-Buffering": "no"
|
|
63799
63801
|
};
|
|
63800
63802
|
if (this.sessionId !== void 0) headers["mcp-session-id"] = this.sessionId;
|
|
63801
|
-
for (const message of
|
|
63803
|
+
for (const message of messages2) if (isJSONRPCRequest2(message)) {
|
|
63802
63804
|
this._streamMapping.set(streamId, {
|
|
63803
63805
|
controller: streamController,
|
|
63804
63806
|
encoder,
|
|
@@ -63814,7 +63816,7 @@ data:
|
|
|
63814
63816
|
this._requestToStreamMapping.set(message.id, streamId);
|
|
63815
63817
|
}
|
|
63816
63818
|
await this.writePrimingEvent(streamController, encoder, streamId, clientProtocolVersion);
|
|
63817
|
-
for (const message of
|
|
63819
|
+
for (const message of messages2) {
|
|
63818
63820
|
let closeSSEStream;
|
|
63819
63821
|
let closeStandaloneSSEStream;
|
|
63820
63822
|
if (isJSONRPCRequest2(message) && this._eventStore && this.supportsEmptySSEData(clientProtocolVersion)) {
|
|
@@ -65811,10 +65813,10 @@ function cut(text22, max) {
|
|
|
65811
65813
|
if (text22.length <= max) return text22;
|
|
65812
65814
|
const half = Math.max(1, Math.floor(max / 2));
|
|
65813
65815
|
const head = text22.slice(0, half).replace(/[\uD800-\uDBFF]$/, "");
|
|
65814
|
-
const
|
|
65816
|
+
const tail2 = text22.slice(-half).replace(/^[\uDC00-\uDFFF]/, "");
|
|
65815
65817
|
return `${head}
|
|
65816
|
-
\u2026 ${text22.length - head.length -
|
|
65817
|
-
${
|
|
65818
|
+
\u2026 ${text22.length - head.length - tail2.length} characters cut \u2026
|
|
65819
|
+
${tail2}`;
|
|
65818
65820
|
}
|
|
65819
65821
|
var Pending = class {
|
|
65820
65822
|
#head = "";
|
|
@@ -65850,6 +65852,10 @@ var DEFAULT_YIELD_MS = 1e4;
|
|
|
65850
65852
|
var MIN_POLL_MS = 5e3;
|
|
65851
65853
|
var WRITE_YIELD_MS = 250;
|
|
65852
65854
|
var MAX_RUNNING = 64;
|
|
65855
|
+
var MAX_ENDED = 64;
|
|
65856
|
+
var KEPT = 64 * 1024;
|
|
65857
|
+
var CMD_SHOWN = 200;
|
|
65858
|
+
var MAX_SIZE = 1e3;
|
|
65853
65859
|
var DEFAULT_MAX_TOKENS = 7e3;
|
|
65854
65860
|
var DRAIN_MS = 200;
|
|
65855
65861
|
var KILL_AFTER_MS = 1e3;
|
|
@@ -65863,48 +65869,183 @@ var SIGNALS = {
|
|
|
65863
65869
|
SIGTERM: 15
|
|
65864
65870
|
};
|
|
65865
65871
|
var clamp = (value, low, high) => Math.min(Math.max(value, low), high);
|
|
65872
|
+
var tail = (text22) => text22.slice(-KEPT).replace(/^[\uDC00-\uDFFF]/, "");
|
|
65866
65873
|
var Sessions = class {
|
|
65867
65874
|
#sessions = /* @__PURE__ */ new Map();
|
|
65875
|
+
/** Those that have ended and are still listed, in the order they ended. */
|
|
65876
|
+
#ended = [];
|
|
65868
65877
|
#root;
|
|
65869
65878
|
#emit;
|
|
65879
|
+
#pty;
|
|
65870
65880
|
constructor(root, emit = () => {
|
|
65871
|
-
}) {
|
|
65881
|
+
}, pty2) {
|
|
65872
65882
|
this.#root = root;
|
|
65873
65883
|
this.#emit = emit;
|
|
65884
|
+
this.#pty = pty2;
|
|
65874
65885
|
}
|
|
65875
65886
|
/** Run `cmd` in a login shell, in `workdir` or the workspace. */
|
|
65876
65887
|
async exec(input2) {
|
|
65877
|
-
|
|
65878
|
-
if (running.length >= MAX_RUNNING)
|
|
65879
|
-
throw new ExecRefused(`${MAX_RUNNING} commands are running. Wait for one, or stop one.`);
|
|
65888
|
+
this.#room();
|
|
65880
65889
|
const started = Date.now();
|
|
65881
65890
|
const session = this.#start(input2.cmd, input2.workdir ?? this.#root);
|
|
65882
65891
|
const wait = clamp(input2.yield_time_ms ?? DEFAULT_YIELD_MS, MIN_YIELD_MS, MAX_YIELD_MS);
|
|
65883
65892
|
return this.#after(session, wait, started, input2.max_output_tokens);
|
|
65884
65893
|
}
|
|
65885
65894
|
/**
|
|
65886
|
-
* Type into a running
|
|
65887
|
-
* (`\u0003`) interrupts it and Ctrl-D (`\u0004`) ends its input
|
|
65895
|
+
* Type into a running terminal, or with no `chars` wait and see what it has written. In a
|
|
65896
|
+
* command, Ctrl-C (`\u0003`) interrupts it and Ctrl-D (`\u0004`) ends its input; a shell on a
|
|
65897
|
+
* terminal device is typed into as it is.
|
|
65888
65898
|
*/
|
|
65889
65899
|
async write(input2) {
|
|
65890
65900
|
const session = this.#sessions.get(input2.session_id);
|
|
65891
|
-
if (!session
|
|
65901
|
+
if (!session || session.reported)
|
|
65902
|
+
throw new ExecRefused(`No session ${input2.session_id.slice(0, 64)} is running.`);
|
|
65892
65903
|
const started = Date.now();
|
|
65893
65904
|
const chars = input2.chars ?? "";
|
|
65894
|
-
if (session.exitCode === void 0)
|
|
65905
|
+
if (session.exitCode === void 0) session.type(chars);
|
|
65895
65906
|
const wait = chars ? clamp(input2.yield_time_ms ?? WRITE_YIELD_MS, MIN_YIELD_MS, MAX_YIELD_MS) : clamp(input2.yield_time_ms ?? MIN_POLL_MS, MIN_POLL_MS, MAX_YIELD_MS);
|
|
65896
65907
|
return this.#after(session, wait, started, input2.max_output_tokens);
|
|
65897
65908
|
}
|
|
65898
|
-
/**
|
|
65909
|
+
/** Every terminal, the oldest first: those running, and the last that ended. */
|
|
65910
|
+
list() {
|
|
65911
|
+
return [...this.#sessions.values()].map((session) => ({
|
|
65912
|
+
id: session.id,
|
|
65913
|
+
by: session.by,
|
|
65914
|
+
cmd: session.cmd,
|
|
65915
|
+
workdir: session.workdir,
|
|
65916
|
+
tty: session.tty,
|
|
65917
|
+
at: session.at,
|
|
65918
|
+
output: tail(session.last),
|
|
65919
|
+
...session.exitCode === void 0 ? {} : { exitCode: session.exitCode, endedAt: session.endedAt }
|
|
65920
|
+
}));
|
|
65921
|
+
}
|
|
65922
|
+
/** Start a person's login shell in the workspace, on a terminal device of this size. */
|
|
65923
|
+
open(columns, rows) {
|
|
65924
|
+
if (!this.#pty)
|
|
65925
|
+
throw new ExecRefused("A shell needs a terminal device, and this host has none to give.");
|
|
65926
|
+
this.#room();
|
|
65927
|
+
const size = sized(columns, rows);
|
|
65928
|
+
const file2 = process.env.SHELL || "/bin/bash";
|
|
65929
|
+
let shell;
|
|
65930
|
+
try {
|
|
65931
|
+
shell = this.#pty(file2, ["-l"], {
|
|
65932
|
+
name: "xterm-256color",
|
|
65933
|
+
...size,
|
|
65934
|
+
cwd: this.#root,
|
|
65935
|
+
env: process.env
|
|
65936
|
+
});
|
|
65937
|
+
} catch (error62) {
|
|
65938
|
+
const why = error62 instanceof Error ? error62.message : String(error62);
|
|
65939
|
+
throw new ExecRefused(`The shell didn't start: ${why}`);
|
|
65940
|
+
}
|
|
65941
|
+
const { session, wrote, finish } = this.#begin("person", file2, this.#root, true, {
|
|
65942
|
+
type: (chars) => shell.write(chars),
|
|
65943
|
+
signal(signal) {
|
|
65944
|
+
try {
|
|
65945
|
+
shell.kill(signal);
|
|
65946
|
+
} catch {
|
|
65947
|
+
}
|
|
65948
|
+
},
|
|
65949
|
+
resize: (cols, lines) => shell.resize(cols, lines)
|
|
65950
|
+
});
|
|
65951
|
+
shell.onData((text22) => wrote(text22));
|
|
65952
|
+
shell.onExit(({ exitCode, signal }) => finish(signal ? 128 + signal : exitCode));
|
|
65953
|
+
return session.id;
|
|
65954
|
+
}
|
|
65955
|
+
/** Type into a running terminal, as `write` does and with no answer. */
|
|
65956
|
+
type(id, chars) {
|
|
65957
|
+
this.#running(id).type(chars);
|
|
65958
|
+
}
|
|
65959
|
+
/** Give a shell's terminal device a new size. */
|
|
65960
|
+
resize(id, columns, rows) {
|
|
65961
|
+
const session = this.#running(id);
|
|
65962
|
+
if (!session.resize) throw new ExecRefused("Only a shell on a terminal device has a size.");
|
|
65963
|
+
const size = sized(columns, rows);
|
|
65964
|
+
session.resize(size.cols, size.rows);
|
|
65965
|
+
}
|
|
65966
|
+
/**
|
|
65967
|
+
* End one terminal: an interrupt, then a certain signal. It resolves once the terminal has
|
|
65968
|
+
* ended or that signal is sent. One that has ended is left alone.
|
|
65969
|
+
*/
|
|
65970
|
+
async stop(id) {
|
|
65971
|
+
const session = this.#sessions.get(id);
|
|
65972
|
+
if (!session) throw new ExecRefused(`No terminal ${id.slice(0, 64)} is here.`);
|
|
65973
|
+
await this.#end([session], "SIGINT");
|
|
65974
|
+
}
|
|
65975
|
+
/** Stop every terminal: a polite signal, then a certain one. */
|
|
65899
65976
|
async stopAll() {
|
|
65900
|
-
|
|
65901
|
-
|
|
65977
|
+
await this.#end([...this.#sessions.values()], "SIGTERM");
|
|
65978
|
+
}
|
|
65979
|
+
async #end(sessions, polite) {
|
|
65980
|
+
const running = sessions.filter((s) => s.exitCode === void 0);
|
|
65981
|
+
for (const session of running) session.signal(session.tty ? "SIGHUP" : polite);
|
|
65982
|
+
let timer;
|
|
65902
65983
|
await Promise.race([
|
|
65903
65984
|
Promise.all(running.map((s) => s.ended)),
|
|
65904
|
-
new Promise((done) =>
|
|
65985
|
+
new Promise((done) => {
|
|
65986
|
+
timer = setTimeout(done, KILL_AFTER_MS);
|
|
65987
|
+
})
|
|
65905
65988
|
]);
|
|
65906
|
-
|
|
65907
|
-
|
|
65989
|
+
clearTimeout(timer);
|
|
65990
|
+
for (const session of running) if (session.exitCode === void 0) session.signal("SIGKILL");
|
|
65991
|
+
}
|
|
65992
|
+
#room() {
|
|
65993
|
+
const running = [...this.#sessions.values()].filter((s) => s.exitCode === void 0);
|
|
65994
|
+
if (running.length >= MAX_RUNNING)
|
|
65995
|
+
throw new ExecRefused(`${MAX_RUNNING} commands are running. Wait for one, or stop one.`);
|
|
65996
|
+
}
|
|
65997
|
+
#running(id) {
|
|
65998
|
+
const session = this.#sessions.get(id);
|
|
65999
|
+
if (!session) throw new ExecRefused(`No terminal ${id.slice(0, 64)} is here.`);
|
|
66000
|
+
if (session.exitCode !== void 0) throw new ExecRefused("That terminal has ended.");
|
|
66001
|
+
return session;
|
|
66002
|
+
}
|
|
66003
|
+
/**
|
|
66004
|
+
* List a terminal that has just started, with the ways to act on its process, and give the two
|
|
66005
|
+
* ways that process reports back.
|
|
66006
|
+
*/
|
|
66007
|
+
#begin(by, cmd, workdir, tty, acts) {
|
|
66008
|
+
const id = `s_${randomBytes(9).toString("hex")}`;
|
|
66009
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
66010
|
+
let done = () => {
|
|
66011
|
+
};
|
|
66012
|
+
const session = {
|
|
66013
|
+
id,
|
|
66014
|
+
by,
|
|
66015
|
+
cmd,
|
|
66016
|
+
workdir,
|
|
66017
|
+
tty,
|
|
66018
|
+
at,
|
|
66019
|
+
pending: new Pending(),
|
|
66020
|
+
last: "",
|
|
66021
|
+
ended: new Promise((resolve42) => {
|
|
66022
|
+
done = resolve42;
|
|
66023
|
+
}),
|
|
66024
|
+
...acts
|
|
66025
|
+
};
|
|
66026
|
+
this.#sessions.set(id, session);
|
|
66027
|
+
this.#emit({ type: "start", id, by, cmd, workdir, tty, at });
|
|
66028
|
+
const wrote = (text22, stream) => {
|
|
66029
|
+
if (!text22) return;
|
|
66030
|
+
session.pending.add(text22);
|
|
66031
|
+
session.last += text22;
|
|
66032
|
+
if (session.last.length > 2 * KEPT) session.last = tail(session.last);
|
|
66033
|
+
this.#emit({ type: "output", id, ...stream ? { stream } : {}, text: text22 });
|
|
66034
|
+
};
|
|
66035
|
+
const finish = (exitCode) => {
|
|
66036
|
+
if (session.exitCode !== void 0) return;
|
|
66037
|
+
session.exitCode = exitCode;
|
|
66038
|
+
session.endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
66039
|
+
this.#emit({ type: "exit", id, exitCode, at: session.endedAt });
|
|
66040
|
+
this.#ended.push(session);
|
|
66041
|
+
if (this.#ended.length > MAX_ENDED) {
|
|
66042
|
+
const read = this.#ended.findIndex((one) => one.reported);
|
|
66043
|
+
const [old] = this.#ended.splice(Math.max(read, 0), 1);
|
|
66044
|
+
this.#sessions.delete(old.id);
|
|
66045
|
+
}
|
|
66046
|
+
done();
|
|
66047
|
+
};
|
|
66048
|
+
return { session, wrote, finish };
|
|
65908
66049
|
}
|
|
65909
66050
|
#start(cmd, cwd) {
|
|
65910
66051
|
const child = spawn2(process.env.SHELL || "/bin/bash", ["-lc", cmd], {
|
|
@@ -65913,62 +66054,44 @@ var Sessions = class {
|
|
|
65913
66054
|
// Its own process group, so a signal reaches what it started.
|
|
65914
66055
|
detached: true
|
|
65915
66056
|
});
|
|
65916
|
-
const
|
|
65917
|
-
|
|
65918
|
-
|
|
65919
|
-
|
|
66057
|
+
const signal = (name) => {
|
|
66058
|
+
try {
|
|
66059
|
+
if (child.pid) process.kill(-child.pid, name);
|
|
66060
|
+
} catch {
|
|
66061
|
+
}
|
|
66062
|
+
};
|
|
66063
|
+
const type = (chars) => {
|
|
66064
|
+
for (const part of chars.split(new RegExp("(\\p{Cc})", "u"))) {
|
|
66065
|
+
if (part === "") signal("SIGINT");
|
|
66066
|
+
else if (part === "") child.stdin.end();
|
|
66067
|
+
else if (part && child.stdin.writable) child.stdin.write(part);
|
|
66068
|
+
}
|
|
66069
|
+
};
|
|
66070
|
+
const { session, wrote, finish } = this.#begin("agent", cmd, cwd, false, { type, signal });
|
|
65920
66071
|
for (const [name, stream] of [
|
|
65921
66072
|
["stdout", child.stdout],
|
|
65922
66073
|
["stderr", child.stderr]
|
|
65923
66074
|
]) {
|
|
65924
66075
|
const decoder = new StringDecoder("utf8");
|
|
65925
|
-
stream.on("data", (chunk) =>
|
|
65926
|
-
const text22 = decoder.write(chunk);
|
|
65927
|
-
pending.add(text22);
|
|
65928
|
-
if (text22) this.#emit({ type: "output", id, stream: name, text: text22 });
|
|
65929
|
-
});
|
|
66076
|
+
stream.on("data", (chunk) => wrote(decoder.write(chunk), name));
|
|
65930
66077
|
}
|
|
65931
66078
|
child.stdin.on("error", () => {
|
|
65932
66079
|
});
|
|
65933
|
-
|
|
65934
|
-
|
|
65935
|
-
|
|
65936
|
-
|
|
65937
|
-
|
|
65938
|
-
|
|
65939
|
-
|
|
65940
|
-
|
|
65941
|
-
|
|
65942
|
-
|
|
65943
|
-
|
|
65944
|
-
` });
|
|
65945
|
-
finish(127);
|
|
65946
|
-
});
|
|
65947
|
-
child.once("exit", (code, signal) => {
|
|
65948
|
-
const exitCode = code ?? 128 + (signal ? SIGNALS[signal] ?? 1 : 1);
|
|
65949
|
-
const late = setTimeout(() => finish(exitCode), DRAIN_MS);
|
|
65950
|
-
child.once("close", () => {
|
|
65951
|
-
clearTimeout(late);
|
|
65952
|
-
finish(exitCode);
|
|
65953
|
-
});
|
|
66080
|
+
child.once("error", (error62) => {
|
|
66081
|
+
wrote(`${error62.message}
|
|
66082
|
+
`, "stderr");
|
|
66083
|
+
finish(127);
|
|
66084
|
+
});
|
|
66085
|
+
child.once("exit", (code, signal2) => {
|
|
66086
|
+
const exitCode = code ?? 128 + (signal2 ? SIGNALS[signal2] ?? 1 : 1);
|
|
66087
|
+
const late = setTimeout(() => finish(exitCode), DRAIN_MS);
|
|
66088
|
+
child.once("close", () => {
|
|
66089
|
+
clearTimeout(late);
|
|
66090
|
+
finish(exitCode);
|
|
65954
66091
|
});
|
|
65955
66092
|
});
|
|
65956
|
-
this.#sessions.set(session.id, session);
|
|
65957
66093
|
return session;
|
|
65958
66094
|
}
|
|
65959
|
-
#type(session, chars) {
|
|
65960
|
-
for (const part of chars.split(new RegExp("(\\p{Cc})", "u"))) {
|
|
65961
|
-
if (part === "") this.#signal(session, "SIGINT");
|
|
65962
|
-
else if (part === "") session.child.stdin.end();
|
|
65963
|
-
else if (part && session.child.stdin.writable) session.child.stdin.write(part);
|
|
65964
|
-
}
|
|
65965
|
-
}
|
|
65966
|
-
#signal(session, signal) {
|
|
65967
|
-
try {
|
|
65968
|
-
if (session.child.pid) process.kill(-session.child.pid, signal);
|
|
65969
|
-
} catch {
|
|
65970
|
-
}
|
|
65971
|
-
}
|
|
65972
66095
|
async #after(session, waitMs, started, maxTokens) {
|
|
65973
66096
|
let timer;
|
|
65974
66097
|
await Promise.race([
|
|
@@ -65979,7 +66102,7 @@ var Sessions = class {
|
|
|
65979
66102
|
]);
|
|
65980
66103
|
clearTimeout(timer);
|
|
65981
66104
|
const exited = session.exitCode !== void 0;
|
|
65982
|
-
if (exited)
|
|
66105
|
+
if (exited) session.reported = true;
|
|
65983
66106
|
return {
|
|
65984
66107
|
exit_code: exited ? session.exitCode : null,
|
|
65985
66108
|
seconds: Math.round(Date.now() - started) / 1e3,
|
|
@@ -65988,6 +66111,12 @@ var Sessions = class {
|
|
|
65988
66111
|
};
|
|
65989
66112
|
}
|
|
65990
66113
|
};
|
|
66114
|
+
function sized(columns, rows) {
|
|
66115
|
+
for (const value of [columns, rows])
|
|
66116
|
+
if (!Number.isInteger(value) || value < 1 || value > MAX_SIZE)
|
|
66117
|
+
throw new ExecRefused(`A terminal has 1 to ${MAX_SIZE} columns and rows.`);
|
|
66118
|
+
return { cols: columns, rows };
|
|
66119
|
+
}
|
|
65991
66120
|
function formatAnswer(answer) {
|
|
65992
66121
|
return [
|
|
65993
66122
|
`exit_code: ${answer.exit_code ?? "running"}`,
|
|
@@ -65997,6 +66126,31 @@ function formatAnswer(answer) {
|
|
|
65997
66126
|
answer.text
|
|
65998
66127
|
].join("\n");
|
|
65999
66128
|
}
|
|
66129
|
+
function listing(terminals) {
|
|
66130
|
+
return terminals.map((one) => {
|
|
66131
|
+
const line = one.cmd.split("\n", 1)[0].slice(0, CMD_SHOWN);
|
|
66132
|
+
const shown = line.replace(/[\uD800-\uDBFF]$/, "");
|
|
66133
|
+
return {
|
|
66134
|
+
session_id: one.id,
|
|
66135
|
+
started_by: one.by,
|
|
66136
|
+
since: one.at,
|
|
66137
|
+
exit_code: one.exitCode ?? null,
|
|
66138
|
+
cmd: shown === one.cmd ? shown : `${shown}\u2026`
|
|
66139
|
+
};
|
|
66140
|
+
});
|
|
66141
|
+
}
|
|
66142
|
+
function formatSessions(listed) {
|
|
66143
|
+
if (listed.length === 0) return "No sessions.";
|
|
66144
|
+
return listed.map(
|
|
66145
|
+
(one) => [
|
|
66146
|
+
`session_id: ${one.session_id}`,
|
|
66147
|
+
`started_by: ${one.started_by}`,
|
|
66148
|
+
`since: ${one.since}`,
|
|
66149
|
+
`exit_code: ${one.exit_code ?? "running"}`,
|
|
66150
|
+
`cmd: ${one.cmd}`
|
|
66151
|
+
].join("\n")
|
|
66152
|
+
).join("\n\n");
|
|
66153
|
+
}
|
|
66000
66154
|
var DEFAULT_LINES = 2e3;
|
|
66001
66155
|
var MAX_READ_CHARS = 28e3;
|
|
66002
66156
|
var MAX_LINE_CHARS = 2e3;
|
|
@@ -66060,10 +66214,10 @@ function createFiles(root) {
|
|
|
66060
66214
|
/** Numbered lines of a file. */
|
|
66061
66215
|
read: (input2) => refusing(async () => {
|
|
66062
66216
|
const lines = (await text22(await at(input2.path), input2.path)).split("\n");
|
|
66063
|
-
const
|
|
66064
|
-
const shown = lines.slice(
|
|
66065
|
-
const last =
|
|
66066
|
-
return `lines ${
|
|
66217
|
+
const first2 = Math.max(input2.offset ?? 1, 1);
|
|
66218
|
+
const shown = lines.slice(first2 - 1, first2 - 1 + (input2.limit ?? DEFAULT_LINES)).map((line, i) => `${first2 + i} ${cut(line, MAX_LINE_CHARS)}`);
|
|
66219
|
+
const last = first2 + shown.length - 1;
|
|
66220
|
+
return `lines ${first2}-${last} of ${lines.length}
|
|
66067
66221
|
${cut(shown.join("\n"), MAX_READ_CHARS)}`;
|
|
66068
66222
|
}),
|
|
66069
66223
|
/** A folder's entries, folders first, each folder ending in `/`. */
|
|
@@ -66409,9 +66563,9 @@ function createServer2(root, sessions, version22, level) {
|
|
|
66409
66563
|
server.registerTool(
|
|
66410
66564
|
"write_stdin",
|
|
66411
66565
|
{
|
|
66412
|
-
description: "Types into a running command and returns what it wrote since. With no chars, waits and returns what it has written. A Ctrl-C character (\\u0003) interrupts it; Ctrl-D (\\u0004) ends its input.",
|
|
66566
|
+
description: "Types into a running command and returns what it wrote since. With no chars, waits and returns what it has written. A Ctrl-C character (\\u0003) interrupts it; Ctrl-D (\\u0004) ends its input. It also reaches a shell a person opened, by its id from list_sessions: there these are keys, what you type joins anything already typed, and Ctrl-D at its prompt closes it. Once an answer has given a session's exit code, that session is refused.",
|
|
66413
66567
|
inputSchema: {
|
|
66414
|
-
session_id: external_exports.string().min(1).describe("From exec_command's answer."),
|
|
66568
|
+
session_id: external_exports.string().min(1).describe("From exec_command's answer, or list_sessions."),
|
|
66415
66569
|
chars: external_exports.string().optional().describe("What to type; include \\n to press Enter."),
|
|
66416
66570
|
yield_time_ms: YieldTime.describe(
|
|
66417
66571
|
"How long to wait: with chars 250 to 30000, by default 250; with none 5000 to 30000."
|
|
@@ -66423,6 +66577,28 @@ function createServer2(root, sessions, version22, level) {
|
|
|
66423
66577
|
},
|
|
66424
66578
|
(input2) => answering(() => sessions.write(input2))
|
|
66425
66579
|
);
|
|
66580
|
+
server.registerTool(
|
|
66581
|
+
"list_sessions",
|
|
66582
|
+
{
|
|
66583
|
+
description: "Lists the sessions here, running or lately ended: each command exec_command started, and each shell a person opened. Gives each one's session_id for write_stdin, who started it, since when, its exit code and the start of its command.",
|
|
66584
|
+
outputSchema: {
|
|
66585
|
+
sessions: external_exports.array(
|
|
66586
|
+
external_exports.object({
|
|
66587
|
+
session_id: external_exports.string(),
|
|
66588
|
+
started_by: external_exports.enum(["agent", "person"]).describe("A person's is their own shell."),
|
|
66589
|
+
since: external_exports.string().describe("When it started."),
|
|
66590
|
+
exit_code: external_exports.number().nullable().describe("Null while it is still running."),
|
|
66591
|
+
cmd: external_exports.string().describe("Its first line, or the start of it.")
|
|
66592
|
+
})
|
|
66593
|
+
)
|
|
66594
|
+
},
|
|
66595
|
+
annotations: READ_ONLY
|
|
66596
|
+
},
|
|
66597
|
+
() => {
|
|
66598
|
+
const listed = listing(sessions.list());
|
|
66599
|
+
return { ...text(formatSessions(listed)), structuredContent: { sessions: listed } };
|
|
66600
|
+
}
|
|
66601
|
+
);
|
|
66426
66602
|
}
|
|
66427
66603
|
server.registerTool(
|
|
66428
66604
|
"read",
|
|
@@ -66478,18 +66654,22 @@ function createServer2(root, sessions, version22, level) {
|
|
|
66478
66654
|
);
|
|
66479
66655
|
return server;
|
|
66480
66656
|
}
|
|
66481
|
-
var VERSION = "0.0.
|
|
66657
|
+
var VERSION = "0.0.5";
|
|
66482
66658
|
function createAgentExec(options) {
|
|
66483
66659
|
const root = realpathSync(resolve3(options.workspace));
|
|
66484
66660
|
const level = options.level ?? "read";
|
|
66485
66661
|
const listeners = /* @__PURE__ */ new Set();
|
|
66486
|
-
const sessions = new Sessions(
|
|
66487
|
-
|
|
66488
|
-
|
|
66489
|
-
|
|
66490
|
-
|
|
66491
|
-
|
|
66492
|
-
|
|
66662
|
+
const sessions = new Sessions(
|
|
66663
|
+
root,
|
|
66664
|
+
(event) => {
|
|
66665
|
+
for (const listener of listeners)
|
|
66666
|
+
try {
|
|
66667
|
+
listener(event);
|
|
66668
|
+
} catch {
|
|
66669
|
+
}
|
|
66670
|
+
},
|
|
66671
|
+
options.pty
|
|
66672
|
+
);
|
|
66493
66673
|
const host = createHostFiles(root, level);
|
|
66494
66674
|
return {
|
|
66495
66675
|
async handle(request, response, body) {
|
|
@@ -66507,6 +66687,16 @@ function createAgentExec(options) {
|
|
|
66507
66687
|
return () => void listeners.delete(listener);
|
|
66508
66688
|
},
|
|
66509
66689
|
files: host.files,
|
|
66690
|
+
terminals: {
|
|
66691
|
+
list: () => sessions.list(),
|
|
66692
|
+
open({ columns, rows }) {
|
|
66693
|
+
if (level !== "terminal") throw new Error("A shell needs the terminal level.");
|
|
66694
|
+
return sessions.open(columns, rows);
|
|
66695
|
+
},
|
|
66696
|
+
write: (id, text22) => sessions.type(id, text22),
|
|
66697
|
+
resize: (id, columns, rows) => sessions.resize(id, columns, rows),
|
|
66698
|
+
stop: (id) => sessions.stop(id)
|
|
66699
|
+
},
|
|
66510
66700
|
async close() {
|
|
66511
66701
|
await Promise.all([sessions.stopAll(), host.close()]);
|
|
66512
66702
|
}
|
|
@@ -66927,11 +67117,6 @@ var BrowserLive = class {
|
|
|
66927
67117
|
}
|
|
66928
67118
|
};
|
|
66929
67119
|
|
|
66930
|
-
// src/live.ts
|
|
66931
|
-
import { chmodSync, existsSync, statSync as statSync2 } from "node:fs";
|
|
66932
|
-
import { createRequire as createRequire3 } from "node:module";
|
|
66933
|
-
import { dirname as dirname3, join as join5 } from "node:path";
|
|
66934
|
-
|
|
66935
67120
|
// node_modules/ws/wrapper.mjs
|
|
66936
67121
|
var import_stream2 = __toESM(require_stream(), 1);
|
|
66937
67122
|
var import_extension = __toESM(require_extension(), 1);
|
|
@@ -67109,183 +67294,263 @@ var FilesLive = class {
|
|
|
67109
67294
|
}
|
|
67110
67295
|
};
|
|
67111
67296
|
|
|
67297
|
+
// src/text.ts
|
|
67298
|
+
var MAX_TEXT = 1e4;
|
|
67299
|
+
function* pieces(text3, most = MAX_TEXT) {
|
|
67300
|
+
for (let from = 0; from < text3.length; ) {
|
|
67301
|
+
let to = Math.min(from + most, text3.length);
|
|
67302
|
+
const last = text3.charCodeAt(to - 1);
|
|
67303
|
+
if (to < text3.length && last >= 55296 && last <= 56319) to -= 1;
|
|
67304
|
+
yield text3.slice(from, to);
|
|
67305
|
+
from = to;
|
|
67306
|
+
}
|
|
67307
|
+
}
|
|
67308
|
+
|
|
67112
67309
|
// src/live.ts
|
|
67113
67310
|
var PROTOCOLS = {
|
|
67114
|
-
|
|
67115
|
-
terminal: "pty@1",
|
|
67311
|
+
terminal: "terminal@1",
|
|
67116
67312
|
files: "files@1",
|
|
67117
|
-
browser: "screencast@1"
|
|
67313
|
+
browser: "screencast@1",
|
|
67314
|
+
load: "metrics@1"
|
|
67118
67315
|
};
|
|
67119
|
-
var
|
|
67120
|
-
var
|
|
67121
|
-
var
|
|
67122
|
-
|
|
67123
|
-
|
|
67124
|
-
|
|
67125
|
-
var
|
|
67126
|
-
var
|
|
67127
|
-
var
|
|
67128
|
-
|
|
67129
|
-
|
|
67130
|
-
|
|
67131
|
-
|
|
67132
|
-
|
|
67133
|
-
|
|
67134
|
-
|
|
67135
|
-
|
|
67136
|
-
|
|
67137
|
-
for (const helper of [
|
|
67138
|
-
join5(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"),
|
|
67139
|
-
join5(root, "build", "Release", "spawn-helper")
|
|
67140
|
-
])
|
|
67141
|
-
try {
|
|
67142
|
-
if (existsSync(helper) && (statSync2(helper).mode & 73) === 0) chmodSync(helper, 493);
|
|
67143
|
-
} catch {
|
|
67144
|
-
return `The terminal needs ${helper} to be executable, and it isn't.`;
|
|
67145
|
-
}
|
|
67146
|
-
return loaded2;
|
|
67147
|
-
})();
|
|
67148
|
-
return pty;
|
|
67316
|
+
var MAX_MESSAGE = 64 * 1024;
|
|
67317
|
+
var MAX_BUFFERED3 = 4 * 1024 * 1024;
|
|
67318
|
+
var deliver = (ws, message) => {
|
|
67319
|
+
if (ws.bufferedAmount > MAX_BUFFERED3) ws.terminate();
|
|
67320
|
+
else ws.send(JSON.stringify(message));
|
|
67321
|
+
};
|
|
67322
|
+
var MAX_CMD = 8e3;
|
|
67323
|
+
var MAX_WORKDIR = 2e3;
|
|
67324
|
+
var SERVERS = {
|
|
67325
|
+
terminal: new import_websocket_server.default({ noServer: true, maxPayload: MAX_MESSAGE }),
|
|
67326
|
+
files: new import_websocket_server.default({ noServer: true, maxPayload: MAX_PART }),
|
|
67327
|
+
browser: new import_websocket_server.default({ noServer: true }),
|
|
67328
|
+
load: new import_websocket_server.default({ noServer: true, maxPayload: MAX_MESSAGE })
|
|
67329
|
+
};
|
|
67330
|
+
var MALFORMED = "That isn't a terminal@1 message.";
|
|
67331
|
+
var first = (text3, most) => {
|
|
67332
|
+
const [head = ""] = pieces(text3, most);
|
|
67333
|
+
return head;
|
|
67149
67334
|
};
|
|
67335
|
+
function* messages(event) {
|
|
67336
|
+
if (event.type === "start")
|
|
67337
|
+
yield { ...event, cmd: first(event.cmd, MAX_CMD), workdir: first(event.workdir, MAX_WORKDIR) };
|
|
67338
|
+
else if (event.type === "exit") yield event;
|
|
67339
|
+
else for (const text3 of pieces(event.text)) yield { ...event, text: text3 };
|
|
67340
|
+
}
|
|
67150
67341
|
var Live = class {
|
|
67151
|
-
#
|
|
67152
|
-
#
|
|
67153
|
-
#events = [];
|
|
67154
|
-
#watchers = /* @__PURE__ */ new Set();
|
|
67155
|
-
#shells = /* @__PURE__ */ new Map();
|
|
67156
|
-
#shell;
|
|
67157
|
-
#scrollback = "";
|
|
67342
|
+
#terminals;
|
|
67343
|
+
#viewers = /* @__PURE__ */ new Set();
|
|
67158
67344
|
#browser;
|
|
67159
67345
|
#files;
|
|
67160
67346
|
/** Whether a person may write files here: not where the agent can only read them. */
|
|
67161
67347
|
#writes;
|
|
67162
|
-
|
|
67163
|
-
|
|
67164
|
-
this.#
|
|
67348
|
+
#load;
|
|
67349
|
+
constructor(exec, access, load, browser) {
|
|
67350
|
+
this.#load = load;
|
|
67351
|
+
if (exec && access === "terminal") {
|
|
67352
|
+
this.#terminals = exec.terminals;
|
|
67353
|
+
exec.onCommand((event) => {
|
|
67354
|
+
for (const message of messages(event)) for (const ws of this.#viewers) deliver(ws, message);
|
|
67355
|
+
});
|
|
67356
|
+
}
|
|
67165
67357
|
this.#files = exec && new FilesLive(exec.files);
|
|
67166
67358
|
this.#writes = access !== "read";
|
|
67167
67359
|
this.#browser = browser;
|
|
67168
|
-
exec?.onCommand((event) => this.#heard(event));
|
|
67169
67360
|
}
|
|
67170
|
-
|
|
67361
|
+
surfaces() {
|
|
67171
67362
|
const surfaces = [];
|
|
67172
|
-
if (this.#
|
|
67173
|
-
|
|
67174
|
-
surfaces.push(
|
|
67175
|
-
{ surface: "commands", protocol: PROTOCOLS.commands, operate: false },
|
|
67176
|
-
{
|
|
67177
|
-
surface: "terminal",
|
|
67178
|
-
protocol: PROTOCOLS.terminal,
|
|
67179
|
-
operate: true,
|
|
67180
|
-
...typeof loaded2 === "string" ? { unavailable: loaded2 } : {}
|
|
67181
|
-
}
|
|
67182
|
-
);
|
|
67183
|
-
}
|
|
67363
|
+
if (this.#terminals)
|
|
67364
|
+
surfaces.push({ surface: "terminal", protocol: PROTOCOLS.terminal, operate: true });
|
|
67184
67365
|
if (this.#files)
|
|
67185
67366
|
surfaces.push({ surface: "files", protocol: PROTOCOLS.files, operate: this.#writes });
|
|
67186
67367
|
if (this.#browser)
|
|
67187
67368
|
surfaces.push({ surface: "browser", protocol: PROTOCOLS.browser, operate: true });
|
|
67369
|
+
surfaces.push({ surface: "load", protocol: PROTOCOLS.load, operate: false });
|
|
67188
67370
|
return surfaces;
|
|
67189
67371
|
}
|
|
67190
67372
|
/** Take an upgraded request as a socket on one surface. */
|
|
67191
67373
|
open(surface, mode, request, socket, head) {
|
|
67192
67374
|
socket.on("error", () => socket.destroy());
|
|
67193
|
-
|
|
67194
|
-
server.handleUpgrade(request, socket, head, (ws) => {
|
|
67375
|
+
SERVERS[surface].handleUpgrade(request, socket, head, (ws) => {
|
|
67195
67376
|
ws.on("error", () => ws.terminate());
|
|
67196
|
-
if (surface === "
|
|
67377
|
+
if (surface === "terminal" && this.#terminals) this.#view(ws, mode, this.#terminals);
|
|
67197
67378
|
else if (surface === "files" && this.#files) this.#files.open(ws, mode);
|
|
67198
67379
|
else if (surface === "browser" && this.#browser) this.#browser.open(ws, mode);
|
|
67199
|
-
else if (surface === "
|
|
67380
|
+
else if (surface === "load") this.#load.open(ws);
|
|
67200
67381
|
else ws.close(1011, `There's no ${surface} here.`);
|
|
67201
67382
|
});
|
|
67202
67383
|
}
|
|
67384
|
+
/** The terminals themselves end with the AgentExec that runs them. */
|
|
67203
67385
|
close() {
|
|
67204
67386
|
void this.#browser?.close();
|
|
67205
67387
|
this.#files?.close();
|
|
67206
|
-
|
|
67207
|
-
this.#
|
|
67208
|
-
|
|
67209
|
-
|
|
67210
|
-
|
|
67211
|
-
|
|
67212
|
-
|
|
67213
|
-
|
|
67214
|
-
|
|
67215
|
-
|
|
67216
|
-
|
|
67217
|
-
|
|
67218
|
-
|
|
67219
|
-
|
|
67220
|
-
|
|
67221
|
-
|
|
67222
|
-
|
|
67223
|
-
|
|
67224
|
-
|
|
67225
|
-
if (
|
|
67226
|
-
|
|
67227
|
-
|
|
67228
|
-
let shell;
|
|
67388
|
+
this.#load.close();
|
|
67389
|
+
for (const ws of this.#viewers) ws.close(1001, "It stopped.");
|
|
67390
|
+
}
|
|
67391
|
+
/**
|
|
67392
|
+
* terminal@1: every terminal on one socket. Those already here come first, each with the end of
|
|
67393
|
+
* what it wrote, and then each event as it happens. Listing and joining are one step, so nothing
|
|
67394
|
+
* falls between them.
|
|
67395
|
+
*/
|
|
67396
|
+
#view(ws, mode, terminals) {
|
|
67397
|
+
for (const { id, by, cmd, workdir, tty, at, output: output2, exitCode, endedAt } of terminals.list()) {
|
|
67398
|
+
const events = [{ type: "start", id, by, cmd, workdir, tty, at }];
|
|
67399
|
+
if (output2) events.push({ type: "output", id, text: output2 });
|
|
67400
|
+
if (exitCode !== void 0 && endedAt)
|
|
67401
|
+
events.push({ type: "exit", id, exitCode, at: endedAt });
|
|
67402
|
+
for (const event of events)
|
|
67403
|
+
for (const message of messages(event)) ws.send(JSON.stringify(message));
|
|
67404
|
+
}
|
|
67405
|
+
this.#viewers.add(ws);
|
|
67406
|
+
ws.on("close", () => this.#viewers.delete(ws));
|
|
67407
|
+
if (mode !== "operate") return;
|
|
67408
|
+
const refuse = (why) => deliver(ws, { type: "refused", message: reason2(why) });
|
|
67409
|
+
ws.on("message", (data) => {
|
|
67229
67410
|
try {
|
|
67230
|
-
|
|
67231
|
-
|
|
67232
|
-
|
|
67233
|
-
|
|
67234
|
-
|
|
67235
|
-
|
|
67236
|
-
|
|
67411
|
+
const sent = JSON.parse(data.toString()) ?? {};
|
|
67412
|
+
const { type, id, text: text3 } = sent;
|
|
67413
|
+
const [columns, rows] = [sent.columns, sent.rows];
|
|
67414
|
+
if (type === "open") terminals.open({ columns, rows });
|
|
67415
|
+
else if (typeof id !== "string") throw new Error(MALFORMED);
|
|
67416
|
+
else if (type === "input" && typeof text3 === "string") terminals.write(id, text3);
|
|
67417
|
+
else if (type === "resize") terminals.resize(id, columns, rows);
|
|
67418
|
+
else if (type === "stop") terminals.stop(id).catch(refuse);
|
|
67419
|
+
else throw new Error(MALFORMED);
|
|
67237
67420
|
} catch (error62) {
|
|
67238
|
-
|
|
67421
|
+
refuse(error62 instanceof SyntaxError ? MALFORMED : error62);
|
|
67239
67422
|
}
|
|
67240
|
-
shell.onData((data) => {
|
|
67241
|
-
this.#scrollback = (this.#scrollback + data).slice(-MAX_SCROLLBACK);
|
|
67242
|
-
const frame = Buffer.concat([Buffer.from([OUTPUT]), Buffer.from(data)]);
|
|
67243
|
-
for (const client of this.#shells.keys()) client.send(frame);
|
|
67244
|
-
});
|
|
67245
|
-
shell.onExit(() => {
|
|
67246
|
-
if (this.#shell !== shell) return;
|
|
67247
|
-
this.#shell = void 0;
|
|
67248
|
-
for (const client of this.#shells.keys()) client.close(1e3, "The shell exited.");
|
|
67249
|
-
});
|
|
67250
|
-
this.#shell = shell;
|
|
67251
|
-
}
|
|
67252
|
-
if (this.#scrollback)
|
|
67253
|
-
ws.send(Buffer.concat([Buffer.from([OUTPUT]), Buffer.from(this.#scrollback)]));
|
|
67254
|
-
this.#shells.set(ws, mode);
|
|
67255
|
-
ws.on("close", () => this.#shells.delete(ws));
|
|
67256
|
-
ws.on("message", (data, binary) => {
|
|
67257
|
-
const frame = binary ? data : Buffer.from(data);
|
|
67258
|
-
if (mode !== "operate" || frame.length === 0 || !this.#shell) return;
|
|
67259
|
-
if (frame[0] === INPUT) this.#shell.write(frame.subarray(1).toString());
|
|
67260
|
-
else if (frame[0] === RESIZE)
|
|
67261
|
-
try {
|
|
67262
|
-
const { columns, rows } = JSON.parse(frame.subarray(1).toString());
|
|
67263
|
-
if (columns > 0 && rows > 0) this.#shell.resize(Math.floor(columns), Math.floor(rows));
|
|
67264
|
-
} catch {
|
|
67265
|
-
}
|
|
67266
67423
|
});
|
|
67267
67424
|
}
|
|
67268
67425
|
};
|
|
67269
67426
|
|
|
67427
|
+
// src/load-live.ts
|
|
67428
|
+
import { execFile } from "node:child_process";
|
|
67429
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
67430
|
+
import { availableParallelism, cpus, freemem, totalmem } from "node:os";
|
|
67431
|
+
import { promisify } from "node:util";
|
|
67432
|
+
var EVERY_MS = 2e3;
|
|
67433
|
+
var run = promisify(execFile);
|
|
67434
|
+
var numberOf = (text3, name) => Number(new RegExp(`^${name}\\s+(\\d+)`, "m").exec(text3)?.[1]);
|
|
67435
|
+
async function disk(folder) {
|
|
67436
|
+
const { stdout } = await run("df", ["-kP", folder], { timeout: EVERY_MS });
|
|
67437
|
+
const [, total, used] = /\s(\d+)\s+(\d+)\s+\d+\s+\d+%/.exec(stdout) ?? [];
|
|
67438
|
+
if (!total) throw new Error("No disk.");
|
|
67439
|
+
return { diskUsed: Number(used) * 1024, diskTotal: Number(total) * 1024 };
|
|
67440
|
+
}
|
|
67441
|
+
async function machine() {
|
|
67442
|
+
const cpu = { used: 0, total: 0 };
|
|
67443
|
+
for (const { times } of cpus()) {
|
|
67444
|
+
cpu.used += times.user + times.nice + times.sys + times.irq;
|
|
67445
|
+
cpu.total += times.user + times.nice + times.sys + times.irq + times.idle;
|
|
67446
|
+
}
|
|
67447
|
+
if (process.platform !== "darwin")
|
|
67448
|
+
return { scope: "machine", cpu, memUsed: totalmem() - freemem() };
|
|
67449
|
+
const { stdout } = await run("/usr/bin/vm_stat", { timeout: EVERY_MS });
|
|
67450
|
+
const pages = numberOf(stdout, "Pages active:") + numberOf(stdout, "Pages wired down:") + numberOf(stdout, "Pages occupied by compressor:");
|
|
67451
|
+
return { scope: "machine", cpu, memUsed: pages * Number(/page size of (\d+)/.exec(stdout)?.[1]) };
|
|
67452
|
+
}
|
|
67453
|
+
async function cgroup() {
|
|
67454
|
+
const read = (file2) => readFile2(`/sys/fs/cgroup/${file2}`, "utf8");
|
|
67455
|
+
const [cpu, current, memory] = await Promise.all([
|
|
67456
|
+
read("cpu.stat"),
|
|
67457
|
+
read("memory.current"),
|
|
67458
|
+
read("memory.stat")
|
|
67459
|
+
]);
|
|
67460
|
+
return {
|
|
67461
|
+
scope: "computer",
|
|
67462
|
+
// No container has a limit, so the time there was is every CPU's.
|
|
67463
|
+
cpu: {
|
|
67464
|
+
used: numberOf(cpu, "usage_usec"),
|
|
67465
|
+
total: performance.now() * 1e3 * availableParallelism()
|
|
67466
|
+
},
|
|
67467
|
+
// Less the files it has read and no longer uses, as `docker stats` counts it.
|
|
67468
|
+
memUsed: Number(current) - numberOf(memory, "inactive_file")
|
|
67469
|
+
};
|
|
67470
|
+
}
|
|
67471
|
+
var LoadLive = class {
|
|
67472
|
+
#folder;
|
|
67473
|
+
#contained;
|
|
67474
|
+
#sockets = /* @__PURE__ */ new Set();
|
|
67475
|
+
#timer;
|
|
67476
|
+
#reading = false;
|
|
67477
|
+
#before;
|
|
67478
|
+
#last;
|
|
67479
|
+
/**
|
|
67480
|
+
* `folder` is on the disk that is reported. `contained` is whether the processes here are one
|
|
67481
|
+
* computer's and nothing else's, as they are inside a container.
|
|
67482
|
+
*/
|
|
67483
|
+
constructor(folder, contained) {
|
|
67484
|
+
this.#folder = folder;
|
|
67485
|
+
this.#contained = contained;
|
|
67486
|
+
}
|
|
67487
|
+
/** metrics@1: a reading every two seconds, the last one at once. What it sends is dropped. */
|
|
67488
|
+
open(ws) {
|
|
67489
|
+
this.#sockets.add(ws);
|
|
67490
|
+
if (this.#last) ws.send(this.#last);
|
|
67491
|
+
ws.on("close", () => {
|
|
67492
|
+
this.#sockets.delete(ws);
|
|
67493
|
+
if (this.#sockets.size === 0) this.close();
|
|
67494
|
+
});
|
|
67495
|
+
if (this.#timer) return;
|
|
67496
|
+
this.#timer = setInterval(() => void this.#read(), EVERY_MS);
|
|
67497
|
+
void this.#read();
|
|
67498
|
+
}
|
|
67499
|
+
close() {
|
|
67500
|
+
clearInterval(this.#timer);
|
|
67501
|
+
this.#timer = this.#before = this.#last = void 0;
|
|
67502
|
+
for (const ws of this.#sockets) ws.close(1001, "It stopped.");
|
|
67503
|
+
}
|
|
67504
|
+
/** One at a time, and for the watching it began under: a reading taken too late is left. */
|
|
67505
|
+
async #read() {
|
|
67506
|
+
const timer = this.#timer;
|
|
67507
|
+
if (this.#reading) return;
|
|
67508
|
+
this.#reading = true;
|
|
67509
|
+
try {
|
|
67510
|
+
const sample = await (this.#contained ? cgroup().catch(machine) : machine());
|
|
67511
|
+
const volume = await disk(this.#folder);
|
|
67512
|
+
if (this.#timer !== timer) return;
|
|
67513
|
+
const before = this.#before;
|
|
67514
|
+
this.#before = sample.cpu;
|
|
67515
|
+
if (!before) return;
|
|
67516
|
+
const share = (sample.cpu.used - before.used) / (sample.cpu.total - before.total) || 0;
|
|
67517
|
+
const reading = {
|
|
67518
|
+
type: "reading",
|
|
67519
|
+
scope: sample.scope,
|
|
67520
|
+
cpuUsedPct: Math.round(Math.min(Math.max(share, 0), 1) * 1e3) / 10,
|
|
67521
|
+
memUsed: sample.memUsed,
|
|
67522
|
+
memTotal: totalmem(),
|
|
67523
|
+
...volume
|
|
67524
|
+
};
|
|
67525
|
+
if (!Number.isFinite(reading.cpuUsedPct + reading.memUsed)) return;
|
|
67526
|
+
this.#last = JSON.stringify(reading);
|
|
67527
|
+
for (const ws of this.#sockets) if (ws.bufferedAmount === 0) ws.send(this.#last);
|
|
67528
|
+
} catch {
|
|
67529
|
+
} finally {
|
|
67530
|
+
this.#reading = false;
|
|
67531
|
+
}
|
|
67532
|
+
}
|
|
67533
|
+
};
|
|
67534
|
+
|
|
67270
67535
|
// src/store.ts
|
|
67271
67536
|
import { createHash, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
|
|
67272
|
-
import { chmodSync
|
|
67273
|
-
import { join as
|
|
67537
|
+
import { chmodSync, mkdirSync, readFileSync as readFileSync2, renameSync, writeFileSync } from "node:fs";
|
|
67538
|
+
import { join as join5 } from "node:path";
|
|
67274
67539
|
var newToken = () => randomBytes4(32).toString("base64url");
|
|
67275
67540
|
var digestOf = (token) => createHash("sha256").update(token).digest("hex");
|
|
67276
67541
|
var sameToken = (token, digest) => timingSafeEqual(Buffer.from(digestOf(token), "hex"), Buffer.from(digest, "hex"));
|
|
67277
67542
|
function writePrivate(file2, text3) {
|
|
67278
67543
|
writeFileSync(`${file2}.tmp`, text3, { mode: 384, flush: true });
|
|
67279
67544
|
renameSync(`${file2}.tmp`, file2);
|
|
67280
|
-
|
|
67545
|
+
chmodSync(file2, 384);
|
|
67281
67546
|
}
|
|
67282
67547
|
var privateFolder = (dir) => {
|
|
67283
67548
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
67284
|
-
|
|
67549
|
+
chmodSync(dir, 448);
|
|
67285
67550
|
return dir;
|
|
67286
67551
|
};
|
|
67287
67552
|
function controlToken(data) {
|
|
67288
|
-
const file2 =
|
|
67553
|
+
const file2 = join5(data, "control-token");
|
|
67289
67554
|
try {
|
|
67290
67555
|
return readFileSync2(file2, "utf8").trim();
|
|
67291
67556
|
} catch (error62) {
|
|
@@ -67305,11 +67570,41 @@ var ApiError = class extends Error {
|
|
|
67305
67570
|
this.status = status;
|
|
67306
67571
|
}
|
|
67307
67572
|
};
|
|
67573
|
+
var pty;
|
|
67574
|
+
var loadPty = () => {
|
|
67575
|
+
pty ??= (async () => {
|
|
67576
|
+
const fails = (why) => () => {
|
|
67577
|
+
throw new Error(why);
|
|
67578
|
+
};
|
|
67579
|
+
const require3 = createRequire3(import.meta.url);
|
|
67580
|
+
let loaded2;
|
|
67581
|
+
try {
|
|
67582
|
+
loaded2 = require3("node-pty");
|
|
67583
|
+
} catch {
|
|
67584
|
+
return fails("node-pty isn't installed with this service.");
|
|
67585
|
+
}
|
|
67586
|
+
const root = dirname3(require3.resolve("node-pty/package.json"));
|
|
67587
|
+
for (const helper of [
|
|
67588
|
+
join6(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"),
|
|
67589
|
+
join6(root, "build", "Release", "spawn-helper")
|
|
67590
|
+
])
|
|
67591
|
+
try {
|
|
67592
|
+
if (existsSync(helper) && (statSync2(helper).mode & 73) === 0) chmodSync2(helper, 493);
|
|
67593
|
+
} catch {
|
|
67594
|
+
return fails(`${helper} has to be executable, and it isn't.`);
|
|
67595
|
+
}
|
|
67596
|
+
return loaded2.spawn;
|
|
67597
|
+
})();
|
|
67598
|
+
return pty;
|
|
67599
|
+
};
|
|
67308
67600
|
var ProcessRuntime = class {
|
|
67309
67601
|
isolation = "none";
|
|
67310
67602
|
#config;
|
|
67311
|
-
|
|
67603
|
+
#contained;
|
|
67604
|
+
/** `contained` is for inside a container, where load is the computer's own. */
|
|
67605
|
+
constructor(config3, contained = false) {
|
|
67312
67606
|
this.#config = config3;
|
|
67607
|
+
this.#contained = contained;
|
|
67313
67608
|
}
|
|
67314
67609
|
async prepare() {
|
|
67315
67610
|
}
|
|
@@ -67320,11 +67615,15 @@ var ProcessRuntime = class {
|
|
|
67320
67615
|
async start(spec, folder, events) {
|
|
67321
67616
|
let exec;
|
|
67322
67617
|
if (spec.access !== "none")
|
|
67323
|
-
exec = createAgentExec({
|
|
67618
|
+
exec = createAgentExec({
|
|
67619
|
+
workspace: spec.workspace,
|
|
67620
|
+
level: spec.access,
|
|
67621
|
+
pty: await loadPty()
|
|
67622
|
+
});
|
|
67324
67623
|
let browser;
|
|
67325
67624
|
let browserDown = false;
|
|
67326
67625
|
if (spec.browser) {
|
|
67327
|
-
const own3 = privateFolder(
|
|
67626
|
+
const own3 = privateFolder(join6(folder, "browser"));
|
|
67328
67627
|
browser = new Browser(
|
|
67329
67628
|
this.#config,
|
|
67330
67629
|
own3,
|
|
@@ -67348,8 +67647,9 @@ var ProcessRuntime = class {
|
|
|
67348
67647
|
browserLive = new BrowserLive(browser.endpoint);
|
|
67349
67648
|
browser.gate = browserLive;
|
|
67350
67649
|
}
|
|
67351
|
-
const
|
|
67352
|
-
const
|
|
67650
|
+
const load = new LoadLive(spec.workspace ?? folder, this.#contained);
|
|
67651
|
+
const live = new Live(exec, spec.access, load, browserLive);
|
|
67652
|
+
const surfaces = live.surfaces();
|
|
67353
67653
|
return {
|
|
67354
67654
|
browserTools: browser?.tools ?? [],
|
|
67355
67655
|
/** As they are now: a browser that has stopped can't be opened, and says so. */
|
|
@@ -67384,13 +67684,13 @@ async function serveInside(options) {
|
|
|
67384
67684
|
if (!token) throw new Error(`${INNER_TOKEN_VARIABLE} is not set.`);
|
|
67385
67685
|
delete process.env[INNER_TOKEN_VARIABLE];
|
|
67386
67686
|
const digest = digestOf(token);
|
|
67387
|
-
const running = new ProcessRuntime({ path: BROWSER, sandbox: false }).start(
|
|
67687
|
+
const running = new ProcessRuntime({ path: BROWSER, sandbox: false }, true).start(
|
|
67388
67688
|
{
|
|
67389
67689
|
id: "inside",
|
|
67390
67690
|
...options,
|
|
67391
67691
|
...options.access === "none" ? {} : { workspace: "/workspace" }
|
|
67392
67692
|
},
|
|
67393
|
-
privateFolder(
|
|
67693
|
+
privateFolder(join7(homedir(), ".agentcomputer")),
|
|
67394
67694
|
{
|
|
67395
67695
|
log: (line) => process.stdout.write(`${line}
|
|
67396
67696
|
`),
|
|
@@ -67425,7 +67725,7 @@ async function serveInside(options) {
|
|
|
67425
67725
|
socket.on("error", () => socket.destroy());
|
|
67426
67726
|
const given = /^Bearer (\S+)$/.exec(request.headers.authorization ?? "")?.[1];
|
|
67427
67727
|
const url3 = new URL(request.url ?? "/", "http://localhost");
|
|
67428
|
-
const surface = /^\/live\/(
|
|
67728
|
+
const surface = /^\/live\/(terminal|files|browser|load)$/.exec(url3.pathname)?.[1];
|
|
67429
67729
|
const mode = url3.searchParams.get("mode");
|
|
67430
67730
|
if (!given || !sameToken(given, digest) || !surface || mode !== "watch" && mode !== "operate")
|
|
67431
67731
|
return void socket.end("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
|
|
@@ -67440,7 +67740,7 @@ async function serveInside(options) {
|
|
|
67440
67740
|
}
|
|
67441
67741
|
|
|
67442
67742
|
// src/container.ts
|
|
67443
|
-
var
|
|
67743
|
+
var run2 = promisify2(execFile2);
|
|
67444
67744
|
var START_MS2 = 6e4;
|
|
67445
67745
|
var STOP_SECONDS = "5";
|
|
67446
67746
|
var NOT_FORWARDED = /* @__PURE__ */ new Set([
|
|
@@ -67454,7 +67754,7 @@ var NOT_FORWARDED = /* @__PURE__ */ new Set([
|
|
|
67454
67754
|
]);
|
|
67455
67755
|
async function docker(args, env = process.env) {
|
|
67456
67756
|
try {
|
|
67457
|
-
return (await
|
|
67757
|
+
return (await run2("docker", args, { env, maxBuffer: 16 * 1024 * 1024 })).stdout.trim();
|
|
67458
67758
|
} catch (error62) {
|
|
67459
67759
|
const { stderr, message } = error62;
|
|
67460
67760
|
throw new Error(stderr?.trim() || message);
|
|
@@ -67533,7 +67833,7 @@ var ContainerRuntime = class {
|
|
|
67533
67833
|
}
|
|
67534
67834
|
/** The token between the service and this container, which a restart has to find again. */
|
|
67535
67835
|
#tokenIn(folder) {
|
|
67536
|
-
const file2 =
|
|
67836
|
+
const file2 = join8(folder, "inner-token");
|
|
67537
67837
|
try {
|
|
67538
67838
|
return readFileSync3(file2, "utf8");
|
|
67539
67839
|
} catch {
|
|
@@ -67672,7 +67972,7 @@ async function forward(url3, authorization, request, response) {
|
|
|
67672
67972
|
}
|
|
67673
67973
|
|
|
67674
67974
|
// src/handlers.ts
|
|
67675
|
-
var VERSION2 = "0.0.
|
|
67975
|
+
var VERSION2 = "0.0.10";
|
|
67676
67976
|
function createHandlers(computers) {
|
|
67677
67977
|
return {
|
|
67678
67978
|
getInfo: async () => ({ version: VERSION2, isolation: computers.isolation }),
|
|
@@ -68254,32 +68554,30 @@ async function openLive(session, onMessage) {
|
|
|
68254
68554
|
ws.addEventListener("message", (event) => onMessage(event.data));
|
|
68255
68555
|
return { ws, closed };
|
|
68256
68556
|
}
|
|
68257
|
-
var
|
|
68258
|
-
var RESIZE2 = 49;
|
|
68259
|
-
var Pty = class {
|
|
68557
|
+
var Terminals = class {
|
|
68260
68558
|
#open;
|
|
68261
68559
|
constructor(open4) {
|
|
68262
68560
|
this.#open = open4;
|
|
68263
68561
|
}
|
|
68264
|
-
/**
|
|
68562
|
+
/**
|
|
68563
|
+
* Each terminal as it starts, writes and exits: those already there first, each with the end of
|
|
68564
|
+
* what it wrote. Operating, the default, can also open a shell and act on any of them.
|
|
68565
|
+
*/
|
|
68265
68566
|
async connect(opts) {
|
|
68266
|
-
const
|
|
68267
|
-
|
|
68268
|
-
|
|
68269
|
-
|
|
68270
|
-
|
|
68271
|
-
|
|
68272
|
-
|
|
68273
|
-
const send2 = (type, text3) => {
|
|
68274
|
-
const body = new TextEncoder().encode(text3);
|
|
68275
|
-
const frame = new Uint8Array(body.length + 1);
|
|
68276
|
-
frame[0] = type;
|
|
68277
|
-
frame.set(body, 1);
|
|
68278
|
-
ws.send(frame);
|
|
68279
|
-
};
|
|
68567
|
+
const { ws, closed } = await openLive(
|
|
68568
|
+
await this.#open("terminal", opts.mode ?? "operate"),
|
|
68569
|
+
(data) => {
|
|
68570
|
+
if (typeof data === "string") opts.onEvent(JSON.parse(data));
|
|
68571
|
+
}
|
|
68572
|
+
);
|
|
68573
|
+
const send2 = (input2) => ws.send(JSON.stringify(input2));
|
|
68280
68574
|
return {
|
|
68281
|
-
|
|
68282
|
-
|
|
68575
|
+
openShell: (columns, rows) => send2({ type: "open", columns, rows }),
|
|
68576
|
+
sendInput: (id, text3) => {
|
|
68577
|
+
for (const piece of pieces(text3)) send2({ type: "input", id, text: piece });
|
|
68578
|
+
},
|
|
68579
|
+
resize: (id, columns, rows) => send2({ type: "resize", id, columns, rows }),
|
|
68580
|
+
stop: (id) => send2({ type: "stop", id }),
|
|
68283
68581
|
close: () => ws.close(),
|
|
68284
68582
|
closed
|
|
68285
68583
|
};
|
|
@@ -68287,17 +68585,8 @@ var Pty = class {
|
|
|
68287
68585
|
};
|
|
68288
68586
|
var Commands = class {
|
|
68289
68587
|
#endpoint;
|
|
68290
|
-
|
|
68291
|
-
constructor(endpoint, open4) {
|
|
68588
|
+
constructor(endpoint) {
|
|
68292
68589
|
this.#endpoint = endpoint;
|
|
68293
|
-
this.#open = open4;
|
|
68294
|
-
}
|
|
68295
|
-
/** Each of the agent's commands as it runs: the ones already heard first, then as they come. */
|
|
68296
|
-
async watch(onEvent) {
|
|
68297
|
-
const { ws, closed } = await openLive(await this.#open("commands", "watch"), (data) => {
|
|
68298
|
-
if (typeof data === "string") onEvent(JSON.parse(data));
|
|
68299
|
-
});
|
|
68300
|
-
return { close: () => ws.close(), closed };
|
|
68301
68590
|
}
|
|
68302
68591
|
async run(cmd, opts = {}) {
|
|
68303
68592
|
let answer = await this.#endpoint.command("exec_command", {
|
|
@@ -68374,7 +68663,7 @@ var Computer = class _Computer {
|
|
|
68374
68663
|
computerID;
|
|
68375
68664
|
commands;
|
|
68376
68665
|
files;
|
|
68377
|
-
|
|
68666
|
+
terminals;
|
|
68378
68667
|
#connection;
|
|
68379
68668
|
#token;
|
|
68380
68669
|
#computer;
|
|
@@ -68385,9 +68674,8 @@ var Computer = class _Computer {
|
|
|
68385
68674
|
this.#token = token;
|
|
68386
68675
|
this.#urls = info.endpoints;
|
|
68387
68676
|
this.#computer = new Endpoint(info.endpoints.computer, token);
|
|
68388
|
-
|
|
68389
|
-
this.
|
|
68390
|
-
this.pty = new Pty(open4);
|
|
68677
|
+
this.commands = new Commands(this.#computer);
|
|
68678
|
+
this.terminals = new Terminals((surface, mode) => this.liveSession(surface, mode));
|
|
68391
68679
|
this.files = new Files(this.#computer);
|
|
68392
68680
|
}
|
|
68393
68681
|
static async create(opts) {
|
|
@@ -68508,7 +68796,7 @@ import {
|
|
|
68508
68796
|
STATUS_CODES as STATUS_CODES3
|
|
68509
68797
|
} from "node:http";
|
|
68510
68798
|
import { createServer as createTlsServer } from "node:https";
|
|
68511
|
-
import { join as
|
|
68799
|
+
import { join as join10 } from "node:path";
|
|
68512
68800
|
|
|
68513
68801
|
// node_modules/@modelcontextprotocol/server/dist/chunk-vYduTEsO.mjs
|
|
68514
68802
|
var __create4 = Object.create;
|
|
@@ -75942,8 +76230,8 @@ var require_utils3 = /* @__PURE__ */ __commonJSMin3(((exports, module) => {
|
|
|
75942
76230
|
}
|
|
75943
76231
|
if (bestLength < 2) return hextets.join(":");
|
|
75944
76232
|
const head = hextets.slice(0, bestStart).join(":");
|
|
75945
|
-
const
|
|
75946
|
-
return head + "::" +
|
|
76233
|
+
const tail2 = hextets.slice(bestStart + bestLength).join(":");
|
|
76234
|
+
return head + "::" + tail2;
|
|
75947
76235
|
}
|
|
75948
76236
|
function normalizeIPv6Address(input2) {
|
|
75949
76237
|
const compression = input2.indexOf("::");
|
|
@@ -82420,9 +82708,9 @@ var WebStandardStreamableHTTPServerTransport2 = class {
|
|
|
82420
82708
|
}
|
|
82421
82709
|
});
|
|
82422
82710
|
}
|
|
82423
|
-
async _checkScopeChallenge(
|
|
82711
|
+
async _checkScopeChallenge(messages2, authInfo) {
|
|
82424
82712
|
if (!this._scopeChallengeResolver) return;
|
|
82425
|
-
const challenge = await findScopeChallenge2(
|
|
82713
|
+
const challenge = await findScopeChallenge2(messages2.filter((message) => isJSONRPCRequest3(message)), authInfo, this._scopeChallengeResolver);
|
|
82426
82714
|
return challenge === void 0 ? void 0 : createScopeChallengeResponse2(challenge, scopeChallengeResourceMetadataUrl2(authInfo));
|
|
82427
82715
|
}
|
|
82428
82716
|
/**
|
|
@@ -82720,21 +83008,21 @@ data:
|
|
|
82720
83008
|
this.onerror?.(/* @__PURE__ */ new Error(`Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE2} messages`));
|
|
82721
83009
|
return this.createJsonErrorResponse(400, -32600, `Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE2} messages`);
|
|
82722
83010
|
}
|
|
82723
|
-
let
|
|
83011
|
+
let messages2;
|
|
82724
83012
|
try {
|
|
82725
|
-
|
|
83013
|
+
messages2 = Array.isArray(rawMessage) ? rawMessage.map((msg) => JSONRPCMessageSchema.parse(msg)) : [JSONRPCMessageSchema.parse(rawMessage)];
|
|
82726
83014
|
} catch (error62) {
|
|
82727
83015
|
this.onerror?.(error62);
|
|
82728
83016
|
return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON-RPC message");
|
|
82729
83017
|
}
|
|
82730
83018
|
if (this._closed) return this.createJsonErrorResponse(404, -32001, "Session not found");
|
|
82731
|
-
const isInitializationRequest =
|
|
83019
|
+
const isInitializationRequest = messages2.some((element) => isInitializeRequest3(element));
|
|
82732
83020
|
if (isInitializationRequest) {
|
|
82733
83021
|
if (this._initialized && this.sessionId !== void 0) {
|
|
82734
83022
|
this.onerror?.(/* @__PURE__ */ new Error("Invalid Request: Server already initialized"));
|
|
82735
83023
|
return this.createJsonErrorResponse(400, -32600, "Invalid Request: Server already initialized");
|
|
82736
83024
|
}
|
|
82737
|
-
if (
|
|
83025
|
+
if (messages2.length > 1) {
|
|
82738
83026
|
this.onerror?.(/* @__PURE__ */ new Error("Invalid Request: Only one initialization request is allowed"));
|
|
82739
83027
|
return this.createJsonErrorResponse(400, -32600, "Invalid Request: Only one initialization request is allowed");
|
|
82740
83028
|
}
|
|
@@ -82751,21 +83039,21 @@ data:
|
|
|
82751
83039
|
if (this._closed) return this.createJsonErrorResponse(404, -32001, "Session not found");
|
|
82752
83040
|
let scopeChallengeResponse;
|
|
82753
83041
|
try {
|
|
82754
|
-
scopeChallengeResponse = await this._checkScopeChallenge(
|
|
83042
|
+
scopeChallengeResponse = await this._checkScopeChallenge(messages2, options?.authInfo);
|
|
82755
83043
|
} catch (error62) {
|
|
82756
83044
|
this.onerror?.(error62);
|
|
82757
83045
|
return this.createJsonErrorResponse(500, -32603, "Internal server error");
|
|
82758
83046
|
}
|
|
82759
83047
|
if (scopeChallengeResponse) return scopeChallengeResponse;
|
|
82760
|
-
if (!
|
|
82761
|
-
for (const message of
|
|
83048
|
+
if (!messages2.some((element) => isJSONRPCRequest3(element))) {
|
|
83049
|
+
for (const message of messages2) this.onmessage?.(message, {
|
|
82762
83050
|
authInfo: options?.authInfo,
|
|
82763
83051
|
request
|
|
82764
83052
|
});
|
|
82765
83053
|
return new Response(null, { status: 202 });
|
|
82766
83054
|
}
|
|
82767
83055
|
const streamId = crypto.randomUUID();
|
|
82768
|
-
const initRequest =
|
|
83056
|
+
const initRequest = messages2.find((m) => isInitializeRequest3(m));
|
|
82769
83057
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
82770
83058
|
if (this._enableJsonResponse) return new Promise((resolve6) => {
|
|
82771
83059
|
this._streamMapping.set(streamId, {
|
|
@@ -82774,8 +83062,8 @@ data:
|
|
|
82774
83062
|
this._streamMapping.delete(streamId);
|
|
82775
83063
|
}
|
|
82776
83064
|
});
|
|
82777
|
-
for (const message of
|
|
82778
|
-
for (const message of
|
|
83065
|
+
for (const message of messages2) if (isJSONRPCRequest3(message)) this._requestToStreamMapping.set(message.id, streamId);
|
|
83066
|
+
for (const message of messages2) this.onmessage?.(message, {
|
|
82779
83067
|
authInfo: options?.authInfo,
|
|
82780
83068
|
request
|
|
82781
83069
|
});
|
|
@@ -82799,7 +83087,7 @@ data:
|
|
|
82799
83087
|
"X-Accel-Buffering": "no"
|
|
82800
83088
|
};
|
|
82801
83089
|
if (this.sessionId !== void 0) headers["mcp-session-id"] = this.sessionId;
|
|
82802
|
-
for (const message of
|
|
83090
|
+
for (const message of messages2) if (isJSONRPCRequest3(message)) {
|
|
82803
83091
|
this._streamMapping.set(streamId, {
|
|
82804
83092
|
controller: streamController,
|
|
82805
83093
|
encoder,
|
|
@@ -82815,7 +83103,7 @@ data:
|
|
|
82815
83103
|
this._requestToStreamMapping.set(message.id, streamId);
|
|
82816
83104
|
}
|
|
82817
83105
|
await this.writePrimingEvent(streamController, encoder, streamId, clientProtocolVersion);
|
|
82818
|
-
for (const message of
|
|
83106
|
+
for (const message of messages2) {
|
|
82819
83107
|
let closeSSEStream;
|
|
82820
83108
|
let closeStandaloneSSEStream;
|
|
82821
83109
|
if (isJSONRPCRequest3(message) && this._eventStore && this.supportsEmptySSEData(clientProtocolVersion)) {
|
|
@@ -84324,11 +84612,11 @@ var NodeStreamableHTTPServerTransport2 = class {
|
|
|
84324
84612
|
// src/computers.ts
|
|
84325
84613
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
84326
84614
|
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
84327
|
-
import { isAbsolute, join as
|
|
84615
|
+
import { isAbsolute, join as join9, resolve as resolve4 } from "node:path";
|
|
84328
84616
|
var TOOLS = {
|
|
84329
84617
|
read: ["read", "list", "search"],
|
|
84330
84618
|
files: ["read", "list", "search", "edit"],
|
|
84331
|
-
terminal: ["read", "list", "search", "edit", "exec_command", "write_stdin"]
|
|
84619
|
+
terminal: ["read", "list", "search", "edit", "exec_command", "write_stdin", "list_sessions"]
|
|
84332
84620
|
};
|
|
84333
84621
|
var MAX_LOG = 256 * 1024;
|
|
84334
84622
|
var MAX_TIMER_S = 2e6;
|
|
@@ -84346,7 +84634,7 @@ var Computers = class {
|
|
|
84346
84634
|
this.#data = data;
|
|
84347
84635
|
this.#base = base;
|
|
84348
84636
|
this.#runtime = runtime;
|
|
84349
|
-
this.#file =
|
|
84637
|
+
this.#file = join9(data, "computers.json");
|
|
84350
84638
|
if (existsSync2(this.#file))
|
|
84351
84639
|
for (const entry of JSON.parse(readFileSync4(this.#file, "utf8")))
|
|
84352
84640
|
this.#stored.set(entry.id, entry);
|
|
@@ -84401,7 +84689,7 @@ var Computers = class {
|
|
|
84401
84689
|
...timeout === void 0 ? {} : { endAt: expiry(timeout) }
|
|
84402
84690
|
};
|
|
84403
84691
|
if (!workspace && access !== "none") {
|
|
84404
|
-
stored.workspace =
|
|
84692
|
+
stored.workspace = join9(this.#folder(id), "workspace");
|
|
84405
84693
|
mkdirSync2(stored.workspace, { recursive: true, mode: 448 });
|
|
84406
84694
|
}
|
|
84407
84695
|
this.#stored.set(id, stored);
|
|
@@ -84552,10 +84840,10 @@ var Computers = class {
|
|
|
84552
84840
|
return stored;
|
|
84553
84841
|
}
|
|
84554
84842
|
#folder(id) {
|
|
84555
|
-
return privateFolder(
|
|
84843
|
+
return privateFolder(join9(this.#data, "computers", id));
|
|
84556
84844
|
}
|
|
84557
84845
|
#logFile(id) {
|
|
84558
|
-
return
|
|
84846
|
+
return join9(this.#folder(id), "log");
|
|
84559
84847
|
}
|
|
84560
84848
|
#log(id, line) {
|
|
84561
84849
|
if (!this.#stored.has(id)) return;
|
|
@@ -84647,7 +84935,7 @@ var OPENAPI = {
|
|
|
84647
84935
|
"openapi": "3.1.0",
|
|
84648
84936
|
"info": {
|
|
84649
84937
|
"title": "AgentComputer",
|
|
84650
|
-
"version": "0.0.
|
|
84938
|
+
"version": "0.0.10",
|
|
84651
84939
|
"description": "Computers for agents. This file is the source of truth: the HTTP API, the MCP control tools and the SDK are all generated from it. An operation with `x-mcp-tool` is also an MCP tool of that name.",
|
|
84652
84940
|
"license": {
|
|
84653
84941
|
"name": "Apache-2.0",
|
|
@@ -84968,7 +85256,7 @@ var OPENAPI = {
|
|
|
84968
85256
|
"post": {
|
|
84969
85257
|
"operationId": "createLiveSession",
|
|
84970
85258
|
"x-mcp-tool": "computer_live",
|
|
84971
|
-
"summary": "A one-time ticket to watch or operate one of its surfaces live:
|
|
85259
|
+
"summary": "A one-time ticket to watch or operate one of its surfaces live: its terminals, its files, its browser, or its load. Open its url as a WebSocket within 60 seconds.",
|
|
84972
85260
|
"requestBody": {
|
|
84973
85261
|
"required": true,
|
|
84974
85262
|
"content": {
|
|
@@ -85099,7 +85387,7 @@ var OPENAPI = {
|
|
|
85099
85387
|
"files",
|
|
85100
85388
|
"terminal"
|
|
85101
85389
|
],
|
|
85102
|
-
"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
|
|
85390
|
+
"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."
|
|
85103
85391
|
},
|
|
85104
85392
|
"ComputerState": {
|
|
85105
85393
|
"type": "string",
|
|
@@ -85307,12 +85595,12 @@ var OPENAPI = {
|
|
|
85307
85595
|
"Surface": {
|
|
85308
85596
|
"type": "string",
|
|
85309
85597
|
"enum": [
|
|
85310
|
-
"commands",
|
|
85311
85598
|
"terminal",
|
|
85312
85599
|
"files",
|
|
85313
|
-
"browser"
|
|
85600
|
+
"browser",
|
|
85601
|
+
"load"
|
|
85314
85602
|
],
|
|
85315
|
-
"description": "
|
|
85603
|
+
"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. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
85316
85604
|
},
|
|
85317
85605
|
"LiveMode": {
|
|
85318
85606
|
"type": "string",
|
|
@@ -85755,6 +86043,266 @@ var OPENAPI = {
|
|
|
85755
86043
|
}
|
|
85756
86044
|
]
|
|
85757
86045
|
},
|
|
86046
|
+
"TerminalEvent": {
|
|
86047
|
+
"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.",
|
|
86048
|
+
"oneOf": [
|
|
86049
|
+
{
|
|
86050
|
+
"type": "object",
|
|
86051
|
+
"description": "A terminal began.",
|
|
86052
|
+
"required": [
|
|
86053
|
+
"type",
|
|
86054
|
+
"id",
|
|
86055
|
+
"by",
|
|
86056
|
+
"cmd",
|
|
86057
|
+
"workdir",
|
|
86058
|
+
"tty",
|
|
86059
|
+
"at"
|
|
86060
|
+
],
|
|
86061
|
+
"properties": {
|
|
86062
|
+
"type": {
|
|
86063
|
+
"const": "start"
|
|
86064
|
+
},
|
|
86065
|
+
"id": {
|
|
86066
|
+
"type": "string"
|
|
86067
|
+
},
|
|
86068
|
+
"by": {
|
|
86069
|
+
"type": "string",
|
|
86070
|
+
"enum": [
|
|
86071
|
+
"agent",
|
|
86072
|
+
"person"
|
|
86073
|
+
],
|
|
86074
|
+
"description": "The way in it came: agent through a tool, person through this surface."
|
|
86075
|
+
},
|
|
86076
|
+
"cmd": {
|
|
86077
|
+
"type": "string",
|
|
86078
|
+
"description": "Its command, the first 8,000 characters of it."
|
|
86079
|
+
},
|
|
86080
|
+
"workdir": {
|
|
86081
|
+
"type": "string",
|
|
86082
|
+
"description": "Its folder, the first 2,000 characters of it."
|
|
86083
|
+
},
|
|
86084
|
+
"tty": {
|
|
86085
|
+
"type": "boolean",
|
|
86086
|
+
"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."
|
|
86087
|
+
},
|
|
86088
|
+
"at": {
|
|
86089
|
+
"type": "string",
|
|
86090
|
+
"format": "date-time"
|
|
86091
|
+
}
|
|
86092
|
+
}
|
|
86093
|
+
},
|
|
86094
|
+
{
|
|
86095
|
+
"type": "object",
|
|
86096
|
+
"description": "What it wrote, as it writes: 10,000 characters a message at most, a longer piece as several. A command that left something running can still write after its exit.",
|
|
86097
|
+
"required": [
|
|
86098
|
+
"type",
|
|
86099
|
+
"id",
|
|
86100
|
+
"text"
|
|
86101
|
+
],
|
|
86102
|
+
"properties": {
|
|
86103
|
+
"type": {
|
|
86104
|
+
"const": "output"
|
|
86105
|
+
},
|
|
86106
|
+
"id": {
|
|
86107
|
+
"type": "string"
|
|
86108
|
+
},
|
|
86109
|
+
"stream": {
|
|
86110
|
+
"type": "string",
|
|
86111
|
+
"enum": [
|
|
86112
|
+
"stdout",
|
|
86113
|
+
"stderr"
|
|
86114
|
+
],
|
|
86115
|
+
"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."
|
|
86116
|
+
},
|
|
86117
|
+
"text": {
|
|
86118
|
+
"type": "string"
|
|
86119
|
+
}
|
|
86120
|
+
}
|
|
86121
|
+
},
|
|
86122
|
+
{
|
|
86123
|
+
"type": "object",
|
|
86124
|
+
"description": "It ended.",
|
|
86125
|
+
"required": [
|
|
86126
|
+
"type",
|
|
86127
|
+
"id",
|
|
86128
|
+
"exitCode",
|
|
86129
|
+
"at"
|
|
86130
|
+
],
|
|
86131
|
+
"properties": {
|
|
86132
|
+
"type": {
|
|
86133
|
+
"const": "exit"
|
|
86134
|
+
},
|
|
86135
|
+
"id": {
|
|
86136
|
+
"type": "string"
|
|
86137
|
+
},
|
|
86138
|
+
"exitCode": {
|
|
86139
|
+
"type": "integer"
|
|
86140
|
+
},
|
|
86141
|
+
"at": {
|
|
86142
|
+
"type": "string",
|
|
86143
|
+
"format": "date-time"
|
|
86144
|
+
}
|
|
86145
|
+
}
|
|
86146
|
+
},
|
|
86147
|
+
{
|
|
86148
|
+
"type": "object",
|
|
86149
|
+
"description": "What this socket asked wasn't done, and why, in words for a person. Sent only to the operate socket that asked. What was done is answered by its event, or by nothing.",
|
|
86150
|
+
"required": [
|
|
86151
|
+
"type",
|
|
86152
|
+
"message"
|
|
86153
|
+
],
|
|
86154
|
+
"properties": {
|
|
86155
|
+
"type": {
|
|
86156
|
+
"const": "refused"
|
|
86157
|
+
},
|
|
86158
|
+
"message": {
|
|
86159
|
+
"type": "string"
|
|
86160
|
+
}
|
|
86161
|
+
}
|
|
86162
|
+
}
|
|
86163
|
+
]
|
|
86164
|
+
},
|
|
86165
|
+
"TerminalInput": {
|
|
86166
|
+
"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.",
|
|
86167
|
+
"oneOf": [
|
|
86168
|
+
{
|
|
86169
|
+
"type": "object",
|
|
86170
|
+
"description": "Start a shell of your own in the workspace, as its user, on a terminal device of this size. It arrives as a start like any other. Refused past the 64 terminals that may run at once, and where the service has no node-pty.",
|
|
86171
|
+
"required": [
|
|
86172
|
+
"type",
|
|
86173
|
+
"columns",
|
|
86174
|
+
"rows"
|
|
86175
|
+
],
|
|
86176
|
+
"properties": {
|
|
86177
|
+
"type": {
|
|
86178
|
+
"const": "open"
|
|
86179
|
+
},
|
|
86180
|
+
"columns": {
|
|
86181
|
+
"type": "integer",
|
|
86182
|
+
"minimum": 1,
|
|
86183
|
+
"maximum": 1e3
|
|
86184
|
+
},
|
|
86185
|
+
"rows": {
|
|
86186
|
+
"type": "integer",
|
|
86187
|
+
"minimum": 1,
|
|
86188
|
+
"maximum": 1e3
|
|
86189
|
+
}
|
|
86190
|
+
}
|
|
86191
|
+
},
|
|
86192
|
+
{
|
|
86193
|
+
"type": "object",
|
|
86194
|
+
"description": "Type into a running terminal, the agent's included. In a command, Ctrl-C (U+0003) interrupts it and Ctrl-D (U+0004) ends its input. Refused for one that has ended or isn't there.",
|
|
86195
|
+
"required": [
|
|
86196
|
+
"type",
|
|
86197
|
+
"id",
|
|
86198
|
+
"text"
|
|
86199
|
+
],
|
|
86200
|
+
"properties": {
|
|
86201
|
+
"type": {
|
|
86202
|
+
"const": "input"
|
|
86203
|
+
},
|
|
86204
|
+
"id": {
|
|
86205
|
+
"type": "string"
|
|
86206
|
+
},
|
|
86207
|
+
"text": {
|
|
86208
|
+
"type": "string"
|
|
86209
|
+
}
|
|
86210
|
+
}
|
|
86211
|
+
},
|
|
86212
|
+
{
|
|
86213
|
+
"type": "object",
|
|
86214
|
+
"description": "Give a terminal on a terminal device a new size, which is the size for everyone looking at it. Refused for a command, which has none, and for one that has ended or isn't there.",
|
|
86215
|
+
"required": [
|
|
86216
|
+
"type",
|
|
86217
|
+
"id",
|
|
86218
|
+
"columns",
|
|
86219
|
+
"rows"
|
|
86220
|
+
],
|
|
86221
|
+
"properties": {
|
|
86222
|
+
"type": {
|
|
86223
|
+
"const": "resize"
|
|
86224
|
+
},
|
|
86225
|
+
"id": {
|
|
86226
|
+
"type": "string"
|
|
86227
|
+
},
|
|
86228
|
+
"columns": {
|
|
86229
|
+
"type": "integer",
|
|
86230
|
+
"minimum": 1,
|
|
86231
|
+
"maximum": 1e3
|
|
86232
|
+
},
|
|
86233
|
+
"rows": {
|
|
86234
|
+
"type": "integer",
|
|
86235
|
+
"minimum": 1,
|
|
86236
|
+
"maximum": 1e3
|
|
86237
|
+
}
|
|
86238
|
+
}
|
|
86239
|
+
},
|
|
86240
|
+
{
|
|
86241
|
+
"type": "object",
|
|
86242
|
+
"description": "End a terminal: an interrupt for a command, a hangup for a shell, then a kill a second later. Its exit is the answer. One that has ended is left as it is, and one that isn't there is refused.",
|
|
86243
|
+
"required": [
|
|
86244
|
+
"type",
|
|
86245
|
+
"id"
|
|
86246
|
+
],
|
|
86247
|
+
"properties": {
|
|
86248
|
+
"type": {
|
|
86249
|
+
"const": "stop"
|
|
86250
|
+
},
|
|
86251
|
+
"id": {
|
|
86252
|
+
"type": "string"
|
|
86253
|
+
}
|
|
86254
|
+
}
|
|
86255
|
+
}
|
|
86256
|
+
]
|
|
86257
|
+
},
|
|
86258
|
+
"LoadReading": {
|
|
86259
|
+
"description": "What the service sends on a metrics@1 socket, as JSON text. What a socket sends is dropped.",
|
|
86260
|
+
"type": "object",
|
|
86261
|
+
"required": [
|
|
86262
|
+
"type",
|
|
86263
|
+
"scope",
|
|
86264
|
+
"cpuUsedPct",
|
|
86265
|
+
"memUsed",
|
|
86266
|
+
"memTotal",
|
|
86267
|
+
"diskUsed",
|
|
86268
|
+
"diskTotal"
|
|
86269
|
+
],
|
|
86270
|
+
"properties": {
|
|
86271
|
+
"type": {
|
|
86272
|
+
"const": "reading"
|
|
86273
|
+
},
|
|
86274
|
+
"scope": {
|
|
86275
|
+
"type": "string",
|
|
86276
|
+
"enum": [
|
|
86277
|
+
"computer",
|
|
86278
|
+
"machine"
|
|
86279
|
+
],
|
|
86280
|
+
"description": "Whose numbers these are. computer: this computer's own, which a container's are. machine: the whole machine's, which a computer with no isolation shares with whatever else runs there, so every computer of that service reads the same; and a container's where it can't read its own."
|
|
86281
|
+
},
|
|
86282
|
+
"cpuUsedPct": {
|
|
86283
|
+
"type": "number",
|
|
86284
|
+
"minimum": 0,
|
|
86285
|
+
"maximum": 100,
|
|
86286
|
+
"description": "Of all the machine's CPUs, since the reading before. One decimal."
|
|
86287
|
+
},
|
|
86288
|
+
"memUsed": {
|
|
86289
|
+
"type": "integer",
|
|
86290
|
+
"description": "Bytes in use."
|
|
86291
|
+
},
|
|
86292
|
+
"memTotal": {
|
|
86293
|
+
"type": "integer",
|
|
86294
|
+
"description": "Bytes the machine has: no computer has a limit."
|
|
86295
|
+
},
|
|
86296
|
+
"diskUsed": {
|
|
86297
|
+
"type": "integer",
|
|
86298
|
+
"description": "Bytes used on the volume its workspace is on, or its own folder where it has no workspace. The volume's, not the workspace's own size."
|
|
86299
|
+
},
|
|
86300
|
+
"diskTotal": {
|
|
86301
|
+
"type": "integer",
|
|
86302
|
+
"description": "Bytes on that volume."
|
|
86303
|
+
}
|
|
86304
|
+
}
|
|
86305
|
+
},
|
|
85758
86306
|
"FilesRequest": {
|
|
85759
86307
|
"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.",
|
|
85760
86308
|
"oneOf": [
|
|
@@ -86224,7 +86772,7 @@ var OPERATIONS = [
|
|
|
86224
86772
|
"files",
|
|
86225
86773
|
"terminal"
|
|
86226
86774
|
],
|
|
86227
|
-
"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
|
|
86775
|
+
"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."
|
|
86228
86776
|
},
|
|
86229
86777
|
"browser": {
|
|
86230
86778
|
"type": "boolean"
|
|
@@ -86313,7 +86861,7 @@ var OPERATIONS = [
|
|
|
86313
86861
|
"files",
|
|
86314
86862
|
"terminal"
|
|
86315
86863
|
],
|
|
86316
|
-
"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
|
|
86864
|
+
"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."
|
|
86317
86865
|
},
|
|
86318
86866
|
"browser": {
|
|
86319
86867
|
"type": "boolean",
|
|
@@ -86383,7 +86931,7 @@ var OPERATIONS = [
|
|
|
86383
86931
|
"files",
|
|
86384
86932
|
"terminal"
|
|
86385
86933
|
],
|
|
86386
|
-
"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
|
|
86934
|
+
"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."
|
|
86387
86935
|
},
|
|
86388
86936
|
"browser": {
|
|
86389
86937
|
"type": "boolean"
|
|
@@ -86523,7 +87071,7 @@ var OPERATIONS = [
|
|
|
86523
87071
|
"files",
|
|
86524
87072
|
"terminal"
|
|
86525
87073
|
],
|
|
86526
|
-
"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
|
|
87074
|
+
"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."
|
|
86527
87075
|
},
|
|
86528
87076
|
"browser": {
|
|
86529
87077
|
"type": "boolean"
|
|
@@ -86607,12 +87155,12 @@ var OPERATIONS = [
|
|
|
86607
87155
|
"surface": {
|
|
86608
87156
|
"type": "string",
|
|
86609
87157
|
"enum": [
|
|
86610
|
-
"commands",
|
|
86611
87158
|
"terminal",
|
|
86612
87159
|
"files",
|
|
86613
|
-
"browser"
|
|
87160
|
+
"browser",
|
|
87161
|
+
"load"
|
|
86614
87162
|
],
|
|
86615
|
-
"description": "
|
|
87163
|
+
"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. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
86616
87164
|
},
|
|
86617
87165
|
"protocol": {
|
|
86618
87166
|
"type": "string"
|
|
@@ -86754,7 +87302,7 @@ var OPERATIONS = [
|
|
|
86754
87302
|
"files",
|
|
86755
87303
|
"terminal"
|
|
86756
87304
|
],
|
|
86757
|
-
"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
|
|
87305
|
+
"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."
|
|
86758
87306
|
},
|
|
86759
87307
|
"browser": {
|
|
86760
87308
|
"type": "boolean"
|
|
@@ -86878,7 +87426,7 @@ var OPERATIONS = [
|
|
|
86878
87426
|
"files",
|
|
86879
87427
|
"terminal"
|
|
86880
87428
|
],
|
|
86881
|
-
"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
|
|
87429
|
+
"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."
|
|
86882
87430
|
},
|
|
86883
87431
|
"browser": {
|
|
86884
87432
|
"type": "boolean"
|
|
@@ -87007,7 +87555,7 @@ var OPERATIONS = [
|
|
|
87007
87555
|
"files",
|
|
87008
87556
|
"terminal"
|
|
87009
87557
|
],
|
|
87010
|
-
"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
|
|
87558
|
+
"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."
|
|
87011
87559
|
},
|
|
87012
87560
|
"browser": {
|
|
87013
87561
|
"type": "boolean"
|
|
@@ -87128,7 +87676,7 @@ var OPERATIONS = [
|
|
|
87128
87676
|
"method": "POST",
|
|
87129
87677
|
"path": "/v1/computers/{computerID}/live",
|
|
87130
87678
|
"tool": "computer_live",
|
|
87131
|
-
"summary": "A one-time ticket to watch or operate one of its surfaces live:
|
|
87679
|
+
"summary": "A one-time ticket to watch or operate one of its surfaces live: its terminals, its files, its browser, or its load. Open its url as a WebSocket within 60 seconds.",
|
|
87132
87680
|
"status": 201,
|
|
87133
87681
|
"hasBody": true,
|
|
87134
87682
|
"pathParameters": [
|
|
@@ -87147,12 +87695,12 @@ var OPERATIONS = [
|
|
|
87147
87695
|
"surface": {
|
|
87148
87696
|
"type": "string",
|
|
87149
87697
|
"enum": [
|
|
87150
|
-
"commands",
|
|
87151
87698
|
"terminal",
|
|
87152
87699
|
"files",
|
|
87153
|
-
"browser"
|
|
87700
|
+
"browser",
|
|
87701
|
+
"load"
|
|
87154
87702
|
],
|
|
87155
|
-
"description": "
|
|
87703
|
+
"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. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
87156
87704
|
},
|
|
87157
87705
|
"mode": {
|
|
87158
87706
|
"allOf": [
|
|
@@ -87194,12 +87742,12 @@ var OPERATIONS = [
|
|
|
87194
87742
|
"surface": {
|
|
87195
87743
|
"type": "string",
|
|
87196
87744
|
"enum": [
|
|
87197
|
-
"commands",
|
|
87198
87745
|
"terminal",
|
|
87199
87746
|
"files",
|
|
87200
|
-
"browser"
|
|
87747
|
+
"browser",
|
|
87748
|
+
"load"
|
|
87201
87749
|
],
|
|
87202
|
-
"description": "
|
|
87750
|
+
"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. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
87203
87751
|
},
|
|
87204
87752
|
"mode": {
|
|
87205
87753
|
"type": "string",
|
|
@@ -87305,7 +87853,7 @@ async function serve(options) {
|
|
|
87305
87853
|
pattern: new RegExp(`^${operation.path.replace(/\{[^}]+\}/g, "([^/]+)")}$`),
|
|
87306
87854
|
check: fromJsonSchema3(operation.input)
|
|
87307
87855
|
}));
|
|
87308
|
-
const
|
|
87856
|
+
const run3 = async (route2, input2) => {
|
|
87309
87857
|
const checked = await route2.check["~standard"].validate(input2);
|
|
87310
87858
|
if (checked.issues)
|
|
87311
87859
|
throw new ApiError(400, checked.issues.map((issue3) => issue3.message).join("; "));
|
|
@@ -87320,7 +87868,7 @@ async function serve(options) {
|
|
|
87320
87868
|
{ description: route2.operation.summary, inputSchema: route2.check },
|
|
87321
87869
|
async (input2) => {
|
|
87322
87870
|
try {
|
|
87323
|
-
const output2 = await
|
|
87871
|
+
const output2 = await run3(route2, input2) ?? {};
|
|
87324
87872
|
return { content: [{ type: "text", text: JSON.stringify(output2) }] };
|
|
87325
87873
|
} catch (error62) {
|
|
87326
87874
|
if (!(error62 instanceof ApiError)) throw error62;
|
|
@@ -87372,7 +87920,7 @@ async function serve(options) {
|
|
|
87372
87920
|
const value = url3.searchParams.get(name);
|
|
87373
87921
|
if (value !== null) input2[name] = value;
|
|
87374
87922
|
}
|
|
87375
|
-
return send(response, operation.status, await
|
|
87923
|
+
return send(response, operation.status, await run3(candidate, input2));
|
|
87376
87924
|
}
|
|
87377
87925
|
throw pathMatched ? new ApiError(405, "Not allowed.") : new ApiError(404, "Not found.");
|
|
87378
87926
|
};
|
|
@@ -87419,7 +87967,7 @@ ${JSON.stringify({ code: status, message })}
|
|
|
87419
87967
|
const scheme = options.tls ? "https" : "http";
|
|
87420
87968
|
base = options.publicUrl?.replace(/\/+$/, "") ?? `${scheme}://${bound.family === "IPv6" ? `[${bound.address}]` : bound.address}:${bound.port}`;
|
|
87421
87969
|
await computers.resume();
|
|
87422
|
-
const record3 =
|
|
87970
|
+
const record3 = join10(data, "server.json");
|
|
87423
87971
|
writePrivate(
|
|
87424
87972
|
record3,
|
|
87425
87973
|
JSON.stringify({ url: base, pid: process.pid, isolation: options.runtime.isolation })
|
|
@@ -87459,7 +88007,7 @@ var USAGE = `Usage: agentcomputer <command> [--data DIR]
|
|
|
87459
88007
|
stop <id> stop it, keeping its folder and token
|
|
87460
88008
|
start <id> [--timeout SECONDS] start a stopped computer again
|
|
87461
88009
|
logs <id> what its servers wrote
|
|
87462
|
-
live <id> --surface
|
|
88010
|
+
live <id> --surface terminal|files|browser|load [--mode watch|operate]
|
|
87463
88011
|
a one-time ticket to open one live, as a WebSocket
|
|
87464
88012
|
kill <id> stop it and remove what the service made
|
|
87465
88013
|
|
|
@@ -87472,13 +88020,13 @@ var UsageError = class extends Error {
|
|
|
87472
88020
|
function dataFolder(given) {
|
|
87473
88021
|
const xdg = process.env.XDG_DATA_HOME;
|
|
87474
88022
|
return resolve5(
|
|
87475
|
-
given ?? process.env.AGENTCOMPUTER_DATA ?? (xdg && isAbsolute2(xdg) ?
|
|
88023
|
+
given ?? process.env.AGENTCOMPUTER_DATA ?? (xdg && isAbsolute2(xdg) ? join11(xdg, "agentcomputer") : join11(homedir2(), ".local", "share", "agentcomputer"))
|
|
87476
88024
|
);
|
|
87477
88025
|
}
|
|
87478
88026
|
function connectionTo(data) {
|
|
87479
88027
|
try {
|
|
87480
|
-
const { url: url3 } = JSON.parse(readFileSync6(
|
|
87481
|
-
return { apiUrl: url3, apiKey: readFileSync6(
|
|
88028
|
+
const { url: url3 } = JSON.parse(readFileSync6(join11(data, "server.json"), "utf8"));
|
|
88029
|
+
return { apiUrl: url3, apiKey: readFileSync6(join11(data, "control-token"), "utf8").trim() };
|
|
87482
88030
|
} catch {
|
|
87483
88031
|
throw new Error(
|
|
87484
88032
|
`No service is running with its data in ${data}. Start one: agentcomputer serve`
|