usebeeline 0.0.61 → 0.0.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,12 +41,12 @@ npx usebeeline connect
41
41
 
42
42
  The command asks for the pairing code shown in the Beeline app, then four questions and no more:
43
43
 
44
- | Step | What it asks |
45
- | --- | --- |
46
- | Harness | Claude Code, Codex, Goose, Pi, or Grok |
47
- | Provider | Goose and Pi only — OpenRouter (default), OpenAI, Anthropic, Google, or xAI |
48
- | API key | Goose and Pi only — verified against the provider, then saved to `~/.config/beeline/providers.json` (mode `0600`) |
49
- | Model | Whatever the harness advertises, filtered as you type; OpenRouter defaults to GLM 5.3 Flash |
44
+ | Step | What it asks |
45
+ | -------- | ----------------------------------------------------------------------------------------------------------------- |
46
+ | Harness | Claude Code, Codex, Goose, Pi, or Grok |
47
+ | Provider | Goose and Pi only — OpenRouter (default), OpenAI, Anthropic, Google, or xAI |
48
+ | API key | Goose and Pi only — verified against the provider, then saved to `~/.config/beeline/providers.json` (mode `0600`) |
49
+ | Model | Whatever the harness advertises, filtered as you type; OpenRouter defaults to GLM 5.3 Flash |
50
50
 
51
51
  It does **not** ask for a name or a soul. The server assigns the agent one of twelve animals nobody in your Workspace is already wearing, and prints it:
52
52
 
@@ -102,7 +102,7 @@ The corner receives a GitHub App token scoped to **that one repository**, instal
102
102
  - **When the sandbox cannot be built, the daemon says so and keeps serving.** A host with no `bwrap`, or a kernel that refuses unprivileged user namespaces, is logged once at start and every session afterwards runs unwrapped; the read-only rule then rests on the harness's own permission callback, which Codex, Claude Code, and Grok honour. Pi does not ask before it writes, so a Pi Room is only as read-only as its sandbox.
103
103
  - **Write access requires a corner.** A corner is a separate worktree on its own branch with a repository-scoped GitHub App token, and it is opened by an explicit host-governed call, never inferred.
104
104
  - **Reach outside the sandbox is a grant.** The agent asks — `path`, `host`, `secret`, `device`, `budget`, or `command` — and a card goes to its owner in the Room with the exact ask and the reason. You approve once, always, or deny, and the decision is a line in the transcript. Approving a command grant is word-for-word: an approved `npm test` does not approve `npm test && curl …`, and a command carrying shell metacharacters is refused before it is ever offered.
105
- - **Yolo mode** flips a single agent to auto-approval, is settable only by the agent's owner or a Workspace manager, and never covers a budget grant.
105
+ - **Yolo mode** flips a single agent to auto-approval and is settable only by that agent's owner. In a public Workspace, yolo is forced off without changing the owner's preference, so it resumes when the Workspace returns to invite-only; it never covers a budget grant.
106
106
  - **Provider keys never reach Beeline's servers.** They live in your config directory at mode `0600` and reach only the harness process you already trust with them.
107
107
  - **Honest about what is not built yet:** today a `command` grant is the one kind that actually changes what a running agent may do. `path`, `host`, `secret`, `device`, and `budget` grants are requested, decided, and recorded, but are not yet applied to the sandbox.
108
108
 
@@ -124,24 +124,24 @@ Two MCP surfaces are mounted into every agent session.
124
124
 
125
125
  `beeline-readonly-mcp` — reading, in a Room and in a corner:
126
126
 
127
- | Tool | What it does |
128
- | --- | --- |
129
- | `list_files`, `read_file` | Walk and read the checkout |
130
- | `search_text` | Search the checkout |
131
- | `git_log`, `git_show`, `git_diff`, `git_status` | Read repository history and state |
132
- | `read_agent_file` | Read the agent's approved skills or Workspace memory |
133
- | `write_memory` | Replace the agent's private Workspace `MEMORY.md` — the only memory write a Room allows |
127
+ | Tool | What it does |
128
+ | ----------------------------------------------- | --------------------------------------------------------------------------------------- |
129
+ | `list_files`, `read_file` | Walk and read the checkout |
130
+ | `search_text` | Search the checkout |
131
+ | `git_log`, `git_show`, `git_diff`, `git_status` | Read repository history and state |
132
+ | `read_agent_file` | Read the agent's approved skills or Workspace memory |
133
+ | `write_memory` | Replace the agent's private Workspace `MEMORY.md` — the only memory write a Room allows |
134
134
 
135
135
  `beeline-agent` — acting, host-governed:
136
136
 
