usebeeline 0.0.50 → 0.0.53

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.
Files changed (2) hide show
  1. package/dist/usebeeline.mjs +180 -50
  2. package/package.json +1 -1
@@ -14141,6 +14141,39 @@ import { basename as basename3, dirname as dirname5, join as join3, relative as
14141
14141
  // apps/body/dist/beeline-skill.js
14142
14142
  import { readFileSync as readFileSync3 } from "node:fs";
14143
14143
  import { resolve as resolve11 } from "node:path";
14144
+
14145
+ // packages/api-contract/dist/system-events.js
14146
+ var SERVER_EVENT_KINDS = [
14147
+ "joined",
14148
+ "schedule-ran",
14149
+ "corner-opened",
14150
+ "check-passed",
14151
+ "check-failed",
14152
+ "merged",
14153
+ "grant-decided"
14154
+ ];
14155
+ function isServerEventKind(value) {
14156
+ return SERVER_EVENT_KINDS.includes(value);
14157
+ }
14158
+ var RESUME_KINDS = ["grant-decided"];
14159
+ function isResumeKind(value) {
14160
+ return RESUME_KINDS.includes(value);
14161
+ }
14162
+
14163
+ // packages/api-contract/dist/agent-pairing-code.js
14164
+ var CURRENT_AGENT_PAIRING_CODE = /^[0-9A-F]{8}-[0-9A-F]{8}$/;
14165
+ var LEGACY_AGENT_PAIRING_CODE = /^BUZZ-(?:[0-9A-F]{8}-[0-9A-F]{8}|[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4})$/;
14166
+ function normalizeAgentPairingCode(value) {
14167
+ if (typeof value !== "string")
14168
+ return void 0;
14169
+ const normalized = value.trim().toUpperCase();
14170
+ return isAgentPairingCode(normalized) ? normalized : void 0;
14171
+ }
14172
+ function isAgentPairingCode(value) {
14173
+ return typeof value === "string" && (CURRENT_AGENT_PAIRING_CODE.test(value) || LEGACY_AGENT_PAIRING_CODE.test(value));
14174
+ }
14175
+
14176
+ // apps/body/dist/beeline-skill.js
14144
14177
  var USING_BEELINE_SKILL_NAME = "using-beeline";
14145
14178
  var BEELINE_ROOM_CAPABILITIES = [
14146
14179
  "The repository filesystem is read-only in this Room session.",
@@ -14151,7 +14184,7 @@ var BEELINE_ROOM_CAPABILITIES = [
14151
14184
  "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.",
14152
14185
  "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 attach_file 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); it is attached to your reply. 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.",
14153
14186
  "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.",
14154
- "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 (joined, schedule-ran, corner-opened, check-passed, check-failed, merged); 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.",
14187
+ `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.`,
14155
14188
  "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.",
14156
14189
  "When repository work is needed, you MUST call beeline-agent open_corner with a name of at most three words - it titles the corner everywhere - and a complete objective of no more than 24 words. The host-governed call is the only way to start write work.",
14157
14190
  "When open_corner succeeds, the server posts the corner card: do not announce or restate the opening. End the turn with nothing more unless the person asked something else.",
@@ -15111,6 +15144,7 @@ async function resolveSharedSkillSources(operatorHome, names) {
15111
15144
  return resolveExplicitSkillSources(operatorHome, names);
15112
15145
  const seen = /* @__PURE__ */ new Set();
15113
15146
  const resolved = [];
15147
+ const skipped = [];
15114
15148
  for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
15115
15149
  const sourceRoot = resolve13(operatorHome, relativeRoot);
15116
15150
  const rootStats = await lstat(sourceRoot).catch(() => void 0);
@@ -15122,23 +15156,61 @@ async function resolveSharedSkillSources(operatorHome, names) {
15122
15156
  const candidate = resolve13(sourceRoot, entry);
15123
15157
  try {
15124
15158
  const candidateStats = await lstat(candidate);
15125
- if (!candidateStats.isDirectory() || candidateStats.isSymbolicLink())
15159
+ if (candidateStats.isSymbolicLink()) {
15160
+ const reason = await realpath(candidate).then(() => "symlinked directory", (error) => isMissingPathError(error) ? "dangling symlink" : "symlinked directory");
15161
+ skipped.push({
15162
+ path: candidate,
15163
+ reason
15164
+ });
15165
+ continue;
15166
+ }
15167
+ if (!candidateStats.isDirectory()) {
15168
+ skipped.push({ path: candidate, reason: "not an ordinary directory" });
15126
15169
  continue;
15170
+ }
15127
15171
  assertContained(sourceRoot, candidate);
15128
15172
  const skillMd = resolve13(candidate, "SKILL.md");
15129
- const skillStats = await lstat(skillMd);
15173
+ const skillStats = await lstat(skillMd).catch((error) => {
15174
+ if (isMissingPathError(error)) {
15175
+ skipped.push({ path: candidate, reason: "missing SKILL.md" });
15176
+ return void 0;
15177
+ }
15178
+ throw error;
15179
+ });
15180
+ if (!skillStats)
15181
+ continue;
15130
15182
  if (!skillStats.isFile() || skillStats.isSymbolicLink() || skillStats.nlink !== 1) {
15131
- throw new Error(`shared skill requires an ordinary SKILL.md: ${entry}`);
15183
+ skipped.push({ path: candidate, reason: "SKILL.md is not an ordinary file" });
15184
+ continue;
15132
15185
  }
15133
15186
  seen.add(entry);
15134
15187
  resolved.push({ name: entry, source: candidate });
15135
15188
  } catch (error) {
15189
+ if (isMissingPathError(error)) {
15190
+ skipped.push({ path: candidate, reason: "missing during discovery" });
15191
+ continue;
15192
+ }
15136
15193
  console.warn(`[body] skipping operator skill ${entry}:`, error);
15137
15194
  }
15138
15195
  }
15139
15196
  }
15197
+ logSkippedOperatorSkills(skipped);
15140
15198
  return resolved;
15141
15199
  }
15200
+ function isMissingPathError(error) {
15201
+ return typeof error === "object" && error !== null && error.code === "ENOENT";
15202
+ }
15203
+ function logSkippedOperatorSkills(skipped) {
15204
+ const totals = /* @__PURE__ */ new Map();
15205
+ for (const { path, reason } of skipped) {
15206
+ console.warn(`[body] skipping operator skill ${path}: ${reason}`);
15207
+ totals.set(reason, (totals.get(reason) ?? 0) + 1);
15208
+ }
15209
+ for (const [reason, count] of totals) {
15210
+ if (count > 1)
15211
+ console.warn(`[body] ${count} skill entries skipped: ${reason}`);
15212
+ }
15213
+ }
15142
15214
  async function resolveExplicitSkillSources(operatorHome, names) {
15143
15215
  const unique = [...new Set(names)];
15144
15216
  for (const name of unique) {
@@ -16968,6 +17040,9 @@ var MonolithCornerTurnLoop = class {
16968
17040
  this.sessionScratchDir = tmpDir;
16969
17041
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
16970
17042
  await Promise.all(homeStateDirs.map((dir) => mkdir9(dir, { recursive: true })));
17043
+ const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
17044
+ if (attachScratchRoot)
17045
+ await mkdir9(attachScratchRoot, { recursive: true });
16971
17046
  const spawnCommand = wrapAgentCommand({
16972
17047
  bwrapPath: this.options.config.bwrapPath,
16973
17048
  spec: {
@@ -16979,6 +17054,7 @@ var MonolithCornerTurnLoop = class {
16979
17054
  harnessStateDirs: stateDirs,
16980
17055
  harnessHomeStateDirs: homeStateDirs,
16981
17056
  ...tmpDir ? { tmpDir } : {},
17057
+ ...attachScratchRoot ? { additionalWritablePaths: [attachScratchRoot] } : {},
16982
17058
  maskPaths: credentialMaskPaths(this.options.config.sandboxMaskPaths, operatorHome)
16983
17059
  },
16984
17060
  command,
@@ -17016,7 +17092,7 @@ var MonolithCornerTurnLoop = class {
17016
17092
  attachRoot: this.options.worktreePath,
17017
17093
  // The whole per-session overlay, not an enumerated subset: see
17018
17094
  // `monolith-room-turn.ts`'s matching comment.
17019
- attachScratchRoot: this.options.config.agentHomeRoot ?? tmpDir,
17095
+ attachScratchRoot,
17020
17096
  ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
17021
17097
  })
17022
17098
  ];
@@ -17411,24 +17487,6 @@ import { join as join6 } from "node:path";
17411
17487
  var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
17412
17488
  var SCHEDULE_RAN_VERB = "ran a schedule for";
17413
17489
 
17414
- // packages/api-contract/dist/system-events.js
17415
- var SERVER_EVENT_KINDS = [
17416
- "joined",
17417
- "schedule-ran",
17418
- "corner-opened",
17419
- "check-passed",
17420
- "check-failed",
17421
- "merged",
17422
- "grant-decided"
17423
- ];
17424
- function isServerEventKind(value) {
17425
- return SERVER_EVENT_KINDS.includes(value);
17426
- }
17427
- var RESUME_KINDS = ["grant-decided"];
17428
- function isResumeKind(value) {
17429
- return RESUME_KINDS.includes(value);
17430
- }
17431
-
17432
17490
  // apps/body/dist/monolith-room-turn.js
17433
17491
  function isRoomMcpPermissionRequest(request, mountedServers = ROOM_MOUNTED_MCP_SERVERS) {
17434
17492
  if (isSquireMcpPermissionRequest(request))
@@ -17501,6 +17559,15 @@ function agentReplyMentionIds(text2, roster, authorId) {
17501
17559
  aliases.set(key, entry);
17502
17560
  }
17503
17561
  }
17562
+ for (const member of roster.members) {
17563
+ if (member.identityId === authorId || !member.handle)
17564
+ continue;
17565
+ const handle = member.handle.trim().replace(/^@/, "").toLocaleLowerCase();
17566
+ const canonical = aliases.get(handle);
17567
+ const legacy = `a_${handle}`;
17568
+ if (canonical && !aliases.has(legacy))
17569
+ aliases.set(legacy, { ...canonical, display: legacy });
17570
+ }
17504
17571
  const mentioned = [];
17505
17572
  for (const { display, ids } of [...aliases.values()].sort((left, right) => right.display.length - left.display.length)) {
17506
17573
  if (ids.size !== 1)
@@ -17749,6 +17816,9 @@ var MonolithRoomTurnLoop = class {
17749
17816
  this.sessionStateDirs = stateDirs;
17750
17817
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
17751
17818
  await Promise.all(homeStateDirs.map((dir) => mkdir10(dir, { recursive: true })));
17819
+ const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
17820
+ if (attachScratchRoot)
17821
+ await mkdir10(attachScratchRoot, { recursive: true });
17752
17822
  const spawnCommand = wrapAgentCommand({
17753
17823
  bwrapPath: this.options.config.bwrapPath,
17754
17824
  spec: {
@@ -17757,6 +17827,7 @@ var MonolithRoomTurnLoop = class {
17757
17827
  harnessStateDirs: stateDirs,
17758
17828
  harnessHomeStateDirs: homeStateDirs,
17759
17829
  ...tmpDir ? { tmpDir } : {},
17830
+ ...attachScratchRoot ? { additionalWritablePaths: [attachScratchRoot] } : {},
17760
17831
  maskPaths: credentialMaskPaths(this.options.config.sandboxMaskPaths, operatorHome)
17761
17832
  },
17762
17833
  command,
@@ -17772,7 +17843,7 @@ var MonolithRoomTurnLoop = class {
17772
17843
  // never picks where a harness writes a file it generates (grok's own
17773
17844
  // images dir, say), so anything inside the overlay it could possibly
17774
17845
  // have written must be attachable, whatever subdirectory that is.
17775
- attachScratchRoot: this.options.config.agentHomeRoot ?? tmpDir,
17846
+ attachScratchRoot,
17776
17847
  directMessage,
17777
17848
  ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
17778
17849
  })
@@ -19502,19 +19573,6 @@ import { chmod as chmod5, mkdir as mkdir14, readFile as readFile10, unlink as un
19502
19573
  import { dirname as dirname10, resolve as resolve22 } from "node:path";
19503
19574
  import { stdin as stdin3, stdout as stdout4 } from "node:process";
19504
19575
 
19505
- // packages/api-contract/dist/agent-pairing-code.js
19506
- var CURRENT_AGENT_PAIRING_CODE = /^[0-9A-F]{8}-[0-9A-F]{8}$/;
19507
- var LEGACY_AGENT_PAIRING_CODE = /^BUZZ-(?:[0-9A-F]{8}-[0-9A-F]{8}|[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4})$/;
19508
- function normalizeAgentPairingCode(value) {
19509
- if (typeof value !== "string")
19510
- return void 0;
19511
- const normalized = value.trim().toUpperCase();
19512
- return isAgentPairingCode(normalized) ? normalized : void 0;
19513
- }
19514
- function isAgentPairingCode(value) {
19515
- return typeof value === "string" && (CURRENT_AGENT_PAIRING_CODE.test(value) || LEGACY_AGENT_PAIRING_CODE.test(value));
19516
- }
19517
-
19518
19576
  // apps/body/dist/clack-support.js
19519
19577
  import { stdout as stdout2 } from "node:process";
19520
19578
  var FALLBACK_TERMINAL_COLUMNS = 80;
@@ -20820,39 +20878,59 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
20820
20878
  `, { mode: 384 });
20821
20879
  return true;
20822
20880
  }
20881
+ function siblingRevertNote(attempt, loadedRelease) {
20882
+ if (!loadedRelease || attempt?.releaseId !== loadedRelease || attempt.status !== "reverted") {
20883
+ return void 0;
20884
+ }
20885
+ return `shared update attempt reverted by sibling ${attempt.revertedBy ?? "unknown"}: ${attempt.failure ?? "no failure recorded"}`;
20886
+ }
20887
+ function describeOwnProof(proof) {
20888
+ return proof.modelAnswer === "unavailable" ? `this daemon's own probe reached the model boundary without an answer (${proof.modelAnswerReason ?? "no reason recorded"})` : "this daemon's own probe passed";
20889
+ }
20890
+ function attemptFailureText(error) {
20891
+ const message = error instanceof Error ? error.message : String(error);
20892
+ return message.replace(/\s+/g, " ").trim().slice(0, 300);
20893
+ }
20823
20894
  async function gateManagedSuccessor(input) {
20824
20895
  try {
20825
20896
  const attempt = await readUpdateAttempt(input.layout);
20826
20897
  const desiredRelease = attempt?.status === "pending" ? attempt.releaseId : void 0;
20827
20898
  if (!desiredRelease || !input.loadedRelease || desiredRelease !== input.loadedRelease) {
20828
- throw new Error(`successor loaded release ${input.loadedRelease ?? "unknown"}, not the pending desired release`);
20899
+ const reverted = siblingRevertNote(attempt, input.loadedRelease);
20900
+ throw new Error(reverted ? `successor release ${input.loadedRelease} was reverted before this daemon probed it: ${reverted}` : `successor loaded release ${input.loadedRelease ?? "unknown"}, not the pending desired release`);
20829
20901
  }
20830
20902
  const proof = await input.probe();
20831
20903
  if (!await proveLoadedReleaseReady(input.layout, input.runtimeDir, input.loadedRelease, {
20832
20904
  probeId: input.probeId,
20833
20905
  functionalProof: proof
20834
20906
  })) {
20835
- throw new Error(`successor release ${input.loadedRelease} did not produce functional proof`);
20907
+ const reverted = siblingRevertNote(await readUpdateAttempt(input.layout), input.loadedRelease);
20908
+ throw new Error(reverted ? `successor release ${input.loadedRelease} lost its attempt while this daemon proved it: ${describeOwnProof(proof)}; ${reverted}` : `successor release ${input.loadedRelease} did not produce functional proof`);
20836
20909
  }
20837
20910
  return { kind: "passed", proof };
20838
20911
  } catch (error) {
20839
20912
  return {
20840
20913
  kind: "failed",
20841
20914
  error,
20842
- rolledBack: await rollbackFailedSuccessor(input.layout, input.runtimeDir)
20915
+ rolledBack: await rollbackFailedSuccessor(input.layout, input.runtimeDir, {
20916
+ probeId: input.probeId,
20917
+ failure: attemptFailureText(error)
20918
+ })
20843
20919
  };
20844
20920
  }
20845
20921
  }
20846
- async function rollbackFailedSuccessor(layout, runtimeDir) {
20922
+ async function rollbackFailedSuccessor(layout, runtimeDir, cause = {}) {
20847
20923
  return withInstallLock(layout, async () => {
20848
20924
  const attempt = await readUpdateAttempt(layout);
20849
20925
  if (!attempt || attempt.status !== "pending")
20850
20926
  return false;
20927
+ const attribution = cause.probeId ? { revertedBy: cause.probeId } : {};
20851
20928
  if (!attempt.previousReleaseId) {
20852
20929
  await replaceUpdateAttempt(layout, {
20853
20930
  ...attempt,
20854
20931
  status: "reverted",
20855
- failure: "functional served-turn proof failed, but no previous release exists"
20932
+ failure: cause.failure ?? "functional served-turn proof failed, but no previous release exists",
20933
+ ...attribution
20856
20934
  });
20857
20935
  return false;
20858
20936
  }
@@ -20860,7 +20938,8 @@ async function rollbackFailedSuccessor(layout, runtimeDir) {
20860
20938
  await replaceUpdateAttempt(layout, {
20861
20939
  ...attempt,
20862
20940
  status: "reverted",
20863
- failure: "functional served-turn proof failed before confirmation"
20941
+ failure: cause.failure ?? "functional served-turn proof failed before confirmation",
20942
+ ...attribution
20864
20943
  });
20865
20944
  if (runtimeDir)
20866
20945
  await queueUpdateRollbackAlert(runtimeDir, attempt.releaseId);
@@ -21067,6 +21146,28 @@ import { resolve as resolve26 } from "node:path";
21067
21146
  var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
21068
21147
  var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
21069
21148
  var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
21149
+ var ACP_ERROR_CODE = /\bACP error (-\d+):/;
21150
+ var ACP_PROMPT_INACTIVITY = /\bACP session\/prompt timed out after \d+ms of inactivity\b/;
21151
+ function isServerInternalCode(code) {
21152
+ return code === -32603 || code <= -32e3 && code >= -32099;
21153
+ }
21154
+ function classifyAcpTurnFailure(error) {
21155
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : void 0;
21156
+ if (!message)
21157
+ return void 0;
21158
+ if (ACP_PROMPT_INACTIVITY.test(message))
21159
+ return { kind: "prompt-inactivity" };
21160
+ const code = Number(ACP_ERROR_CODE.exec(message)?.[1]);
21161
+ if (Number.isFinite(code) && isServerInternalCode(code))
21162
+ return { kind: "server-internal", code };
21163
+ return void 0;
21164
+ }
21165
+ function sameAcpTurnFailure(one, other) {
21166
+ if (one.kind === "server-internal") {
21167
+ return other.kind === "server-internal" && one.code === other.code;
21168
+ }
21169
+ return other.kind === one.kind;
21170
+ }
21070
21171
  var UpdateFunctionalProbeError = class extends Error {
21071
21172
  reason;
21072
21173
  code = "BEELINE_UPDATE_FUNCTIONAL_PROBE_FAILED";
@@ -21138,6 +21239,7 @@ async function runUpdateFunctionalProbe(input) {
21138
21239
  args: agentArgsWithModelSelection(selectedAgent, input.config.modelSelection)
21139
21240
  };
21140
21241
  let modelAnswer = {};
21242
+ let turnCompleted = true;
21141
21243
  if (input.config.bwrapPath) {
21142
21244
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
21143
21245
  const operatorHome = input.config.operatorHome ?? homedir10();
@@ -21199,7 +21301,11 @@ async function runUpdateFunctionalProbe(input) {
21199
21301
  ...refusal ? { providerRefusal: refusal } : {}
21200
21302
  });
21201
21303
  }
21202
- const current = await input.compareWithCurrentRelease(refusal);
21304
+ const current = await input.compareWithCurrentRelease({
21305
+ kind: "provider-refusal",
21306
+ reason: refusal.reason,
21307
+ refusal
21308
+ });
21203
21309
  if (current.kind !== "refused" || current.status !== refusal.status) {
21204
21310
  throw new UpdateFunctionalProbeError("turn-failed", `${detail}; ${describeCurrentReleaseOutcome(current)}`, { providerRefusal: refusal });
21205
21311
  }
@@ -21214,7 +21320,26 @@ async function runUpdateFunctionalProbe(input) {
21214
21320
  } catch (error) {
21215
21321
  if (error instanceof UpdateFunctionalProbeError)
21216
21322
  throw error;
21217
- throw new UpdateFunctionalProbeError("turn-failed", error instanceof Error ? error.message : String(error), { cause: error });
21323
+ const detail = error instanceof Error ? error.message : String(error);
21324
+ const failure = classifyAcpTurnFailure(error);
21325
+ if (!failure || !input.compareWithCurrentRelease) {
21326
+ throw new UpdateFunctionalProbeError("turn-failed", detail, { cause: error });
21327
+ }
21328
+ const current = await input.compareWithCurrentRelease({
21329
+ kind: "acp-turn-failure",
21330
+ reason: detail,
21331
+ failure
21332
+ });
21333
+ const currentFailure = current.kind === "unavailable" ? classifyAcpTurnFailure(current.reason) : void 0;
21334
+ if (!currentFailure || !sameAcpTurnFailure(failure, currentFailure)) {
21335
+ throw new UpdateFunctionalProbeError("turn-failed", `${detail}; ${describeCurrentReleaseOutcome(current)}`, { cause: error });
21336
+ }
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
+ };
21218
21343
  }
21219
21344
  } catch (error) {
21220
21345
  if (error instanceof UpdateFunctionalProbeError)
@@ -21225,7 +21350,7 @@ async function runUpdateFunctionalProbe(input) {
21225
21350
  harness,
21226
21351
  sandboxed: Boolean(input.config.bwrapPath),
21227
21352
  sessionStarted: true,
21228
- turnCompleted: true,
21353
+ turnCompleted,
21229
21354
  nativeTools: [],
21230
21355
  ...modelAnswer
21231
21356
  };
@@ -21239,7 +21364,7 @@ async function runUpdateFunctionalProbe(input) {
21239
21364
  import { spawn as spawn7 } from "node:child_process";
21240
21365
  import { dirname as dirname14, join as join8 } from "node:path";
21241
21366
  init_self_update();
21242
- var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 8e4;
21367
+ var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
21243
21368
  var UPDATE_PROBE_COMMAND = "update-probe";
21244
21369
  function parseReport(line) {
21245
21370
  let parsed;
@@ -21567,8 +21692,8 @@ async function runStoredDaemon(pathOrPointer) {
21567
21692
  releaseId: loadedRelease ?? "unknown",
21568
21693
  sandboxRequired: runtime.sandbox !== "off",
21569
21694
  ...currentReleaseId ? {
21570
- compareWithCurrentRelease: async (refusal) => {
21571
- console.warn(`[thin-core] successor probe refused by the provider (${refusal.reason}); probing the current release ${currentReleaseId} for the same refusal`);
21695
+ compareWithCurrentRelease: async (appeal) => {
21696
+ console.warn(`[thin-core] successor probe got no answer from the provider (${appeal.reason}); probing the current release ${currentReleaseId} for the same outcome`);
21572
21697
  await extendSystemdStartTimeout(CURRENT_RELEASE_PROBE_TIMEOUT_MS + 15e3);
21573
21698
  return probeReleaseInSubprocess({
21574
21699
  layout,
@@ -21614,7 +21739,12 @@ async function runStoredDaemon(pathOrPointer) {
21614
21739
  console.log(`[beeline] agent ${runtime.agent.publicKey} removed; runtime archived at ${archivedRuntime}`);
21615
21740
  }
21616
21741
  } catch (error) {
21617
- const rolledBack = successorRolledBack || layout && pendingSuccessor && !ready && await rollbackFailedSuccessor(layout, runtimeDir);
21742
+ const rolledBack = successorRolledBack || layout && pendingSuccessor && !ready && // Named, so a sibling daemon's journal can say whose failure reverted
21743
+ // the attempt it shares with this one.
21744
+ await rollbackFailedSuccessor(layout, runtimeDir, {
21745
+ probeId: runtime.agent.publicKey,
21746
+ failure: attemptFailureText(error)
21747
+ });
21618
21748
  if (rolledBack) {
21619
21749
  console.error("[thin-core] successor failed before READY; previous release restored once");
21620
21750
  const alertRoom = runtime.rooms[0]?.channelId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usebeeline",
3
- "version": "0.0.50",
3
+ "version": "0.0.53",
4
4
  "description": "Connect an AI coding agent to Beeline with one command.",
5
5
  "homepage": "https://usebeeline.app",
6
6
  "bugs": {