usebeeline 0.0.107 → 0.0.108

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 +480 -86
  2. package/package.json +1 -1
@@ -3989,7 +3989,7 @@ import { constants as fsConstants2 } from "node:fs";
3989
3989
  import { access, chmod as chmod5, lstat as lstat3, mkdir as mkdir15, open, readFile as readFile10, rename as rename4, rm as rm6, symlink as symlink3, writeFile as writeFile10 } from "node:fs/promises";
3990
3990
  import { spawn as spawn6 } from "node:child_process";
3991
3991
  import { homedir as homedir9 } from "node:os";
3992
- import { dirname as dirname11, join as join9, resolve as resolve22 } from "node:path";
3992
+ import { dirname as dirname11, join as join10, resolve as resolve22 } from "node:path";
3993
3993
  function anchorLayout(rawLibDir) {
3994
3994
  const libDir = resolve22(rawLibDir);
3995
3995
  const segments = libDir.split(/[/\\]/);
@@ -4039,7 +4039,7 @@ function hostPlatformKey() {
4039
4039
  return `${os}-${arch}`;
4040
4040
  }
4041
4041
  function bundleJsonCandidates(bundleDir) {
4042
- return [join9(bundleDir, "lib", "beeline", "bundle.json"), join9(bundleDir, "bundle.json")];
4042
+ return [join10(bundleDir, "lib", "beeline", "bundle.json"), join10(bundleDir, "bundle.json")];
4043
4043
  }
4044
4044
  async function readBundleJson(bundleDir) {
4045
4045
  let raw;
@@ -4063,7 +4063,7 @@ async function readBundleJson(bundleDir) {
4063
4063
  }
4064
4064
  }
4065
4065
  function updateStatePath(layout) {
4066
- return join9(layout.releasesRoot, ".state", "update-state.json");
4066
+ return join10(layout.releasesRoot, ".state", "update-state.json");
4067
4067
  }
4068
4068
  async function readUpdateState(layout) {
4069
4069
  try {
@@ -4073,7 +4073,7 @@ async function readUpdateState(layout) {
4073
4073
  }
4074
4074
  }
4075
4075
  async function writeUpdateState(layout, state) {
4076
- await mkdir15(join9(layout.releasesRoot, ".state"), { recursive: true });
4076
+ await mkdir15(join10(layout.releasesRoot, ".state"), { recursive: true });
4077
4077
  await writeFile10(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
4078
4078
  `, "utf8");
4079
4079
  }
@@ -4155,7 +4155,7 @@ function run(command, args, timeoutMs) {
4155
4155
  });
4156
4156
  }
4157
4157
  function entrypointCandidates(bundleDir) {
4158
- return [join9(bundleDir, BUNDLE_ENTRYPOINT), join9(bundleDir, "beeline-cli.mjs")];
4158
+ return [join10(bundleDir, BUNDLE_ENTRYPOINT), join10(bundleDir, "beeline-cli.mjs")];
4159
4159
  }
4160
4160
  async function resolveBundleEntrypoint(bundleDir) {
4161
4161
  for (const candidate of entrypointCandidates(bundleDir)) {
@@ -4177,8 +4177,8 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
4177
4177
  const fetchImpl = opts.fetchImpl ?? fetch;
4178
4178
  const log2 = opts.logger ?? ((line) => console.log(`[body] self-update: ${line}`));
4179
4179
  const releaseId = sanitizeReleaseId(published.commit ?? published.version ?? `release-${Date.now()}`);
4180
- const releaseDir = join9(layout.releasesRoot, releaseId);
4181
- const okMarker = join9(releaseDir, ".stage-ok");
4180
+ const releaseDir = join10(layout.releasesRoot, releaseId);
4181
+ const okMarker = join10(releaseDir, ".stage-ok");
4182
4182
  let previouslyVerified = false;
4183
4183
  try {
4184
4184
  const recorded = await readFile10(okMarker, "utf8");
@@ -4188,7 +4188,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
4188
4188
  } catch {
4189
4189
  }
4190
4190
  await mkdir15(releaseDir, { recursive: true });
4191
- const tempArchive = join9(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
4191
+ const tempArchive = join10(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
4192
4192
  try {
4193
4193
  log2(`downloading ${published.file}`);
4194
4194
  const response = await fetchImpl(archiveUrlFor(manifestUrl, published.file), {
@@ -4228,13 +4228,13 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
4228
4228
  throw new Error(`extracting bundle failed: ${extract2.stderr}`);
4229
4229
  for (const relative3 of requiredBundlePaths()) {
4230
4230
  try {
4231
- await access(join9(releaseDir, relative3), fsConstants2.F_OK);
4231
+ await access(join10(releaseDir, relative3), fsConstants2.F_OK);
4232
4232
  } catch {
4233
4233
  throw new Error(`staged bundle is missing ${relative3}`);
4234
4234
  }
4235
4235
  }
4236
4236
  if (opts.smokeTestCli !== false) {
4237
- const probe = await run(process.execPath, [join9(releaseDir, BUNDLE_ENTRYPOINT), "--version"], 6e4);
4237
+ const probe = await run(process.execPath, [join10(releaseDir, BUNDLE_ENTRYPOINT), "--version"], 6e4);
4238
4238
  if (probe.status !== 0) {
4239
4239
  throw new Error(`staged bundle failed its startup smoke test (--version exited ${probe.status})${probe.stderr ? `: ${probe.stderr.trim()}` : ""}`);
4240
4240
  }
@@ -4272,8 +4272,8 @@ async function replaceFile(path, contents, mode) {
4272
4272
  await rename4(temp, path);
4273
4273
  }
4274
4274
  async function activateRelease(layout, releaseId) {
4275
- const releaseDir = join9(layout.releasesRoot, releaseId);
4276
- await access(join9(releaseDir, BUNDLE_ENTRYPOINT), fsConstants2.F_OK);
4275
+ const releaseDir = join10(layout.releasesRoot, releaseId);
4276
+ await access(join10(releaseDir, BUNDLE_ENTRYPOINT), fsConstants2.F_OK);
4277
4277
  await mkdir15(layout.releasesRoot, { recursive: true });
4278
4278
  await mkdir15(layout.binDir, { recursive: true });
4279
4279
  let previousReleaseId = await activeReleaseId(layout);
@@ -4281,12 +4281,12 @@ async function activateRelease(layout, releaseId) {
4281
4281
  if (kind === "directory") {
4282
4282
  const legacyIdentity = await readBundleJson(layout.libDir);
4283
4283
  const legacyId = sanitizeReleaseId(legacyIdentity?.commit ?? legacyIdentity?.version ?? `legacy-${Date.now()}`);
4284
- const legacyDir = join9(layout.releasesRoot, legacyId);
4284
+ const legacyDir = join10(layout.releasesRoot, legacyId);
4285
4285
  try {
4286
4286
  await access(legacyDir, fsConstants2.F_OK);
4287
4287
  previousReleaseId = `${legacyId}-${Date.now()}`;
4288
- await rename4(layout.libDir, join9(layout.releasesRoot, previousReleaseId));
4289
- await normalizeLegacyBundleShape(join9(layout.releasesRoot, previousReleaseId));
4288
+ await rename4(layout.libDir, join10(layout.releasesRoot, previousReleaseId));
4289
+ await normalizeLegacyBundleShape(join10(layout.releasesRoot, previousReleaseId));
4290
4290
  } catch {
4291
4291
  await rename4(layout.libDir, legacyDir);
4292
4292
  await normalizeLegacyBundleShape(legacyDir);
@@ -4295,18 +4295,18 @@ async function activateRelease(layout, releaseId) {
4295
4295
  }
4296
4296
  const tempLink = `${layout.libDir}.new-${process.pid}`;
4297
4297
  await rm6(tempLink, { force: true });
4298
- await symlink3(join9("beeline-releases", releaseId), tempLink);
4298
+ await symlink3(join10("beeline-releases", releaseId), tempLink);
4299
4299
  await rename4(tempLink, layout.libDir);
4300
4300
  await fsyncDir(dirname11(layout.libDir));
4301
4301
  await writeBinForwarders(layout, releaseDir);
4302
4302
  return { previousReleaseId };
4303
4303
  }
4304
4304
  async function normalizeLegacyBundleShape(bundleDir) {
4305
- const innerLib = join9(bundleDir, "lib", "beeline");
4305
+ const innerLib = join10(bundleDir, "lib", "beeline");
4306
4306
  let anyFlat = false;
4307
4307
  for (const name of LEGACY_FLAT_BUNDLE_FILES) {
4308
4308
  try {
4309
- await access(join9(bundleDir, name), fsConstants2.F_OK);
4309
+ await access(join10(bundleDir, name), fsConstants2.F_OK);
4310
4310
  anyFlat = true;
4311
4311
  break;
4312
4312
  } catch {
@@ -4317,11 +4317,11 @@ async function normalizeLegacyBundleShape(bundleDir) {
4317
4317
  await mkdir15(innerLib, { recursive: true });
4318
4318
  for (const name of LEGACY_FLAT_BUNDLE_FILES) {
4319
4319
  try {
4320
- await access(join9(innerLib, name), fsConstants2.F_OK);
4320
+ await access(join10(innerLib, name), fsConstants2.F_OK);
4321
4321
  continue;
4322
4322
  } catch {
4323
4323
  }
4324
- await rename4(join9(bundleDir, name), join9(innerLib, name)).catch(() => void 0);
4324
+ await rename4(join10(bundleDir, name), join10(innerLib, name)).catch(() => void 0);
4325
4325
  }
4326
4326
  }
4327
4327
  async function writeBinForwarders(layout, activeBundleRoot) {
@@ -4330,13 +4330,13 @@ async function writeBinForwarders(layout, activeBundleRoot) {
4330
4330
  ...Object.entries(FORWARDER_ALIASES).map(([alias, tool]) => [alias, tool])
4331
4331
  ];
4332
4332
  for (const [name, tool] of entries) {
4333
- const target = join9(activeBundleRoot, "bin", tool);
4333
+ const target = join10(activeBundleRoot, "bin", tool);
4334
4334
  try {
4335
4335
  await access(target, fsConstants2.X_OK);
4336
4336
  } catch {
4337
4337
  continue;
4338
4338
  }
4339
- await replaceFile(join9(layout.binDir, name), forwarderScript(tool), 493);
4339
+ await replaceFile(join10(layout.binDir, name), forwarderScript(tool), 493);
4340
4340
  }
4341
4341
  }
4342
4342
  async function repairInstallForwarders(layout, opts = {}) {
@@ -4345,7 +4345,7 @@ async function repairInstallForwarders(layout, opts = {}) {
4345
4345
  const forwarderHealthy = async (name, tool) => {
4346
4346
  let current;
4347
4347
  try {
4348
- current = await readFile10(join9(layout.binDir, name), "utf8");
4348
+ current = await readFile10(join10(layout.binDir, name), "utf8");
4349
4349
  } catch {
4350
4350
  current = void 0;
4351
4351
  }
@@ -4364,19 +4364,19 @@ async function repairInstallForwarders(layout, opts = {}) {
4364
4364
  return true;
4365
4365
  }
4366
4366
  async function rollbackToPreviousRelease(layout, previousReleaseId) {
4367
- const releaseDir = join9(layout.releasesRoot, previousReleaseId);
4367
+ const releaseDir = join10(layout.releasesRoot, previousReleaseId);
4368
4368
  const entrypoint = await resolveBundleEntrypoint(releaseDir);
4369
4369
  if (!entrypoint) {
4370
4370
  throw new Error(`release ${previousReleaseId} has no runnable CLI entrypoint`);
4371
4371
  }
4372
4372
  const tempLink = `${layout.libDir}.rollback-${process.pid}`;
4373
4373
  await rm6(tempLink, { force: true });
4374
- await symlink3(join9("beeline-releases", previousReleaseId), tempLink);
4374
+ await symlink3(join10("beeline-releases", previousReleaseId), tempLink);
4375
4375
  await rename4(tempLink, layout.libDir);
4376
4376
  await fsyncDir(dirname11(layout.libDir));
4377
4377
  }
4378
4378
  function updateAttemptPath(layout) {
4379
- return join9(layout.releasesRoot, ".state", "update-attempt.json");
4379
+ return join10(layout.releasesRoot, ".state", "update-attempt.json");
4380
4380
  }
4381
4381
  async function readUpdateAttempt(layout) {
4382
4382
  try {
@@ -4390,7 +4390,7 @@ async function readUpdateAttempt(layout) {
4390
4390
  }
4391
4391
  }
4392
4392
  async function writeUpdateAttempt(layout, record3) {
4393
- await mkdir15(join9(layout.releasesRoot, ".state"), { recursive: true });
4393
+ await mkdir15(join10(layout.releasesRoot, ".state"), { recursive: true });
4394
4394
  const path = updateAttemptPath(layout);
4395
4395
  const staged = `${path}.${process.pid}.tmp`;
4396
4396
  await writeFile10(staged, `${JSON.stringify(record3, null, 2)}
@@ -8156,6 +8156,363 @@ async function syncAgentModelCatalog(input) {
8156
8156
  }
8157
8157
  }
8158
8158
 
8159
+ // apps/body/dist/connector-google.js
8160
+ import { readFileSync as readFileSync3 } from "node:fs";
8161
+ import { join as join2 } from "node:path";
8162
+
8163
+ // apps/body/dist/google-workspace-client.js
8164
+ function credentialsTokenSource(credentials) {
8165
+ return {
8166
+ accessToken: () => Promise.resolve(credentials.accessToken),
8167
+ accountEmail: credentials.accountEmail ? () => credentials.accountEmail : void 0
8168
+ };
8169
+ }
8170
+ var defaultGoogleApiTransport = {
8171
+ async request(method, url, body, headers) {
8172
+ const response = await fetch(url, {
8173
+ method,
8174
+ headers: {
8175
+ "content-type": "application/json",
8176
+ ...headers
8177
+ },
8178
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
8179
+ });
8180
+ let json = null;
8181
+ const text2 = await response.text();
8182
+ if (text2) {
8183
+ try {
8184
+ json = JSON.parse(text2);
8185
+ } catch {
8186
+ json = { raw: text2 };
8187
+ }
8188
+ }
8189
+ return { status: response.status, json };
8190
+ }
8191
+ };
8192
+ var GoogleApiError = class extends Error {
8193
+ status;
8194
+ detail;
8195
+ constructor(status, detail) {
8196
+ super(`Google API ${status}: ${detail}`);
8197
+ this.status = status;
8198
+ this.detail = detail;
8199
+ }
8200
+ };
8201
+ var MAX_RESULTS = 25;
8202
+ function assertOk(status, json) {
8203
+ if (status >= 200 && status < 300)
8204
+ return;
8205
+ const detail = json && typeof json === "object" && "error" in json ? JSON.stringify(json.error) : `HTTP ${status}`;
8206
+ throw new GoogleApiError(status, detail);
8207
+ }
8208
+ function rfc822(input) {
8209
+ return `To: ${input.to}\r
8210
+ Subject: ${input.subject}\r
8211
+ Content-Type: text/plain; charset="UTF-8"\r
8212
+ \r
8213
+ ${input.body}`;
8214
+ }
8215
+ function googleWorkspaceClient(tokenSource, transport = defaultGoogleApiTransport) {
8216
+ const authorized = {
8217
+ async request(method, url, body) {
8218
+ const token = await tokenSource.accessToken();
8219
+ const response = await transport.request(method, url, body, {
8220
+ authorization: `Bearer ${token}`
8221
+ });
8222
+ if (response.status === 401) {
8223
+ throw new GoogleApiError(401, "access token rejected; reconnect the Google tool");
8224
+ }
8225
+ return response;
8226
+ }
8227
+ };
8228
+ const gmailFetch = async (path) => {
8229
+ const { status, json } = await authorized.request("GET", `https://gmail.googleapis.com/gmail/v1/users/me${path}`);
8230
+ assertOk(status, json);
8231
+ return json;
8232
+ };
8233
+ return {
8234
+ gmail: {
8235
+ async listMessages(query) {
8236
+ const params = new URLSearchParams({ maxResults: String(MAX_RESULTS) });
8237
+ if (query)
8238
+ params.set("q", query);
8239
+ const { status, json } = await authorized.request("GET", `https://gmail.googleapis.com/gmail/v1/users/me/messages?${params}`);
8240
+ assertOk(status, json);
8241
+ const messages = json.messages ?? [];
8242
+ return messages.map((entry) => ({ id: entry.id, snippet: entry.snippet }));
8243
+ },
8244
+ async getMessage(id) {
8245
+ const message = await gmailFetch(`/messages/${encodeURIComponent(id)}?format=metadata`);
8246
+ const snippet = typeof message.snippet === "string" ? message.snippet : void 0;
8247
+ const payload = message.payload;
8248
+ const subject = payload?.headers?.find((header) => header.name === "Subject")?.value;
8249
+ const bodyText = payload?.body?.data !== void 0 ? Buffer.from(payload.body.data, "base64url").toString("utf8") : void 0;
8250
+ return { id, snippet: subject ?? snippet, body: bodyText };
8251
+ },
8252
+ async createDraft(input) {
8253
+ const { status, json } = await authorized.request("POST", "https://gmail.googleapis.com/gmail/v1/users/me/drafts", { message: { raw: Buffer.from(rfc822(input), "utf8").toString("base64url") } });
8254
+ assertOk(status, json);
8255
+ return { id: String(json.id) };
8256
+ },
8257
+ async sendMessage(input) {
8258
+ const raw = Buffer.from(rfc822(input), "utf8").toString("base64url");
8259
+ const { status, json } = await authorized.request("POST", "https://gmail.googleapis.com/gmail/v1/users/me/messages/send", { raw });
8260
+ assertOk(status, json);
8261
+ return { id: String(json.id) };
8262
+ }
8263
+ },
8264
+ calendar: {
8265
+ async listEvents(input) {
8266
+ const params = new URLSearchParams({
8267
+ maxResults: String(input?.maxResults ?? MAX_RESULTS),
8268
+ singleEvents: "true",
8269
+ orderBy: "startTime",
8270
+ timeMin: (/* @__PURE__ */ new Date()).toISOString()
8271
+ });
8272
+ const { status, json } = await authorized.request("GET", `https://www.googleapis.com/calendar/v3/calendars/primary/events?${params}`);
8273
+ assertOk(status, json);
8274
+ const events = json.items ?? [];
8275
+ return events.map((event) => ({
8276
+ id: String(event.id),
8277
+ summary: typeof event.summary === "string" ? event.summary : void 0,
8278
+ start: event.start?.dateTime,
8279
+ end: event.end?.dateTime
8280
+ }));
8281
+ },
8282
+ async createEvent(input) {
8283
+ const { status, json } = await authorized.request("POST", `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(input.calendarId ?? "primary")}/events`, {
8284
+ summary: input.summary,
8285
+ ...input.description ? { description: input.description } : {},
8286
+ start: { dateTime: input.start },
8287
+ end: { dateTime: input.end }
8288
+ });
8289
+ assertOk(status, json);
8290
+ const event = json;
8291
+ return { id: event.id, ...event.htmlLink ? { htmlLink: event.htmlLink } : {} };
8292
+ }
8293
+ },
8294
+ drive: {
8295
+ async searchFiles(query) {
8296
+ const params = new URLSearchParams({
8297
+ q: `name contains '${query.replace(/'/g, "\\'")}' and trashed = false`,
8298
+ pageSize: String(MAX_RESULTS),
8299
+ fields: "files(id,name,mimeType)"
8300
+ });
8301
+ const { status, json } = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files?${params}`);
8302
+ assertOk(status, json);
8303
+ return (json.files ?? []).map((file) => ({
8304
+ id: String(file.id),
8305
+ name: typeof file.name === "string" ? file.name : void 0,
8306
+ mimeType: typeof file.mimeType === "string" ? file.mimeType : void 0
8307
+ }));
8308
+ },
8309
+ async readFile(fileId) {
8310
+ const meta = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}?fields=id,name`);
8311
+ assertOk(meta.status, meta.json);
8312
+ const content = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}?alt=media`);
8313
+ assertOk(content.status, content.json);
8314
+ const body = content.json;
8315
+ return {
8316
+ id: fileId,
8317
+ name: meta.json.name,
8318
+ content: body.raw ?? JSON.stringify(content.json)
8319
+ };
8320
+ }
8321
+ },
8322
+ youtube: {
8323
+ async listPlaylists(mine = true) {
8324
+ const params = new URLSearchParams({
8325
+ part: "snippet",
8326
+ maxResults: String(MAX_RESULTS),
8327
+ ...mine ? { mine: "true" } : {}
8328
+ });
8329
+ const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/playlists?${params}`);
8330
+ assertOk(status, json);
8331
+ return (json.items ?? []).map((item) => ({
8332
+ id: String(item.id),
8333
+ title: item.snippet?.title
8334
+ }));
8335
+ },
8336
+ async listPlaylistItems(playlistId) {
8337
+ const params = new URLSearchParams({
8338
+ part: "snippet",
8339
+ maxResults: String(MAX_RESULTS),
8340
+ playlistId
8341
+ });
8342
+ const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/playlistItems?${params}`);
8343
+ assertOk(status, json);
8344
+ return (json.items ?? []).map((item) => ({
8345
+ videoId: String(item.snippet?.resourceId?.videoId ?? item.id),
8346
+ title: item.snippet?.title
8347
+ }));
8348
+ },
8349
+ async getTranscript(videoId) {
8350
+ const params = new URLSearchParams({ lang: "en", v: videoId });
8351
+ const { status, json } = await authorized.request("GET", `https://video.google.com/timedtext?${params}`);
8352
+ if (status < 200 || status >= 300) {
8353
+ throw new GoogleApiError(status, `no caption track could be fetched for ${videoId} (timedtext ${status})`);
8354
+ }
8355
+ const raw = json.raw ?? "";
8356
+ const transcript = raw.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
8357
+ if (!transcript) {
8358
+ throw new GoogleApiError(404, `video ${videoId} has no fetchable captions`);
8359
+ }
8360
+ return { videoId, transcript };
8361
+ }
8362
+ },
8363
+ async verify() {
8364
+ try {
8365
+ const { status, json } = await authorized.request("GET", "https://www.googleapis.com/oauth2/v3/userinfo");
8366
+ if (status === 401)
8367
+ return { ok: false, reason: "Google rejected the access token" };
8368
+ assertOk(status, json);
8369
+ const email = json.email;
8370
+ return { ok: true, ...email ? { account: email } : {} };
8371
+ } catch (error) {
8372
+ return {
8373
+ ok: false,
8374
+ reason: error instanceof Error ? error.message : String(error)
8375
+ };
8376
+ }
8377
+ }
8378
+ };
8379
+ }
8380
+
8381
+ // apps/body/dist/connector-google.js
8382
+ var GOOGLE_TOOL_SCOPES = {
8383
+ "google-gmail": [
8384
+ "https://www.googleapis.com/auth/gmail.send",
8385
+ "https://www.googleapis.com/auth/gmail.readonly",
8386
+ "https://www.googleapis.com/auth/gmail.compose"
8387
+ ],
8388
+ "google-calendar": ["https://www.googleapis.com/auth/calendar.events", "https://www.googleapis.com/auth/calendar.readonly"],
8389
+ "google-drive": ["https://www.googleapis.com/auth/drive.readonly"],
8390
+ "google-youtube": ["https://www.googleapis.com/auth/youtube.readonly"]
8391
+ };
8392
+ function isGoogleToolConnectorType(type) {
8393
+ return type in GOOGLE_TOOL_SCOPES;
8394
+ }
8395
+ async function readGoogleCredentialsFromVault(mcp) {
8396
+ if (!mcp)
8397
+ return { source: "unavailable", reason: "no Trusty Squire connector is paired" };
8398
+ let raw;
8399
+ try {
8400
+ raw = await mcp.call("google_oauth_credentials", {});
8401
+ } catch (error) {
8402
+ return {
8403
+ source: "unavailable",
8404
+ reason: `Squire has no Google OAuth grant on record yet (connect your Google account in Squire first: ${describe(error)})`
8405
+ };
8406
+ }
8407
+ const record3 = raw && typeof raw === "object" ? raw : {};
8408
+ const inner = record3.credentials && typeof record3.credentials === "object" ? record3.credentials : record3;
8409
+ const accessToken = inner.accessToken ?? inner.access_token;
8410
+ if (!accessToken || typeof accessToken !== "string") {
8411
+ return { source: "unavailable", reason: "Squire returned a Google grant without an access token" };
8412
+ }
8413
+ return {
8414
+ source: "squire",
8415
+ credentials: {
8416
+ accessToken,
8417
+ refreshToken: typeof record3.refreshToken === "string" ? record3.refreshToken : typeof record3.refresh_token === "string" ? record3.refresh_token : void 0,
8418
+ expiresAt: typeof record3.expiresAt === "number" ? record3.expiresAt : void 0,
8419
+ accountEmail: typeof record3.accountEmail === "string" ? record3.accountEmail : typeof record3.email === "string" ? record3.email : void 0
8420
+ }
8421
+ };
8422
+ }
8423
+ function manualGoogleCredentialsSearchPaths(home) {
8424
+ return [join2(home, "google-credentials.json")];
8425
+ }
8426
+ function loadManualGoogleCredentials(home, env = process.env) {
8427
+ if (env.BEELINE_GOOGLE_ACCESS_TOKEN) {
8428
+ return {
8429
+ source: "manual",
8430
+ credentials: { accessToken: env.BEELINE_GOOGLE_ACCESS_TOKEN }
8431
+ };
8432
+ }
8433
+ for (const path of manualGoogleCredentialsSearchPaths(home)) {
8434
+ try {
8435
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
8436
+ if (typeof parsed.accessToken === "string" || typeof parsed.access_token === "string") {
8437
+ return {
8438
+ source: "manual",
8439
+ credentials: {
8440
+ accessToken: parsed.accessToken ?? parsed.access_token,
8441
+ refreshToken: typeof parsed.refreshToken === "string" ? parsed.refreshToken : void 0,
8442
+ accountEmail: typeof parsed.accountEmail === "string" ? parsed.accountEmail : void 0
8443
+ }
8444
+ };
8445
+ }
8446
+ } catch {
8447
+ }
8448
+ }
8449
+ return {
8450
+ source: "manual-missing",
8451
+ reason: `no Google credentials found. Put a google-credentials.json (OAuth access token) at ${manualGoogleCredentialsSearchPaths(home)[0]} or connect your Google account in Trusty Squire first.`
8452
+ };
8453
+ }
8454
+ var step = (label, status, extra) => ({
8455
+ label,
8456
+ status,
8457
+ ...extra
8458
+ });
8459
+ function outputTail(text2, maxChars = 800) {
8460
+ const trimmed = text2.trim();
8461
+ return trimmed.length <= maxChars ? trimmed : `\u2026${trimmed.slice(-maxChars)}`;
8462
+ }
8463
+ async function installGoogleTool(options) {
8464
+ const steps = [step("helper reached", "done")];
8465
+ const emit = () => options.onProgress?.([...steps]);
8466
+ const push = (next) => {
8467
+ steps.push(next);
8468
+ emit();
8469
+ };
8470
+ const fail = (label, reason, output) => {
8471
+ push(step(label, "failed", { reason, ...output ? { output } : {} }));
8472
+ return { status: "error", steps, errorMessage: reason };
8473
+ };
8474
+ emit();
8475
+ if (!isGoogleToolConnectorType(options.connectorType)) {
8476
+ return fail("connector type", `${options.connectorType} is not a Google tool connector`);
8477
+ }
8478
+ push(step("Google credentials resolved", "running", { output: "resolving\u2026" }));
8479
+ const resolved = options.resolveCredentials ? await options.resolveCredentials() : await (async () => {
8480
+ const oneClick = await readGoogleCredentialsFromVault(options.squire);
8481
+ return oneClick.source === "squire" ? { ...oneClick } : { ...loadManualGoogleCredentials(options.home, options.env) };
8482
+ })();
8483
+ if (!("credentials" in resolved)) {
8484
+ const reason = resolved.reason;
8485
+ steps[1] = step("Google credentials resolved", "failed", { reason, output: outputTail(reason) });
8486
+ emit();
8487
+ return { status: "error", steps, errorMessage: reason };
8488
+ }
8489
+ steps[1] = step("Google credentials resolved", "done", {
8490
+ output: resolved.source === "squire" ? "one-click: read the Google grant from Trusty Squire" : "manual: local google-credentials.json"
8491
+ });
8492
+ emit();
8493
+ const client = options.client ?? googleWorkspaceClient(credentialsTokenSource(resolved.credentials));
8494
+ push(step("authorized with Google", "running", { output: "verifying the grant with Google\u2026" }));
8495
+ const verify = await client.verify();
8496
+ if (!verify.ok) {
8497
+ return fail("authorized with Google", verify.reason, outputTail(verify.reason));
8498
+ }
8499
+ steps[2] = step("authorized with Google", "done", {
8500
+ ...verify.account ? { output: `signed in as ${verify.account}` } : {}
8501
+ });
8502
+ emit();
8503
+ push(step("tools enabled", "done", {
8504
+ output: `${GOOGLE_TOOL_SCOPES[options.connectorType].length} Google scopes granted`
8505
+ }));
8506
+ return {
8507
+ status: "connected",
8508
+ steps,
8509
+ ...verify.account ? { signedInAs: verify.account } : {}
8510
+ };
8511
+ }
8512
+ function describe(error) {
8513
+ return error instanceof Error ? error.message : String(error);
8514
+ }
8515
+
8159
8516
  // apps/body/dist/connector-squire.js