137
- | Tool | Where | What it does |
138
- | --- | --- | --- |
139
- | `open_corner` | Top-level Rooms | Open one write-enabled corner with a ≤24-word objective |
140
- | `pr_checks_status` | Corners | Read the server-posted checks verdict and human hold state |
141
- | `attach_file` | Everywhere | Attach one file from the checkout or scratch dir to the reply |
142
- | `create_schedule`, `list_schedules`, `delete_schedule` | Everywhere | Run a prompt again later — interval minutes or a 5-field cron |
143
- | `request_grant` | Everywhere | Ask the owner for reach outside the sandbox |
144
- | `run_granted_command` | Everywhere | Run a command an approved grant covers, outside the sandbox |
137
+ | Tool | Where | What it does |
138
+ | ------------------------------------------------------ | --------------- | ------------------------------------------------------------- |
139
+ | `open_corner` | Top-level Rooms | Open one write-enabled corner with a ≤24-word objective |
140
+ | `pr_checks_status` | Corners | Read the server-posted checks verdict and human hold state |
141
+ | `attach_file` | Everywhere | Attach one file from the checkout or scratch dir to the reply |
142
+ | `create_schedule`, `list_schedules`, `delete_schedule` | Everywhere | Run a prompt again later — interval minutes or a 5-field cron |
143
+ | `request_grant` | Everywhere | Ask the owner for reach outside the sandbox |
144
+ | `run_granted_command` | Everywhere | Run a command an approved grant covers, outside the sandbox |
145
145
 
146
146
  ## The app
147
147
 
