usebeeline 0.0.52 → 0.0.54

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 +122 -16
  2. package/package.json +1 -1
@@ -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 resolve28 } from "node:path";
959
- import { readFile as readFile14, unlink as unlink3, writeFile as writeFile15 } from "node:fs/promises";
958
+ import { dirname as dirname15, resolve as resolve29 } from "node:path";
959
+ import { readFile as readFile14, unlink as unlink4, 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
@@ -3832,7 +3832,7 @@ var AcpClient = class extends EventEmitter {
3832
3832
  const current = this.activeRunIds.get(sessionId);
3833
3833
  if (current)
3834
3834
  return Promise.resolve(current);
3835
- return new Promise((resolve29, reject) => {
3835
+ return new Promise((resolve30, reject) => {
3836
3836
  const onUpdate = (update) => {
3837
3837
  if (update.sessionId !== sessionId)
3838
3838
  return;
@@ -3840,7 +3840,7 @@ var AcpClient = class extends EventEmitter {
3840
3840
  if (!runId)
3841
3841
  return;
3842
3842
  cleanup();
3843
- resolve29(runId);
3843
+ resolve30(runId);
3844
3844
  };
3845
3845
  const timer = setTimeout(() => {
3846
3846
  cleanup();
@@ -3924,13 +3924,13 @@ var AcpClient = class extends EventEmitter {
3924
3924
  }
3925
3925
  const id = this.nextId++;
3926
3926
  const payload = { jsonrpc: "2.0", id, method, params };
3927
- return new Promise((resolve29, reject) => {
3927
+ return new Promise((resolve30, reject) => {
3928
3928
  const timer = setTimeout(() => {
3929
3929
  this.pending.delete(id);
3930
3930
  reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart), detail));
3931
3931
  }, timeoutMs);
3932
3932
  this.pending.set(id, {
3933
- resolve: resolve29,
3933
+ resolve: resolve30,
3934
3934
  reject,
3935
3935
  timer,
3936
3936
  method,
@@ -15355,6 +15355,8 @@ function harnessStateDirsFromEnv(env) {
15355
15355
  import { mkdir as mkdir5, writeFile as writeFile6 } from "node:fs/promises";
15356
15356
  import { basename as basename4, extname, join as join4 } from "node:path";
15357
15357
  var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
15358
+ var MEDIA_TTL_HOURS = 24;
15359
+ var EXPIRED_REASON = `expired: attachments are kept for ${MEDIA_TTL_HOURS} hours and these bytes are past that window`;
15358
15360
  var FETCH_TIMEOUT_MS = 3e4;
15359
15361
  var MAX_INLINE_IMAGE_BYTES = 5 * 1024 * 1024;
15360
15362
  function safeFileName(attachment, index, taken) {
@@ -15379,10 +15381,14 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
15379
15381
  });
15380
15382
  if (attachment.size && attachment.size > MAX_ATTACHMENT_BYTES)
15381
15383
  return tooLarge(attachment.size);
15384
+ if (attachment.expired)
15385
+ return { attachment, reason: EXPIRED_REASON };
15382
15386
  try {
15383
15387
  const response = await fetchImpl(attachment.url, {
15384
15388
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
15385
15389
  });
15390
+ if (response.status === 410)
15391
+ return { attachment, reason: EXPIRED_REASON };
15386
15392
  if (!response.ok)
15387
15393
  throw new Error(`HTTP ${response.status}`);
15388
15394
  const declared = Number(response.headers.get("content-length") ?? 0);
@@ -17040,6 +17046,9 @@ var MonolithCornerTurnLoop = class {
17040
17046
  this.sessionScratchDir = tmpDir;
17041
17047
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
17042
17048
  await Promise.all(homeStateDirs.map((dir) => mkdir9(dir, { recursive: true })));
17049
+ const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
17050
+ if (attachScratchRoot)
17051
+ await mkdir9(attachScratchRoot, { recursive: true });
17043
17052
  const spawnCommand = wrapAgentCommand({
17044
17053
  bwrapPath: this.options.config.bwrapPath,
17045
17054
  spec: {
@@ -17051,6 +17060,7 @@ var MonolithCornerTurnLoop = class {
17051
17060
  harnessStateDirs: stateDirs,
17052
17061
  harnessHomeStateDirs: homeStateDirs,
17053
17062
  ...tmpDir ? { tmpDir } : {},
17063
+ ...attachScratchRoot ? { additionalWritablePaths: [attachScratchRoot] } : {},
17054
17064
  maskPaths: credentialMaskPaths(this.options.config.sandboxMaskPaths, operatorHome)
17055
17065
  },
17056
17066
  command,
@@ -17088,7 +17098,7 @@ var MonolithCornerTurnLoop = class {
17088
17098
  attachRoot: this.options.worktreePath,
17089
17099
  // The whole per-session overlay, not an enumerated subset: see
17090
17100
  // `monolith-room-turn.ts`'s matching comment.
17091
- attachScratchRoot: this.options.config.agentHomeRoot ?? tmpDir,
17101
+ attachScratchRoot,
17092
17102
  ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
17093
17103
  })
17094
17104
  ];
@@ -17812,6 +17822,9 @@ var MonolithRoomTurnLoop = class {
17812
17822
  this.sessionStateDirs = stateDirs;
17813
17823
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
17814
17824
  await Promise.all(homeStateDirs.map((dir) => mkdir10(dir, { recursive: true })));
17825
+ const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
17826
+ if (attachScratchRoot)
17827
+ await mkdir10(attachScratchRoot, { recursive: true });
17815
17828
  const spawnCommand = wrapAgentCommand({
17816
17829
  bwrapPath: this.options.config.bwrapPath,
17817
17830
  spec: {
@@ -17820,6 +17833,7 @@ var MonolithRoomTurnLoop = class {
17820
17833
  harnessStateDirs: stateDirs,
17821
17834
  harnessHomeStateDirs: homeStateDirs,
17822
17835
  ...tmpDir ? { tmpDir } : {},
17836
+ ...attachScratchRoot ? { additionalWritablePaths: [attachScratchRoot] } : {},
17823
17837
  maskPaths: credentialMaskPaths(this.options.config.sandboxMaskPaths, operatorHome)
17824
17838
  },
17825
17839
  command,
@@ -17835,7 +17849,7 @@ var MonolithRoomTurnLoop = class {
17835
17849
  // never picks where a harness writes a file it generates (grok's own
17836
17850
  // images dir, say), so anything inside the overlay it could possibly
17837
17851
  // have written must be attachable, whatever subdirectory that is.
17838
- attachScratchRoot: this.options.config.agentHomeRoot ?? tmpDir,
17852
+ attachScratchRoot,
17839
17853
  directMessage,
17840
17854
  ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
17841
17855
  })
@@ -21395,7 +21409,7 @@ async function probeReleaseInSubprocess(input) {
21395
21409
  return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
21396
21410
  }
21397
21411
  const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
21398
- return new Promise((resolve29) => {
21412
+ return new Promise((resolve30) => {
21399
21413
  const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
21400
21414
  let stdout6 = "";
21401
21415
  let stderr = "";
@@ -21405,7 +21419,7 @@ async function probeReleaseInSubprocess(input) {
21405
21419
  return;
21406
21420
  settled = true;
21407
21421
  clearTimeout(timer);
21408
- resolve29(outcome);
21422
+ resolve30(outcome);
21409
21423
  };
21410
21424
  const timer = setTimeout(() => {
21411
21425
  child.kill("SIGKILL");
@@ -21510,6 +21524,90 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
21510
21524
  return status;
21511
21525
  }
21512
21526
 
21527
+ // apps/body/dist/scratch-sweep.js
21528
+ import { lstat as lstat3, readdir as readdir6, rmdir, unlink as unlink3 } from "node:fs/promises";
21529
+ import { resolve as resolve28 } from "node:path";
21530
+ var DEFAULT_SCRATCH_TTL_HOURS = 72;
21531
+ var NEVER_SWEEP_SUBDIR_NAMES = new Set(HOME_SUBDIRS.filter((name) => name !== "tmp"));
21532
+ function scratchTtlMs(env = process.env) {
21533
+ const raw = env.BEELINE_SCRATCH_TTL_HOURS?.trim();
21534
+ const hours = raw ? Number(raw) : DEFAULT_SCRATCH_TTL_HOURS;
21535
+ return (Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_SCRATCH_TTL_HOURS) * 60 * 60 * 1e3;
21536
+ }
21537
+ async function discoverAttachScratchRoots(runtimeDir) {
21538
+ const roomsDir = resolve28(runtimeDir, "rooms");
21539
+ let entries;
21540
+ try {
21541
+ entries = await readdir6(roomsDir, { withFileTypes: true });
21542
+ } catch {
21543
+ return [];
21544
+ }
21545
+ const roots = [];
21546
+ for (const entry of entries) {
21547
+ if (!entry.isDirectory())
21548
+ continue;
21549
+ const home = resolve28(roomsDir, entry.name, "agent-home");
21550
+ const stats = await lstat3(home).catch(() => void 0);
21551
+ if (stats?.isDirectory())
21552
+ roots.push(home);
21553
+ }
21554
+ return roots;
21555
+ }
21556
+ async function removeStaleFiles(dir, cutoffMs, protectNamesHere) {
21557
+ let entries;
21558
+ try {
21559
+ entries = await readdir6(dir, { withFileTypes: true });
21560
+ } catch {
21561
+ return { removedFiles: 0, removedBytes: 0 };
21562
+ }
21563
+ let removedFiles = 0;
21564
+ let removedBytes = 0;
21565
+ for (const entry of entries) {
21566
+ if (protectNamesHere && NEVER_SWEEP_SUBDIR_NAMES.has(entry.name))
21567
+ continue;
21568
+ const path = resolve28(dir, entry.name);
21569
+ const stats = await lstat3(path).catch(() => void 0);
21570
+ if (!stats || stats.isSymbolicLink())
21571
+ continue;
21572
+ if (stats.isDirectory()) {
21573
+ const nested = await removeStaleFiles(path, cutoffMs, false);
21574
+ removedFiles += nested.removedFiles;
21575
+ removedBytes += nested.removedBytes;
21576
+ const remaining = await readdir6(path).catch(() => void 0);
21577
+ if (remaining && remaining.length === 0)
21578
+ await rmdir(path).catch(() => void 0);
21579
+ continue;
21580
+ }
21581
+ if (!stats.isFile() || stats.mtimeMs >= cutoffMs)
21582
+ continue;
21583
+ await unlink3(path).catch(() => void 0);
21584
+ removedFiles += 1;
21585
+ removedBytes += stats.size;
21586
+ }
21587
+ return { removedFiles, removedBytes };
21588
+ }
21589
+ async function sweepAttachScratchRoots(roots, ttlMs, now2 = Date.now()) {
21590
+ const cutoffMs = now2 - ttlMs;
21591
+ let removedFiles = 0;
21592
+ let removedBytes = 0;
21593
+ for (const root of roots) {
21594
+ const stats = await lstat3(root).catch(() => void 0);
21595
+ if (!stats?.isDirectory())
21596
+ continue;
21597
+ const result = await removeStaleFiles(root, cutoffMs, true);
21598
+ removedFiles += result.removedFiles;
21599
+ removedBytes += result.removedBytes;
21600
+ }
21601
+ return { removedFiles, removedBytes, roots: roots.length };
21602
+ }
21603
+ async function runScratchSweep(runtimeDir, env = process.env) {
21604
+ const roots = await discoverAttachScratchRoots(runtimeDir);
21605
+ const ttlMs = scratchTtlMs(env);
21606
+ const summary = await sweepAttachScratchRoots(roots, ttlMs);
21607
+ 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`);
21608
+ return summary;
21609
+ }
21610
+
21513
21611
  // apps/body/dist/cli.js
21514
21612
  function usage(exitCode = 1) {
21515
21613
  console.error(`
@@ -21540,6 +21638,10 @@ All other config via env vars (see config.ts).
21540
21638
  process.exit(exitCode);
21541
21639
  }
21542
21640
  var daemonFailureRuntimeDir;
21641
+ var SCRATCH_SWEEP_INTERVAL_MS = 6 * 60 * 6e4;
21642
+ function runScratchSweepLogged(runtimeDir) {
21643
+ void runScratchSweep(runtimeDir).catch((error) => console.error("[body] scratch sweep failed:", error));
21644
+ }
21543
21645
  var DaemonExitError = class extends Error {
21544
21646
  exitStatus;
21545
21647
  constructor(message, exitStatus) {
@@ -21562,7 +21664,7 @@ async function runStoredDaemon(pathOrPointer) {
21562
21664
  runtime = activated.runtime;
21563
21665
  const daemonApi = activated.client;
21564
21666
  const agent = runtimeAgentCommand(runtime);
21565
- await writeFile15(resolve28(dirname15(configPath), "daemon.pid"), `${process.pid}
21667
+ await writeFile15(resolve29(dirname15(configPath), "daemon.pid"), `${process.pid}
21566
21668
  `, { mode: 384 });
21567
21669
  const env = {
21568
21670
  ...process.env,
@@ -21570,7 +21672,7 @@ async function runStoredDaemon(pathOrPointer) {
21570
21672
  BUZZ_DEV_MCP_BIN: runtime.mcpBinary
21571
21673
  };
21572
21674
  const config = loadBodyConfig({
21573
- workspaceRoot: resolve28(dirname15(configPath), "workspace"),
21675
+ workspaceRoot: resolve29(dirname15(configPath), "workspace"),
21574
21676
  llmEnvFile: runtime.llmEnvFile,
21575
21677
  env,
21576
21678
  agent
@@ -21647,6 +21749,9 @@ async function runStoredDaemon(pathOrPointer) {
21647
21749
  console.log(`[beeline] thin daemon core ${runtime.communityId} starting with ${runtime.rooms.length} Room binding(s)`);
21648
21750
  console.log(`[body] agent binary: ${formatAgentCommand(agent)}`);
21649
21751
  console.log(`[body] ${sandbox.advisory}`);
21752
+ runScratchSweepLogged(runtimeDir);
21753
+ const scratchSweepTimer = setInterval(() => runScratchSweepLogged(runtimeDir), SCRATCH_SWEEP_INTERVAL_MS);
21754
+ scratchSweepTimer.unref();
21650
21755
  let ready = false;
21651
21756
  let stoppingStatus = "daemon stopped";
21652
21757
  try {
@@ -21744,11 +21849,12 @@ async function runStoredDaemon(pathOrPointer) {
21744
21849
  }
21745
21850
  throw error;
21746
21851
  } finally {
21852
+ clearInterval(scratchSweepTimer);
21747
21853
  await notifier.stopping(stoppingStatus).catch(() => void 0);
21748
- const pidPath = resolve28(dirname15(configPath), "daemon.pid");
21854
+ const pidPath = resolve29(dirname15(configPath), "daemon.pid");
21749
21855
  const recorded = Number((await readFile14(pidPath, "utf8").catch(() => "")).trim());
21750
21856
  if (recorded === process.pid) {
21751
- await unlink3(pidPath).catch(() => void 0);
21857
+ await unlink4(pidPath).catch(() => void 0);
21752
21858
  }
21753
21859
  }
21754
21860
  }
@@ -21773,7 +21879,7 @@ async function main() {
21773
21879
  const roomId = roomFlag >= 0 ? args[roomFlag + 1] : void 0;
21774
21880
  if (!configPath || !roomId)
21775
21881
  throw new Error("corner-read-token requires --config and --room");
21776
- const activated = await activateDaemonTransport(resolve28(configPath));
21882
+ const activated = await activateDaemonTransport(resolve29(configPath));
21777
21883
  if (!activated)
21778
21884
  throw new Error("corner-read-token requires monolith transport");
21779
21885
  const credential = await activated.client.execute("getRoomGitHubToken", { roomId });
@@ -21835,7 +21941,7 @@ async function main() {
21835
21941
  }
21836
21942
  if (!configPath)
21837
21943
  throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
21838
- await runStoredDaemon(resolve28(configPath));
21944
+ await runStoredDaemon(resolve29(configPath));
21839
21945
  return;
21840
21946
  }
21841
21947
  if (command === "update") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usebeeline",
3
- "version": "0.0.52",
3
+ "version": "0.0.54",
4
4
  "description": "Connect an AI coding agent to Beeline with one command.",
5
5
  "homepage": "https://usebeeline.app",
6
6
  "bugs": {