8160
8517
  import { execFile, spawn as spawn2 } from "node:child_process";
8161
8518
  var SQUIRE_CONNECT_PACKAGE = "@trusty-squire/mcp@next";
@@ -8221,7 +8578,7 @@ ${stderr}`;
8221
8578
  } });
8222
8579
  });
8223
8580
  });
8224
- var step = (label, status, reason) => ({
8581
+ var step2 = (label, status, reason) => ({
8225
8582
  label,
8226
8583
  status,
8227
8584
  ...reason ? { reason } : {}
@@ -8249,14 +8606,14 @@ function parseSignedInAs(output) {
8249
8606
  async function installSquire(options) {
8250
8607
  const run2 = options.run ?? defaultShellRunner;
8251
8608
  const streamRun = options.streamRun ?? defaultStreamedRunner;
8252
- const steps = [step("helper reached", "done")];
8609
+ const steps = [step2("helper reached", "done")];
8253
8610
  const emit = () => options.onProgress?.([...steps]);
8254
8611
  const push = (next) => {
8255
8612
  steps.push(next);
8256
8613
  emit();
8257
8614
  };
8258
8615
  const fail = (reason) => {
8259
- steps.push(step("waiting for sign-in", "pending"));
8616
+ steps.push(step2("waiting for sign-in", "pending"));
8260
8617
  emit();
8261
8618
  return { status: "error", steps, errorMessage: reason };
8262
8619
  };
@@ -8271,18 +8628,18 @@ async function installSquire(options) {
8271
8628
  ]);
8272
8629
  if (!install.signIn) {
8273
8630
  const stderr = install.stderr.trim();
8274
- push(step("trusty-squire installed", "failed", stderr || "connect printed no sign-in URL"));
8631
+ push(step2("trusty-squire installed", "failed", stderr || "connect printed no sign-in URL"));
8275
8632
  return fail(stderr || "the trusty-squire connect command printed no sign-in surface");
8276
8633
  }
8277
8634
  const version = await installedSquireVersion(run2);
8278
- push(step(`trusty-squire${version ? ` ${version}` : ""} installed`, "done"));
8635
+ push(step2(`trusty-squire${version ? ` ${version}` : ""} installed`, "done"));
8279
8636
  const signIn = install.signIn;
8280
8637
  const signedInAs = parseSignedInAs(`${install.stdout}