@@ -8126,6 +8126,7 @@ async function syncAgentModelCatalog(input) {
8126
8126
 
8127
8127
  // apps/body/dist/daemon-api-client.js
8128
8128
  import { resolve as resolve7 } from "node:path";
8129
+ import { randomUUID } from "node:crypto";
8129
8130
 
8130
8131
  // node_modules/ws/wrapper.mjs
8131
8132
  var import_stream = __toESM(require_stream(), 1);
@@ -16940,6 +16941,7 @@ var DaemonApiClient = class {
16940
16941
  agentId;
16941
16942
  fetchImpl;
16942
16943
  webSocketFactory;
16944
+ presenceLifecycleId = randomUUID();
16943
16945
  liveSocket;
16944
16946
  liveReconnect;
16945
16947
  liveReconnectDelayMs = 1e3;
@@ -17012,7 +17014,9 @@ var DaemonApiClient = class {
17012
17014
  ensureLiveSocket() {
17013
17015
  if (this.liveSocket || !this.liveRooms.size)
17014
17016
  return;
17015
- const socket = this.webSocketFactory(this.baseUrl.replace(/^http/, "ws") + "/v1/phone/live", [`bearer.${this.daemonToken}`]);
17017
+ const socket = this.webSocketFactory(this.baseUrl.replace(/^http/, "ws") + "/v1/phone/live", [
17018
+ `bearer.${this.daemonToken}`
17019
+ ]);
17016
17020
  this.liveSocket = socket;
17017
17021
  socket.onopen = () => {
17018
17022
  this.liveReconnectDelayMs = 1e3;
@@ -17081,6 +17085,7 @@ var DaemonApiClient = class {
17081
17085
  this.liveSocket.send(JSON.stringify({
17082
17086
  type: "subscribe",
17083
17087
  roomId,
17088
+ lifecycleId: this.presenceLifecycleId,
17084
17089
  ...room.cursor ? { cursor: room.cursor } : {},
17085
17090
  ...room.presence
17086
17091
  }));
@@ -17981,7 +17986,7 @@ import { promisify as promisify3 } from "node:util";
17981
17986
 
17982
17987
  // apps/body/dist/agent-home.js
17983
17988
  import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
17984
- import { createHash as createHash3, randomUUID } from "node:crypto";
17989
+ import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
17985
17990
  import { chmod as chmod2, copyFile, lstat, mkdir as mkdir4, readFile as readFile6, readdir as readdir2, realpath, rename as rename2, rm as rm2, symlink, unlink, writeFile as writeFile5 } from "node:fs/promises";
17986
17991
  import { homedir as homedir5 } from "node:os";
17987
17992
  import { basename as basename3, dirname as dirname5, join as join3, relative as relative2, resolve as resolve13, sep } from "node:path";
@@ -18903,7 +18908,7 @@ async function provisionManagedSkillsDir(target, managedSkills, sharedSkills, op
18903
18908
  const plan = await planManagedSkills(managedSkills, sharedSkills, optionalShares);
18904
18909
  if (await materializedSkillManifest(target) === plan.manifest)
18905
18910
  return;
18906
- const staged = resolve13(parent, `.skills.${process.pid}.${randomUUID()}.tmp`);
18911
+ const staged = resolve13(parent, `.skills.${process.pid}.${randomUUID2()}.tmp`);
18907
18912
  await mkdir4(staged, { mode: 448 });
18908
18913
  try {
18909
18914
  for (const entry of plan.entries) {
@@ -19155,7 +19160,7 @@ async function writeIsolatedHarnessFile(path, content) {
19155
19160
  if (!parentStats.isDirectory() || parentStats.isSymbolicLink()) {
19156
19161
  throw new Error(`isolated harness parent is not a real directory: ${parent}`);
19157
19162
  }
19158
- const temporary = resolve13(parent, `.${basename3(path)}.${process.pid}.${randomUUID()}.tmp`);
19163
+ const temporary = resolve13(parent, `.${basename3(path)}.${process.pid}.${randomUUID2()}.tmp`);
19159
19164
  try {
19160
19165
  await writeFile5(temporary, content, { mode: 384, flag: "wx" });
19161
19166
  await chmod2(temporary, 384);
@@ -22231,42 +22236,12 @@ var MonolithRoomTurnLoop = class {
22231
22236
  }
22232
22237
  async run() {
22233
22238
  const { api, roomId, signal } = this.options;
22234
- const status = this.options.config.modelUnavailable ? "offline" : "online";
22235
- let legacyPresence = false;
22236
- let legacyPresenceHeartbeat;
22237
- let legacyPresenceFallback;
22238
- const postLegacyPresence = async (presence) => {
22239
- await api.execute("postAgentPresence", {
22240
- agentId: this.agent.publicKey,
22241
- roomId,
22242
- status: presence,
22243
- ...this.options.config.daemonReleaseVersion ? { releaseVersion: this.options.config.daemonReleaseVersion } : {},
22244
- ...this.options.config.daemonSourceSha ? { sourceSha: this.options.config.daemonSourceSha } : {}
22245
- });
22246
- };
22247
- const useLegacyPresence = () => {
22248
- if (legacyPresence)
22249
- return;
22250
- legacyPresence = true;
22251
- void postLegacyPresence(status).catch((error) => console.error(`[thin-core] monolith Room ${roomId} presence fallback failed:`, error));
22252
- legacyPresenceHeartbeat = setInterval(() => void postLegacyPresence(status).catch((error) => console.error(`[thin-core] monolith Room ${roomId} presence fallback failed:`, error)), 3e4);
22253
- legacyPresenceHeartbeat.unref?.();
22254
- };
22255
- const stopLegacyPresence = () => {
22256
- legacyPresence = false;
22257
- clearTimeout(legacyPresenceFallback);
22258
- legacyPresenceFallback = void 0;
22259
- clearInterval(legacyPresenceHeartbeat);
22260
- legacyPresenceHeartbeat = void 0;
22261
- };
22262
22239
  let cursor3;
22263
22240
  const processedInboxIds = /* @__PURE__ */ new Set();
22264
22241
  const pushedInbox = [];
22265
22242
  let pendingPushedCursor;
22266
22243
  let liveConnected = false;
22267
22244
  let stopLive;
22268
- legacyPresenceFallback = setTimeout(useLegacyPresence, 1e3);
22269
- legacyPresenceFallback.unref?.();
22270
22245
  try {
22271
22246
  const activation = await api.execute("getRoomInbox", { roomId, startAtLatest: true });
22272
22247
  cursor3 = activation.cursor;
@@ -22280,10 +22255,6 @@ var MonolithRoomTurnLoop = class {
22280
22255
  this.wakeIntake = void 0;
22281
22256
  }, (connected, capabilities) => {
22282
22257
  liveConnected = connected && capabilities?.pushIntake === true;
22283
- if (connected && capabilities?.connectionPresence !== true)
22284
- useLegacyPresence();
22285
- else if (connected)
22286
- stopLegacyPresence();
22287
22258
  this.options.health.presence(connected && !this.options.config.modelUnavailable ? "online" : "offline");
22288
22259
  this.wakeIntake?.();
22289
22260
  this.wakeIntake = void 0;
@@ -22362,11 +22333,6 @@ var MonolithRoomTurnLoop = class {
22362
22333
  this.client.sessionCancel(this.sessionId);
22363
22334
  }
22364
22335
  await this.activeTurn?.promise;
22365
- clearTimeout(legacyPresenceFallback);
22366
- clearInterval(legacyPresenceHeartbeat);
22367
- if (legacyPresence) {
22368
- await postLegacyPresence("offline").catch((error) => console.error(`[thin-core] monolith Room ${roomId} offline presence failed:`, error));
22369
- }
22370
22336
  await this.options.scheduler.suspend(roomId);
22371
22337
  }
22372
22338
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usebeeline",
3
- "version": "0.0.61",
3
+ "version": "0.0.63",
4
4
  "description": "Connect an AI coding agent to Beeline with one command.",
5
5
  "homepage": "https://usebeeline.app",
6
6
  "bugs": {