usebeeline 0.0.53 → 0.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/usebeeline.mjs +499 -130
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -955,8 +955,8 @@ var init_self_update = __esm({
|
|
|
955
955
|
});
|
|
956
956
|
|
|
957
957
|
// apps/body/dist/cli.js
|
|
958
|
-
import { dirname as dirname15, resolve as
|
|
959
|
-
import { readFile as readFile14, unlink as
|
|
958
|
+
import { dirname as dirname15, resolve as resolve29 } from "node:path";
|
|
959
|
+
import { readFile as readFile14, unlink as unlink5, writeFile as writeFile15 } from "node:fs/promises";
|
|
960
960
|
import { stdin as stdin4, stdout as stdout5 } from "node:process";
|
|
961
961
|
|
|
962
962
|
// node_modules/@clack/core/dist/index.mjs
|
|
@@ -2951,13 +2951,17 @@ function parseSandboxMaskEnv(env) {
|
|
|
2951
2951
|
return entries.length ? entries : void 0;
|
|
2952
2952
|
}
|
|
2953
2953
|
|
|
2954
|
-
//
|
|
2954
|
+
// packages/api-contract/dist/agent-access.js
|
|
2955
2955
|
var AGENT_ACCESS_POLICIES = ["everyone", "creator", "allowlist"];
|
|
2956
|
-
var
|
|
2957
|
-
var LEGACY_ACCESS_POLICY = "everyone";
|
|
2956
|
+
var DEFAULT_AGENT_ACCESS_POLICY = "everyone";
|
|
2958
2957
|
function isAgentAccessPolicy(value) {
|
|
2959
2958
|
return AGENT_ACCESS_POLICIES.includes(value);
|
|
2960
2959
|
}
|
|
2960
|
+
var ACCESS_NOTICE_WINDOW_MS = 10 * 6e4;
|
|
2961
|
+
|
|
2962
|
+
// apps/body/dist/access-policy.js
|
|
2963
|
+
var DEFAULT_ACCESS_POLICY = DEFAULT_AGENT_ACCESS_POLICY;
|
|
2964
|
+
var LEGACY_ACCESS_POLICY = "everyone";
|
|
2961
2965
|
var ACCESS_REFUSAL_WINDOW_MS = 60 * 60 * 1e3;
|
|
2962
2966
|
function isSenderPermitted(policy, senderPubkey, ownerPubkey, allowlist = void 0) {
|
|
2963
2967
|
if (!senderPubkey)
|
|
@@ -3832,7 +3836,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
3832
3836
|
const current = this.activeRunIds.get(sessionId);
|
|
3833
3837
|
if (current)
|
|
3834
3838
|
return Promise.resolve(current);
|
|
3835
|
-
return new Promise((
|
|
3839
|
+
return new Promise((resolve30, reject) => {
|
|
3836
3840
|
const onUpdate = (update) => {
|
|
3837
3841
|
if (update.sessionId !== sessionId)
|
|
3838
3842
|
return;
|
|
@@ -3840,7 +3844,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
3840
3844
|
if (!runId)
|
|
3841
3845
|
return;
|
|
3842
3846
|
cleanup();
|
|
3843
|
-
|
|
3847
|
+
resolve30(runId);
|
|
3844
3848
|
};
|
|
3845
3849
|
const timer = setTimeout(() => {
|
|
3846
3850
|
cleanup();
|
|
@@ -3924,13 +3928,13 @@ var AcpClient = class extends EventEmitter {
|
|
|
3924
3928
|
}
|
|
3925
3929
|
const id = this.nextId++;
|
|
3926
3930
|
const payload = { jsonrpc: "2.0", id, method, params };
|
|
3927
|
-
return new Promise((
|
|
3931
|
+
return new Promise((resolve30, reject) => {
|
|
3928
3932
|
const timer = setTimeout(() => {
|
|
3929
3933
|
this.pending.delete(id);
|
|
3930
3934
|
reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart), detail));
|
|
3931
3935
|
}, timeoutMs);
|
|
3932
3936
|
this.pending.set(id, {
|
|
3933
|
-
resolve:
|
|
3937
|
+
resolve: resolve30,
|
|
3934
3938
|
reject,
|
|
3935
3939
|
timer,
|
|
3936
3940
|
method,
|
|
@@ -13280,12 +13284,12 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
|
|
|
13280
13284
|
}
|
|
13281
13285
|
|
|
13282
13286
|
// apps/body/dist/room-runtime.js
|
|
13283
|
-
import { execFile as
|
|
13287
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
13284
13288
|
import { createHash as createHash4 } from "node:crypto";
|
|
13285
13289
|
import { existsSync as existsSync4, mkdirSync } from "node:fs";
|
|
13286
13290
|
import { mkdir as mkdir11, rm as rm4 } from "node:fs/promises";
|
|
13287
13291
|
import { dirname as dirname6, resolve as resolve19 } from "node:path";
|
|
13288
|
-
import { promisify as
|
|
13292
|
+
import { promisify as promisify4 } from "node:util";
|
|
13289
13293
|
|
|
13290
13294
|
// apps/body/dist/grant-runner.js
|
|
13291
13295
|
import { execFile as execFile2 } from "node:child_process";
|
|
@@ -14125,11 +14129,11 @@ var GrantRunnerServer = class {
|
|
|
14125
14129
|
};
|
|
14126
14130
|
|
|
14127
14131
|
// apps/body/dist/monolith-corner-turn.js
|
|
14128
|
-
import { execFile as
|
|
14132
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
14129
14133
|
import { mkdir as mkdir9 } from "node:fs/promises";
|
|
14130
14134
|
import { homedir as homedir6 } from "node:os";
|
|
14131
14135
|
import { join as join5 } from "node:path";
|
|
14132
|
-
import { promisify as
|
|
14136
|
+
import { promisify as promisify3 } from "node:util";
|
|
14133
14137
|
|
|
14134
14138
|
// apps/body/dist/agent-home.js
|
|
14135
14139
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
|
|
@@ -14177,7 +14181,7 @@ function isAgentPairingCode(value) {
|
|
|
14177
14181
|
var USING_BEELINE_SKILL_NAME = "using-beeline";
|
|
14178
14182
|
var BEELINE_ROOM_CAPABILITIES = [
|
|
14179
14183
|
"The repository filesystem is read-only in this Room session.",
|
|
14180
|
-
"You may address any Room member, including another agent, by writing @name in your reply; the server routes that mention to them.",
|
|
14184
|
+
"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.",
|
|
14181
14185
|
"Tag another agent only when you need something from them: a question, a handoff, a task. Never tag to acknowledge, agree, or say you are ready. If nothing is actionable, do not reply.",
|
|
14182
14186
|
"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.",
|
|
14183
14187
|
"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.",
|
|
@@ -15355,6 +15359,8 @@ function harnessStateDirsFromEnv(env) {
|
|
|
15355
15359
|
import { mkdir as mkdir5, writeFile as writeFile6 } from "node:fs/promises";
|
|
15356
15360
|
import { basename as basename4, extname, join as join4 } from "node:path";
|
|
15357
15361
|
var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
15362
|
+
var MEDIA_TTL_HOURS = 24;
|
|
15363
|
+
var EXPIRED_REASON = `expired: attachments are kept for ${MEDIA_TTL_HOURS} hours and these bytes are past that window`;
|
|
15358
15364
|
var FETCH_TIMEOUT_MS = 3e4;
|
|
15359
15365
|
var MAX_INLINE_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
15360
15366
|
function safeFileName(attachment, index, taken) {
|
|
@@ -15379,10 +15385,14 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
|
|
|
15379
15385
|
});
|
|
15380
15386
|
if (attachment.size && attachment.size > MAX_ATTACHMENT_BYTES)
|
|
15381
15387
|
return tooLarge(attachment.size);
|
|
15388
|
+
if (attachment.expired)
|
|
15389
|
+
return { attachment, reason: EXPIRED_REASON };
|
|
15382
15390
|
try {
|
|
15383
15391
|
const response = await fetchImpl(attachment.url, {
|
|
15384
15392
|
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
15385
15393
|
});
|
|
15394
|
+
if (response.status === 410)
|
|
15395
|
+
return { attachment, reason: EXPIRED_REASON };
|
|
15386
15396
|
if (!response.ok)
|
|
15387
15397
|
throw new Error(`HTTP ${response.status}`);
|
|
15388
15398
|
const declared = Number(response.headers.get("content-length") ?? 0);
|
|
@@ -15925,6 +15935,55 @@ export default async function (pi) {
|
|
|
15925
15935
|
}
|
|
15926
15936
|
`;
|
|
15927
15937
|
|
|
15938
|
+
// apps/body/dist/corner-branch-sync.js
|
|
15939
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
15940
|
+
import { promisify as promisify2 } from "node:util";
|
|
15941
|
+
var execFileAsync2 = promisify2(execFile3);
|
|
15942
|
+
var CornerBranchDivergedError = class extends Error {
|
|
15943
|
+
name = "CornerBranchDivergedError";
|
|
15944
|
+
};
|
|
15945
|
+
async function syncCornerBranch(input) {
|
|
15946
|
+
const git = input.git ?? (async (args) => (await execFileAsync2("git", ["-C", input.worktreePath, ...args], {
|
|
15947
|
+
...input.env ? { env: input.env } : {},
|
|
15948
|
+
maxBuffer: 4 * 1024 * 1024
|
|
15949
|
+
})).stdout);
|
|
15950
|
+
const remoteRef = `refs/remotes/origin/${input.featureBranch}`;
|
|
15951
|
+
const fetched = await git([
|
|
15952
|
+
"fetch",
|
|
15953
|
+
"origin",
|
|
15954
|
+
`+refs/heads/${input.featureBranch}:${remoteRef}`
|
|
15955
|
+
]).then(() => true, () => false);
|
|
15956
|
+
if (!fetched)
|
|
15957
|
+
return "unchanged";
|
|
15958
|
+
const remote = await git(["rev-parse", remoteRef]).then((value) => value.trim(), () => "");
|
|
15959
|
+
if (!remote)
|
|
15960
|
+
return "unchanged";
|
|
15961
|
+
const local = (await git(["rev-parse", "HEAD"])).trim();
|
|
15962
|
+
if (local === remote)
|
|
15963
|
+
return "unchanged";
|
|
15964
|
+
if (await contains(git, local, remote))
|
|
15965
|
+
return "unchanged";
|
|
15966
|
+
const behind = await contains(git, remote, local);
|
|
15967
|
+
try {
|
|
15968
|
+
await git(behind ? ["merge", "--ff-only", remote] : ["rebase", remote]);
|
|
15969
|
+
return behind ? "fast-forwarded" : "rebased";
|
|
15970
|
+
} catch (error) {
|
|
15971
|
+
await git(["rebase", "--abort"]).catch(() => void 0);
|
|
15972
|
+
throw new CornerBranchDivergedError(divergedReason(input.featureBranch, error));
|
|
15973
|
+
}
|
|
15974
|
+
}
|
|
15975
|
+
async function contains(git, head, ancestor) {
|
|
15976
|
+
return git(["merge-base", "--is-ancestor", ancestor, head]).then(() => true, () => false);
|
|
15977
|
+
}
|
|
15978
|
+
function divergedReason(featureBranch, error) {
|
|
15979
|
+
const detail = String(error?.stderr ?? "").split("\n").map((line) => line.trim()).find((line) => /conflict|could not|error:/i.test(line));
|
|
15980
|
+
return [
|
|
15981
|
+
`could not rebase onto origin/${featureBranch}: another agent pushed to this corner's branch`,
|
|
15982
|
+
detail ? ` (${detail})` : "",
|
|
15983
|
+
". Nothing was pushed; the branch needs a person."
|
|
15984
|
+
].join("").slice(0, 200);
|
|
15985
|
+
}
|
|
15986
|
+
|
|
15928
15987
|
// apps/body/dist/room-session.js
|
|
15929
15988
|
import { resolve as resolve15 } from "node:path";
|
|
15930
15989
|
|
|
@@ -16734,7 +16793,7 @@ process.exit(result.status ?? 1);
|
|
|
16734
16793
|
}
|
|
16735
16794
|
|
|
16736
16795
|
// apps/body/dist/monolith-corner-turn.js
|
|
16737
|
-
var
|
|
16796
|
+
var execFileAsync3 = promisify3(execFile4);
|
|
16738
16797
|
var TOOL_ARGUMENT_MAX_BYTES = 1200;
|
|
16739
16798
|
var TOOL_OUTPUT_MAX_BYTES = 3200;
|
|
16740
16799
|
var TOOL_PATH_LIMIT = 12;
|
|
@@ -16838,7 +16897,7 @@ async function cornerToolActivity(call, worktreePath, requestedBy) {
|
|
|
16838
16897
|
let title = oneLine(redactToolDetail(call.title ?? "")) || `${operation} tool`;
|
|
16839
16898
|
if (isSuccessfulCommit(call)) {
|
|
16840
16899
|
try {
|
|
16841
|
-
const shown = await
|
|
16900
|
+
const shown = await execFileAsync3("git", ["-C", worktreePath, "show", "--format=%s", "--name-only", "--no-renames", "HEAD"], { maxBuffer: 1024 * 1024 });
|
|
16842
16901
|
const lines = shown.stdout.split(/\r?\n/);
|
|
16843
16902
|
const subject = oneLine(lines.shift() ?? "commit");
|
|
16844
16903
|
const files = new Set(lines.map(oneLine).filter(Boolean));
|
|
@@ -16894,6 +16953,10 @@ var MonolithCornerTurnLoop = class {
|
|
|
16894
16953
|
/** Operator-local turn traces; built once when the daemon configured a directory. */
|
|
16895
16954
|
turnTraceSink;
|
|
16896
16955
|
memberNames = /* @__PURE__ */ new Map();
|
|
16956
|
+
/** Agent identities in this Workspace, so a mention can be told from a human's. */
|
|
16957
|
+
agentMembers = /* @__PURE__ */ new Set();
|
|
16958
|
+
/** The member agent that answered in this corner last (`carriesCorner`). */
|
|
16959
|
+
carrier;
|
|
16897
16960
|
/** The last server check state that started a turn; the same state never starts another. */
|
|
16898
16961
|
lastChecksState;
|
|
16899
16962
|
constructor(options) {
|
|
@@ -16935,6 +16998,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
16935
16998
|
workspaceId: this.options.workspaceId
|
|
16936
16999
|
});
|
|
16937
17000
|
this.memberNames = new Map(roster.members.map((member) => [member.identityId, member.name]));
|
|
17001
|
+
this.agentMembers = new Set(roster.members.filter((member) => member.kind === "agent").map((member) => member.identityId));
|
|
16938
17002
|
return roster;
|
|
16939
17003
|
}
|
|
16940
17004
|
/**
|
|
@@ -17011,8 +17075,8 @@ var MonolithCornerTurnLoop = class {
|
|
|
17011
17075
|
GITHUB_TOKEN: this.options.githubToken
|
|
17012
17076
|
};
|
|
17013
17077
|
if (this.options.config.runtimeConfigPath && this.options.config.agentHomeRoot) {
|
|
17014
|
-
const gitBinary = (await
|
|
17015
|
-
const ghBinary = await
|
|
17078
|
+
const gitBinary = (await execFileAsync3("which", ["git"])).stdout.trim();
|
|
17079
|
+
const ghBinary = await execFileAsync3("which", ["gh"]).then((result) => result.stdout.trim()).catch(() => void 0);
|
|
17016
17080
|
githubEnv = await installCornerGitHubWrappers({
|
|
17017
17081
|
root: this.options.config.agentHomeRoot,
|
|
17018
17082
|
runtimeConfigPath: this.options.config.runtimeConfigPath,
|
|
@@ -17117,6 +17181,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
17117
17181
|
personaInstructions,
|
|
17118
17182
|
`You are in an isolated git worktree on ${this.options.featureBranch}, targeting ${this.options.targetBranch}.`,
|
|
17119
17183
|
"Work normally with the full coding tools. Commit and push only this feature branch. Use gh to open its pull request.",
|
|
17184
|
+
`This corner is shared: any of its member agents may be addressed in it and work on ${this.options.featureBranch}. Run git pull --rebase origin ${this.options.featureBranch} before you push, and never force-push it.`,
|
|
17120
17185
|
"PR-opening turn rule: as soon as a pull request exists, print its full GitHub URL as your final response and end the turn immediately. Do not call pr_checks_status in that same turn and do not wait for checks inside it. Then stay idle until a later corner fact or human message starts another turn.",
|
|
17121
17186
|
'Never merge because local tests pass or because gh reports passing checks. On a later turn triggered by a server-posted checks-passed note, call beeline-agent pr_checks_status. Merge only when it returns checks="passed", held=false, and approvalPending=false.',
|
|
17122
17187
|
"Merge the PR yourself only after the checks-passed event shows every check green; if any check failed or is still running, say exactly which and stop - never merge red.",
|
|
@@ -17216,6 +17281,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
17216
17281
|
...this.memberNames.get(requestedById) ? { name: this.memberNames.get(requestedById) } : {}
|
|
17217
17282
|
} : void 0;
|
|
17218
17283
|
this.currentTurn = { requestId, ...requester ? { requester } : {} };
|
|
17284
|
+
this.carrier = this.agent.publicKey;
|
|
17219
17285
|
const trace = this.beginTurnTrace(requestId);
|
|
17220
17286
|
try {
|
|
17221
17287
|
await withTurnReceiptHeartbeat(api, {
|
|
@@ -17232,6 +17298,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
17232
17298
|
if (this.forcedStop)
|
|
17233
17299
|
throw new Error("corner turn stopped for daemon handoff");
|
|
17234
17300
|
this.busy = true;
|
|
17301
|
+
await this.syncBranch();
|
|
17235
17302
|
const [conversation, roster, delivered] = await trace.measure("context-fetch", () => Promise.all([
|
|
17236
17303
|
api.execute("getRoomConversation", { roomId: cornerId, limit: 200 }),
|
|
17237
17304
|
this.roster(),
|
|
@@ -17355,6 +17422,63 @@ ${trigger}`,
|
|
|
17355
17422
|
this.currentTurn = void 0;
|
|
17356
17423
|
}
|
|
17357
17424
|
}
|
|
17425
|
+
/** Whether this agent opened the corner. A corner with no recorded opener
|
|
17426
|
+
* behaves exactly as it did before members could carry it. */
|
|
17427
|
+
isOpener() {
|
|
17428
|
+
return !this.options.openedBy || this.options.openedBy === this.agent.publicKey;
|
|
17429
|
+
}
|
|
17430
|
+
/**
|
|
17431
|
+
* Whether this agent is the one carrying the corner right now.
|
|
17432
|
+
*
|
|
17433
|
+
* Every member agent polls the corner, but its lifecycle — a server check
|
|
17434
|
+
* note, a close request answered with work — is ONE fact and must start ONE
|
|
17435
|
+
* turn, not one per member (the "one check turn per changed server state"
|
|
17436
|
+
* rule). The carrier is whoever answered in the corner last, which is the
|
|
17437
|
+
* opener until a human hands the work to someone else.
|
|
17438
|
+
*/
|
|
17439
|
+
carriesCorner() {
|
|
17440
|
+
return (this.carrier ?? this.options.openedBy ?? this.agent.publicKey) === this.agent.publicKey;
|
|
17441
|
+
}
|
|
17442
|
+
/** Notes an agent's durable message as the corner changing hands. */
|
|
17443
|
+
noteCarrier(authorId) {
|
|
17444
|
+
if (this.agentMembers.has(authorId))
|
|
17445
|
+
this.carrier = authorId;
|
|
17446
|
+
}
|
|
17447
|
+
/**
|
|
17448
|
+
* Whether a human message in this corner is addressed to THIS agent.
|
|
17449
|
+
*
|
|
17450
|
+
* A corner now runs like a Room — every member agent polls it — so an
|
|
17451
|
+
* unrouted message would start one turn per member on one branch. A mention
|
|
17452
|
+
* routes: the mentioned agent answers and nobody else. A message that names
|
|
17453
|
+
* no agent at all keeps the old behaviour and falls to the opener, which is
|
|
17454
|
+
* every single-agent corner ever opened.
|
|
17455
|
+
*/
|
|
17456
|
+
async addressesThisAgent(item) {
|
|
17457
|
+
if (item.mentionIds.includes(this.agent.publicKey))
|
|
17458
|
+
return true;
|
|
17459
|
+
if (!item.mentionIds.length)
|
|
17460
|
+
return this.carriesCorner();
|
|
17461
|
+
await this.roster().catch(() => void 0);
|
|
17462
|
+
return item.mentionIds.some((id) => this.agentMembers.has(id)) ? false : this.carriesCorner();
|
|
17463
|
+
}
|
|
17464
|
+
/**
|
|
17465
|
+
* Bring this worktree onto the corner's branch as GitHub currently has it,
|
|
17466
|
+
* before any work is done on top of it.
|
|
17467
|
+
*
|
|
17468
|
+
* The branch is the shared artifact: another member agent may have pushed to
|
|
17469
|
+
* it since this helper last looked, and a first touch of a corner this
|
|
17470
|
+
* helper did not open starts from whatever `room-runtime.ts` restored. A
|
|
17471
|
+
* divergence this cannot rebase away is raised, not pushed over — the turn
|
|
17472
|
+
* fails with that sentence and the server inscribes it in the corner.
|
|
17473
|
+
*/
|
|
17474
|
+
async syncBranch() {
|
|
17475
|
+
const token = await this.options.api.execute("getRoomGitHubToken", { roomId: this.options.parentRoomId }).then((granted) => granted.token).catch(() => this.options.githubToken);
|
|
17476
|
+
await syncCornerBranch({
|
|
17477
|
+
worktreePath: this.options.worktreePath,
|
|
17478
|
+
featureBranch: this.options.featureBranch,
|
|
17479
|
+
env: { ...process.env, GH_TOKEN: token, GITHUB_TOKEN: token, GIT_TERMINAL_PROMPT: "0" }
|
|
17480
|
+
});
|
|
17481
|
+
}
|
|
17358
17482
|
/** The server's check state for this head, or the notes' own verdict when the server carries none. */
|
|
17359
17483
|
async checksState(notes) {
|
|
17360
17484
|
try {
|
|
@@ -17373,8 +17497,12 @@ ${trigger}`,
|
|
|
17373
17497
|
const { api, cornerId, signal } = this.options;
|
|
17374
17498
|
let cursor3 = (await api.execute("getRoomInbox", { roomId: cornerId, startAtLatest: true })).cursor;
|
|
17375
17499
|
const history = await api.execute("getRoomConversation", { roomId: cornerId, limit: 200 });
|
|
17500
|
+
await this.roster().catch(() => void 0);
|
|
17501
|
+
for (const item of history.items)
|
|
17502
|
+
if (item.type === "message")
|
|
17503
|
+
this.noteCarrier(item.authorId);
|
|
17376
17504
|
const durableAgentReplies = history.items.filter((item) => item.type === "message" && item.authorId === this.agent.publicKey && item.body.trim() !== this.options.objective.trim());
|
|
17377
|
-
if (durableAgentReplies.length === 0) {
|
|
17505
|
+
if (durableAgentReplies.length === 0 && this.isOpener()) {
|
|
17378
17506
|
await this.prompt(history.items.find((item) => item.requestId)?.requestId ?? cornerId.replaceAll("-", ""), this.options.objective);
|
|
17379
17507
|
}
|
|
17380
17508
|
try {
|
|
@@ -17392,8 +17520,11 @@ ${trigger}`,
|
|
|
17392
17520
|
const checkNotes = [];
|
|
17393
17521
|
for (const item of inbox.items) {
|
|
17394
17522
|
if (item.type === "message") {
|
|
17523
|
+
this.noteCarrier(item.authorId);
|
|
17395
17524
|
if (item.authorId === this.agent.publicKey)
|
|
17396
17525
|
continue;
|
|
17526
|
+
if (!await this.addressesThisAgent(item))
|
|
17527
|
+
continue;
|
|
17397
17528
|
const authority = await api.execute("getRoomAuthority", {
|
|
17398
17529
|
roomId: cornerId,
|
|
17399
17530
|
principalId: item.authorId
|
|
@@ -17418,7 +17549,7 @@ This answers your grant request; resume the paused work. If approved and it is a
|
|
|
17418
17549
|
if (completedCheckNote(item))
|
|
17419
17550
|
checkNotes.push(item);
|
|
17420
17551
|
}
|
|
17421
|
-
if (checkNotes.length) {
|
|
17552
|
+
if (checkNotes.length && this.carriesCorner()) {
|
|
17422
17553
|
const state = await this.checksState(checkNotes);
|
|
17423
17554
|
if (state && state !== "pending" && state !== this.lastChecksState) {
|
|
17424
17555
|
this.lastChecksState = state;
|
|
@@ -17494,7 +17625,13 @@ function isRoomMcpPermissionRequest(request, mountedServers = ROOM_MOUNTED_MCP_S
|
|
|
17494
17625
|
return isMountedMcpToolPermissionRequest(request, mountedServers);
|
|
17495
17626
|
}
|
|
17496
17627
|
function roomPrincipalMayAddressAgent(authority, humanPermitted) {
|
|
17497
|
-
|
|
17628
|
+
if (!authority.member)
|
|
17629
|
+
return false;
|
|
17630
|
+
if (authority.principalKind === "agent")
|
|
17631
|
+
return true;
|
|
17632
|
+
if (authority.principalKind !== "human")
|
|
17633
|
+
return false;
|
|
17634
|
+
return authority.mayAddressAgent ?? humanPermitted;
|
|
17498
17635
|
}
|
|
17499
17636
|
function isScheduledPrompt(item, agentId) {
|
|
17500
17637
|
if (item.type !== "system" || !item.mentionIds.includes(agentId))
|
|
@@ -17541,6 +17678,27 @@ function pendingGrantToolCall(call) {
|
|
|
17541
17678
|
return false;
|
|
17542
17679
|
return /pending, card posted/i.test(typeof call.content === "string" ? call.content : JSON.stringify(call.content ?? ""));
|
|
17543
17680
|
}
|
|
17681
|
+
function roomMentionDirectory(roster, selfId) {
|
|
17682
|
+
const rows = [];
|
|
17683
|
+
for (const member of roster.members) {
|
|
17684
|
+
if (member.identityId === selfId)
|
|
17685
|
+
continue;
|
|
17686
|
+
const handle = member.handle?.trim().replace(/^@/, "");
|
|
17687
|
+
const name = member.name?.trim() ?? "";
|
|
17688
|
+
const alias = handle || name;
|
|
17689
|
+
if (!alias)
|
|
17690
|
+
continue;
|
|
17691
|
+
const kind = member.kind === "agent" ? "agent" : "person";
|
|
17692
|
+
rows.push(`- @${alias}${name && name !== alias ? ` \u2014 ${name}` : ""} (${kind})`);
|
|
17693
|
+
}
|
|
17694
|
+
if (!rows.length)
|
|
17695
|
+
return "";
|
|
17696
|
+
return [
|
|
17697
|
+
"Room members, and the exact spelling that tags each one:",
|
|
17698
|
+
...rows,
|
|
17699
|
+
"Write a tag exactly as spelled here. An @name spelled any other way is plain text: it reaches nobody, and nobody is told it was meant for them. Never invent a handle, shorten one, or copy an @name out of the conversation \u2014 old messages carry spellings that no longer exist."
|
|
17700
|
+
].join("\n");
|
|
17701
|
+
}
|
|
17544
17702
|
function escapeRegExp(value) {
|
|
17545
17703
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17546
17704
|
}
|
|
@@ -18051,6 +18209,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
18051
18209
|
"If it was approved and it is a command grant, run it with run_granted_command and the exact argv.",
|
|
18052
18210
|
"If it was declined, try another way or say plainly what you cannot do."
|
|
18053
18211
|
].join(" ") : "",
|
|
18212
|
+
roomMentionDirectory(roster, this.agent.publicKey),
|
|
18054
18213
|
[
|
|
18055
18214
|
"Write only the substantive Room message you want the human to read.",
|
|
18056
18215
|
"Do not repeat or paraphrase these instructions.",
|
|
@@ -18675,8 +18834,77 @@ var ROOM_JOIN_CONCURRENCY = 4;
|
|
|
18675
18834
|
var DEFAULT_ROOM_WATCHDOG_STALE_MS = 9e4;
|
|
18676
18835
|
var DEFAULT_RECONCILE_HEARTBEAT_MS = 6e4;
|
|
18677
18836
|
var DEFAULT_DRAIN_DEADLINE_MS = 30 * 6e4;
|
|
18678
|
-
function shouldPostInitialCornerWorkingState(restore) {
|
|
18679
|
-
return !restore.featureBranch && !restore.lifecycle?.branch && !restore.lifecycle?.pr;
|
|
18837
|
+
function shouldPostInitialCornerWorkingState(restore, isOpener = true) {
|
|
18838
|
+
return isOpener && !restore.featureBranch && !restore.lifecycle?.branch && !restore.lifecycle?.pr;
|
|
18839
|
+
}
|
|
18840
|
+
async function materializeCornerWorktree(input) {
|
|
18841
|
+
const remote = roomCheckoutRemote(input.remote);
|
|
18842
|
+
const repositoryHash = createHash4("sha256").update(remote).digest("hex").slice(0, 24);
|
|
18843
|
+
const gitCommonDir = resolve19(input.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
|
|
18844
|
+
const path = resolve19(input.supervisorRoot, "beeline", "corners", input.cornerId);
|
|
18845
|
+
await mkdir11(dirname6(gitCommonDir), { recursive: true, mode: 448 });
|
|
18846
|
+
await mkdir11(dirname6(path), { recursive: true, mode: 448 });
|
|
18847
|
+
const authEnv = githubGitEnv(input.token);
|
|
18848
|
+
if (!existsSync4(resolve19(gitCommonDir, "HEAD"))) {
|
|
18849
|
+
await execFileAsync4("git", ["clone", "--bare", remote, gitCommonDir], {
|
|
18850
|
+
env: authEnv,
|
|
18851
|
+
maxBuffer: 4 * 1024 * 1024
|
|
18852
|
+
});
|
|
18853
|
+
}
|
|
18854
|
+
await execFileAsync4("git", [
|
|
18855
|
+
`--git-dir=${gitCommonDir}`,
|
|
18856
|
+
"fetch",
|
|
18857
|
+
"--prune",
|
|
18858
|
+
"origin",
|
|
18859
|
+
`+refs/heads/${input.targetBranch}:refs/remotes/origin/${input.targetBranch}`
|
|
18860
|
+
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
|
|
18861
|
+
const restored = await execFileAsync4("git", [
|
|
18862
|
+
`--git-dir=${gitCommonDir}`,
|
|
18863
|
+
"fetch",
|
|
18864
|
+
"origin",
|
|
18865
|
+
`+refs/heads/${input.featureBranch}:refs/remotes/origin/${input.featureBranch}`
|
|
18866
|
+
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 }).then(() => true, () => false);
|
|
18867
|
+
if (!existsSync4(resolve19(path, ".git"))) {
|
|
18868
|
+
await rm4(path, { recursive: true, force: true });
|
|
18869
|
+
await execFileAsync4("git", [
|
|
18870
|
+
`--git-dir=${gitCommonDir}`,
|
|
18871
|
+
"worktree",
|
|
18872
|
+
"add",
|
|
18873
|
+
"-B",
|
|
18874
|
+
input.featureBranch,
|
|
18875
|
+
path,
|
|
18876
|
+
restored ? `refs/remotes/origin/${input.featureBranch}` : `refs/remotes/origin/${input.targetBranch}`
|
|
18877
|
+
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
|
|
18878
|
+
}
|
|
18879
|
+
await execFileAsync4("git", [
|
|
18880
|
+
`--git-dir=${gitCommonDir}`,
|
|
18881
|
+
"config",
|
|
18882
|
+
"extensions.worktreeConfig",
|
|
18883
|
+
"true"
|
|
18884
|
+
]);
|
|
18885
|
+
await execFileAsync4("git", ["-C", path, "config", "--worktree", "core.bare", "false"]);
|
|
18886
|
+
await execFileAsync4("git", [
|
|
18887
|
+
"-C",
|
|
18888
|
+
path,
|
|
18889
|
+
"config",
|
|
18890
|
+
"--worktree",
|
|
18891
|
+
"credential.https://github.com.helper",
|
|
18892
|
+
"!f() { echo username=x-access-token; echo password=$GH_TOKEN; }; f"
|
|
18893
|
+
]);
|
|
18894
|
+
await execFileAsync4("git", ["-C", path, "config", "--worktree", "user.name", input.committer.name]);
|
|
18895
|
+
await execFileAsync4("git", [
|
|
18896
|
+
"-C",
|
|
18897
|
+
path,
|
|
18898
|
+
"config",
|
|
18899
|
+
"--worktree",
|
|
18900
|
+
"user.email",
|
|
18901
|
+
`${input.committer.publicKey.slice(0, 16)}@users.noreply.github.com`
|
|
18902
|
+
]);
|
|
18903
|
+
const top = await execFileAsync4("git", ["-C", path, "rev-parse", "--show-toplevel"]);
|
|
18904
|
+
if (resolve19(top.stdout.trim()) !== resolve19(path)) {
|
|
18905
|
+
throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
|
|
18906
|
+
}
|
|
18907
|
+
return { path, gitCommonDir };
|
|
18680
18908
|
}
|
|
18681
18909
|
function reconcileRetryMs(error, pollMs) {
|
|
18682
18910
|
const match = String(error).match(/retry in\s+(\d+)s/i);
|
|
@@ -18691,7 +18919,7 @@ async function mapWithConcurrency(values, limit, visit) {
|
|
|
18691
18919
|
}
|
|
18692
18920
|
}));
|
|
18693
18921
|
}
|
|
18694
|
-
var
|
|
18922
|
+
var execFileAsync4 = promisify4(execFile5);
|
|
18695
18923
|
var RoomRuntimeCoordinator = class {
|
|
18696
18924
|
configPath;
|
|
18697
18925
|
baseConfig;
|
|
@@ -18699,6 +18927,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
18699
18927
|
runtime;
|
|
18700
18928
|
running = /* @__PURE__ */ new Map();
|
|
18701
18929
|
startingCorners = /* @__PURE__ */ new Set();
|
|
18930
|
+
/** Corners whose start failure has already been said out loud, once each. */
|
|
18931
|
+
reportedCornerStartFailures = /* @__PURE__ */ new Set();
|
|
18702
18932
|
scheduler;
|
|
18703
18933
|
agent;
|
|
18704
18934
|
/** Parent ownership retained so a failed corner listing never authorizes removal. */
|
|
@@ -18824,7 +19054,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
18824
19054
|
desired.add(corner.cornerId);
|
|
18825
19055
|
desiredCorners.set(corner.cornerId, {
|
|
18826
19056
|
cornerId: corner.cornerId,
|
|
18827
|
-
parentRoomId: room.roomId
|
|
19057
|
+
parentRoomId: room.roomId,
|
|
19058
|
+
...corner.createdBy ? { openedBy: corner.createdBy } : {}
|
|
18828
19059
|
});
|
|
18829
19060
|
}
|
|
18830
19061
|
}
|
|
@@ -18966,12 +19197,12 @@ var RoomRuntimeCoordinator = class {
|
|
|
18966
19197
|
const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
|
|
18967
19198
|
const env = token ? githubGitEnv(token.token) : process.env;
|
|
18968
19199
|
if (!existsSync4(resolve19(path, ".git"))) {
|
|
18969
|
-
await
|
|
19200
|
+
await execFileAsync4("git", ["clone", "--no-checkout", remote, path], {
|
|
18970
19201
|
env,
|
|
18971
19202
|
maxBuffer: 4 * 1024 * 1024
|
|
18972
19203
|
});
|
|
18973
19204
|
}
|
|
18974
|
-
await
|
|
19205
|
+
await execFileAsync4("git", [
|
|
18975
19206
|
"-C",
|
|
18976
19207
|
path,
|
|
18977
19208
|
"fetch",
|
|
@@ -18979,7 +19210,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
18979
19210
|
"origin",
|
|
18980
19211
|
`+refs/heads/${targetBranch}:refs/remotes/origin/${targetBranch}`
|
|
18981
19212
|
], { env, maxBuffer: 4 * 1024 * 1024 });
|
|
18982
|
-
await
|
|
19213
|
+
await execFileAsync4("git", ["-C", path, "checkout", "--detach", "--force", `origin/${targetBranch}`], {
|
|
18983
19214
|
env,
|
|
18984
19215
|
maxBuffer: 4 * 1024 * 1024
|
|
18985
19216
|
});
|
|
@@ -19022,7 +19253,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
19022
19253
|
featureBranch,
|
|
19023
19254
|
token: granted.token
|
|
19024
19255
|
});
|
|
19025
|
-
|
|
19256
|
+
const isOpener = !corner.openedBy || corner.openedBy === this.agent.publicKey;
|
|
19257
|
+
if (shouldPostInitialCornerWorkingState(restore, isOpener)) {
|
|
19026
19258
|
await this.options.daemonApi.execute("postCornerRemoteState", {
|
|
19027
19259
|
cornerId: corner.cornerId,
|
|
19028
19260
|
branch: featureBranch,
|
|
@@ -19039,6 +19271,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
19039
19271
|
...grantRunnerEndpoint ? { grantRunnerEndpoint } : {},
|
|
19040
19272
|
parentRoomId: corner.parentRoomId,
|
|
19041
19273
|
workspaceId: this.runtime.communityId,
|
|
19274
|
+
...corner.openedBy ? { openedBy: corner.openedBy } : {},
|
|
19042
19275
|
objective,
|
|
19043
19276
|
featureBranch,
|
|
19044
19277
|
targetBranch,
|
|
@@ -19080,79 +19313,60 @@ var RoomRuntimeCoordinator = class {
|
|
|
19080
19313
|
branch: featureBranch
|
|
19081
19314
|
}
|
|
19082
19315
|
});
|
|
19316
|
+
this.reportedCornerStartFailures.delete(corner.cornerId);
|
|
19083
19317
|
console.log(`[thin-core] serving corner ${corner.cornerId} on ${featureBranch} at ${worktree.path}`);
|
|
19084
19318
|
} catch (error) {
|
|
19085
19319
|
console.error(`[thin-core] failed to start corner ${corner.cornerId}:`, error);
|
|
19320
|
+
await this.reportCornerStartFailure(corner.cornerId, error);
|
|
19086
19321
|
} finally {
|
|
19087
19322
|
this.startingCorners.delete(corner.cornerId);
|
|
19088
19323
|
}
|
|
19089
19324
|
}
|
|
19090
|
-
|
|
19091
|
-
|
|
19092
|
-
|
|
19093
|
-
|
|
19094
|
-
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
|
|
19098
|
-
|
|
19099
|
-
|
|
19100
|
-
|
|
19101
|
-
|
|
19325
|
+
/**
|
|
19326
|
+
* An agent addressed in a corner it then could not restore must not be
|
|
19327
|
+
* silent about it.
|
|
19328
|
+
*
|
|
19329
|
+
* The corner never starts, so no turn ever runs and nothing else in the
|
|
19330
|
+
* daemon has a Room to say it in. This posts a FAILED receipt against the
|
|
19331
|
+
* message that asked, which the server inscribes as `<agent> could not
|
|
19332
|
+
* answer · <reason>` in the corner itself. Once per corner per process: the
|
|
19333
|
+
* reconciliation heartbeat retries the start for as long as it keeps
|
|
19334
|
+
* failing, and the fact is worth saying once, not once a minute.
|
|
19335
|
+
*/
|
|
19336
|
+
async reportCornerStartFailure(cornerId, error) {
|
|
19337
|
+
if (this.reportedCornerStartFailures.has(cornerId))
|
|
19338
|
+
return;
|
|
19339
|
+
this.reportedCornerStartFailures.add(cornerId);
|
|
19340
|
+
try {
|
|
19341
|
+
const conversation = await this.options.daemonApi.execute("getRoomConversation", {
|
|
19342
|
+
roomId: cornerId,
|
|
19343
|
+
limit: 50
|
|
19102
19344
|
});
|
|
19345
|
+
const asked = [...conversation.items].reverse().find((item) => item.type === "message" && item.mentionIds.includes(this.agent.publicKey));
|
|
19346
|
+
if (!asked)
|
|
19347
|
+
return;
|
|
19348
|
+
await this.options.daemonApi.execute("postAgentTurnReceipt", {
|
|
19349
|
+
agentId: this.agent.publicKey,
|
|
19350
|
+
roomId: cornerId,
|
|
19351
|
+
requestId: asked.id,
|
|
19352
|
+
status: "failed",
|
|
19353
|
+
generationId: `${this.agent.publicKey}:${cornerId}`,
|
|
19354
|
+
reason: distillTurnFailureReason(error)
|
|
19355
|
+
});
|
|
19356
|
+
} catch (reportError) {
|
|
19357
|
+
console.error(`[thin-core] corner ${cornerId} start-failure report failed:`, reportError);
|
|
19103
19358
|
}
|
|
19104
|
-
|
|
19105
|
-
|
|
19106
|
-
|
|
19107
|
-
|
|
19108
|
-
|
|
19109
|
-
|
|
19110
|
-
|
|
19111
|
-
if (!existsSync4(resolve19(path, ".git"))) {
|
|
19112
|
-
await rm4(path, { recursive: true, force: true });
|
|
19113
|
-
await execFileAsync3("git", [
|
|
19114
|
-
`--git-dir=${gitCommonDir}`,
|
|
19115
|
-
"worktree",
|
|
19116
|
-
"add",
|
|
19117
|
-
"-B",
|
|
19118
|
-
input.featureBranch,
|
|
19119
|
-
path,
|
|
19120
|
-
`refs/remotes/origin/${input.targetBranch}`
|
|
19121
|
-
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
|
|
19122
|
-
}
|
|
19123
|
-
await execFileAsync3("git", [
|
|
19124
|
-
`--git-dir=${gitCommonDir}`,
|
|
19125
|
-
"config",
|
|
19126
|
-
"extensions.worktreeConfig",
|
|
19127
|
-
"true"
|
|
19128
|
-
]);
|
|
19129
|
-
await execFileAsync3("git", ["-C", path, "config", "--worktree", "core.bare", "false"]);
|
|
19130
|
-
await execFileAsync3("git", [
|
|
19131
|
-
"-C",
|
|
19132
|
-
path,
|
|
19133
|
-
"config",
|
|
19134
|
-
"--worktree",
|
|
19135
|
-
"credential.https://github.com.helper",
|
|
19136
|
-
"!f() { echo username=x-access-token; echo password=$GH_TOKEN; }; f"
|
|
19137
|
-
]);
|
|
19138
|
-
await execFileAsync3("git", ["-C", path, "config", "--worktree", "user.name", this.agent.name]);
|
|
19139
|
-
await execFileAsync3("git", [
|
|
19140
|
-
"-C",
|
|
19141
|
-
path,
|
|
19142
|
-
"config",
|
|
19143
|
-
"--worktree",
|
|
19144
|
-
"user.email",
|
|
19145
|
-
`${this.agent.publicKey.slice(0, 16)}@users.noreply.github.com`
|
|
19146
|
-
]);
|
|
19147
|
-
const top = await execFileAsync3("git", ["-C", path, "rev-parse", "--show-toplevel"]);
|
|
19148
|
-
if (resolve19(top.stdout.trim()) !== resolve19(path)) {
|
|
19149
|
-
throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
|
|
19150
|
-
}
|
|
19151
|
-
return { path, gitCommonDir };
|
|
19359
|
+
}
|
|
19360
|
+
async materializeCornerWorktree(input) {
|
|
19361
|
+
return materializeCornerWorktree({
|
|
19362
|
+
...input,
|
|
19363
|
+
supervisorRoot: this.runtime.supervisorRoot,
|
|
19364
|
+
committer: { name: this.agent.name, publicKey: this.agent.publicKey }
|
|
19365
|
+
});
|
|
19152
19366
|
}
|
|
19153
19367
|
async reapCornerWorktree(worktree) {
|
|
19154
19368
|
if (existsSync4(worktree.path)) {
|
|
19155
|
-
await
|
|
19369
|
+
await execFileAsync4("git", [
|
|
19156
19370
|
`--git-dir=${worktree.gitCommonDir}`,
|
|
19157
19371
|
"worktree",
|
|
19158
19372
|
"remove",
|
|
@@ -19322,13 +19536,13 @@ var ThinDaemonCore = class {
|
|
|
19322
19536
|
};
|
|
19323
19537
|
|
|
19324
19538
|
// apps/body/dist/systemd.js
|
|
19325
|
-
import { execFile as
|
|
19539
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
19326
19540
|
import { mkdir as mkdir12, readFile as readFile8, writeFile as writeFile8 } from "node:fs/promises";
|
|
19327
19541
|
import { homedir as homedir8 } from "node:os";
|
|
19328
19542
|
import { dirname as dirname7, resolve as resolve20 } from "node:path";
|
|
19329
19543
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
19330
|
-
import { promisify as
|
|
19331
|
-
var
|
|
19544
|
+
import { promisify as promisify5 } from "node:util";
|
|
19545
|
+
var execFileAsync5 = promisify5(execFile6);
|
|
19332
19546
|
var DELIBERATE_REMOVAL_EXIT_STATUS = 78;
|
|
19333
19547
|
var DAEMON_DISTRESS_EXIT_STATUS = 77;
|
|
19334
19548
|
var UNKNOWN_AGENT_EXIT_STATUS = 79;
|
|
@@ -19381,7 +19595,7 @@ function systemdUserUnitPath(env = process.env) {
|
|
|
19381
19595
|
return resolve20(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
|
|
19382
19596
|
}
|
|
19383
19597
|
var runSystemctl = async (args) => {
|
|
19384
|
-
const result = await
|
|
19598
|
+
const result = await execFileAsync5("systemctl", ["--user", ...args], {
|
|
19385
19599
|
timeout: SYSTEMD_COMMAND_TIMEOUT_MS,
|
|
19386
19600
|
encoding: "utf8"
|
|
19387
19601
|
});
|
|
@@ -19447,7 +19661,7 @@ async function disableAgentService(publicKey, options = {}) {
|
|
|
19447
19661
|
async function notify(fields) {
|
|
19448
19662
|
if (process.env.BEELINE_MANAGED_BY_SYSTEMD !== "1")
|
|
19449
19663
|
return;
|
|
19450
|
-
await
|
|
19664
|
+
await execFileAsync5("systemd-notify", fields, { timeout: SYSTEMD_COMMAND_TIMEOUT_MS });
|
|
19451
19665
|
}
|
|
19452
19666
|
async function extendSystemdStartTimeout(ms) {
|
|
19453
19667
|
await notify([`EXTEND_TIMEOUT_USEC=${Math.max(0, Math.round(ms)) * 1e3}`]).catch(() => void 0);
|
|
@@ -20408,8 +20622,10 @@ import { mkdir as mkdir16, rm as rm6, stat as stat2, writeFile as writeFile12 }
|
|
|
20408
20622
|
import { dirname as dirname12, resolve as resolve24 } from "node:path";
|
|
20409
20623
|
|
|
20410
20624
|
// apps/body/dist/update-rollback-alert.js
|
|
20411
|
-
import { mkdir as mkdir15, readFile as readFile11, rename as rename4, writeFile as writeFile11 } from "node:fs/promises";
|
|
20625
|
+
import { mkdir as mkdir15, readFile as readFile11, rename as rename4, unlink as unlink3, writeFile as writeFile11 } from "node:fs/promises";
|
|
20412
20626
|
import { dirname as dirname11, resolve as resolve23 } from "node:path";
|
|
20627
|
+
var REPORT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
20628
|
+
var lastLogged = /* @__PURE__ */ new Map();
|
|
20413
20629
|
function updateRollbackAlertPath(runtimeDir) {
|
|
20414
20630
|
return resolve23(runtimeDir, "update-rollback-alert.json");
|
|
20415
20631
|
}
|
|
@@ -20437,11 +20653,37 @@ async function readUpdateRollbackAlert(runtimeDir) {
|
|
|
20437
20653
|
return void 0;
|
|
20438
20654
|
}
|
|
20439
20655
|
}
|
|
20656
|
+
async function clearUpdateRollbackAlert(runtimeDir) {
|
|
20657
|
+
const existing = await readUpdateRollbackAlert(runtimeDir);
|
|
20658
|
+
if (!existing)
|
|
20659
|
+
return false;
|
|
20660
|
+
await unlink3(updateRollbackAlertPath(runtimeDir)).catch(() => void 0);
|
|
20661
|
+
lastLogged.delete(runtimeDir);
|
|
20662
|
+
return true;
|
|
20663
|
+
}
|
|
20664
|
+
async function clearUpdateRollbackAlertIfConfirmed(runtimeDir, loadedRelease) {
|
|
20665
|
+
if (!loadedRelease)
|
|
20666
|
+
return false;
|
|
20667
|
+
const existing = await readUpdateRollbackAlert(runtimeDir);
|
|
20668
|
+
if (!existing || existing.releaseId !== loadedRelease)
|
|
20669
|
+
return false;
|
|
20670
|
+
await unlink3(updateRollbackAlertPath(runtimeDir)).catch(() => void 0);
|
|
20671
|
+
lastLogged.delete(runtimeDir);
|
|
20672
|
+
return true;
|
|
20673
|
+
}
|
|
20440
20674
|
async function reportUpdateRollback(input) {
|
|
20441
20675
|
const pending = await readUpdateRollbackAlert(input.runtimeDir);
|
|
20442
|
-
if (!pending)
|
|
20676
|
+
if (!pending) {
|
|
20677
|
+
lastLogged.delete(input.runtimeDir);
|
|
20443
20678
|
return false;
|
|
20679
|
+
}
|
|
20680
|
+
const now2 = input.now ?? Date.now();
|
|
20681
|
+
const last = lastLogged.get(input.runtimeDir);
|
|
20682
|
+
if (last && last.releaseId === pending.releaseId && now2 - last.loggedAt < REPORT_INTERVAL_MS) {
|
|
20683
|
+
return false;
|
|
20684
|
+
}
|
|
20444
20685
|
console.error(`[thin-core] UPDATE ROLLBACK: ${pending.releaseId}; durable operator record: ` + updateRollbackAlertPath(input.runtimeDir));
|
|
20686
|
+
lastLogged.set(input.runtimeDir, { releaseId: pending.releaseId, loggedAt: now2 });
|
|
20445
20687
|
return true;
|
|
20446
20688
|
}
|
|
20447
20689
|
|
|
@@ -21146,6 +21388,7 @@ import { resolve as resolve26 } from "node:path";
|
|
|
21146
21388
|
var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
|
|
21147
21389
|
var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
|
|
21148
21390
|
var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
|
|
21391
|
+
var UPDATE_PROBE_RETRY_DELAY_MS = 2e3;
|
|
21149
21392
|
var ACP_ERROR_CODE = /\bACP error (-\d+):/;
|
|
21150
21393
|
var ACP_PROMPT_INACTIVITY = /\bACP session\/prompt timed out after \d+ms of inactivity\b/;
|
|
21151
21394
|
function isServerInternalCode(code) {
|
|
@@ -21269,8 +21512,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21269
21512
|
});
|
|
21270
21513
|
const sessionTimeoutMs = input.sessionTimeoutMs ?? UPDATE_PROBE_SESSION_TIMEOUT_MS;
|
|
21271
21514
|
const sessionOpenTimeoutMs = input.sessionOpenTimeoutMs ?? input.sessionTimeoutMs ?? UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS;
|
|
21272
|
-
|
|
21273
|
-
await client.start(sessionTimeoutMs);
|
|
21515
|
+
const openSessionAndPrompt = async () => {
|
|
21274
21516
|
const opened = await client.sessionNew({
|
|
21275
21517
|
cwd,
|
|
21276
21518
|
mcpServers: [],
|
|
@@ -21281,15 +21523,22 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21281
21523
|
if (input.config.modelSelection) {
|
|
21282
21524
|
await applyAgentModelSelection(client, opened.sessionId, parseAdvertisedConfigOptions(opened.raw, input.config.modelSelection.model, isGrokAgentCommand(selectedAgent)), input.config.modelSelection);
|
|
21283
21525
|
}
|
|
21526
|
+
return {
|
|
21527
|
+
sessionId: opened.sessionId,
|
|
21528
|
+
served: await client.sessionPrompt(opened.sessionId, "Reply READY.", input.turnTimeoutMs ?? UPDATE_PROBE_TURN_TIMEOUT_MS)
|
|
21529
|
+
};
|
|
21530
|
+
};
|
|
21531
|
+
try {
|
|
21532
|
+
await client.start(sessionTimeoutMs);
|
|
21284
21533
|
try {
|
|
21285
|
-
const
|
|
21534
|
+
const { sessionId, served } = await openSessionAndPrompt();
|
|
21286
21535
|
if (served.agentText.trim()) {
|
|
21287
21536
|
modelAnswer = { modelAnswer: "served" };
|
|
21288
21537
|
} else {
|
|
21289
21538
|
const explained = await explainEmptyAgentTurn({
|
|
21290
21539
|
agentLabel: command,
|
|
21291
21540
|
agentEnv,
|
|
21292
|
-
sessionId
|
|
21541
|
+
sessionId,
|
|
21293
21542
|
result: served
|
|
21294
21543
|
});
|
|
21295
21544
|
const modelSide = isAccountOrProviderRefusal(explained.record) || explained.record?.kind === "empty";
|
|
@@ -21317,29 +21566,55 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21317
21566
|
modelAnswer = { modelAnswer: "unavailable", modelAnswerReason: explained.reason };
|
|
21318
21567
|
}
|
|
21319
21568
|
}
|
|
21320
|
-
} catch (
|
|
21321
|
-
if (
|
|
21322
|
-
throw
|
|
21323
|
-
|
|
21324
|
-
|
|
21325
|
-
|
|
21326
|
-
|
|
21569
|
+
} catch (initialError) {
|
|
21570
|
+
if (initialError instanceof UpdateFunctionalProbeError)
|
|
21571
|
+
throw initialError;
|
|
21572
|
+
let error = initialError;
|
|
21573
|
+
let detail = error instanceof Error ? error.message : String(error);
|
|
21574
|
+
let failure = classifyAcpTurnFailure(error);
|
|
21575
|
+
if (failure) {
|
|
21576
|
+
await new Promise((resolveWait) => setTimeout(resolveWait, input.retryDelayMs ?? UPDATE_PROBE_RETRY_DELAY_MS));
|
|
21577
|
+
try {
|
|
21578
|
+
const retried = await openSessionAndPrompt();
|
|
21579
|
+
if (retried.served.agentText.trim()) {
|
|
21580
|
+
turnCompleted = true;
|
|
21581
|
+
modelAnswer = { modelAnswer: "served" };
|
|
21582
|
+
console.warn(`[body] update probe: the probe turn failed once (${detail}) but a fresh retry answered; treating the first failure as the provider's, not this bundle's`);
|
|
21583
|
+
error = void 0;
|
|
21584
|
+
}
|
|
21585
|
+
} catch (retryError) {
|
|
21586
|
+
const retryDetail = retryError instanceof Error ? retryError.message : String(retryError);
|
|
21587
|
+
const retryFailure = classifyAcpTurnFailure(retryError);
|
|
21588
|
+
if (!retryFailure || !sameAcpTurnFailure(failure, retryFailure)) {
|
|
21589
|
+
throw new UpdateFunctionalProbeError("turn-failed", retryDetail, {
|
|
21590
|
+
cause: retryError
|
|
21591
|
+
});
|
|
21592
|
+
}
|
|
21593
|
+
error = retryError;
|
|
21594
|
+
detail = retryDetail;
|
|
21595
|
+
failure = retryFailure;
|
|
21596
|
+
}
|
|
21327
21597
|
}
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
|
|
21598
|
+
if (error === void 0) {
|
|
21599
|
+
} else if (!failure || !input.compareWithCurrentRelease) {
|
|
21600
|
+
throw new UpdateFunctionalProbeError("turn-failed", detail, { cause: error });
|
|
21601
|
+
} else {
|
|
21602
|
+
const current = await input.compareWithCurrentRelease({
|
|
21603
|
+
kind: "acp-turn-failure",
|
|
21604
|
+
reason: detail,
|
|
21605
|
+
failure
|
|
21606
|
+
});
|
|
21607
|
+
const currentFailure = current.kind === "unavailable" ? classifyAcpTurnFailure(current.reason) : void 0;
|
|
21608
|
+
if (!currentFailure || !sameAcpTurnFailure(failure, currentFailure)) {
|
|
21609
|
+
throw new UpdateFunctionalProbeError("turn-failed", `${detail}; ${describeCurrentReleaseOutcome(current)}`, { cause: error });
|
|
21610
|
+
}
|
|
21611
|
+
console.warn(`[body] update probe: the probe turn failed the same way on this release and the current release (${detail}); that failure is not this bundle's doing, so the probe passes as inconclusive`);
|
|
21612
|
+
turnCompleted = false;
|
|
21613
|
+
modelAnswer = {
|
|
21614
|
+
modelAnswer: "unavailable",
|
|
21615
|
+
modelAnswerReason: `${detail} (the current release fails the same way)`
|
|
21616
|
+
};
|
|
21336
21617
|
}
|
|
21337
|
-
console.warn(`[body] update probe: the probe turn failed the same way on this release and the current release (${detail}); that failure is not this bundle's doing, so the probe passes as inconclusive`);
|
|
21338
|
-
turnCompleted = false;
|
|
21339
|
-
modelAnswer = {
|
|
21340
|
-
modelAnswer: "unavailable",
|
|
21341
|
-
modelAnswerReason: `${detail} (the current release fails the same way)`
|
|
21342
|
-
};
|
|
21343
21618
|
}
|
|
21344
21619
|
} catch (error) {
|
|
21345
21620
|
if (error instanceof UpdateFunctionalProbeError)
|
|
@@ -21403,7 +21678,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21403
21678
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
21404
21679
|
}
|
|
21405
21680
|
const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
|
|
21406
|
-
return new Promise((
|
|
21681
|
+
return new Promise((resolve30) => {
|
|
21407
21682
|
const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
21408
21683
|
let stdout6 = "";
|
|
21409
21684
|
let stderr = "";
|
|
@@ -21413,7 +21688,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21413
21688
|
return;
|
|
21414
21689
|
settled = true;
|
|
21415
21690
|
clearTimeout(timer);
|
|
21416
|
-
|
|
21691
|
+
resolve30(outcome);
|
|
21417
21692
|
};
|
|
21418
21693
|
const timer = setTimeout(() => {
|
|
21419
21694
|
child.kill("SIGKILL");
|
|
@@ -21518,6 +21793,90 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
21518
21793
|
return status;
|
|
21519
21794
|
}
|
|
21520
21795
|
|
|
21796
|
+
// apps/body/dist/scratch-sweep.js
|
|
21797
|
+
import { lstat as lstat3, readdir as readdir6, rmdir, unlink as unlink4 } from "node:fs/promises";
|
|
21798
|
+
import { resolve as resolve28 } from "node:path";
|
|
21799
|
+
var DEFAULT_SCRATCH_TTL_HOURS = 72;
|
|
21800
|
+
var NEVER_SWEEP_SUBDIR_NAMES = new Set(HOME_SUBDIRS.filter((name) => name !== "tmp"));
|
|
21801
|
+
function scratchTtlMs(env = process.env) {
|
|
21802
|
+
const raw = env.BEELINE_SCRATCH_TTL_HOURS?.trim();
|
|
21803
|
+
const hours = raw ? Number(raw) : DEFAULT_SCRATCH_TTL_HOURS;
|
|
21804
|
+
return (Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_SCRATCH_TTL_HOURS) * 60 * 60 * 1e3;
|
|
21805
|
+
}
|
|
21806
|
+
async function discoverAttachScratchRoots(runtimeDir) {
|
|
21807
|
+
const roomsDir = resolve28(runtimeDir, "rooms");
|
|
21808
|
+
let entries;
|
|
21809
|
+
try {
|
|
21810
|
+
entries = await readdir6(roomsDir, { withFileTypes: true });
|
|
21811
|
+
} catch {
|
|
21812
|
+
return [];
|
|
21813
|
+
}
|
|
21814
|
+
const roots = [];
|
|
21815
|
+
for (const entry of entries) {
|
|
21816
|
+
if (!entry.isDirectory())
|
|
21817
|
+
continue;
|
|
21818
|
+
const home = resolve28(roomsDir, entry.name, "agent-home");
|
|
21819
|
+
const stats = await lstat3(home).catch(() => void 0);
|
|
21820
|
+
if (stats?.isDirectory())
|
|
21821
|
+
roots.push(home);
|
|
21822
|
+
}
|
|
21823
|
+
return roots;
|
|
21824
|
+
}
|
|
21825
|
+
async function removeStaleFiles(dir, cutoffMs, protectNamesHere) {
|
|
21826
|
+
let entries;
|
|
21827
|
+
try {
|
|
21828
|
+
entries = await readdir6(dir, { withFileTypes: true });
|
|
21829
|
+
} catch {
|
|
21830
|
+
return { removedFiles: 0, removedBytes: 0 };
|
|
21831
|
+
}
|
|
21832
|
+
let removedFiles = 0;
|
|
21833
|
+
let removedBytes = 0;
|
|
21834
|
+
for (const entry of entries) {
|
|
21835
|
+
if (protectNamesHere && NEVER_SWEEP_SUBDIR_NAMES.has(entry.name))
|
|
21836
|
+
continue;
|
|
21837
|
+
const path = resolve28(dir, entry.name);
|
|
21838
|
+
const stats = await lstat3(path).catch(() => void 0);
|
|
21839
|
+
if (!stats || stats.isSymbolicLink())
|
|
21840
|
+
continue;
|
|
21841
|
+
if (stats.isDirectory()) {
|
|
21842
|
+
const nested = await removeStaleFiles(path, cutoffMs, false);
|
|
21843
|
+
removedFiles += nested.removedFiles;
|
|
21844
|
+
removedBytes += nested.removedBytes;
|
|
21845
|
+
const remaining = await readdir6(path).catch(() => void 0);
|
|
21846
|
+
if (remaining && remaining.length === 0)
|
|
21847
|
+
await rmdir(path).catch(() => void 0);
|
|
21848
|
+
continue;
|
|
21849
|
+
}
|
|
21850
|
+
if (!stats.isFile() || stats.mtimeMs >= cutoffMs)
|
|
21851
|
+
continue;
|
|
21852
|
+
await unlink4(path).catch(() => void 0);
|
|
21853
|
+
removedFiles += 1;
|
|
21854
|
+
removedBytes += stats.size;
|
|
21855
|
+
}
|
|
21856
|
+
return { removedFiles, removedBytes };
|
|
21857
|
+
}
|
|
21858
|
+
async function sweepAttachScratchRoots(roots, ttlMs, now2 = Date.now()) {
|
|
21859
|
+
const cutoffMs = now2 - ttlMs;
|
|
21860
|
+
let removedFiles = 0;
|
|
21861
|
+
let removedBytes = 0;
|
|
21862
|
+
for (const root of roots) {
|
|
21863
|
+
const stats = await lstat3(root).catch(() => void 0);
|
|
21864
|
+
if (!stats?.isDirectory())
|
|
21865
|
+
continue;
|
|
21866
|
+
const result = await removeStaleFiles(root, cutoffMs, true);
|
|
21867
|
+
removedFiles += result.removedFiles;
|
|
21868
|
+
removedBytes += result.removedBytes;
|
|
21869
|
+
}
|
|
21870
|
+
return { removedFiles, removedBytes, roots: roots.length };
|
|
21871
|
+
}
|
|
21872
|
+
async function runScratchSweep(runtimeDir, env = process.env) {
|
|
21873
|
+
const roots = await discoverAttachScratchRoots(runtimeDir);
|
|
21874
|
+
const ttlMs = scratchTtlMs(env);
|
|
21875
|
+
const summary = await sweepAttachScratchRoots(roots, ttlMs);
|
|
21876
|
+
console.log(`[body] scratch sweep: removed ${summary.removedFiles} files (${summary.removedBytes} bytes) older than ${Math.round(ttlMs / (60 * 60 * 1e3))}h under ${summary.roots} roots`);
|
|
21877
|
+
return summary;
|
|
21878
|
+
}
|
|
21879
|
+
|
|
21521
21880
|
// apps/body/dist/cli.js
|
|
21522
21881
|
function usage(exitCode = 1) {
|
|
21523
21882
|
console.error(`
|
|
@@ -21548,6 +21907,10 @@ All other config via env vars (see config.ts).
|
|
|
21548
21907
|
process.exit(exitCode);
|
|
21549
21908
|
}
|
|
21550
21909
|
var daemonFailureRuntimeDir;
|
|
21910
|
+
var SCRATCH_SWEEP_INTERVAL_MS = 6 * 60 * 6e4;
|
|
21911
|
+
function runScratchSweepLogged(runtimeDir) {
|
|
21912
|
+
void runScratchSweep(runtimeDir).catch((error) => console.error("[body] scratch sweep failed:", error));
|
|
21913
|
+
}
|
|
21551
21914
|
var DaemonExitError = class extends Error {
|
|
21552
21915
|
exitStatus;
|
|
21553
21916
|
constructor(message, exitStatus) {
|
|
@@ -21570,7 +21933,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21570
21933
|
runtime = activated.runtime;
|
|
21571
21934
|
const daemonApi = activated.client;
|
|
21572
21935
|
const agent = runtimeAgentCommand(runtime);
|
|
21573
|
-
await writeFile15(
|
|
21936
|
+
await writeFile15(resolve29(dirname15(configPath), "daemon.pid"), `${process.pid}
|
|
21574
21937
|
`, { mode: 384 });
|
|
21575
21938
|
const env = {
|
|
21576
21939
|
...process.env,
|
|
@@ -21578,7 +21941,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21578
21941
|
BUZZ_DEV_MCP_BIN: runtime.mcpBinary
|
|
21579
21942
|
};
|
|
21580
21943
|
const config = loadBodyConfig({
|
|
21581
|
-
workspaceRoot:
|
|
21944
|
+
workspaceRoot: resolve29(dirname15(configPath), "workspace"),
|
|
21582
21945
|
llmEnvFile: runtime.llmEnvFile,
|
|
21583
21946
|
env,
|
|
21584
21947
|
agent
|
|
@@ -21645,6 +22008,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21645
22008
|
pendingSuccessor = true;
|
|
21646
22009
|
}
|
|
21647
22010
|
loadedRelease = await activeReleaseId(layout);
|
|
22011
|
+
await clearUpdateRollbackAlertIfConfirmed(runtimeDir, loadedRelease);
|
|
21648
22012
|
loadedReleaseIdentity = await readInstalledBundleIdentity(layout);
|
|
21649
22013
|
config.daemonReleaseVersion = loadedReleaseIdentity?.version;
|
|
21650
22014
|
config.daemonSourceSha = loadedReleaseIdentity?.commit;
|
|
@@ -21655,6 +22019,9 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21655
22019
|
console.log(`[beeline] thin daemon core ${runtime.communityId} starting with ${runtime.rooms.length} Room binding(s)`);
|
|
21656
22020
|
console.log(`[body] agent binary: ${formatAgentCommand(agent)}`);
|
|
21657
22021
|
console.log(`[body] ${sandbox.advisory}`);
|
|
22022
|
+
runScratchSweepLogged(runtimeDir);
|
|
22023
|
+
const scratchSweepTimer = setInterval(() => runScratchSweepLogged(runtimeDir), SCRATCH_SWEEP_INTERVAL_MS);
|
|
22024
|
+
scratchSweepTimer.unref();
|
|
21658
22025
|
let ready = false;
|
|
21659
22026
|
let stoppingStatus = "daemon stopped";
|
|
21660
22027
|
try {
|
|
@@ -21710,6 +22077,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21710
22077
|
}
|
|
21711
22078
|
functionalProof = gate.proof;
|
|
21712
22079
|
pendingSuccessor = false;
|
|
22080
|
+
await clearUpdateRollbackAlert(runtimeDir);
|
|
21713
22081
|
console.log(`[thin-core] successor functional probe passed on exact release ${loadedRelease}: ${functionalProof?.harness ?? "unknown"} session/new + turn` + (functionalProof?.modelAnswer === "unavailable" ? ` (model answer unavailable: ${functionalProof.modelAnswerReason})` : ""));
|
|
21714
22082
|
}
|
|
21715
22083
|
await clearDaemonStartFailures(runtimeDir);
|
|
@@ -21752,11 +22120,12 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21752
22120
|
}
|
|
21753
22121
|
throw error;
|
|
21754
22122
|
} finally {
|
|
22123
|
+
clearInterval(scratchSweepTimer);
|
|
21755
22124
|
await notifier.stopping(stoppingStatus).catch(() => void 0);
|
|
21756
|
-
const pidPath =
|
|
22125
|
+
const pidPath = resolve29(dirname15(configPath), "daemon.pid");
|
|
21757
22126
|
const recorded = Number((await readFile14(pidPath, "utf8").catch(() => "")).trim());
|
|
21758
22127
|
if (recorded === process.pid) {
|
|
21759
|
-
await
|
|
22128
|
+
await unlink5(pidPath).catch(() => void 0);
|
|
21760
22129
|
}
|
|
21761
22130
|
}
|
|
21762
22131
|
}
|
|
@@ -21781,7 +22150,7 @@ async function main() {
|
|
|
21781
22150
|
const roomId = roomFlag >= 0 ? args[roomFlag + 1] : void 0;
|
|
21782
22151
|
if (!configPath || !roomId)
|
|
21783
22152
|
throw new Error("corner-read-token requires --config and --room");
|
|
21784
|
-
const activated = await activateDaemonTransport(
|
|
22153
|
+
const activated = await activateDaemonTransport(resolve29(configPath));
|
|
21785
22154
|
if (!activated)
|
|
21786
22155
|
throw new Error("corner-read-token requires monolith transport");
|
|
21787
22156
|
const credential = await activated.client.execute("getRoomGitHubToken", { roomId });
|
|
@@ -21843,7 +22212,7 @@ async function main() {
|
|
|
21843
22212
|
}
|
|
21844
22213
|
if (!configPath)
|
|
21845
22214
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
21846
|
-
await runStoredDaemon(
|
|
22215
|
+
await runStoredDaemon(resolve29(configPath));
|
|
21847
22216
|
return;
|
|
21848
22217
|
}
|
|
21849
22218
|
if (command === "update") {
|