usebeeline 0.0.104 → 0.0.105
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 +1 -1
- package/dist/usebeeline.mjs +560 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -141,7 +141,7 @@ Two MCP surfaces are mounted into every agent session.
|
|
|
141
141
|
| ------------------------------------------------------ | --------------- | ------------------------------------------------------------- |
|
|
142
142
|
| `open_corner` | Top-level Rooms | Open one write-enabled corner with a ≤24-word objective |
|
|
143
143
|
| `pr_checks_status` | Corners | Read checks, human hold, and PR/head-bound merge approval |
|
|
144
|
-
| `
|
|
144
|
+
| `post_artifact` | Everywhere | Upload one file (path or html/bytes) as an attachment |
|
|
145
145
|
| `create_schedule`, `list_schedules`, `delete_schedule` | Everywhere | Run a prompt again later — interval minutes or a 5-field cron |
|
|
146
146
|
| `request_grant` | Everywhere | Ask the owner for reach outside the sandbox |
|
|
147
147
|
| `run_granted_command` | Everywhere | Run a command an approved grant covers, outside the sandbox |
|
package/dist/usebeeline.mjs
CHANGED
|
@@ -3987,7 +3987,7 @@ __export(self_update_exports, {
|
|
|
3987
3987
|
import { createHash as createHash7 } from "node:crypto";
|
|
3988
3988
|
import { constants as fsConstants2 } from "node:fs";
|
|
3989
3989
|
import { access, chmod as chmod5, lstat as lstat3, mkdir as mkdir15, open, readFile as readFile10, rename as rename4, rm as rm6, symlink as symlink3, writeFile as writeFile10 } from "node:fs/promises";
|
|
3990
|
-
import { spawn as
|
|
3990
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
3991
3991
|
import { homedir as homedir9 } from "node:os";
|
|
3992
3992
|
import { dirname as dirname11, join as join9, resolve as resolve22 } from "node:path";
|
|
3993
3993
|
function anchorLayout(rawLibDir) {
|
|
@@ -4137,7 +4137,7 @@ async function fetchText(url, fetchImpl) {
|
|
|
4137
4137
|
}
|
|
4138
4138
|
function run(command, args, timeoutMs) {
|
|
4139
4139
|
return new Promise((resolveRun) => {
|
|
4140
|
-
const child =
|
|
4140
|
+
const child = spawn5(command, args, { stdio: ["ignore", "ignore", "pipe"] });
|
|
4141
4141
|
let stderr = "";
|
|
4142
4142
|
child.stderr?.setEncoding("utf8");
|
|
4143
4143
|
child.stderr?.on("data", (chunk) => {
|
|
@@ -4210,7 +4210,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4210
4210
|
}
|
|
4211
4211
|
await writeFile10(tempArchive, Buffer.concat(chunks), { mode: 384 });
|
|
4212
4212
|
const entries = (await new Promise((resolveList, rejectList) => {
|
|
4213
|
-
const child =
|
|
4213
|
+
const child = spawn5("tar", ["-tzf", tempArchive], { stdio: ["ignore", "pipe", "inherit"] });
|
|
4214
4214
|
let out = "";
|
|
4215
4215
|
child.stdout?.on("data", (chunk) => {
|
|
4216
4216
|
out += chunk.toString("utf8");
|
|
@@ -6898,14 +6898,8 @@ var PI_ACP_HARNESS = /(^|[/\\])pi-acp(?:\.[a-z]+)?$/i;
|
|
|
6898
6898
|
function isPiAcpHarness(agentLabel) {
|
|
6899
6899
|
return Boolean(agentLabel && PI_ACP_HARNESS.test(agentLabel));
|
|
6900
6900
|
}
|
|
6901
|
-
function
|
|
6902
|
-
|
|
6903
|
-
return text2;
|
|
6904
|
-
const stripped = text2.replace(/\r?\n$/, "");
|
|
6905
|
-
return stripped || text2;
|
|
6906
|
-
}
|
|
6907
|
-
function normalizeStreamDelta(text2, agentLabel) {
|
|
6908
|
-
return agentLabel && PI_ACP_HARNESS.test(agentLabel) ? withoutOneTrailingLineEnding(text2) : text2;
|
|
6901
|
+
function normalizeStreamDelta(text2, _agentLabel) {
|
|
6902
|
+
return text2;
|
|
6909
6903
|
}
|
|
6910
6904
|
function agentMessageRuns(updates, agentLabel) {
|
|
6911
6905
|
const runs = [];
|
|
@@ -8162,6 +8156,483 @@ async function syncAgentModelCatalog(input) {
|
|
|
8162
8156
|
}
|
|
8163
8157
|
}
|
|
8164
8158
|
|
|
8159
|
+
// apps/body/dist/connector-squire.js
|
|
8160
|
+
import { execFile } from "node:child_process";
|
|
8161
|
+
var REMOTE_LOGIN_BINARIES = ["Xvfb", "x11vnc", "websockify", "cloudflared"];
|
|
8162
|
+
var SQUIRE_CONNECT_PACKAGE = "@trusty-squire/mcp";
|
|
8163
|
+
var defaultShellRunner = (command, args) => new Promise((resolve31) => {
|
|
8164
|
+
execFile(command, [...args], { timeout: 12e4, maxBuffer: 4 * 1024 * 1024, encoding: "utf8" }, (error, stdout6, stderr) => {
|
|
8165
|
+
const code = error?.code;
|
|
8166
|
+
resolve31({
|
|
8167
|
+
code: typeof code === "number" ? code : error ? 1 : 0,
|
|
8168
|
+
stdout: String(stdout6 ?? ""),
|
|
8169
|
+
stderr: String(stderr ?? "")
|
|
8170
|
+
});
|
|
8171
|
+
});
|
|
8172
|
+
});
|
|
8173
|
+
var step = (label, status, reason) => ({
|
|
8174
|
+
label,
|
|
8175
|
+
status,
|
|
8176
|
+
...reason ? { reason } : {}
|
|
8177
|
+
});
|
|
8178
|
+
function binaryExists(binary) {
|
|
8179
|
+
return new Promise((resolve31) => {
|
|
8180
|
+
execFile("sh", ["-c", `command -v ${JSON.stringify(binary)}`], (error, stdout6) => {
|
|
8181
|
+
const path = String(stdout6 ?? "").trim();
|
|
8182
|
+
resolve31({ binary, found: !error && path.length > 0, ...path ? { path } : {} });
|
|
8183
|
+
});
|
|
8184
|
+
});
|
|
8185
|
+
}
|
|
8186
|
+
async function checkRemoteLoginPrerequisites(probe = binaryExists) {
|
|
8187
|
+
return Promise.all(REMOTE_LOGIN_BINARIES.map(probe));
|
|
8188
|
+
}
|
|
8189
|
+
function missingPrerequisiteStep(checks) {
|
|
8190
|
+
const missing = checks.filter((check) => !check.found).map((check) => check.binary);
|
|
8191
|
+
return step("remote sign-in prerequisites", "failed", `missing on this helper: ${missing.join(", ")}`);
|
|
8192
|
+
}
|
|
8193
|
+
function parseConnectOutput(output) {
|
|
8194
|
+
const url = output.match(/https:\/\/[^\s"'<>]+/)?.[0];
|
|
8195
|
+
if (!url)
|
|
8196
|
+
return void 0;
|
|
8197
|
+
if (/oauth|authorize/i.test(url) || /oauth/i.test(output)) {
|
|
8198
|
+
return { method: "oauth", url };
|
|
8199
|
+
}
|
|
8200
|
+
if (/novnc|vnc\.html|remote|stream/i.test(url) || /novnc|remote login|vnc/i.test(output)) {
|
|
8201
|
+
return { method: "streamed-page", url };
|
|
8202
|
+
}
|
|
8203
|
+
return { method: "streamed-page", url };
|
|
8204
|
+
}
|
|
8205
|
+
async function installedSquireVersion(run2) {
|
|
8206
|
+
const probe = await run2("npx", ["-y", SQUIRE_CONNECT_PACKAGE, "--version"]);
|
|
8207
|
+
const version = probe.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0];
|
|
8208
|
+
return version;
|
|
8209
|
+
}
|
|
8210
|
+
function parseSignedInAs(output) {
|
|
8211
|
+
return output.match(/signed in as ([^\s,;]+)/i)?.[1];
|
|
8212
|
+
}
|
|
8213
|
+
async function installSquire(options) {
|
|
8214
|
+
const run2 = options.run ?? defaultShellRunner;
|
|
8215
|
+
const steps = [step("helper reached", "done")];
|
|
8216
|
+
const emit = () => options.onProgress?.([...steps]);
|
|
8217
|
+
const push = (next) => {
|
|
8218
|
+
steps.push(next);
|
|
8219
|
+
emit();
|
|
8220
|
+
};
|
|
8221
|
+
const fail = (reason) => {
|
|
8222
|
+
steps.push(step("waiting for sign-in", "pending"));
|
|
8223
|
+
emit();
|
|
8224
|
+
return { status: "error", steps, errorMessage: reason };
|
|
8225
|
+
};
|
|
8226
|
+
emit();
|
|
8227
|
+
const checks = await checkRemoteLoginPrerequisites(options.probeBinary);
|
|
8228
|
+
if (checks.some((check) => !check.found)) {
|
|
8229
|
+
push(missingPrerequisiteStep(checks));
|
|
8230
|
+
return fail("this helper cannot host the remote sign-in surface");
|
|
8231
|
+
}
|
|
8232
|
+
push(step("remote sign-in prerequisites", "done"));
|
|
8233
|
+
const install = await run2("npx", [
|
|
8234
|
+
"-y",
|
|
8235
|
+
SQUIRE_CONNECT_PACKAGE,
|
|
8236
|
+
"connect",
|
|
8237
|
+
"--target=pi",
|
|
8238
|
+
"--skip-browser"
|
|
8239
|
+
]);
|
|
8240
|
+
if (install.code !== 0) {
|
|
8241
|
+
push(step("trusty-squire installed", "failed", install.stderr.trim() || "connect failed"));
|
|
8242
|
+
return fail("the trusty-squire install command failed");
|
|
8243
|
+
}
|
|
8244
|
+
const version = await installedSquireVersion(run2);
|
|
8245
|
+
push(step(`trusty-squire${version ? ` ${version}` : ""} installed`, "done"));
|
|
8246
|
+
const output = `${install.stdout}
|
|
8247
|
+
${install.stderr}`;
|
|
8248
|
+
const signIn = parseConnectOutput(output);
|
|
8249
|
+
if (!signIn) {
|
|
8250
|
+
push(step("waiting for sign-in", "failed", "connect printed no sign-in URL"));
|
|
8251
|
+
return fail("the trusty-squire connect command printed no sign-in surface");
|
|
8252
|
+
}
|
|
8253
|
+
push(step("waiting for sign-in", "done"));
|
|
8254
|
+
const signedInAs = parseSignedInAs(output);
|
|
8255
|
+
const pair = await pairSquire(options.mcp, options.workspaceId);
|
|
8256
|
+
if (!pair.ok) {
|
|
8257
|
+
push(step("paired to workspace", "failed", pair.reason));
|
|
8258
|
+
return {
|
|
8259
|
+
status: "installing",
|
|
8260
|
+
steps,
|
|
8261
|
+
signIn,
|
|
8262
|
+
...version ? { squireVersion: version } : {},
|
|
8263
|
+
...signedInAs ? { signedInAs } : {}
|
|
8264
|
+
};
|
|
8265
|
+
}
|
|
8266
|
+
push(step("paired to workspace", "done"));
|
|
8267
|
+
return {
|
|
8268
|
+
status: "connected",
|
|
8269
|
+
steps,
|
|
8270
|
+
signIn,
|
|
8271
|
+
...version ? { squireVersion: version } : {},
|
|
8272
|
+
...signedInAs ? { signedInAs } : {}
|
|
8273
|
+
};
|
|
8274
|
+
}
|
|
8275
|
+
async function pairSquire(mcp, _workspaceId) {
|
|
8276
|
+
if (!mcp)
|
|
8277
|
+
return { ok: false, reason: "the Squire MCP surface is not mounted on this helper" };
|
|
8278
|
+
try {
|
|
8279
|
+
await mcp.call("list_credentials", { fields: "summary" });
|
|
8280
|
+
return { ok: true };
|
|
8281
|
+
} catch (error) {
|
|
8282
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
8283
|
+
}
|
|
8284
|
+
}
|
|
8285
|
+
function asRecord(value) {
|
|
8286
|
+
return value && typeof value === "object" ? value : {};
|
|
8287
|
+
}
|
|
8288
|
+
function asArray(value) {
|
|
8289
|
+
return Array.isArray(value) ? value : [];
|
|
8290
|
+
}
|
|
8291
|
+
function stringList(value) {
|
|
8292
|
+
return asArray(value).filter((entry) => typeof entry === "string");
|
|
8293
|
+
}
|
|
8294
|
+
function numberOrNull(value) {
|
|
8295
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
8296
|
+
}
|
|
8297
|
+
function vaultConnectionMeta(raw) {
|
|
8298
|
+
const record3 = asRecord(raw);
|
|
8299
|
+
const reference = String(record3.reference ?? record3.id ?? "");
|
|
8300
|
+
return {
|
|
8301
|
+
reference,
|
|
8302
|
+
service: typeof record3.service === "string" ? record3.service : null,
|
|
8303
|
+
label: String(record3.label ?? record3.service ?? reference),
|
|
8304
|
+
fieldNames: stringList(record3.field_names ?? record3.fieldNames),
|
|
8305
|
+
allowedHosts: stringList(record3.allowed_hosts ?? record3.allowedHosts ?? record3.login_hosts),
|
|
8306
|
+
createdAt: numberOrNull(record3.created_at ?? record3.createdAt) ?? 0,
|
|
8307
|
+
stale: record3.stale === true,
|
|
8308
|
+
state: record3.state === "error" ? "error" : "active"
|
|
8309
|
+
};
|
|
8310
|
+
}
|
|
8311
|
+
async function readVault(mcp) {
|
|
8312
|
+
const result = asRecord(await mcp.call("list_credentials"));
|
|
8313
|
+
return asArray(result.credentials ?? result.items ?? result).map(vaultConnectionMeta);
|
|
8314
|
+
}
|
|
8315
|
+
function connectionGrant(raw) {
|
|
8316
|
+
const record3 = asRecord(raw);
|
|
8317
|
+
return {
|
|
8318
|
+
grantId: String(record3.grant_id ?? record3.grantId ?? record3.id ?? ""),
|
|
8319
|
+
credentialRef: String(record3.credential_ref ?? record3.credentialRef ?? record3.reference ?? ""),
|
|
8320
|
+
createdAt: numberOrNull(record3.created_at ?? record3.createdAt) ?? 0,
|
|
8321
|
+
...numberOrNull(record3.revoked_at ?? record3.revokedAt) !== null ? { revokedAt: numberOrNull(record3.revoked_at ?? record3.revokedAt) } : {},
|
|
8322
|
+
...numberOrNull(record3.rate_limit_per_hour) !== null ? { rateLimitPerHour: numberOrNull(record3.rate_limit_per_hour) } : {},
|
|
8323
|
+
...numberOrNull(record3.spend_cap_usd) !== null ? { spendCapUsd: numberOrNull(record3.spend_cap_usd) } : {}
|
|
8324
|
+
};
|
|
8325
|
+
}
|
|
8326
|
+
async function readGrants(mcp, ref) {
|
|
8327
|
+
const result = asRecord(await mcp.call("list_app_access", {}));
|
|
8328
|
+
return asArray(result.grants ?? result.items ?? result).map(connectionGrant).filter((grant) => grant.credentialRef === ref && grant.revokedAt === void 0);
|
|
8329
|
+
}
|
|
8330
|
+
async function revokeGrants(mcp, ref) {
|
|
8331
|
+
const grants = await readGrants(mcp, ref);
|
|
8332
|
+
let revoked = 0;
|
|
8333
|
+
let failed = 0;
|
|
8334
|
+
for (const grant of grants) {
|
|
8335
|
+
try {
|
|
8336
|
+
const result = asRecord(await mcp.call("revoke_app_access", { grant_id: grant.grantId }));
|
|
8337
|
+
if (result.revoked === false)
|
|
8338
|
+
failed += 1;
|
|
8339
|
+
else
|
|
8340
|
+
revoked += 1;
|
|
8341
|
+
} catch {
|
|
8342
|
+
failed += 1;
|
|
8343
|
+
}
|
|
8344
|
+
}
|
|
8345
|
+
return { revoked, failed };
|
|
8346
|
+
}
|
|
8347
|
+
|
|
8348
|
+
// apps/body/dist/squire-mcp-client.js
|
|
8349
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
8350
|
+
var INITIALIZE_TIMEOUT_MS = 3e4;
|
|
8351
|
+
var CALL_TIMEOUT_MS = 12e4;
|
|
8352
|
+
var StdioSquireMcpClient = class {
|
|
8353
|
+
options;
|
|
8354
|
+
child;
|
|
8355
|
+
nextId = 1;
|
|
8356
|
+
pending = /* @__PURE__ */ new Map();
|
|
8357
|
+
buffer = "";
|
|
8358
|
+
initialized;
|
|
8359
|
+
closed = false;
|
|
8360
|
+
log;
|
|
8361
|
+
constructor(options = {}) {
|
|
8362
|
+
this.options = options;
|
|
8363
|
+
this.log = options.log ?? (() => {
|
|
8364
|
+
});
|
|
8365
|
+
}
|
|
8366
|
+
/** One Squire MCP tool call; resolves with the tool's parsed result. */
|
|
8367
|
+
async call(tool, args = {}) {
|
|
8368
|
+
await this.ensureSession();
|
|
8369
|
+
const response = await this.request("tools/call", { name: tool, arguments: args });
|
|
8370
|
+
if (response.isError) {
|
|
8371
|
+
const text3 = response.content?.find((entry) => entry.type === "text")?.text ?? "tool error";
|
|
8372
|
+
throw new Error(`${tool} failed: ${text3}`);
|
|
8373
|
+
}
|
|
8374
|
+
const text2 = response.content?.find((entry) => entry.type === "text")?.text;
|
|
8375
|
+
if (typeof text2 !== "string")
|
|
8376
|
+
return response;
|
|
8377
|
+
try {
|
|
8378
|
+
return JSON.parse(text2);
|
|
8379
|
+
} catch {
|
|
8380
|
+
return response;
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
8383
|
+
/** Tear the session down; safe to call repeatedly. */
|
|
8384
|
+
close() {
|
|
8385
|
+
this.closed = true;
|
|
8386
|
+
this.initialized = void 0;
|
|
8387
|
+
for (const entry of this.pending.values()) {
|
|
8388
|
+
clearTimeout(entry.timer);
|
|
8389
|
+
entry.reject(new Error("Squire MCP session closed"));
|
|
8390
|
+
}
|
|
8391
|
+
this.pending.clear();
|
|
8392
|
+
this.child?.kill();
|
|
8393
|
+
this.child = void 0;
|
|
8394
|
+
}
|
|
8395
|
+
ensureSession() {
|
|
8396
|
+
if (this.closed)
|
|
8397
|
+
throw new Error("Squire MCP client is closed");
|
|
8398
|
+
this.initialized ??= this.initialize().catch((error) => {
|
|
8399
|
+
this.initialized = void 0;
|
|
8400
|
+
throw error;
|
|
8401
|
+
});
|
|
8402
|
+
return this.initialized;
|
|
8403
|
+
}
|
|
8404
|
+
initialize() {
|
|
8405
|
+
const child = (this.options.spawn ?? spawn2)(this.options.command ?? "npx", [
|
|
8406
|
+
...this.options.args ?? ["-y", "@trusty-squire/mcp"]
|
|
8407
|
+
]);
|
|
8408
|
+
this.child = child;
|
|
8409
|
+
this.buffer = "";
|
|
8410
|
+
child.stdout.setEncoding("utf8");
|
|
8411
|
+
child.stderr.setEncoding("utf8");
|
|
8412
|
+
child.stdout.on("data", (chunk) => this.onData(chunk));
|
|
8413
|
+
child.stderr.on("data", (chunk) => this.log(`squire mcp stderr: ${chunk.trim()}`));
|
|
8414
|
+
child.on("exit", (code) => {
|
|
8415
|
+
this.log(`squire mcp exited (${String(code)})`);
|
|
8416
|
+
this.initialized = void 0;
|
|
8417
|
+
this.child = void 0;
|
|
8418
|
+
for (const entry of this.pending.values()) {
|
|
8419
|
+
clearTimeout(entry.timer);
|
|
8420
|
+
entry.reject(new Error("Squire MCP server exited"));
|
|
8421
|
+
}
|
|
8422
|
+
this.pending.clear();
|
|
8423
|
+
});
|
|
8424
|
+
return this.request("initialize", {
|
|
8425
|
+
protocolVersion: "2024-11-05",
|
|
8426
|
+
capabilities: {},
|
|
8427
|
+
clientInfo: { name: "beeline-helper", version: "1.0.0" }
|
|
8428
|
+
}).then(() => {
|
|
8429
|
+
this.notify("notifications/initialized");
|
|
8430
|
+
});
|
|
8431
|
+
}
|
|
8432
|
+
notify(method, params) {
|
|
8433
|
+
this.child?.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, ...params ? { params } : {} })}
|
|
8434
|
+
`);
|
|
8435
|
+
}
|
|
8436
|
+
request(method, params) {
|
|
8437
|
+
const id = this.nextId++;
|
|
8438
|
+
const child = this.child;
|
|
8439
|
+
if (!child)
|
|
8440
|
+
return Promise.reject(new Error("Squire MCP session is not running"));
|
|
8441
|
+
return new Promise((resolve31, reject) => {
|
|
8442
|
+
const timer = setTimeout(() => {
|
|
8443
|
+
this.pending.delete(id);
|
|
8444
|
+
reject(new Error(`${method} timed out`));
|
|
8445
|
+
}, method === "initialize" ? INITIALIZE_TIMEOUT_MS : CALL_TIMEOUT_MS);
|
|
8446
|
+
this.pending.set(id, { resolve: resolve31, reject, timer });
|
|
8447
|
+
child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}
|
|
8448
|
+
`);
|
|
8449
|
+
});
|
|
8450
|
+
}
|
|
8451
|
+
onData(chunk) {
|
|
8452
|
+
this.buffer += chunk;
|
|
8453
|
+
for (; ; ) {
|
|
8454
|
+
const newline = this.buffer.indexOf("\n");
|
|
8455
|
+
if (newline < 0)
|
|
8456
|
+
return;
|
|
8457
|
+
const line = this.buffer.slice(0, newline).trim();
|
|
8458
|
+
this.buffer = this.buffer.slice(newline + 1);
|
|
8459
|
+
if (!line)
|
|
8460
|
+
continue;
|
|
8461
|
+
let message;
|
|
8462
|
+
try {
|
|
8463
|
+
message = JSON.parse(line);
|
|
8464
|
+
} catch {
|
|
8465
|
+
continue;
|
|
8466
|
+
}
|
|
8467
|
+
const id = typeof message.id === "number" ? message.id : void 0;
|
|
8468
|
+
if (id === void 0)
|
|
8469
|
+
continue;
|
|
8470
|
+
const entry = this.pending.get(id);
|
|
8471
|
+
if (!entry)
|
|
8472
|
+
continue;
|
|
8473
|
+
this.pending.delete(id);
|
|
8474
|
+
clearTimeout(entry.timer);
|
|
8475
|
+
if (message.error) {
|
|
8476
|
+
const error = message.error;
|
|
8477
|
+
entry.reject(new Error(error.message ?? "Squire MCP error"));
|
|
8478
|
+
} else {
|
|
8479
|
+
entry.resolve(message.result);
|
|
8480
|
+
}
|
|
8481
|
+
}
|
|
8482
|
+
}
|
|
8483
|
+
};
|
|
8484
|
+
function defaultSquireMcpClient() {
|
|
8485
|
+
return new StdioSquireMcpClient();
|
|
8486
|
+
}
|
|
8487
|
+
|
|
8488
|
+
// apps/body/dist/connector-assignments.js
|
|
8489
|
+
var CONNECTOR_POLL_INTERVAL_MS = 1e4;
|
|
8490
|
+
var ConnectorAssignmentLoop = class {
|
|
8491
|
+
agentId;
|
|
8492
|
+
api;
|
|
8493
|
+
intervalMs;
|
|
8494
|
+
log;
|
|
8495
|
+
install;
|
|
8496
|
+
readVaultFn;
|
|
8497
|
+
revokeGrantsFn;
|
|
8498
|
+
schedule;
|
|
8499
|
+
cancel;
|
|
8500
|
+
timer;
|
|
8501
|
+
started = false;
|
|
8502
|
+
stopped = false;
|
|
8503
|
+
/** One install at a time per connector; other polls skip it. */
|
|
8504
|
+
inFlight = /* @__PURE__ */ new Set();
|
|
8505
|
+
mcp;
|
|
8506
|
+
constructor(options) {
|
|
8507
|
+
this.agentId = options.agentId;
|
|
8508
|
+
this.api = options.api;
|
|
8509
|
+
this.intervalMs = options.intervalMs ?? CONNECTOR_POLL_INTERVAL_MS;
|
|
8510
|
+
this.log = options.log ?? (() => {
|
|
8511
|
+
});
|
|
8512
|
+
this.install = options.install ?? installSquire;
|
|
8513
|
+
this.readVaultFn = options.readVault ?? readVault;
|
|
8514
|
+
this.revokeGrantsFn = options.revokeGrants ?? revokeGrants;
|
|
8515
|
+
this.schedule = options.schedule ?? ((fn, ms) => {
|
|
8516
|
+
const timer = setTimeout(fn, ms);
|
|
8517
|
+
timer.unref?.();
|
|
8518
|
+
return timer;
|
|
8519
|
+
});
|
|
8520
|
+
this.cancel = options.cancel ?? ((handle) => clearTimeout(handle));
|
|
8521
|
+
}
|
|
8522
|
+
start() {
|
|
8523
|
+
if (this.stopped || this.started)
|
|
8524
|
+
return;
|
|
8525
|
+
this.started = true;
|
|
8526
|
+
void this.runOnce();
|
|
8527
|
+
this.timer = this.schedule(() => this.poll(), this.intervalMs);
|
|
8528
|
+
}
|
|
8529
|
+
stop() {
|
|
8530
|
+
this.stopped = true;
|
|
8531
|
+
if (this.timer !== void 0) {
|
|
8532
|
+
this.cancel(this.timer);
|
|
8533
|
+
this.timer = void 0;
|
|
8534
|
+
}
|
|
8535
|
+
}
|
|
8536
|
+
/** One interval tick: poll, then re-arm. */
|
|
8537
|
+
poll() {
|
|
8538
|
+
if (this.stopped)
|
|
8539
|
+
return;
|
|
8540
|
+
void this.runOnce();
|
|
8541
|
+
this.timer = this.schedule(() => this.poll(), this.intervalMs);
|
|
8542
|
+
}
|
|
8543
|
+
/** Drain the queue once; every failure is logged, never raised. */
|
|
8544
|
+
async runOnce() {
|
|
8545
|
+
let assignments;
|
|
8546
|
+
try {
|
|
8547
|
+
const result = await this.api.execute("getConnectorAssignments", { agentId: this.agentId });
|
|
8548
|
+
assignments = result.assignments;
|
|
8549
|
+
} catch (error) {
|
|
8550
|
+
this.log(`connector assignments unavailable: ${describe(error)}`);
|
|
8551
|
+
return;
|
|
8552
|
+
}
|
|
8553
|
+
for (const assignment of assignments) {
|
|
8554
|
+
const key = `${assignment.kind}:${assignment.connectorId}`;
|
|
8555
|
+
if (assignment.kind === "uninstall")
|
|
8556
|
+
continue;
|
|
8557
|
+
if (this.inFlight.has(key))
|
|
8558
|
+
continue;
|
|
8559
|
+
this.inFlight.add(key);
|
|
8560
|
+
void this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${describe(error)}`)).finally(() => this.inFlight.delete(key));
|
|
8561
|
+
}
|
|
8562
|
+
}
|
|
8563
|
+
squire() {
|
|
8564
|
+
this.mcp ??= defaultSquireMcpClient();
|
|
8565
|
+
return this.mcp;
|
|
8566
|
+
}
|
|
8567
|
+
async handle(assignment) {
|
|
8568
|
+
if (assignment.kind === "install")
|
|
8569
|
+
await this.runInstall(assignment.connectorId);
|
|
8570
|
+
else if (assignment.kind === "sync")
|
|
8571
|
+
await this.runSync();
|
|
8572
|
+
else if (assignment.kind === "revoke-grants")
|
|
8573
|
+
await this.runRevoke(assignment.connectorId, assignment.reference);
|
|
8574
|
+
}
|
|
8575
|
+
/** Install Trusty Squire, reporting every step as it settles. */
|
|
8576
|
+
async runInstall(connectorId) {
|
|
8577
|
+
const report = async (steps) => {
|
|
8578
|
+
try {
|
|
8579
|
+
await this.api.execute("postConnectorStatus", { agentId: this.agentId, connectorId, steps });
|
|
8580
|
+
} catch (error) {
|
|
8581
|
+
this.log(`step report failed: ${describe(error)}`);
|
|
8582
|
+
}
|
|
8583
|
+
};
|
|
8584
|
+
const result = await this.install({
|
|
8585
|
+
workspaceId: this.agentId,
|
|
8586
|
+
mcp: this.squire(),
|
|
8587
|
+
onProgress: report
|
|
8588
|
+
});
|
|
8589
|
+
if (result.status === "error") {
|
|
8590
|
+
await this.api.execute("postConnectorStatus", {
|
|
8591
|
+
agentId: this.agentId,
|
|
8592
|
+
connectorId,
|
|
8593
|
+
steps: result.steps,
|
|
8594
|
+
errorMessage: result.errorMessage
|
|
8595
|
+
});
|
|
8596
|
+
return;
|
|
8597
|
+
}
|
|
8598
|
+
if (result.status === "connected") {
|
|
8599
|
+
await this.api.execute("installConnector", {
|
|
8600
|
+
agentId: this.agentId,
|
|
8601
|
+
connectorId,
|
|
8602
|
+
...result.squireVersion ? { squireVersion: result.squireVersion } : {},
|
|
8603
|
+
...result.signedInAs ? { signedInAs: result.signedInAs } : {},
|
|
8604
|
+
...result.signIn ? { signIn: result.signIn } : {}
|
|
8605
|
+
});
|
|
8606
|
+
await this.reportVault(connectorId);
|
|
8607
|
+
return;
|
|
8608
|
+
}
|
|
8609
|
+
await this.api.execute("postConnectorStatus", {
|
|
8610
|
+
agentId: this.agentId,
|
|
8611
|
+
connectorId,
|
|
8612
|
+
steps: result.steps,
|
|
8613
|
+
...result.squireVersion ? { squireVersion: result.squireVersion } : {},
|
|
8614
|
+
...result.signedInAs ? { signedInAs: result.signedInAs } : {},
|
|
8615
|
+
...result.signIn ? { signIn: result.signIn } : {}
|
|
8616
|
+
});
|
|
8617
|
+
}
|
|
8618
|
+
/** One vault report covers every live trusty-squire connector on this helper. */
|
|
8619
|
+
async runSync() {
|
|
8620
|
+
await this.reportVault();
|
|
8621
|
+
}
|
|
8622
|
+
async runRevoke(connectorId, reference) {
|
|
8623
|
+
const outcome = await this.revokeGrantsFn(this.squire(), reference);
|
|
8624
|
+
this.log(`revoked ${outcome.revoked} grant(s) on ${reference}` + (outcome.failed ? `, ${outcome.failed} failed` : ""));
|
|
8625
|
+
void connectorId;
|
|
8626
|
+
}
|
|
8627
|
+
async reportVault(_connectorId) {
|
|
8628
|
+
const connections = await this.readVaultFn(this.squire());
|
|
8629
|
+
await this.api.execute("postConnectorVault", { agentId: this.agentId, connections });
|
|
8630
|
+
}
|
|
8631
|
+
};
|
|
8632
|
+
function describe(error) {
|
|
8633
|
+
return error instanceof Error ? error.message : String(error);
|
|
8634
|
+
}
|
|
8635
|
+
|
|
8165
8636
|
// packages/api-contract/dist/daemon-operations.js
|
|
8166
8637
|
function isAgentCommand(value) {
|
|
8167
8638
|
if (!value || typeof value !== "object")
|
|
@@ -8185,7 +8656,7 @@ function isAgentCommand(value) {
|
|
|
8185
8656
|
}
|
|
8186
8657
|
|
|
8187
8658
|
// packages/api-contract/dist/artifacts.js
|
|
8188
|
-
var ARTIFACT_MAXIMUM_BYTES =
|
|
8659
|
+
var ARTIFACT_MAXIMUM_BYTES = 25 * 1024 * 1024;
|
|
8189
8660
|
|
|
8190
8661
|
// packages/api-contract/dist/system-events.js
|
|
8191
8662
|
var SERVER_EVENT_KINDS = [
|
|
@@ -8216,12 +8687,12 @@ var wrapper_default = import_websocket.default;
|
|
|
8216
8687
|
|
|
8217
8688
|
// apps/body/dist/runtime.js
|
|
8218
8689
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
8219
|
-
import { execFile } from "node:child_process";
|
|
8690
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
8220
8691
|
import { closeSync, openSync } from "node:fs";
|
|
8221
8692
|
import { mkdir, readFile as readFile2, readdir, rename, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
8222
8693
|
import { homedir as homedir2 } from "node:os";
|
|
8223
8694
|
import { dirname as dirname2, resolve as resolve6 } from "node:path";
|
|
8224
|
-
import { spawn as
|
|
8695
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
8225
8696
|
import { promisify } from "node:util";
|
|
8226
8697
|
|
|
8227
8698
|
// node_modules/@noble/hashes/_u64.js
|
|
@@ -16344,13 +16815,13 @@ var NegentropyStorageVector = class {
|
|
|
16344
16815
|
let count = last - first;
|
|
16345
16816
|
while (count > 0) {
|
|
16346
16817
|
let it = first;
|
|
16347
|
-
let
|
|
16348
|
-
it +=
|
|
16818
|
+
let step2 = Math.floor(count / 2);
|
|
16819
|
+
it += step2;
|
|
16349
16820
|
if (cmp(arr[it])) {
|
|
16350
16821
|
first = ++it;
|
|
16351
|
-
count -=
|
|
16822
|
+
count -= step2 + 1;
|
|
16352
16823
|
} else {
|
|
16353
|
-
count =
|
|
16824
|
+
count = step2;
|
|
16354
16825
|
}
|
|
16355
16826
|
}
|
|
16356
16827
|
return first;
|
|
@@ -16752,7 +17223,7 @@ function decodeNsec(nsec) {
|
|
|
16752
17223
|
}
|
|
16753
17224
|
|
|
16754
17225
|
// apps/body/dist/runtime.js
|
|
16755
|
-
var execFileAsync = promisify(
|
|
17226
|
+
var execFileAsync = promisify(execFile2);
|
|
16756
17227
|
var DEFAULT_AGENT_IDENTITY_NAME = "beeline-agent";
|
|
16757
17228
|
var DEFAULT_BODY_IDENTITY_NAME = "beeline-body";
|
|
16758
17229
|
var DEFAULT_DAEMON_MONOLITH_BASE_URL = "https://server.usebeeline.app";
|
|
@@ -16942,7 +17413,7 @@ async function launchRuntimeDaemon(configPath, opts = {}) {
|
|
|
16942
17413
|
const entrypoint = opts.entrypoint ?? process.argv[1];
|
|
16943
17414
|
if (!entrypoint)
|
|
16944
17415
|
throw new Error("cannot resolve daemon CLI entrypoint");
|
|
16945
|
-
const child =
|
|
17416
|
+
const child = spawn3(process.execPath, [...opts.execArgv ?? [], entrypoint, "daemon", "--config", resolve6(configPath)], {
|
|
16946
17417
|
cwd: directory,
|
|
16947
17418
|
env: opts.env ?? process.env,
|
|
16948
17419
|
detached: !foreground,
|
|
@@ -17213,7 +17684,7 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
|
|
|
17213
17684
|
}
|
|
17214
17685
|
|
|
17215
17686
|
// apps/body/dist/room-runtime.js
|
|
17216
|
-
import { execFile as
|
|
17687
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
17217
17688
|
import { createHash as createHash6 } from "node:crypto";
|
|
17218
17689
|
import { existsSync as existsSync4, mkdirSync } from "node:fs";
|
|
17219
17690
|
import { mkdir as mkdir13, rm as rm5 } from "node:fs/promises";
|
|
@@ -17221,7 +17692,7 @@ import { dirname as dirname8, resolve as resolve20 } from "node:path";
|
|
|
17221
17692
|
import { promisify as promisify4 } from "node:util";
|
|
17222
17693
|
|
|
17223
17694
|
// apps/body/dist/grant-runner.js
|
|
17224
|
-
import { execFile as
|
|
17695
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
17225
17696
|
import { createHash as createHash2, randomBytes as randomBytes6 } from "node:crypto";
|
|
17226
17697
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
17227
17698
|
import { createServer } from "node:http";
|
|
@@ -17880,9 +18351,9 @@ var GrantCommandRunner = class {
|
|
|
17880
18351
|
...Object.fromEntries(secrets)
|
|
17881
18352
|
};
|
|
17882
18353
|
const cap = this.options.outputCapBytes ?? GRANT_COMMAND_OUTPUT_CAP_BYTES;
|
|
17883
|
-
const
|
|
18354
|
+
const spawn9 = surfaceAllows(policy.surface, "run-host-command") ? { command: argv[0], args: argv.slice(1) } : roomSandboxCommand(policy, room.cwd, argv);
|
|
17884
18355
|
const outcome = await new Promise((resolveRun) => {
|
|
17885
|
-
const child =
|
|
18356
|
+
const child = execFile3(spawn9.command, spawn9.args, {
|
|
17886
18357
|
cwd: room.cwd,
|
|
17887
18358
|
env,
|
|
17888
18359
|
timeout: this.options.timeoutMs ?? GRANT_COMMAND_TIMEOUT_MS,
|
|
@@ -18318,7 +18789,7 @@ async function runServerCommandIntake(options) {
|
|
|
18318
18789
|
}
|
|
18319
18790
|
|
|
18320
18791
|
// apps/body/dist/monolith-corner-turn.js
|
|
18321
|
-
import { execFile as
|
|
18792
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
18322
18793
|
import { createHash as createHash5 } from "node:crypto";
|
|
18323
18794
|
import { mkdir as mkdir12 } from "node:fs/promises";
|
|
18324
18795
|
import { homedir as homedir7 } from "node:os";
|
|
@@ -18352,6 +18823,9 @@ function isAgentPairingCode(value) {
|
|
|
18352
18823
|
// apps/body/dist/beeline-skill.js
|
|
18353
18824
|
var USING_BEELINE_SKILL_NAME = "using-beeline";
|
|
18354
18825
|
var BEELINE_REVIEW_SKILL_NAME = "beeline-review";
|
|
18826
|
+
function isConfiguredReviewer(agentHandle, reviewerHandle) {
|
|
18827
|
+
return Boolean(agentHandle && reviewerHandle && agentHandle.replace(/^@/, "") === reviewerHandle.replace(/^@/, ""));
|
|
18828
|
+
}
|
|
18355
18829
|
var BEELINE_ROOM_CAPABILITIES = [
|
|
18356
18830
|
"The repository filesystem is read-only in this Room session.",
|
|
18357
18831
|
"You may address any Room member, including another agent, by writing @name in your reply; the server routes that mention to them. Each turn prompt lists the Room members and the exact spelling that tags each one - use those spellings, and never guess or reuse one from an older message.",
|
|
@@ -18359,7 +18833,7 @@ var BEELINE_ROOM_CAPABILITIES = [
|
|
|
18359
18833
|
"Tag the user only when you need a decision or input, or when the task they asked for is finished. Never tag for progress, acknowledgement, or questions the transcript already answers.",
|
|
18360
18834
|
"Every MCP server mounted into this session is approved tool by tool - use operator and host tools freely; the read-only filesystem sandbox is the boundary, not a tool list. Network web search is enabled.",
|
|
18361
18835
|
"Files and photos people share are downloaded for you: read them at the local path named in the prompt (photos may also arrive inline); never fetch the reference URL.",
|
|
18362
|
-
"To create a file (this Room has no other way to write one), call beeline-agent write_scratch_file with a relative path and content - text by default, or base64 for bytes you computed; it returns a path in your writable session home. To send a file, call beeline-agent
|
|
18836
|
+
"To create a file (this Room has no other way to write one), call beeline-agent write_scratch_file with a relative path and content - text by default, or base64 for bytes you computed; it returns a path in your writable session home. To send a file, call beeline-agent post_artifact with a path inside your checkout or anywhere in your writable session home (wherever a file you or your harness generated actually landed, including one you just wrote), or with html/bytes content directly; it is uploaded and attached to your reply, and title and mime default from the file when you post by path. write_scratch_file produces the file, not a picture - turning it into a raster image needs a converter, which needs shell, which this Room does not have.",
|
|
18363
18837
|
"To run something later or repeatedly, call beeline-agent create_schedule (interval in minutes or a 5-field cron, optional maxRuns); list_schedules / delete_schedule manage them.",
|
|
18364
18838
|
`To react to things that HAPPEN in this Room rather than only to what is said to you, call beeline-agent subscribe_events with the kinds you want (${SERVER_EVENT_KINDS.join(", ")}); each one then wakes you for a turn. It replaces your list, so send every kind you want - list_event_subscriptions shows the current one. You do this yourself: nobody has to configure it for you. grant-decided carries the grant id and status and resumes the turn that asked for the grant.`,
|
|
18365
18839
|
"To state something that happened so the Room and other agents can act on it, call beeline-agent emit_event with your own agent:<slug> kind, one sentence, and optionally the agent members to wake. Chains of events are bounded and a refused emit posts nothing.",
|
|
@@ -18375,7 +18849,7 @@ var BEELINE_DM_CAPABILITIES = [
|
|
|
18375
18849
|
"The repository filesystem is read-only in this session.",
|
|
18376
18850
|
"Every MCP server mounted into this session is approved tool by tool - use operator and host tools freely; the read-only filesystem sandbox is the boundary, not a tool list. Network web search is enabled.",
|
|
18377
18851
|
"Files and photos people share are downloaded for you: read them at the local path named in the prompt (photos may also arrive inline); never fetch the reference URL.",
|
|
18378
|
-
"To create a file (this Room has no other way to write one), call beeline-agent write_scratch_file with a relative path and content - text by default, or base64 for bytes you computed; it returns a path in your writable session home. To send a file, call beeline-agent
|
|
18852
|
+
"To create a file (this Room has no other way to write one), call beeline-agent write_scratch_file with a relative path and content - text by default, or base64 for bytes you computed; it returns a path in your writable session home. To send a file, call beeline-agent post_artifact with a path inside your checkout or anywhere in your writable session home (wherever a file you or your harness generated actually landed, including one you just wrote), or with html/bytes content directly; it is uploaded and attached to your reply, and title and mime default from the file when you post by path. write_scratch_file produces the file, not a picture - turning it into a raster image needs a converter, which needs shell, which this Room does not have.",
|
|
18379
18853
|
"Tag the person only when you need a decision or input, or when the task they asked for is finished.",
|
|
18380
18854
|
"Never claim an action or reply happened unless the prompt or a tool result proves it."
|
|
18381
18855
|
].join(" ");
|
|
@@ -18417,6 +18891,8 @@ description: How to answer inside a Beeline Room.
|
|
|
18417
18891
|
|
|
18418
18892
|
You are answering inside a Room whose filesystem is read-only. ${BEELINE_ROOM_CAPABILITIES}
|
|
18419
18893
|
|
|
18894
|
+
When your corner's pull request is ready, merging is your step: once the configured reviewer approves and tags you, you run \`gh pr merge\` yourself - nothing merges it for you.
|
|
18895
|
+
|
|
18420
18896
|
## Tools and the Workbench
|
|
18421
18897
|
|
|
18422
18898
|
A **tool** is something you can use once a human pairs it; a **key** is the credential that tool holds for that human. You spend a key through the mounted connector and never see the credential itself.
|
|
@@ -18507,7 +18983,7 @@ Then take exactly one action:
|
|
|
18507
18983
|
|
|
18508
18984
|
- FAIL: reply \`@author\` with the confirmed findings to fix.
|
|
18509
18985
|
- PASS: call \`approve_merge\` with the reviewed head SHA, then reply \`@author approved <reviewed sha>, merge\`.
|
|
18510
|
-
-
|
|
18986
|
+
- Approving is your last step as reviewer. The author merges it; you never do, and nothing merges it automatically.
|
|
18511
18987
|
`;
|
|
18512
18988
|
}
|
|
18513
18989
|
|
|
@@ -19177,7 +19653,7 @@ async function prepareRoomAgentHome(input) {
|
|
|
19177
19653
|
await symlink(source, target).catch(() => void 0);
|
|
19178
19654
|
}
|
|
19179
19655
|
const prior = agentHomeProvisionQueues.get(root) ?? Promise.resolve();
|
|
19180
|
-
const provision = prior.catch(() => void 0).then(() => provisionAgentSkillsAndMcp(root, operatorHome, input.skillReleaseId ?? runningBeelineReleaseId(), input.failClosed ?? false, input.sharedSkills ?? [], agentSkillDir(input.agentKind), input.openRouterRouting));
|
|
19656
|
+
const provision = prior.catch(() => void 0).then(() => provisionAgentSkillsAndMcp(root, operatorHome, input.skillReleaseId ?? runningBeelineReleaseId(), input.failClosed ?? false, input.sharedSkills ?? [], agentSkillDir(input.agentKind), input.openRouterRouting, input.isReviewer ?? false));
|
|
19181
19657
|
agentHomeProvisionQueues.set(root, provision);
|
|
19182
19658
|
try {
|
|
19183
19659
|
await provision;
|
|
@@ -19187,10 +19663,10 @@ async function prepareRoomAgentHome(input) {
|
|
|
19187
19663
|
}
|
|
19188
19664
|
return roomAgentHomeEnv(root);
|
|
19189
19665
|
}
|
|
19190
|
-
async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, failClosed, sharedSkills, skillDir, openRouterRouting) {
|
|
19666
|
+
async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, failClosed, sharedSkills, skillDir, openRouterRouting, isReviewer) {
|
|
19191
19667
|
const managedSkills = [
|
|
19192
19668
|
{ name: USING_BEELINE_SKILL_NAME, content: usingBeelineSkillMarkdown(skillReleaseId) },
|
|
19193
|
-
{ name: BEELINE_REVIEW_SKILL_NAME, content: beelineReviewSkillMarkdown(skillReleaseId) }
|
|
19669
|
+
...isReviewer ? [{ name: BEELINE_REVIEW_SKILL_NAME, content: beelineReviewSkillMarkdown(skillReleaseId) }] : []
|
|
19194
19670
|
];
|
|
19195
19671
|
const shared = await resolveSharedSkillSources(operatorHome, sharedSkills);
|
|
19196
19672
|
await provisionManagedSkillsDir(resolve13(root, skillDir, "skills"), managedSkills, shared, sharedSkills.length === 0);
|
|
@@ -20245,9 +20721,9 @@ export default async function (pi) {
|
|
|
20245
20721
|
`;
|
|
20246
20722
|
|
|
20247
20723
|
// apps/body/dist/corner-branch-sync.js
|
|
20248
|
-
import { execFile as
|
|
20724
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
20249
20725
|
import { promisify as promisify2 } from "node:util";
|
|
20250
|
-
var execFileAsync2 = promisify2(
|
|
20726
|
+
var execFileAsync2 = promisify2(execFile4);
|
|
20251
20727
|
async function syncCornerBranch(input) {
|
|
20252
20728
|
const git = input.git ?? (async (args) => (await execFileAsync2("git", ["-C", input.worktreePath, ...args], {
|
|
20253
20729
|
...input.env ? { env: input.env } : {},
|
|
@@ -20426,7 +20902,7 @@ function isMountedMcpToolPermissionRequest(request, mountedServers = ROOM_MOUNTE
|
|
|
20426
20902
|
var AGENT_SURFACE_TOOL_NAMES = [
|
|
20427
20903
|
"open_corner",
|
|
20428
20904
|
"pr_checks_status",
|
|
20429
|
-
"
|
|
20905
|
+
"post_artifact",
|
|
20430
20906
|
"write_scratch_file"
|
|
20431
20907
|
];
|
|
20432
20908
|
var SQUIRE_TITLE_PREFIXES = [
|
|
@@ -21267,7 +21743,7 @@ async function seedWarmNodeModules(input) {
|
|
|
21267
21743
|
for (const target of placed) {
|
|
21268
21744
|
await rm4(target, { recursive: true, force: true }).catch(() => void 0);
|
|
21269
21745
|
}
|
|
21270
|
-
return { reason: "failed", key: plan.key, detail:
|
|
21746
|
+
return { reason: "failed", key: plan.key, detail: describe2(error) };
|
|
21271
21747
|
} finally {
|
|
21272
21748
|
await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
21273
21749
|
}
|
|
@@ -21310,7 +21786,7 @@ async function harvestWarmNodeModules(input) {
|
|
|
21310
21786
|
} catch (error) {
|
|
21311
21787
|
if (await pathExists(entry))
|
|
21312
21788
|
return { reason: "already-warm", key: plan.key };
|
|
21313
|
-
return { reason: "failed", key: plan.key, detail:
|
|
21789
|
+
return { reason: "failed", key: plan.key, detail: describe2(error) };
|
|
21314
21790
|
} finally {
|
|
21315
21791
|
await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
21316
21792
|
}
|
|
@@ -21453,7 +21929,7 @@ async function deviceOf(path) {
|
|
|
21453
21929
|
async function isDirectory(path) {
|
|
21454
21930
|
return stat2(path).then((info) => info.isDirectory(), () => false);
|
|
21455
21931
|
}
|
|
21456
|
-
function
|
|
21932
|
+
function describe2(error) {
|
|
21457
21933
|
return error instanceof Error ? error.message : String(error);
|
|
21458
21934
|
}
|
|
21459
21935
|
|
|
@@ -21731,10 +22207,13 @@ var MonolithRoomTurnLoop = class {
|
|
|
21731
22207
|
});
|
|
21732
22208
|
const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
|
|
21733
22209
|
await mkdir11(this.options.cwd, { recursive: true });
|
|
21734
|
-
const
|
|
22210
|
+
const selectionModel = configuration.model ?? this.options.config.modelSelection?.model;
|
|
22211
|
+
const selectionEffort = configuration.effort ?? this.options.config.modelSelection?.effort;
|
|
22212
|
+
const selection = selectionModel || selectionEffort ? { model: selectionModel, effort: selectionEffort } : void 0;
|
|
21735
22213
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
21736
22214
|
root: this.options.config.agentHomeRoot,
|
|
21737
22215
|
sharedSkills: this.options.config.sharedSkills ?? [],
|
|
22216
|
+
isReviewer: isConfiguredReviewer(self?.handle, configuration.reviewerHandle),
|
|
21738
22217
|
...this.options.config.agentKind ? { agentKind: this.options.config.agentKind } : {},
|
|
21739
22218
|
...this.options.config.operatorHome ? { operatorHome: this.options.config.operatorHome } : {},
|
|
21740
22219
|
...openRouterRoutingInput(this.options.config, selection, this.options.fetchImpl, {
|
|
@@ -21957,6 +22436,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
21957
22436
|
this.busy = true;
|
|
21958
22437
|
const trace = this.beginTurnTrace(item.id);
|
|
21959
22438
|
let liveStream;
|
|
22439
|
+
let liveCornerOpened = false;
|
|
21960
22440
|
try {
|
|
21961
22441
|
if (!this.memberNames.has(item.authorId))
|
|
21962
22442
|
await this.roster().catch(() => void 0);
|
|
@@ -22038,7 +22518,11 @@ ${JSON.stringify((corners.corners ?? []).filter((corner) => !corner.archived))}`
|
|
|
22038
22518
|
result2 = await this.client.sessionPrompt(this.sessionId, nextPrompt, ROOM_PROMPT_INACTIVITY_TIMEOUT_MS, (delta, full) => {
|
|
22039
22519
|
trace.firstModelOutput();
|
|
22040
22520
|
stream.onChunk(delta, full);
|
|
22041
|
-
}, void 0, (calls) =>
|
|
22521
|
+
}, void 0, (calls) => {
|
|
22522
|
+
trace.toolCalls(calls);
|
|
22523
|
+
if (openedACorner(openCornerToolCall(calls)))
|
|
22524
|
+
liveCornerOpened = true;
|
|
22525
|
+
});
|
|
22042
22526
|
} catch (error) {
|
|
22043
22527
|
promptError = error;
|
|
22044
22528
|
}
|
|
@@ -22132,6 +22616,22 @@ ${JSON.stringify((corners.corners ?? []).filter((corner) => !corner.archived))}`
|
|
|
22132
22616
|
await trace.finish("cancelled");
|
|
22133
22617
|
return;
|
|
22134
22618
|
}
|
|
22619
|
+
if (liveCornerOpened && error instanceof AcpRequestTimeoutError && error.inactivity && error.method === "session/prompt") {
|
|
22620
|
+
console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id}: inactivity timeout after opening a corner; the work continues in the corner`);
|
|
22621
|
+
this.options.onCornerOpened?.();
|
|
22622
|
+
await liveStream?.retract().catch((retractError) => {
|
|
22623
|
+
console.error(`[thin-core] monolith Room ${this.options.roomId} draft retract failed:`, retractError);
|
|
22624
|
+
});
|
|
22625
|
+
await api.execute("postAgentTurnReceipt", {
|
|
22626
|
+
agentId: this.agent.publicKey,
|
|
22627
|
+
roomId: this.options.roomId,
|
|
22628
|
+
requestId: item.id,
|
|
22629
|
+
status: "complete",
|
|
22630
|
+
generationId: this.commandContext.generationId
|
|
22631
|
+
});
|
|
22632
|
+
await trace.finish("complete");
|
|
22633
|
+
return;
|
|
22634
|
+
}
|
|
22135
22635
|
await liveStream?.retract().catch((retractError) => {
|
|
22136
22636
|
console.error(`[thin-core] monolith Room ${this.options.roomId} draft retract failed:`, retractError);
|
|
22137
22637
|
});
|
|
@@ -22201,7 +22701,7 @@ function roomMessagePrompt(author, body, attachments, delivered, harnessAcceptsI
|
|
|
22201
22701
|
}
|
|
22202
22702
|
|
|
22203
22703
|
// apps/body/dist/monolith-corner-turn.js
|
|
22204
|
-
var execFileAsync3 = promisify3(
|
|
22704
|
+
var execFileAsync3 = promisify3(execFile5);
|
|
22205
22705
|
var TOOL_ARGUMENT_MAX_BYTES = 1200;
|
|
22206
22706
|
var TOOL_OUTPUT_MAX_BYTES = 3200;
|
|
22207
22707
|
var TOOL_PATH_LIMIT = 12;
|
|
@@ -22592,6 +23092,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
22592
23092
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
22593
23093
|
root: this.options.config.agentHomeRoot,
|
|
22594
23094
|
sharedSkills: this.options.config.sharedSkills ?? [],
|
|
23095
|
+
isReviewer: isConfiguredReviewer(self?.handle, configuration.reviewerHandle),
|
|
22595
23096
|
...this.options.config.agentKind ? { agentKind: this.options.config.agentKind } : {},
|
|
22596
23097
|
...this.options.config.operatorHome ? { operatorHome: this.options.config.operatorHome } : {},
|
|
22597
23098
|
...openRouterRoutingInput(this.options.config, selection, this.options.fetchImpl, {
|
|
@@ -22742,7 +23243,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
22742
23243
|
"Never restate server check or merge notes. On a checks turn, say nothing unless you merge or push a fix, then use one short line. Never merge while approvalPending is true. When approval is pending, wait for the reviewer to tag you. Never merge another pull request. Never create a schedule to poll pr_checks_status or the merge gate: the green transition wakes the reviewer and the reviewer's approval tag wakes you, and tagging any agent other than the configured reviewer cannot clear the gate. If a schedule wakes you in this corner anyway, follow the same rule as a checks turn: say nothing unless you merge, push a fix, or report a genuinely new blocker."
|
|
22743
23244
|
] : [
|
|
22744
23245
|
"This is a chat-only corner with no repository or GitHub workflow.",
|
|
22745
|
-
"Work in this corner's writable workspace. Use write_scratch_file or ordinary tools to create files, then
|
|
23246
|
+
"Work in this corner's writable workspace. Use write_scratch_file or ordinary tools to create files, then post_artifact with the path to send them back to the corner.",
|
|
22746
23247
|
"Do not initialize a repository, create a branch, push, open a pull request, or wait for GitHub checks."
|
|
22747
23248
|
]
|
|
22748
23249
|
].filter(Boolean).join("\n\n")
|
|
@@ -23729,7 +24230,7 @@ async function removeCornerWorktreeAndBranches(worktree) {
|
|
|
23729
24230
|
]);
|
|
23730
24231
|
}
|
|
23731
24232
|
}
|
|
23732
|
-
var execFileAsync4 = promisify4(
|
|
24233
|
+
var execFileAsync4 = promisify4(execFile6);
|
|
23733
24234
|
async function removeCornerScratchWorkspace(input) {
|
|
23734
24235
|
const expected = resolve20(input.roomRoot, "scratch");
|
|
23735
24236
|
if (resolve20(input.scratchPath) !== expected) {
|
|
@@ -24464,13 +24965,13 @@ var ThinDaemonCore = class {
|
|
|
24464
24965
|
};
|
|
24465
24966
|
|
|
24466
24967
|
// apps/body/dist/systemd.js
|
|
24467
|
-
import { execFile as
|
|
24968
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
24468
24969
|
import { mkdir as mkdir14, readFile as readFile9, writeFile as writeFile9 } from "node:fs/promises";
|
|
24469
24970
|
import { homedir as homedir8 } from "node:os";
|
|
24470
24971
|
import { dirname as dirname9, resolve as resolve21 } from "node:path";
|
|
24471
24972
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
24472
24973
|
import { promisify as promisify5 } from "node:util";
|
|
24473
|
-
var execFileAsync5 = promisify5(
|
|
24974
|
+
var execFileAsync5 = promisify5(execFile7);
|
|
24474
24975
|
var DELIBERATE_REMOVAL_EXIT_STATUS = 78;
|
|
24475
24976
|
var DAEMON_DISTRESS_EXIT_STATUS = 77;
|
|
24476
24977
|
var UNKNOWN_AGENT_EXIT_STATUS = 79;
|
|
@@ -24709,7 +25210,7 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
24709
25210
|
}
|
|
24710
25211
|
|
|
24711
25212
|
// apps/body/dist/connect-command.js
|
|
24712
|
-
import { spawn as
|
|
25213
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
24713
25214
|
import { createHash as createHash8 } from "node:crypto";
|
|
24714
25215
|
import { chmod as chmod6, mkdir as mkdir16, readFile as readFile11, unlink as unlink2, writeFile as writeFile11 } from "node:fs/promises";
|
|
24715
25216
|
import { dirname as dirname12, resolve as resolve23 } from "node:path";
|
|
@@ -24796,7 +25297,7 @@ async function verifyProviderKey(input) {
|
|
|
24796
25297
|
}
|
|
24797
25298
|
|
|
24798
25299
|
// apps/body/dist/pair-agent-selection.js
|
|
24799
|
-
import { spawn as
|
|
25300
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
24800
25301
|
import { stdin as stdin2, stdout as stdout3 } from "node:process";
|
|
24801
25302
|
var NO_AGENT_MESSAGE = `No supported ACP-capable coding agent was detected.
|
|
24802
25303
|
Install one of these supported agents:
|
|
@@ -24824,7 +25325,7 @@ async function clackSelectAgent(candidates) {
|
|
|
24824
25325
|
}
|
|
24825
25326
|
async function installAdapter(install, opts) {
|
|
24826
25327
|
await new Promise((resolveInstall, rejectInstall) => {
|
|
24827
|
-
const child =
|
|
25328
|
+
const child = spawn4(install.command, install.args, {
|
|
24828
25329
|
cwd: opts.cwd,
|
|
24829
25330
|
env: opts.env ?? process.env,
|
|
24830
25331
|
stdio: "inherit"
|
|
@@ -25419,7 +25920,7 @@ async function writeProviderEnv(selection, agentPubkey) {
|
|
|
25419
25920
|
}
|
|
25420
25921
|
async function runInstalledFinish(binary, grantPath) {
|
|
25421
25922
|
await new Promise((resolveRun, rejectRun) => {
|
|
25422
|
-
const child =
|
|
25923
|
+
const child = spawn6(binary, ["connect-finish", grantPath], {
|
|
25423
25924
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25424
25925
|
});
|
|
25425
25926
|
let diagnostic = "";
|
|
@@ -25592,7 +26093,7 @@ init_self_update_manifest();
|
|
|
25592
26093
|
|
|
25593
26094
|
// apps/body/dist/managed-update.js
|
|
25594
26095
|
init_self_update();
|
|
25595
|
-
import { spawn as
|
|
26096
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
25596
26097
|
import { mkdir as mkdir18, rm as rm7, stat as stat3, writeFile as writeFile13 } from "node:fs/promises";
|
|
25597
26098
|
import { dirname as dirname14, resolve as resolve25 } from "node:path";
|
|
25598
26099
|
|
|
@@ -26006,7 +26507,7 @@ async function runManagedUpdateWorkerProcess() {
|
|
|
26006
26507
|
if (!entrypoint)
|
|
26007
26508
|
throw new Error("cannot resolve the current Beeline entrypoint");
|
|
26008
26509
|
await new Promise((resolveWorker, rejectWorker) => {
|
|
26009
|
-
const child =
|
|
26510
|
+
const child = spawn7(process.execPath, [entrypoint, "managed-update-worker"], {
|
|
26010
26511
|
detached: true,
|
|
26011
26512
|
env: { ...process.env, BEELINE_INTERNAL_UPDATE_WORKER: "1" },
|
|
26012
26513
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -26638,7 +27139,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
26638
27139
|
}
|
|
26639
27140
|
|
|
26640
27141
|
// apps/body/dist/current-release-probe.js
|
|
26641
|
-
import { spawn as
|
|
27142
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
26642
27143
|
import { dirname as dirname16, join as join10 } from "node:path";
|
|
26643
27144
|
init_self_update();
|
|
26644
27145
|
var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
|
|
@@ -26689,7 +27190,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
26689
27190
|
}
|
|
26690
27191
|
const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
|
|
26691
27192
|
return new Promise((resolve31) => {
|
|
26692
|
-
const child =
|
|
27193
|
+
const child = spawn8(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
26693
27194
|
let stdout6 = "";
|
|
26694
27195
|
let stderr = "";
|
|
26695
27196
|
let settled = false;
|
|
@@ -27034,6 +27535,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
27034
27535
|
const scratchSweepTimer = setInterval(() => runScratchSweepLogged(runtimeDir), SCRATCH_SWEEP_INTERVAL_MS);
|
|
27035
27536
|
scratchSweepTimer.unref();
|
|
27036
27537
|
let ready = false;
|
|
27538
|
+
let connectorLoop;
|
|
27037
27539
|
let stoppingStatus = "daemon stopped";
|
|
27038
27540
|
try {
|
|
27039
27541
|
const core = new ThinDaemonCore(runtime, configPath, config, { daemonApi });
|
|
@@ -27106,6 +27608,12 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
27106
27608
|
...runtime.modelSelection ? { runtimeSelection: runtime.modelSelection } : {},
|
|
27107
27609
|
...config.modelUnavailable ? { startupUnavailable: config.modelUnavailable.unavailable.label } : {}
|
|
27108
27610
|
});
|
|
27611
|
+
connectorLoop ??= new ConnectorAssignmentLoop({
|
|
27612
|
+
api: daemonApi,
|
|
27613
|
+
agentId: runtime.agent.publicKey,
|
|
27614
|
+
log: (message) => console.log(`[body] connector: ${message}`)
|
|
27615
|
+
});
|
|
27616
|
+
connectorLoop.start();
|
|
27109
27617
|
},
|
|
27110
27618
|
onProgress: async (status) => {
|
|
27111
27619
|
void drainRollbackAlert(core.activeRoomIds()[0] ?? runtime.rooms[0]?.channelId);
|