usebeeline 0.0.108 → 0.0.109

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 +147 -24
  2. package/package.json +1 -1
@@ -8476,7 +8476,7 @@ async function installGoogleTool(options) {
8476
8476
  return fail("connector type", `${options.connectorType} is not a Google tool connector`);
8477
8477
  }
8478
8478
  push(step("Google credentials resolved", "running", { output: "resolving\u2026" }));
8479
- const resolved = options.resolveCredentials ? await options.resolveCredentials() : await (async () => {
8479
+ const resolved = options.resolvedCredentials ? await options.resolvedCredentials : options.resolveCredentials ? await options.resolveCredentials() : await (async () => {
8480
8480
  const oneClick = await readGoogleCredentialsFromVault(options.squire);
8481
8481
  return oneClick.source === "squire" ? { ...oneClick } : { ...loadManualGoogleCredentials(options.home, options.env) };
8482
8482
  })();
@@ -8515,7 +8515,31 @@ function describe(error) {
8515
8515
 
8516
8516
  // apps/body/dist/connector-squire.js
8517
8517
  import { execFile, spawn as spawn2 } from "node:child_process";
8518
- var SQUIRE_CONNECT_PACKAGE = "@trusty-squire/mcp@next";
8518
+ var SQUIRE_MCP_NAME = "@trusty-squire/mcp";
8519
+ var SQUIRE_CONNECT_PACKAGE = `${SQUIRE_MCP_NAME}@latest`;
8520
+ var activeConnectSession;
8521
+ function isProcessAlive(pid) {
8522
+ if (pid === void 0 || pid <= 0)
8523
+ return false;
8524
+ try {
8525
+ process.kill(pid, 0);
8526
+ return true;
8527
+ } catch (error) {
8528
+ return error?.code === "EPERM";
8529
+ }
8530
+ }
8531
+ function releaseSquireConnectSession(log2) {
8532
+ const claim = activeConnectSession;
8533
+ activeConnectSession = void 0;
8534
+ if (!claim)
8535
+ return;
8536
+ if (isProcessAlive(claim.pid)) {
8537
+ log2?.(`released trusty-squire connect session claim (pid ${String(claim.pid)} still live \u2014 a fresh connect owns the browser now)`);
8538
+ claim.abort();
8539
+ } else {
8540
+ log2?.("cleared dead trusty-squire connect session claim (owner process gone)");
8541
+ }
8542
+ }
8519
8543
  var defaultShellRunner = (command, args) => new Promise((resolve31) => {
8520
8544
  execFile(command, [...args], { timeout: 12e4, maxBuffer: 4 * 1024 * 1024, encoding: "utf8" }, (error, stdout6, stderr) => {
8521
8545
  const code = error?.code;
@@ -8537,7 +8561,7 @@ var defaultStreamedRunner = (command, args) => new Promise((resolve31) => {
8537
8561
  const safetyTimer = setTimeout(() => {
8538
8562
  if (!resolved) {
8539
8563
  resolved = true;
8540
- resolve31({ stdout: stdout6, stderr, signIn: void 0, abort: () => {
8564
+ resolve31({ stdout: stdout6, stderr, pid: child.pid ?? void 0, signIn: void 0, abort: () => {
8541
8565
  } });
8542
8566
  }
8543
8567
  child.kill();
@@ -8546,6 +8570,12 @@ var defaultStreamedRunner = (command, args) => new Promise((resolve31) => {
8546
8570
  clearTimeout(safetyTimer);
8547
8571
  child.kill();
8548
8572
  };
8573
+ const claim = {
8574
+ pid: child.pid ?? void 0,
8575
+ claimedAt: Date.now(),
8576
+ abort
8577
+ };
8578
+ activeConnectSession = claim;
8549
8579
  const finish = (result) => {
8550
8580
  if (!resolved) {
8551
8581
  resolved = true;
@@ -8570,11 +8600,11 @@ ${stderr}`;
8570
8600
  checkOutput();
8571
8601
  });
8572
8602
  child.on("close", () => {
8573
- finish({ stdout: stdout6, stderr, signIn: void 0, abort: () => {
8603
+ finish({ stdout: stdout6, stderr, pid: child.pid ?? void 0, signIn: void 0, abort: () => {
8574
8604
  } });
8575
8605
  });
8576
8606
  child.on("error", () => {
8577
- finish({ stdout: stdout6, stderr, signIn: void 0, abort: () => {
8607
+ finish({ stdout: stdout6, stderr, pid: child.pid ?? void 0, signIn: void 0, abort: () => {
8578
8608
  } });
8579
8609
  });
8580
8610
  });
@@ -8595,17 +8625,57 @@ function parseConnectOutput(output) {
8595
8625
  }
8596
8626
  return { method: "streamed-page", url };
8597
8627
  }
8598
- async function installedSquireVersion(run2) {
8599
- const probe = await run2("npx", ["-y", SQUIRE_CONNECT_PACKAGE, "--version"]);
8628
+ async function installedSquireVersion(run2, spec = SQUIRE_CONNECT_PACKAGE, preferOnline = false) {
8629
+ const probe = await run2("npx", [
8630
+ ...preferOnline ? ["--prefer-online"] : [],
8631
+ "-y",
8632
+ spec,
8633
+ "--version"
8634
+ ]);
8600
8635
  const version = probe.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0];
8601
8636
  return version;
8602
8637
  }
8638
+ async function currentSquireRelease(run2) {
8639
+ const probe = await run2("npm", ["view", SQUIRE_MCP_NAME, "version"]);
8640
+ if (probe.code !== 0)
8641
+ return void 0;
8642
+ return probe.stdout.match(/\d+\.\d+\.\d+[^\s]*/)?.[0];
8643
+ }
8644
+ async function resolveSquireConnectSpec(run2) {
8645
+ const currentRelease = await currentSquireRelease(run2);
8646
+ const first = await installedSquireVersion(run2);
8647
+ if (currentRelease === void 0 || first === currentRelease) {
8648
+ return {
8649
+ npxArgs: ["-y", SQUIRE_CONNECT_PACKAGE],
8650
+ ...first !== void 0 ? { resolvedVersion: first } : {},
8651
+ ...currentRelease !== void 0 ? { currentRelease } : {},
8652
+ reResolved: false
8653
+ };
8654
+ }
8655
+ const fresh = await installedSquireVersion(run2, SQUIRE_CONNECT_PACKAGE, true);
8656
+ if (fresh === currentRelease) {
8657
+ return {
8658
+ npxArgs: ["--prefer-online", "-y", SQUIRE_CONNECT_PACKAGE],
8659
+ resolvedVersion: fresh,
8660
+ currentRelease,
8661
+ reResolved: true
8662
+ };
8663
+ }
8664
+ return {
8665
+ npxArgs: ["-y", `${SQUIRE_MCP_NAME}@${currentRelease}`],
8666
+ ...fresh !== void 0 ? { resolvedVersion: fresh } : {},
8667
+ currentRelease,
8668
+ reResolved: true
8669
+ };
8670
+ }
8603
8671
  function parseSignedInAs(output) {
8604
8672
  return output.match(/signed in as ([^\s,;]+)/i)?.[1];
8605
8673
  }
8606
8674
  async function installSquire(options) {
8607
8675
  const run2 = options.run ?? defaultShellRunner;
8608
8676
  const streamRun = options.streamRun ?? defaultStreamedRunner;
8677
+ const log2 = options.log ?? (() => {
8678
+ });
8609
8679
  const steps = [step2("helper reached", "done")];
8610
8680
  const emit = () => options.onProgress?.([...steps]);
8611
8681
  const push = (next) => {
@@ -8618,9 +8688,13 @@ async function installSquire(options) {
8618
8688
  return { status: "error", steps, errorMessage: reason };
8619
8689
  };
8620
8690
  emit();
8691
+ releaseSquireConnectSession(log2);
8692
+ const resolution = await resolveSquireConnectSpec(run2);
8693
+ if (resolution.reResolved) {
8694
+ log2(`trusty-squire stale copy ${resolution.resolvedVersion ?? "unknown"} re-resolved against current release ${resolution.currentRelease}`);
8695
+ }
8621
8696
  const install = await streamRun("npx", [
8622
- "-y",
8623
- SQUIRE_CONNECT_PACKAGE,
8697
+ ...resolution.npxArgs,
8624
8698
  "connect",
8625
8699
  "--force-relogin=google",
8626
8700
  "--target=codex",
@@ -8631,7 +8705,7 @@ async function installSquire(options) {
8631
8705
  push(step2("trusty-squire installed", "failed", stderr || "connect printed no sign-in URL"));
8632
8706
  return fail(stderr || "the trusty-squire connect command printed no sign-in surface");
8633
8707
  }
8634
- const version = await installedSquireVersion(run2);
8708
+ const version = resolution.resolvedVersion;
8635
8709
  push(step2(`trusty-squire${version ? ` ${version}` : ""} installed`, "done"));
8636
8710
  const signIn = install.signIn;
8637
8711
  const signedInAs = parseSignedInAs(`${install.stdout}
@@ -8788,9 +8862,10 @@ var StdioSquireMcpClient = class {
8788
8862
  }
8789
8863
  initialize() {
8790
8864
  const child = (this.options.spawn ?? spawn3)(this.options.command ?? "npx", [
8791
- // `@next` RC: only the RC coordinates with a running Trusty Squire broker
8792
- // for concurrent sessions; stable `latest` cannot share its browser.
8793
- ...this.options.args ?? ["-y", "@trusty-squire/mcp@next"]
8865
+ // `@latest`: the current release, never a source-level version pin
8866
+ // (captain). Only the vault MCP server the agent spawns; the connect
8867
+ // install path verifies freshness itself (connector-squire.ts).
8868
+ ...this.options.args ?? ["-y", "@trusty-squire/mcp@latest"]
8794
8869
  ]);
8795
8870
  this.child = child;
8796
8871
  this.buffer = "";
@@ -8899,7 +8974,12 @@ var ConnectorAssignmentLoop = class {
8899
8974
  this.log = options.log ?? (() => {
8900
8975
  });
8901
8976
  this.install = options.install ?? installSquire;
8902
- this.installGoogle = options.installGoogle ?? ((connectorType, onProgress) => installGoogleTool({ connectorType, home: this.googleHome(), onProgress }));
8977
+ this.installGoogle = options.installGoogle ?? ((connectorType, onProgress, sharedCredentials) => installGoogleTool({
8978
+ connectorType,
8979
+ home: this.googleHome(),
8980
+ onProgress,
8981
+ resolvedCredentials: sharedCredentials ? sharedCredentials() : this.resolveGoogleCredentials()
8982
+ }));
8903
8983
  this.googleHomeDir = options.googleHome ?? process.env.BEELINE_AGENT_HOME ?? process.cwd();
8904
8984
  this.readVaultFn = options.readVault ?? readVault;
8905
8985
  this.revokeGrantsFn = options.revokeGrants ?? revokeGrants;
@@ -8941,15 +9021,60 @@ var ConnectorAssignmentLoop = class {
8941
9021
  this.log(`connector assignments unavailable: ${describe2(error)}`);
8942
9022
  return;
8943
9023
  }
9024
+ let googleBatch;
8944
9025
  for (const assignment of assignments) {
8945
9026
  const key = `${assignment.kind}:${assignment.connectorId}`;
8946
9027
  if (assignment.kind === "uninstall")
8947
9028
  continue;
9029
+ if (assignment.kind === "install" && isGoogleToolConnectorType(assignment.connectorType)) {
9030
+ if (this.inFlight.has(key))
9031
+ continue;
9032
+ this.inFlight.add(key);
9033
+ (googleBatch ??= []).push(assignment);
9034
+ continue;
9035
+ }
8948
9036
  if (this.inFlight.has(key))
8949
9037
  continue;
8950
9038
  this.inFlight.add(key);
8951
9039
  void this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${describe2(error)}`)).finally(() => this.inFlight.delete(key));
8952
9040
  }
9041
+ if (googleBatch)
9042
+ this.flushGoogleBatch(googleBatch);
9043
+ }
9044
+ flushGoogleBatch(batch) {
9045
+ const keys = batch.map((a2) => `${a2.kind}:${a2.connectorId}`);
9046
+ void this.runGoogleBatch(batch).catch((error) => this.log(`google connector installs failed: ${describe2(error)}`)).finally(() => {
9047
+ for (const key of keys)
9048
+ this.inFlight.delete(key);
9049
+ });
9050
+ }
9051
+ /** The Google tool connectors ride ONE grant: every install in the batch
9052
+ * shares one credential resolution (the single Google consent) and the
9053
+ * installs run one at a time. Each tool still verifies and fails
9054
+ * independently — a grant that cannot serve one tool's scope refuses that
9055
+ * tool alone, never its siblings. */
9056
+ async runGoogleBatch(batch) {
9057
+ let shared;
9058
+ const sharedCredentials = () => shared ??= this.resolveGoogleCredentials();
9059
+ for (const assignment of batch) {
9060
+ await this.runGoogleInstall(assignment.connectorId, assignment.connectorType, sharedCredentials);
9061
+ }
9062
+ }
9063
+ /** The ONE grant resolution shared by every Google tool install of a
9064
+ * drain: the Squire one-click vault path first, then the manual
9065
+ * credentials path. Never rejects — a failure resolves as an unusable
9066
+ * grant each install reports through its own steps. */
9067
+ resolveGoogleCredentials() {
9068
+ return (async () => {
9069
+ try {
9070
+ const oneClick = await readGoogleCredentialsFromVault(this.squire());
9071
+ if (oneClick.source === "squire")
9072
+ return oneClick;
9073
+ } catch (error) {
9074
+ this.log(`google one-click grant lookup failed: ${describe2(error)}`);
9075
+ }
9076
+ return loadManualGoogleCredentials(this.googleHome(), process.env);
9077
+ })();
8953
9078
  }
8954
9079
  squire() {
8955
9080
  this.mcp ??= defaultSquireMcpClient();
@@ -8957,11 +9082,7 @@ var ConnectorAssignmentLoop = class {
8957
9082
  }
8958
9083
  async handle(assignment) {
8959
9084
  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
- }
9085
+ await this.runInstall(assignment.connectorId);
8965
9086
  } else if (assignment.kind === "sync")
8966
9087
  await this.runSync();
8967
9088
  else if (assignment.kind === "revoke-grants")
@@ -8971,8 +9092,9 @@ var ConnectorAssignmentLoop = class {
8971
9092
  googleHome() {
8972
9093
  return this.googleHomeDir;
8973
9094
  }
8974
- /** Install one Google tool connector (Gmail/Calendar/Drive/YouTube). */
8975
- async runGoogleInstall(connectorId, connectorType) {
9095
+ /** Install one Google tool connector (Gmail/Calendar/Drive/YouTube),
9096
+ * riding the drain's shared grant resolution. */
9097
+ async runGoogleInstall(connectorId, connectorType, sharedCredentials) {
8976
9098
  const report = async (steps) => {
8977
9099
  try {
8978
9100
  await this.api.execute("postConnectorStatus", { agentId: this.agentId, connectorId, steps });
@@ -8980,7 +9102,7 @@ var ConnectorAssignmentLoop = class {
8980
9102
  this.log(`step report failed: ${describe2(error)}`);
8981
9103
  }
8982
9104
  };
8983
- const result = await this.installGoogle(connectorType, report);
9105
+ const result = await this.installGoogle(connectorType, report, sharedCredentials);
8984
9106
  if (result.status === "error") {
8985
9107
  await this.api.execute("postConnectorStatus", {
8986
9108
  agentId: this.agentId,
@@ -9008,7 +9130,8 @@ var ConnectorAssignmentLoop = class {
9008
9130
  const result = await this.install({
9009
9131
  workspaceId: this.agentId,
9010
9132
  mcp: this.squire(),
9011
- onProgress: report
9133
+ onProgress: report,
9134
+ log: (message) => this.log(`[trusty-squire] ${message}`)
9012
9135
  });
9013
9136
  if (result.status === "error") {
9014
9137
  await this.api.execute("postConnectorStatus", {
@@ -19412,7 +19535,7 @@ Then take exactly one action:
19412
19535
  }
19413
19536
 
19414
19537
  // apps/body/dist/external-mcp-capabilities.js
19415
- var SQUIRE_MCP_VERSION = "next";
19538
+ var SQUIRE_MCP_VERSION = "latest";
19416
19539
  var SQUIRE_MCP_PACKAGE = `@trusty-squire/mcp@${SQUIRE_MCP_VERSION}`;
19417
19540
  function isTrustySquireMcpLaunch(command, args = []) {
19418
19541
  return [command, ...args].some((value) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usebeeline",
3
- "version": "0.0.108",
3
+ "version": "0.0.109",
4
4
  "description": "Connect an AI coding agent to Beeline with one command.",
5
5
  "homepage": "https://usebeeline.app",
6
6
  "bugs": {