8281
8638
  ${install.stderr}`);
8282
- push(step("waiting for sign-in", "done"));
8639
+ push(step2("waiting for sign-in", "done"));
8283
8640
  const pair = await pairSquire(options.mcp, options.workspaceId);
8284
8641
  if (!pair.ok) {
8285
- push(step("paired to workspace", "failed", pair.reason));
8642
+ push(step2("paired to workspace", "failed", pair.reason));
8286
8643
  return {
8287
8644
  status: "installing",
8288
8645
  steps,
@@ -8291,7 +8648,7 @@ ${install.stderr}`);
8291
8648
  ...signedInAs ? { signedInAs } : {}
8292
8649
  };
8293
8650
  }
8294
- push(step("paired to workspace", "done"));
8651
+ push(step2("paired to workspace", "done"));
8295
8652
  return {
8296
8653
  status: "connected",
8297
8654
  steps,
@@ -8523,6 +8880,8 @@ var ConnectorAssignmentLoop = class {
8523
8880
  intervalMs;
8524
8881
  log;
8525
8882
  install;
8883
+ installGoogle;
8884
+ googleHomeDir;
8526
8885
  readVaultFn;
8527
8886
  revokeGrantsFn;
8528
8887
  schedule;
@@ -8540,6 +8899,8 @@ var ConnectorAssignmentLoop = class {
8540
8899
  this.log = options.log ?? (() => {
8541
8900
  });
8542
8901
  this.install = options.install ?? installSquire;
8902
+ this.installGoogle = options.installGoogle ?? ((connectorType, onProgress) => installGoogleTool({ connectorType, home: this.googleHome(), onProgress }));
8903
+ this.googleHomeDir = options.googleHome ?? process.env.BEELINE_AGENT_HOME ?? process.cwd();
8543
8904
  this.readVaultFn = options.readVault ?? readVault;
8544
8905
  this.revokeGrantsFn = options.revokeGrants ?? revokeGrants;
8545
8906
  this.schedule = options.schedule ?? ((fn, ms) => {
@@ -8577,7 +8938,7 @@ var ConnectorAssignmentLoop = class {
8577
8938
  const result = await this.api.execute("getConnectorAssignments", { agentId: this.agentId });
8578
8939
  assignments = result.assignments;
8579
8940
  } catch (error) {
8580
- this.log(`connector assignments unavailable: ${describe(error)}`);
8941
+ this.log(`connector assignments unavailable: ${describe2(error)}`);
8581
8942
  return;
8582
8943
  }
8583
8944
  for (const assignment of assignments) {
@@ -8587,7 +8948,7 @@ var ConnectorAssignmentLoop = class {
8587
8948
  if (this.inFlight.has(key))
8588
8949
  continue;
8589
8950
  this.inFlight.add(key);
8590
- void this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${describe(error)}`)).finally(() => this.inFlight.delete(key));
8951
+ void this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${describe2(error)}`)).finally(() => this.inFlight.delete(key));
8591
8952
  }
8592
8953
  }
8593
8954
  squire() {
@@ -8595,20 +8956,53 @@ var ConnectorAssignmentLoop = class {
8595
8956
  return this.mcp;
8596
8957
  }
8597
8958
  async handle(assignment) {
8598
- if (assignment.kind === "install")
8599
- await this.runInstall(assignment.connectorId);
8600
- else if (assignment.kind === "sync")
8959
+ if (assignment.kind === "install") {
8960
+ if (isGoogleToolConnectorType(assignment.connectorType)) {
8961
+ await this.runGoogleInstall(assignment.connectorId, assignment.connectorType);
8962
+ } else {
8963
+ await this.runInstall(assignment.connectorId);
8964
+ }
8965
+ } else if (assignment.kind === "sync")
8601
8966
  await this.runSync();
8602
8967
  else if (assignment.kind === "revoke-grants")
8603
8968
  await this.runRevoke(assignment.connectorId, assignment.reference);
8604
8969
  }
8970
+ /** Google tool connectors keep their manual credentials next to the runtime. */
8971
+ googleHome() {
8972
+ return this.googleHomeDir;
8973
+ }
8974
+ /** Install one Google tool connector (Gmail/Calendar/Drive/YouTube). */
8975
+ async runGoogleInstall(connectorId, connectorType) {
8976
+ const report = async (steps) => {
8977
+ try {
8978
+ await this.api.execute("postConnectorStatus", { agentId: this.agentId, connectorId, steps });
8979
+ } catch (error) {
8980
+ this.log(`step report failed: ${describe2(error)}`);
8981
+ }
8982
+ };
8983
+ const result = await this.installGoogle(connectorType, report);
8984
+ if (result.status === "error") {
8985
+ await this.api.execute("postConnectorStatus", {
8986
+ agentId: this.agentId,
8987
+ connectorId,
8988
+ steps: result.steps,
8989
+ errorMessage: result.errorMessage
8990
+ });
8991
+ return;
8992
+ }
8993
+ await this.api.execute("installConnector", {
8994
+ agentId: this.agentId,
8995
+ connectorId,
8996
+ ...result.signedInAs ? { signedInAs: result.signedInAs } : {}
8997
+ });
8998
+ }
8605
8999
  /** Install Trusty Squire, reporting every step as it settles. */
8606
9000
  async runInstall(connectorId) {
8607
9001
  const report = async (steps) => {
8608
9002
  try {
8609
9003
  await this.api.execute("postConnectorStatus", { agentId: this.agentId, connectorId, steps });
8610
9004
  } catch (error) {
8611
- this.log(`step report failed: ${describe(error)}`);
9005
+ this.log(`step report failed: ${describe2(error)}`);
8612
9006
  }
8613
9007
  };
8614
9008
  const result = await this.install({
@@ -8659,7 +9053,7 @@ var ConnectorAssignmentLoop = class {
8659
9053
  await this.api.execute("postConnectorVault", { agentId: this.agentId, connections });
8660
9054
  }
8661
9055
  };
8662
- function describe(error) {
9056
+ function describe2(error) {
8663
9057
  return error instanceof Error ? error.message : String(error);
8664
9058
  }
8665
9059
 
@@ -13109,7 +13503,7 @@ function alphabet(letters) {
13109
13503
  };
13110
13504
  }
13111
13505
  // @__NO_SIDE_EFFECTS__
13112
- function join2(separator = "") {
13506
+ function join3(separator = "") {
13113
13507
  astr("join", separator);
13114
13508
  return {
13115
13509
  encode: (from) => {
@@ -13239,8 +13633,8 @@ var base64 = hasBase64Builtin ? {
13239
13633
  decode(s) {
13240
13634
  return decodeBase64Builtin(s, false);
13241
13635
  }
13242
- } : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join2(""));
13243
- var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join2(""));
13636
+ } : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join3(""));
13637
+ var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join3(""));
13244
13638
  var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
13245
13639
  function bech32Polymod(pre) {
13246
13640
  const b = pre >> 25;
@@ -16845,13 +17239,13 @@ var NegentropyStorageVector = class {
16845
17239
  let count = last - first;
16846
17240
  while (count > 0) {
16847
17241
  let it = first;
16848
- let step2 = Math.floor(count / 2);
16849
- it += step2;
17242
+ let step3 = Math.floor(count / 2);
17243
+ it += step3;
16850
17244
  if (cmp(arr[it])) {
16851
17245
  first = ++it;
16852
- count -= step2 + 1;
17246
+ count -= step3 + 1;
16853
17247
  } else {
16854
- count = step2;
17248
+ count = step3;
16855
17249
  }
16856
17250
  }
16857
17251
  return first;
@@ -18656,13 +19050,13 @@ function captureConnectionUsage(recorder, turn, calls) {
18656
19050
  import { randomUUID as randomUUID2 } from "node:crypto";
18657
19051
  import { mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
18658
19052
  import { tmpdir as tmpdir2 } from "node:os";
18659
- import { dirname as dirname5, join as join3 } from "node:path";
19053
+ import { dirname as dirname5, join as join4 } from "node:path";
18660
19054
  var CommandExecutionContext = class {
18661
19055
  generationId = randomUUID2();
18662
19056
  path;
18663
19057
  current;
18664
19058
  constructor(root) {
18665
- this.path = join3(root ?? tmpdir2(), `beeline-command-${this.generationId}.json`);
19059
+ this.path = join4(root ?? tmpdir2(), `beeline-command-${this.generationId}.json`);
18666
19060
  }
18667
19061
  async enter(command) {
18668
19062
  this.current = command;
@@ -18823,18 +19217,18 @@ import { execFile as execFile5 } from "node:child_process";
18823
19217
  import { createHash as createHash5 } from "node:crypto";
18824
19218
  import { mkdir as mkdir12 } from "node:fs/promises";
18825
19219
  import { homedir as homedir7 } from "node:os";
18826
- import { join as join8 } from "node:path";
19220
+ import { join as join9 } from "node:path";
18827
19221
  import { promisify as promisify3 } from "node:util";
18828
19222
 
18829
19223
  // apps/body/dist/agent-home.js
18830
- import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
19224
+ import { existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
18831
19225
  import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
18832
19226
  import { chmod as chmod2, copyFile, lstat, mkdir as mkdir5, readFile as readFile6, readdir as readdir2, realpath, rename as rename2, rm as rm2, symlink, unlink, writeFile as writeFile6 } from "node:fs/promises";
18833
19227
  import { homedir as homedir5 } from "node:os";
18834
- import { basename as basename3, dirname as dirname6, join as join4, relative as relative2, resolve as resolve13, sep } from "node:path";
19228
+ import { basename as basename3, dirname as dirname6, join as join5, relative as relative2, resolve as resolve13, sep } from "node:path";
18835
19229
 
18836
19230
  // apps/body/dist/beeline-skill.js
18837
- import { readFileSync as readFileSync3 } from "node:fs";
19231
+ import { readFileSync as readFileSync4 } from "node:fs";
18838
19232
  import { resolve as resolve11 } from "node:path";
18839
19233
 
18840
19234
  // packages/api-contract/dist/agent-pairing-code.js
@@ -18898,7 +19292,7 @@ function beelineCapabilityContextForHarness(agentCommand, repository, directMess
18898
19292
  ...harnessHonorsSessionSystemPrompt(agentCommand) ? {} : { compatibilityTurnPrefix: primer }
18899
19293
  };
18900
19294
  }
18901
- function runningBeelineReleaseId(env = process.env, read = (path) => readFileSync3(path, "utf8")) {
19295
+ function runningBeelineReleaseId(env = process.env, read = (path) => readFileSync4(path, "utf8")) {
18902
19296
  try {
18903
19297
  const lib = env.BEELINE_LIB_DIR;
18904
19298
  if (!lib)
@@ -19704,7 +20098,7 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
19704
20098
  try {
19705
20099
  const source = resolve13(operatorHome, config.toml);
19706
20100
  const target = resolve13(root, config.dir, "config.toml");
19707
- const mcpSection = existsSync3(source) ? filteredHarnessMcpToml(readFileSync4(source, "utf8")) : void 0;
20101
+ const mcpSection = existsSync3(source) ? filteredHarnessMcpToml(readFileSync5(source, "utf8")) : void 0;
19708
20102
  const section = config.dir === "codex" ? [CODEX_ROOM_AGENT_LOCKDOWN_TOML, CODEX_ROOM_WEB_SEARCH_TOML, mcpSection].filter(Boolean).join("\n") : mcpSection;
19709
20103
  if (!section) {
19710
20104
  await unlink(target).catch(() => void 0);
@@ -19724,7 +20118,7 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
19724
20118
  const source = resolve13(operatorHome, ".config", "goose", name);
19725
20119
  const target = resolve13(gooseConfigDir, name);
19726
20120
  if (existsSync3(source)) {
19727
- await writeIsolatedHarnessFile(target, readFileSync4(source, "utf8"));
20121
+ await writeIsolatedHarnessFile(target, readFileSync5(source, "utf8"));
19728
20122
  } else {
19729
20123
  await unlink(target).catch(() => void 0);
19730
20124
  }
@@ -19795,7 +20189,7 @@ async function provisionPiCustomModelConfig(root, operatorHome, failClosed, open
19795
20189
  if (resolvedSource !== source) {
19796
20190
  throw new AgentHomeSecurityError(`Pi custom model config resolves through a link: ${source}`);
19797
20191
  }
19798
- const sourceValue = JSON.parse(readFileSync4(resolvedSource, "utf8"));
20192
+ const sourceValue = JSON.parse(readFileSync5(resolvedSource, "utf8"));
19799
20193
  await writeIsolatedHarnessFile(target, `${JSON.stringify(withOpenRouterModelRouting(sourceValue, pin), null, 2)}
19800
20194
  `);
19801
20195
  } catch (error) {
@@ -19807,7 +20201,7 @@ async function provisionPiCustomModelConfig(root, operatorHome, failClosed, open
19807
20201
  }
19808
20202
  function readClaudeUserScopeMcpServers(path) {
19809
20203
  try {
19810
- const parsed = JSON.parse(readFileSync4(path, "utf8"));
20204
+ const parsed = JSON.parse(readFileSync5(path, "utf8"));
19811
20205
  if (parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null) {
19812
20206
  return Object.fromEntries(Object.entries(parsed.mcpServers).filter(([name, value]) => {
19813
20207
  if (name === "squire")
@@ -19872,8 +20266,8 @@ async function planManagedSkills(managedSkills, sharedSkills, optionalShares) {
19872
20266
  try {
19873
20267
  const tree = [];
19874
20268
  await walkSafeSkillTree(shared.source, shared.source, {
19875
- directory: async (rel) => void tree.push(`d ${join4(shared.name, rel)}`),
19876
- file: async (rel, realPath) => void tree.push(`f ${join4(shared.name, rel)} ${sha2563(await readFile6(realPath))}`)
20269
+ directory: async (rel) => void tree.push(`d ${join5(shared.name, rel)}`),
20270
+ file: async (rel, realPath) => void tree.push(`f ${join5(shared.name, rel)} ${sha2563(await readFile6(realPath))}`)
19877
20271
  });
19878
20272
  entries.push({ kind: "shared", name: shared.name, source: shared.source });
19879
20273
  lines.push(...tree);
@@ -19893,7 +20287,7 @@ async function materializedSkillManifest(target) {
19893
20287
  const visit = async (directory, prefix) => {
19894
20288
  for (const entry of await readdir2(directory)) {
19895
20289
  const path = resolve13(directory, entry);
19896
- const rel = prefix ? join4(prefix, entry) : entry;
20290
+ const rel = prefix ? join5(prefix, entry) : entry;
19897
20291
  const entryStats = await lstat(path);
19898
20292
  if (entryStats.isSymbolicLink())
19899
20293
  return false;
@@ -20061,7 +20455,7 @@ async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
20061
20455
  for (const entry of await readdir2(resolvedSource)) {
20062
20456
  if (entry === "." || entry === "..")
20063
20457
  throw new Error("invalid shared skill entry");
20064
- await walkSafeSkillTree(resolve13(source, entry), sourceRoot, visitor, rel ? join4(rel, entry) : entry);
20458
+ await walkSafeSkillTree(resolve13(source, entry), sourceRoot, visitor, rel ? join5(rel, entry) : entry);
20065
20459
  }
20066
20460
  return;
20067
20461
  }
@@ -20134,7 +20528,7 @@ function harnessStateDirsFromEnv(env) {
20134
20528
 
20135
20529
  // apps/body/dist/attachment-delivery.js
20136
20530
  import { mkdir as mkdir6, writeFile as writeFile7 } from "node:fs/promises";
20137
- import { basename as basename4, extname, join as join5 } from "node:path";
20531
+ import { basename as basename4, extname, join as join6 } from "node:path";
20138
20532
  var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
20139
20533
  var MEDIA_TTL_HOURS = 24;
20140
20534
  var EXPIRED_REASON = `expired: attachments are kept for ${MEDIA_TTL_HOURS} hours and these bytes are past that window`;
@@ -20178,7 +20572,7 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
20178
20572
  const bytes = Buffer.from(await response.arrayBuffer());
20179
20573
  if (bytes.length > MAX_ATTACHMENT_BYTES)
20180
20574
  return tooLarge(bytes.length);
20181
- const path = join5(dir, safeFileName(attachment, index, taken));
20575
+ const path = join6(dir, safeFileName(attachment, index, taken));
20182
20576
  await writeFile7(path, bytes);
20183
20577
  const mimeType = attachment.mimeType ?? response.headers.get("content-type") ?? "";
20184
20578
  if (!mimeType.startsWith("image/"))
@@ -21685,7 +22079,7 @@ process.exit(result.status ?? 1);
21685
22079
  import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
21686
22080
  import { constants as fsConstants } from "node:fs";
21687
22081
  import { chmod as chmod4, copyFile as copyFile2, link, lstat as lstat2, mkdir as mkdir10, readdir as readdir5, readFile as readFile8, readlink, rename as rename3, rm as rm4, stat as stat2, symlink as symlink2, utimes } from "node:fs/promises";
21688
- import { dirname as dirname7, join as join6, resolve as resolve19 } from "node:path";
22082
+ import { dirname as dirname7, join as join7, resolve as resolve19 } from "node:path";
21689
22083
  var STORE_FORMAT = "v1";
21690
22084
  var STAGING_PREFIX = ".beeline-warm-";
21691
22085
  var STAGING_SWEEP_MS = 24 * 60 * 60 * 1e3;
@@ -21773,7 +22167,7 @@ async function seedWarmNodeModules(input) {
21773
22167
  for (const target of placed) {
21774
22168
  await rm4(target, { recursive: true, force: true }).catch(() => void 0);
21775
22169
  }
21776
- return { reason: "failed", key: plan.key, detail: describe2(error) };
22170
+ return { reason: "failed", key: plan.key, detail: describe3(error) };
21777
22171
  } finally {
21778
22172
  await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
21779
22173
  }
@@ -21816,7 +22210,7 @@ async function harvestWarmNodeModules(input) {
21816
22210
  } catch (error) {
21817
22211
  if (await pathExists(entry))
21818
22212
  return { reason: "already-warm", key: plan.key };
21819
- return { reason: "failed", key: plan.key, detail: describe2(error) };
22213
+ return { reason: "failed", key: plan.key, detail: describe3(error) };
21820
22214
  } finally {
21821
22215
  await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
21822
22216
  }
@@ -21825,7 +22219,7 @@ async function stagedTreeIsPublishable(worktreePath, staging, key) {
21825
22219
  const settled = await readWarmPlan(worktreePath);
21826
22220
  if (isPlanRefusal(settled) || settled.key !== key)
21827
22221
  return false;
21828
- const hidden = join6("node_modules", ".package-lock.json");
22222
+ const hidden = join7("node_modules", ".package-lock.json");
21829
22223
  const [copied, current] = await Promise.all([
21830
22224
  readFile8(resolve19(staging, hidden)).catch(() => void 0),
21831
22225
  readFile8(resolve19(worktreePath, hidden)).catch(() => void 0)
@@ -21863,7 +22257,7 @@ async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
21863
22257
  return missing.sort();
21864
22258
  }
21865
22259
  async function isInstalledPackage(path) {
21866
- return stat2(join6(path, "package.json")).then((info) => info.isFile(), () => false);
22260
+ return stat2(join7(path, "package.json")).then((info) => info.isFile(), () => false);
21867
22261
  }
21868
22262
  var INTEGRITY_READ_CONCURRENCY = 64;
21869
22263
  async function mapWithLimit(values, limit, visit) {
@@ -21897,8 +22291,8 @@ function isContainedTreePath(value) {
21897
22291
  async function cloneTree(source, target, file, topLevel = true) {
21898
22292
  await mkdir10(target, { recursive: true, mode: 493 });
21899
22293
  for (const entry of await readdir5(source, { withFileTypes: true })) {
21900
- const from = join6(source, entry.name);
21901
- const to = join6(target, entry.name);
22294
+ const from = join7(source, entry.name);
22295
+ const to = join7(target, entry.name);
21902
22296
  if (entry.isSymbolicLink()) {
21903
22297
  await symlink2(await readlink(from), to);
21904
22298
  continue;
@@ -21928,13 +22322,13 @@ async function pruneWarmStore(storeRoot, keep) {
21928
22322
  const names = (await readdir5(storeRoot).catch(() => [])).filter((name) => !name.startsWith(STAGING_PREFIX));
21929
22323
  const entries = [];
21930
22324
  for (const name of names) {
21931
- const info = await lstat2(join6(storeRoot, name)).catch(() => void 0);
22325
+ const info = await lstat2(join7(storeRoot, name)).catch(() => void 0);
21932
22326
  if (info?.isDirectory())
21933
22327
  entries.push({ name, usedAt: info.mtimeMs });
21934
22328
  }
21935
22329
  const dropped = entries.sort((a2, b) => b.usedAt - a2.usedAt || a2.name.localeCompare(b.name)).slice(keep);
21936
22330
  for (const entry of dropped) {
21937
- await rm4(join6(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
22331
+ await rm4(join7(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
21938
22332
  }
21939
22333
  return dropped.map((entry) => entry.name);
21940
22334
  }
@@ -21943,7 +22337,7 @@ async function sweepStaleStaging(storeRoot, now2) {
21943
22337
  for (const name of entries) {
21944
22338
  if (!name.startsWith(STAGING_PREFIX))
21945
22339
  continue;
21946
- const path = join6(storeRoot, name);
22340
+ const path = join7(storeRoot, name);
21947
22341
  const info = await lstat2(path).catch(() => void 0);
21948
22342
  if (!info || now2 - info.mtimeMs < STAGING_SWEEP_MS)
21949
22343
  continue;
@@ -21959,14 +22353,14 @@ async function deviceOf(path) {
21959
22353
  async function isDirectory(path) {
21960
22354
  return stat2(path).then((info) => info.isDirectory(), () => false);
21961
22355
  }
21962
- function describe2(error) {
22356
+ function describe3(error) {
21963
22357
  return error instanceof Error ? error.message : String(error);
21964
22358
  }
21965
22359
 
21966
22360
  // apps/body/dist/monolith-room-turn.js
21967
22361
  import { mkdir as mkdir11 } from "node:fs/promises";
21968
22362
  import { homedir as homedir6 } from "node:os";
21969
- import { join as join7 } from "node:path";
22363
+ import { join as join8 } from "node:path";
21970
22364
 
21971
22365
  // packages/api-contract/dist/scheduled-prompts.js
21972
22366
  var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
@@ -22169,7 +22563,7 @@ var MonolithRoomTurnLoop = class {
22169
22563
  const cached = this.deliveredAttachments.get(item.id);
22170
22564
  if (cached)
22171
22565
  return cached;
22172
- const delivered = await deliverAttachments(item.attachments, join7(this.attachmentDir, item.id.replace(/[^\w-]/g, "_")), this.options.fetchImpl);
22566
+ const delivered = await deliverAttachments(item.attachments, join8(this.attachmentDir, item.id.replace(/[^\w-]/g, "_")), this.options.fetchImpl);
22173
22567
  this.deliveredAttachments.set(item.id, withoutImageData(delivered));
22174
22568
  return delivered;
22175
22569
  }
@@ -22265,7 +22659,7 @@ var MonolithRoomTurnLoop = class {
22265
22659
  }, selection);
22266
22660
  const operatorHome = this.options.config.operatorHome ?? homedir6();
22267
22661
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
22268
- this.attachmentDir = tmpDir ? join7(tmpDir, "beeline-attachments") : void 0;
22662
+ this.attachmentDir = tmpDir ? join8(tmpDir, "beeline-attachments") : void 0;
22269
22663
  this.sessionScratchDir = tmpDir;
22270
22664
  this.sessionStateDirs = stateDirs;
22271
22665
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
@@ -23168,7 +23562,7 @@ var MonolithCornerTurnLoop = class {
23168
23562
  }, selection);
23169
23563
  const operatorHome = this.options.config.operatorHome ?? homedir7();
23170
23564
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
23171
- this.attachmentDir = tmpDir ? join8(tmpDir, "beeline-attachments") : void 0;
23565
+ this.attachmentDir = tmpDir ? join9(tmpDir, "beeline-attachments") : void 0;
23172
23566
  this.sessionScratchDir = tmpDir;
23173
23567
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
23174
23568
  await Promise.all(homeStateDirs.map((dir) => mkdir12(dir, { recursive: true })));
@@ -23389,7 +23783,7 @@ var MonolithCornerTurnLoop = class {
23389
23783
  const [conversation, roster, delivered] = await trace.measure("context-fetch", () => Promise.all([
23390
23784
  api.execute("getRoomConversation", { roomId: cornerId, limit: 200 }),
23391
23785
  this.roster(),
23392
- this.attachmentDir && attachments.length ? deliverAttachments(attachments, join8(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : Promise.resolve([])
23786
+ this.attachmentDir && attachments.length ? deliverAttachments(attachments, join9(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : Promise.resolve([])
23393
23787
  ]));
23394
23788
  const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
23395
23789
  const requestedBy = requester && !requester.name && names.get(requester.pubkey) ? { ...requester, name: names.get(requester.pubkey) } : requester;
@@ -27195,7 +27589,7 @@ async function runUpdateFunctionalProbe(input) {
27195
27589
 
27196
27590
  // apps/body/dist/current-release-probe.js
27197
27591
  import { spawn as spawn9 } from "node:child_process";
27198
- import { dirname as dirname16, join as join10 } from "node:path";
27592
+ import { dirname as dirname16, join as join11 } from "node:path";
27199
27593
  init_self_update();
27200
27594
  var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
27201
27595
  var UPDATE_PROBE_COMMAND = "update-probe";
@@ -27238,7 +27632,7 @@ function outcomeFromReport(report) {
27238
27632
  }
27239
27633
  }
27240
27634
  async function probeReleaseInSubprocess(input) {
27241
- const bundleDir = join10(input.layout.releasesRoot, input.releaseId);
27635
+ const bundleDir = join11(input.layout.releasesRoot, input.releaseId);
27242
27636
  const entrypoint = await resolveBundleEntrypoint(bundleDir);
27243
27637
  if (!entrypoint) {
27244
27638
  return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
@@ -27301,7 +27695,7 @@ async function runUpdateProbeCommand(args, options = {}) {
27301
27695
  const runtime = await readRuntimeRecord(configPath);
27302
27696
  const agent = runtimeAgentCommand(runtime);
27303
27697
  const config = loadBodyConfig({
27304
- workspaceRoot: join10(dirname16(configPath), "workspace"),
27698
+ workspaceRoot: join11(dirname16(configPath), "workspace"),
27305
27699
  llmEnvFile: runtime.llmEnvFile,
27306
27700
  env: { ...env, BUZZ_AGENT_BIN: agent.command, BUZZ_DEV_MCP_BIN: runtime.mcpBinary },
27307
27701
  agent
@@ -27327,7 +27721,7 @@ async function runUpdateProbeCommand(args, options = {}) {
27327
27721
  sandboxRequired: runtime.sandbox !== "off",
27328
27722
  sandboxUnavailableDetail: sandbox.advisory,
27329
27723
  // The successor's probe still holds `<runtimeDir>/update-functional-probe`.
27330
- probeRoot: join10(runtimeDir, "current-release-probe")
27724
+ probeRoot: join11(runtimeDir, "current-release-probe")
27331
27725
  }));
27332
27726
  const report = outcome.kind === "served" ? { probe: "served" } : outcome.kind === "refused" ? { probe: "refused", status: outcome.status, reason: outcome.reason } : outcome.kind === "sandbox-unavailable" ? { probe: "sandbox-unavailable", reason: outcome.reason } : { probe: "failed", reason: outcome.reason };
27333
27727
  write(JSON.stringify(report));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usebeeline",
3
- "version": "0.0.107",
3
+ "version": "0.0.108",
4
4
  "description": "Connect an AI coding agent to Beeline with one command.",
5
5
  "homepage": "https://usebeeline.app",
6
6
  "bugs": {