@rosthq/cli 0.7.113 → 0.7.114

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/dist/index.js CHANGED
@@ -38708,6 +38708,14 @@ function accessLevelForScope(scopeTier) {
38708
38708
  return "admin";
38709
38709
  }
38710
38710
  }
38711
+ var RUNNER_WIRED_CONNECTOR_IDS = /* @__PURE__ */ new Set([
38712
+ "gmail.read",
38713
+ "gmail.draft",
38714
+ "gmail.send",
38715
+ "sheets.read",
38716
+ "sheets.write",
38717
+ "slack.post_message"
38718
+ ]);
38711
38719
  function providerRequirementFor(entry) {
38712
38720
  if (!entry.credential_required) {
38713
38721
  return entry.provider === "rost" || entry.provider === "web" ? "platform_managed" : "none";
@@ -38730,6 +38738,12 @@ function trustedRequiredMetadataFor(entry) {
38730
38738
  "authorization_revoked_at"
38731
38739
  ];
38732
38740
  }
38741
+ function laneSupportFor(entry) {
38742
+ if (providerRequirementFor(entry) === "connection" && !RUNNER_WIRED_CONNECTOR_IDS.has(entry.id)) {
38743
+ return ["cloud"];
38744
+ }
38745
+ return ["cloud", "runner", "mcp"];
38746
+ }
38733
38747
  function enrichCatalogEntry(entry) {
38734
38748
  const accessLevels = [...new Set(entry.scope_tiers.map(accessLevelForScope))];
38735
38749
  return {
@@ -38738,7 +38752,7 @@ function enrichCatalogEntry(entry) {
38738
38752
  default_access_level: accessLevelForScope(entry.default_scope_tier),
38739
38753
  provider_requirement: providerRequirementFor(entry),
38740
38754
  cost_class: entry.id === "script.run" || entry.id === "secret.broker" || entry.id === "baserow.read" || entry.id === "baserow.write" ? "metered_standard" : entry.id === "web.search" || entry.id === "web.fetch" || entry.id === "browser.read" ? "metered_low" : "included",
38741
- lane_support: ["cloud", "runner", "mcp"],
38755
+ lane_support: laneSupportFor(entry),
38742
38756
  trusted_required_metadata: trustedRequiredMetadataFor(entry)
38743
38757
  };
38744
38758
  }
@@ -48681,7 +48695,7 @@ Use the lower-level commands after health names a finding: \`agent.get_run\` for
48681
48695
  order: 46,
48682
48696
  title: "Tool access and vault",
48683
48697
  summary: "How to give agents access to tools without exposing raw credentials or expanding authority by accident.",
48684
- version: "2026-07-19.1",
48698
+ version: "2026-07-21.1",
48685
48699
  public: true,
48686
48700
  audiences: ["human", "cli", "mcp", "in_app_agent"],
48687
48701
  stages: ["staffing"],
@@ -48737,6 +48751,10 @@ The native Gmail handlers run inside the same broker boundary as the REST and Sl
48737
48751
 
48738
48752
  Google can be connected from Settings once the workspace OAuth app is configured. The connection flow requests offline access for Gmail read/compose/send and Sheets, stores the returned credential in the vault, and records only account, scope, and capability-availability metadata in the integration row. Partial grants are accepted when at least one connector capability is usable; missing or revoked scopes reduce the affected capability instead of granting more authority. The test action refreshes the vaulted credential and performs a minimal Gmail profile read. Gmail read/draft/send, bounded Sheets read, and approval-held Sheets write handlers run through the guarded broker when Google is connected; connecting Google still does not bypass the signed Charter manifest, tenant policy ceiling, credential vault, or tool-call audit. Sheet grants should use exact signed argument bindings for approved spreadsheet ids and ranges.
48739
48753
 
48754
+ ## Connectors work the same on either lane
48755
+
48756
+ A seat's governed connectors are available whether its agent runs on the cloud lane or the runner lane. {{brand}} projects each connector the seat's signed Charter grants onto the seat's own MCP surface and executes it server-side \u2014 so a runner-lane agent calls the same Gmail, Sheets, and Slack connectors a cloud-lane agent does, with identical governance: the same server guard, the same held-write approval for send/write tiers, and the same tool-call audit row. The OAuth or vaulted credential is resolved and bound only on the server inside the credential closure and never travels to the runner. Because this projection is derived from the Charter manifest and the connected integration, connecting a new integration makes its capabilities available to an already-live runner seat with no charter re-sign or code change. Connectors without a server-side handler yet stay cloud-only and are shown on the seat's Tools tab as not available on the runner lane until one ships.
48757
+
48740
48758
  A connected Baserow REST integration (\`integration.connect_rest\`) derives a \`baserow.read\` tenant capability ceiling the same way: a live connection surfaces read, and a disconnected/revoked one collapses to off. The derivation is read-only by design \u2014 \`baserow.write\` is never inferred from the connection and is granted only through an explicit per-seat brokered secret grant, matching the conservative-by-default rule for every connection-backed ceiling.
48741
48759
 
48742
48760
  CLI and MCP can inspect connector readiness without seeing secrets: \`integration.list\` / \`rost_list_integrations\` lists connected providers and health metadata, \`integration.status\` / \`rost_get_integration_status\` reads one provider by id or name, and \`integration.test\` / \`rost_test_integration_connection\` runs the installed provider-specific health check. For Google, the test refreshes the vaulted OAuth credential and reads the Gmail profile, then records only account, scope, and health metadata.
@@ -56032,6 +56050,20 @@ function forgeBuildUnsupportedReason(platform2) {
56032
56050
  }
56033
56051
  return `Forge build execution is unsupported on this host: no macOS seatbelt (sandbox-exec) confinement is available on '${platform2}', so this runner cannot prove filesystem/egress isolation for an untrusted build turn. The server will not offer Forge-phase work to this runner \u2014 unless its tenant is on the narrow, operator-established trust allowlist (FORGE_SANDBOX_TRUSTED_TENANT_IDS) \u2014 until real Linux confinement (namespaces/Landlock, tracked as a DER-1343 follow-up) ships.`;
56034
56052
  }
56053
+ function sandboxRequiredTurnRefusal(input) {
56054
+ if (input.spec.kind === "seatbelt") {
56055
+ return null;
56056
+ }
56057
+ if (input.mode === "off") {
56058
+ return null;
56059
+ }
56060
+ const postureLabel = input.mode === "strict" ? "strict" : "guard";
56061
+ const override = "Set RUNNER_SANDBOX=off only on a trusted, founder-authorized host to override.";
56062
+ if (input.platform !== "darwin") {
56063
+ return `Refusing to run this turn unconfined: sandbox mode is '${postureLabel}', but macOS seatbelt confinement does not exist on this host ('${input.platform}') \u2014 seatbelt is macOS-only, and Linux confinement is a DER-1343 follow-up. The runner refuses rather than running an attacker-influenceable build turn unconfined. ${override}`;
56064
+ }
56065
+ return `Refusing to run this turn unconfined: sandbox mode is '${postureLabel}', but sandbox-exec is unavailable on this macOS host, so filesystem/egress confinement cannot be applied (${input.spec.reason}). The runner refuses rather than silently degrading to no sandbox. ${override}`;
56066
+ }
56035
56067
  function wrapCommandWithSandbox(spec, command, args, profilePath) {
56036
56068
  if (spec.kind === "none" || profilePath === null) {
56037
56069
  return { command, args, profilePath: null };
@@ -59005,6 +59037,17 @@ async function spawnRunnerTurn(ctx, workOrder, runtime, kind) {
59005
59037
  if (execution?.profile === "forge_merge") {
59006
59038
  return runForgeMergeTurn(ctx, workOrder, execution, runtime);
59007
59039
  }
59040
+ const requiresSandbox = Boolean(execution?.needs_repo) || execution?.local_tools === "workspace_write";
59041
+ if (requiresSandbox) {
59042
+ const refusal = sandboxRequiredTurnRefusal({
59043
+ mode: ctx.config.sandboxMode,
59044
+ platform: process.platform,
59045
+ spec: ctx.config.sandbox
59046
+ });
59047
+ if (refusal) {
59048
+ return { ok: false, summary: refusal };
59049
+ }
59050
+ }
59008
59051
  let forgePrep = null;
59009
59052
  if (execution?.needs_repo) {
59010
59053
  const prepared = await prepareForgeTurn(ctx, workOrder, execution);
@@ -59206,6 +59249,11 @@ async function resolveMergeConflictTurn(ctx, input) {
59206
59249
  ],
59207
59250
  allowNetwork: ctx.config.sandboxAllowNetwork
59208
59251
  });
59252
+ const sandboxRefusal = sandboxRequiredTurnRefusal({ mode: ctx.config.sandboxMode, platform: process.platform, spec: sandbox });
59253
+ if (sandboxRefusal) {
59254
+ await removeWorkspace(workspace).catch(() => void 0);
59255
+ return { pushed: false, result: { ok: false, summary: sandboxRefusal.slice(0, MERGE_CONFLICT_SUMMARY_MAX) } };
59256
+ }
59209
59257
  const modelResult = await spawnMergeConflictModel(ctx, {
59210
59258
  workOrder: input.workOrder,
59211
59259
  execution: input.execution,