@integrity-labs/agt-cli 0.28.855 → 0.28.856

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 (25) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-7YVKIYVW.js → chunk-6CLS6G7Y.js} +2 -2
  3. package/dist/{chunk-RKCG63PT.js → chunk-6I5IMMWR.js} +356 -194
  4. package/dist/chunk-6I5IMMWR.js.map +1 -0
  5. package/dist/{chunk-IHBWFKOW.js → chunk-M6E42Z4Z.js} +82 -1
  6. package/dist/chunk-M6E42Z4Z.js.map +1 -0
  7. package/dist/{claude-pair-runtime-FFUPKRVC.js → claude-pair-runtime-QQSSCLXU.js} +2 -2
  8. package/dist/lib/manager-worker.js +14 -14
  9. package/dist/mcp/computer-use-proxy.js +98 -1
  10. package/dist/mcp/direct-chat-channel.js +81 -0
  11. package/dist/mcp/index.js +81 -0
  12. package/dist/mcp/origami.js +81 -0
  13. package/dist/mcp/slack-channel.js +81 -0
  14. package/dist/mcp/telegram-channel.js +81 -0
  15. package/dist/{persistent-session-CNVU25IF.js → persistent-session-GZLPDUMN.js} +3 -3
  16. package/dist/{responsiveness-probe-TZOKOH6C.js → responsiveness-probe-GSCW4NBC.js} +3 -3
  17. package/dist/{session-auth-dead-GRYXFDYD.js → session-auth-dead-NWLDIYTW.js} +2 -2
  18. package/package.json +1 -1
  19. package/dist/chunk-IHBWFKOW.js.map +0 -1
  20. package/dist/chunk-RKCG63PT.js.map +0 -1
  21. /package/dist/{chunk-7YVKIYVW.js.map → chunk-6CLS6G7Y.js.map} +0 -0
  22. /package/dist/{claude-pair-runtime-FFUPKRVC.js.map → claude-pair-runtime-QQSSCLXU.js.map} +0 -0
  23. /package/dist/{persistent-session-CNVU25IF.js.map → persistent-session-GZLPDUMN.js.map} +0 -0
  24. /package/dist/{responsiveness-probe-TZOKOH6C.js.map → responsiveness-probe-GSCW4NBC.js.map} +0 -0
  25. /package/dist/{session-auth-dead-GRYXFDYD.js.map → session-auth-dead-NWLDIYTW.js.map} +0 -0
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-CNVU25IF.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-GZLPDUMN.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-FFUPKRVC.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-QQSSCLXU.js.map
@@ -60,7 +60,7 @@ import {
60
60
  safeWriteJsonAtomic,
61
61
  setConfigHash,
62
62
  tripClass
63
- } from "../chunk-RKCG63PT.js";
63
+ } from "../chunk-6I5IMMWR.js";
64
64
  import {
65
65
  getProjectDir as getProjectDir2,
66
66
  getReadyTasks,
@@ -126,7 +126,7 @@ import {
126
126
  takeZombieDetection,
127
127
  toOpencodeModel,
128
128
  writeEgressAllowlist
129
- } from "../chunk-7YVKIYVW.js";
129
+ } from "../chunk-6CLS6G7Y.js";
130
130
  import {
131
131
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
132
132
  AnchorSessionClient,
@@ -221,7 +221,7 @@ import {
221
221
  subagentActivityAgeSeconds,
222
222
  sumTranscriptUsageInWindow,
223
223
  transcriptActivityAgeSeconds
224
- } from "../chunk-IHBWFKOW.js";
224
+ } from "../chunk-M6E42Z4Z.js";
225
225
  import {
226
226
  reapOrphanChannelMcps
227
227
  } from "../chunk-XWVM4KPK.js";
@@ -13001,7 +13001,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
13001
13001
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
13002
13002
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
13003
13003
  async function channelInboundActivityAgeSecondsFor(codeName) {
13004
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-TZOKOH6C.js");
13004
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-GSCW4NBC.js");
13005
13005
  const newest = newestPendingInboundActivityMtimeMs(dirname11(paneLogPath(codeName)));
13006
13006
  if (newest === null) return null;
13007
13007
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -13669,7 +13669,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13669
13669
  var lastVersionCheckAt = 0;
13670
13670
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13671
13671
  var lastResponsivenessProbeAt = 0;
13672
- var agtCliVersion = true ? "0.28.855" : "dev";
13672
+ var agtCliVersion = true ? "0.28.856" : "dev";
13673
13673
  function resolveBrewPath(execFileSync2) {
13674
13674
  try {
13675
13675
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -15259,7 +15259,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
15259
15259
  if (codeNames.length === 0) return;
15260
15260
  void (async () => {
15261
15261
  try {
15262
- const { collectDiagnostics } = await import("../persistent-session-CNVU25IF.js");
15262
+ const { collectDiagnostics } = await import("../persistent-session-GZLPDUMN.js");
15263
15263
  await api.post("/host/heartbeat", {
15264
15264
  host_id: hostId,
15265
15265
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -15401,7 +15401,7 @@ async function pollCycleInner() {
15401
15401
  }
15402
15402
  try {
15403
15403
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
15404
- const { collectDiagnostics } = await import("../persistent-session-CNVU25IF.js");
15404
+ const { collectDiagnostics } = await import("../persistent-session-GZLPDUMN.js");
15405
15405
  const diagCodeNames = [...agentState.persistentSessionAgents];
15406
15406
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
15407
15407
  let tailscaleHostname;
@@ -15570,7 +15570,7 @@ async function pollCycleInner() {
15570
15570
  collectPanelessActivityProbes,
15571
15571
  getResponsivenessIntervalMs,
15572
15572
  occupancyQualificationClassifications
15573
- } = await import("../responsiveness-probe-TZOKOH6C.js");
15573
+ } = await import("../responsiveness-probe-GSCW4NBC.js");
15574
15574
  const probeIntervalMs = getResponsivenessIntervalMs();
15575
15575
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
15576
15576
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -15687,7 +15687,7 @@ async function pollCycleInner() {
15687
15687
  collectResponsivenessProbes,
15688
15688
  livePendingInboundOldestAgeSeconds,
15689
15689
  parkPendingInbound
15690
- } = await import("../responsiveness-probe-TZOKOH6C.js");
15690
+ } = await import("../responsiveness-probe-GSCW4NBC.js");
15691
15691
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
15692
15692
  const wedgeNow = /* @__PURE__ */ new Date();
15693
15693
  const liveAgents = agentState.persistentSessionAgents;
@@ -15843,7 +15843,7 @@ async function pollCycleInner() {
15843
15843
  }
15844
15844
  try {
15845
15845
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
15846
- const { probeSessionAuth } = await import("../session-auth-dead-GRYXFDYD.js");
15846
+ const { probeSessionAuth } = await import("../session-auth-dead-NWLDIYTW.js");
15847
15847
  const observations = [];
15848
15848
  const pendingCacheCommits = [];
15849
15849
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -20071,7 +20071,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
20071
20071
  try {
20072
20072
  const freshId = rotateSessionForWedge(codeName);
20073
20073
  consecutiveWedgeCycles.delete(codeName);
20074
- const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-TZOKOH6C.js");
20074
+ const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-GSCW4NBC.js");
20075
20075
  const { parked, deadLettered } = parkForRestart(codeName, /* @__PURE__ */ new Date());
20076
20076
  const parkNote = parked > 0 ? `, ${parked} inbound parked` : "";
20077
20077
  const deadNote = deadLettered > 0 ? `, ${deadLettered} undeliverable dead-lettered` : "";
@@ -20109,7 +20109,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
20109
20109
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
20110
20110
  void (async () => {
20111
20111
  try {
20112
- const { collectDiagnostics } = await import("../persistent-session-CNVU25IF.js");
20112
+ const { collectDiagnostics } = await import("../persistent-session-GZLPDUMN.js");
20113
20113
  await api.post("/host/heartbeat", {
20114
20114
  host_id: hostId,
20115
20115
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -20155,7 +20155,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
20155
20155
  }
20156
20156
  try {
20157
20157
  const hostId = await getHostId();
20158
- const { collectDiagnostics } = await import("../persistent-session-CNVU25IF.js");
20158
+ const { collectDiagnostics } = await import("../persistent-session-GZLPDUMN.js");
20159
20159
  await api.post("/host/heartbeat", {
20160
20160
  host_id: hostId,
20161
20161
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -20791,7 +20791,7 @@ async function processClaudePairSessions(agents) {
20791
20791
  killPairSession,
20792
20792
  pairTmuxSession,
20793
20793
  finalizeClaudePairOnboarding
20794
- } = await import("../claude-pair-runtime-FFUPKRVC.js");
20794
+ } = await import("../claude-pair-runtime-QQSSCLXU.js");
20795
20795
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
20796
20796
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
20797
20797
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -6,6 +6,89 @@ globalThis.require ??= __augmentedCreateRequire(import.meta.url);
6
6
  import { createInterface } from "readline";
7
7
  import { spawn } from "child_process";
8
8
  import { fileURLToPath } from "url";
9
+
10
+ // src/computer-use-ssh-identity.ts
11
+ import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "fs";
12
+ import { tmpdir } from "os";
13
+ import { join } from "path";
14
+ var SSH_KEY_ENV = "OPEN_COMPUTER_USE_API_KEY";
15
+ var PEM_PREFIX = "-----BEGIN";
16
+ function decodePrivateKey(raw) {
17
+ const trimmed = raw.trim();
18
+ if (trimmed.length === 0) return null;
19
+ if (trimmed.startsWith(PEM_PREFIX)) return ensureTrailingNewline(trimmed);
20
+ let decoded;
21
+ try {
22
+ decoded = Buffer.from(trimmed, "base64").toString("utf8");
23
+ } catch {
24
+ return null;
25
+ }
26
+ if (!decoded.trimStart().startsWith(PEM_PREFIX)) return null;
27
+ return ensureTrailingNewline(decoded.trim());
28
+ }
29
+ function ensureTrailingNewline(pem) {
30
+ return pem.endsWith("\n") ? pem : `${pem}
31
+ `;
32
+ }
33
+ function removeIdentityDir(dir) {
34
+ if (dir === void 0) return;
35
+ try {
36
+ rmSync(dir, { recursive: true, force: true });
37
+ } catch {
38
+ }
39
+ }
40
+ function materializeSshIdentity(upstream, opts = {}) {
41
+ const env = opts.env ?? process.env;
42
+ const noop = { upstream: [...upstream], cleanup: () => {
43
+ }, problem: null, installed: false };
44
+ const raw = env[SSH_KEY_ENV];
45
+ if (raw === void 0 || raw.trim().length === 0) {
46
+ return noop;
47
+ }
48
+ if (raw.trim() === `\${${SSH_KEY_ENV}}`) {
49
+ return {
50
+ ...noop,
51
+ problem: `${SSH_KEY_ENV} is still the literal placeholder, so the manager has not materialized the credential for this agent yet`
52
+ };
53
+ }
54
+ if (upstream[0] !== "ssh") return noop;
55
+ const pem = decodePrivateKey(raw);
56
+ if (pem === null) {
57
+ return {
58
+ ...noop,
59
+ problem: `${SSH_KEY_ENV} is set but is neither base64-encoded PEM nor raw PEM (no ${PEM_PREFIX} header after decoding)`
60
+ };
61
+ }
62
+ let dir;
63
+ let keyPath;
64
+ try {
65
+ dir = mkdtempSync(join(opts.baseDir ?? tmpdir(), "agt-cu-"));
66
+ keyPath = join(dir, "id");
67
+ writeFileSync(keyPath, pem, { mode: 384 });
68
+ chmodSync(keyPath, 384);
69
+ } catch (err) {
70
+ removeIdentityDir(dir);
71
+ return {
72
+ ...noop,
73
+ problem: `could not write the ssh identity file: ${err.message}`
74
+ };
75
+ }
76
+ const createdDir = dir;
77
+ let removed = false;
78
+ const cleanup = () => {
79
+ if (removed) return;
80
+ removed = true;
81
+ removeIdentityDir(createdDir);
82
+ };
83
+ return {
84
+ upstream: [upstream[0], "-i", keyPath, ...upstream.slice(1)],
85
+ cleanup,
86
+ problem: null,
87
+ installed: true
88
+ };
89
+ }
90
+
91
+ // src/computer-use-proxy.ts
9
92
  import { resolve as resolvePath } from "path";
10
93
 
11
94
  // src/computer-use-gate.ts
@@ -543,9 +626,23 @@ async function main(argv = process.argv) {
543
626
  logErr("no upstream command; usage: computer-use-proxy -- <cmd> [args...]");
544
627
  process.exit(1);
545
628
  }
629
+ const identity = materializeSshIdentity(upstream);
630
+ if (identity.problem !== null) {
631
+ logErr(`ssh identity not installed: ${identity.problem}`);
632
+ }
633
+ if (identity.installed) {
634
+ process.on("exit", identity.cleanup);
635
+ for (const sig of ["SIGINT", "SIGTERM"]) {
636
+ process.on(sig, () => {
637
+ identity.cleanup();
638
+ process.exit(sig === "SIGINT" ? 130 : 143);
639
+ });
640
+ }
641
+ }
642
+ const spawnArgv = identity.upstream;
546
643
  let child;
547
644
  try {
548
- child = spawn(upstream[0], upstream.slice(1), { stdio: ["pipe", "pipe", "inherit"] });
645
+ child = spawn(spawnArgv[0], spawnArgv.slice(1), { stdio: ["pipe", "pipe", "inherit"] });
549
646
  } catch (err) {
550
647
  logErr(`failed to spawn upstream: ${err.message}`);
551
648
  process.exit(1);
@@ -33918,6 +33918,71 @@ var INTEGRATION_REGISTRY = [
33918
33918
  }
33919
33919
  }
33920
33920
  },
33921
+ {
33922
+ // ENG-10133 (epic ENG-10127). Drives a HUMAN'S macOS desktop — clicks,
33923
+ // keystrokes, window state — through `open-computer-use` running on that
33924
+ // Mac, reached over an SSH reverse tunnel the Mac itself opens.
33925
+ //
33926
+ // READ THIS BEFORE CHANGING ANY FIELD BELOW. Three properties are what make
33927
+ // this safe to ship at all, and each is easy to undo by accident:
33928
+ //
33929
+ // 1. Every forwarded call is gated per-action against a human-granted
33930
+ // approval (ENG-10132, packages/mcp/src/computer-use-gate.ts). The gate
33931
+ // lives INSIDE the proxy binary rather than beside it, so there is no
33932
+ // build in which the tools exist and the gate does not.
33933
+ // 2. The `open-computer-use` FLAG_REGISTRY flag decides whether the row is
33934
+ // forwarded to the host at all, and it is `sensitive` — arming it costs
33935
+ // a confirmation. The flag governs whether the PATH EXISTS; the gate
33936
+ // governs whether a call may travel it. Neither substitutes for the other.
33937
+ // 3. `beta` keeps it off every customer's picker until the operator runbook
33938
+ // (ENG-10135) exists. Setting up the Mac side — launchd tunnel, the
33939
+ // `from="127.0.0.1,::1"` pin on authorized_keys, Accessibility
33940
+ // permissions — is not something a connect dialog can do, and offering
33941
+ // it without those steps produces an integration that installs cleanly
33942
+ // and does nothing.
33943
+ //
33944
+ // NOT a `nativeMcp` spec: the entry needs a host-absolute proxy path and
33945
+ // per-install ssh config (user, port, remote command), neither of which the
33946
+ // ENG-5815 templating vocabulary can express. Rendered by
33947
+ // provisioning/computer-use-mcp.ts instead — see its header.
33948
+ id: "open-computer-use",
33949
+ name: "Computer Use (macOS)",
33950
+ category: "infrastructure",
33951
+ description: "Drive a macOS desktop by accessibility tree \u2014 read window state, click, type and press keys in any app. Every action requires a human approval granted per session and bound to one application.",
33952
+ // The credential is an OpenSSH private key, supplied by the operator who
33953
+ // set up the Mac. `api_key` is this codebase's "customer pastes a secret"
33954
+ // flow; there is no ssh-specific auth type and inventing one would buy
33955
+ // nothing the credential pipeline does not already do.
33956
+ supported_auth_types: ["api_key"],
33957
+ beta: true,
33958
+ // DELIBERATELY NOT `installable`, i.e. never in the Add Integration picker.
33959
+ // It joins augmented-admin / augmented-support / augmented-help-kb as a
33960
+ // GRANTED integration, and for a stronger version of their reason. A picker
33961
+ // entry promises self-service, and there is none to offer: the Mac side
33962
+ // needs a launchd tunnel, an authorized_keys entry pinned to loopback, an
33963
+ // SSH keypair and macOS Accessibility permission, none of which a connect
33964
+ // dialog can do. A customer who "installed" it from a picker would get a
33965
+ // dialog, paste something, and own a broken integration.
33966
+ //
33967
+ // It would also contradict the flag. `open-computer-use` is `sensitive`, so
33968
+ // arming it costs a deliberate confirmation — offering one-click install of
33969
+ // the thing behind it is incoherent.
33970
+ capabilities: [
33971
+ {
33972
+ id: "open-computer-use:read-screen",
33973
+ name: "Read Screen State",
33974
+ description: "List running applications and read a window's accessibility tree (element indices, labels, values). Screenshots are stripped by default and returned only on explicit request.",
33975
+ access: "read"
33976
+ },
33977
+ {
33978
+ id: "open-computer-use:control",
33979
+ name: "Control the Desktop",
33980
+ description: "Open apps, click, scroll, type text, press keys and set field values. Every call is refused unless a human has granted an approval for the target application.",
33981
+ access: "write"
33982
+ }
33983
+ ],
33984
+ docs_url: "https://github.com/anthropics/open-computer-use"
33985
+ },
33921
33986
  {
33922
33987
  // ENG-6195: admin-only debugging surface for Integrity Labs STAFF agents.
33923
33988
  // Provisions the @integrity-labs/augmented-admin-mcp stdio broker, which
@@ -37549,6 +37614,22 @@ var FLAG_REGISTRY = [
37549
37614
  // No `since` for the same reason: there is no host-side reader and no fleet
37550
37615
  // to converge, so `classifyHostReach` returning `honors` for every host is
37551
37616
  // the literal truth here rather than the trap it is one flag above.
37617
+ },
37618
+ {
37619
+ key: "open-computer-use",
37620
+ description: "ENG-10133 (epic ENG-10127) - gates whether an agent gets the `open-computer-use` stdio MCP server, i.e. whether it can drive a human's macOS desktop at all. OFF (default) = the `.mcp.json` entry is not written, so the tools do not exist for the agent and `--allowedTools` never carries the wildcard (the allowlist is DERIVED from the server keys - see apps/cli/src/lib/claude-tools.ts, which is why there is no second lever to flip). ON = the entry is materialized for any agent that also holds the integration row; the flag is necessary, never sufficient. THE FLAG IS NOT THE SAFETY CONTROL AND MUST NOT BE READ AS ONE. Every forwarded call is gated per-action against a human-granted approval by packages/mcp/src/computer-use-gate.ts (ENG-10132); this flag decides whether the PATH EXISTS, the gate decides whether a call may travel it. Turning this on for an agent whose host runs a proxy build predating that gate hands it an ungated route to someone's desktop - which is why the gate ships in the same proxy binary rather than beside it, so there is no build in which the path exists and the gate does not. Org/agent-scoped rather than global: a desktop belongs to one person, and the blast radius of a wrong answer is that person's open windows, mail client and password manager. Deliberately NO envVar - a host-level env override would let a compromised or misconfigured host arm itself, and this is precisely the gate that must be armed centrally (ENG-8303 pin, ENG-7972 4KB cap).",
37621
+ flagType: "boolean",
37622
+ // Dark. There is no "today's behaviour" to preserve - nothing on the fleet
37623
+ // has this integration - so the safe direction is unambiguous.
37624
+ defaultValue: false,
37625
+ // Enforcement gate (ADR-0022 section 4). Arming it is "relaxing a security
37626
+ // control" in the most literal sense available in this codebase: it is the
37627
+ // difference between an agent that can and cannot move a human's mouse.
37628
+ // One confirmation is a cheap price for that.
37629
+ sensitive: true
37630
+ // Deliberately NOT public. The browser has no decision to make here; the
37631
+ // consumers are the host payload that builds `input.integrations` and the
37632
+ // grant route that refuses to install the row while the flag is off.
37552
37633
  }
37553
37634
  ];
37554
37635
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
package/dist/mcp/index.js CHANGED
@@ -26467,6 +26467,71 @@ var INTEGRATION_REGISTRY = [
26467
26467
  }
26468
26468
  }
26469
26469
  },
26470
+ {
26471
+ // ENG-10133 (epic ENG-10127). Drives a HUMAN'S macOS desktop — clicks,
26472
+ // keystrokes, window state — through `open-computer-use` running on that
26473
+ // Mac, reached over an SSH reverse tunnel the Mac itself opens.
26474
+ //
26475
+ // READ THIS BEFORE CHANGING ANY FIELD BELOW. Three properties are what make
26476
+ // this safe to ship at all, and each is easy to undo by accident:
26477
+ //
26478
+ // 1. Every forwarded call is gated per-action against a human-granted
26479
+ // approval (ENG-10132, packages/mcp/src/computer-use-gate.ts). The gate
26480
+ // lives INSIDE the proxy binary rather than beside it, so there is no
26481
+ // build in which the tools exist and the gate does not.
26482
+ // 2. The `open-computer-use` FLAG_REGISTRY flag decides whether the row is
26483
+ // forwarded to the host at all, and it is `sensitive` — arming it costs
26484
+ // a confirmation. The flag governs whether the PATH EXISTS; the gate
26485
+ // governs whether a call may travel it. Neither substitutes for the other.
26486
+ // 3. `beta` keeps it off every customer's picker until the operator runbook
26487
+ // (ENG-10135) exists. Setting up the Mac side — launchd tunnel, the
26488
+ // `from="127.0.0.1,::1"` pin on authorized_keys, Accessibility
26489
+ // permissions — is not something a connect dialog can do, and offering
26490
+ // it without those steps produces an integration that installs cleanly
26491
+ // and does nothing.
26492
+ //
26493
+ // NOT a `nativeMcp` spec: the entry needs a host-absolute proxy path and
26494
+ // per-install ssh config (user, port, remote command), neither of which the
26495
+ // ENG-5815 templating vocabulary can express. Rendered by
26496
+ // provisioning/computer-use-mcp.ts instead — see its header.
26497
+ id: "open-computer-use",
26498
+ name: "Computer Use (macOS)",
26499
+ category: "infrastructure",
26500
+ description: "Drive a macOS desktop by accessibility tree \u2014 read window state, click, type and press keys in any app. Every action requires a human approval granted per session and bound to one application.",
26501
+ // The credential is an OpenSSH private key, supplied by the operator who
26502
+ // set up the Mac. `api_key` is this codebase's "customer pastes a secret"
26503
+ // flow; there is no ssh-specific auth type and inventing one would buy
26504
+ // nothing the credential pipeline does not already do.
26505
+ supported_auth_types: ["api_key"],
26506
+ beta: true,
26507
+ // DELIBERATELY NOT `installable`, i.e. never in the Add Integration picker.
26508
+ // It joins augmented-admin / augmented-support / augmented-help-kb as a
26509
+ // GRANTED integration, and for a stronger version of their reason. A picker
26510
+ // entry promises self-service, and there is none to offer: the Mac side
26511
+ // needs a launchd tunnel, an authorized_keys entry pinned to loopback, an
26512
+ // SSH keypair and macOS Accessibility permission, none of which a connect
26513
+ // dialog can do. A customer who "installed" it from a picker would get a
26514
+ // dialog, paste something, and own a broken integration.
26515
+ //
26516
+ // It would also contradict the flag. `open-computer-use` is `sensitive`, so
26517
+ // arming it costs a deliberate confirmation — offering one-click install of
26518
+ // the thing behind it is incoherent.
26519
+ capabilities: [
26520
+ {
26521
+ id: "open-computer-use:read-screen",
26522
+ name: "Read Screen State",
26523
+ description: "List running applications and read a window's accessibility tree (element indices, labels, values). Screenshots are stripped by default and returned only on explicit request.",
26524
+ access: "read"
26525
+ },
26526
+ {
26527
+ id: "open-computer-use:control",
26528
+ name: "Control the Desktop",
26529
+ description: "Open apps, click, scroll, type text, press keys and set field values. Every call is refused unless a human has granted an approval for the target application.",
26530
+ access: "write"
26531
+ }
26532
+ ],
26533
+ docs_url: "https://github.com/anthropics/open-computer-use"
26534
+ },
26470
26535
  {
26471
26536
  // ENG-6195: admin-only debugging surface for Integrity Labs STAFF agents.
26472
26537
  // Provisions the @integrity-labs/augmented-admin-mcp stdio broker, which
@@ -29819,6 +29884,22 @@ var FLAG_REGISTRY = [
29819
29884
  // No `since` for the same reason: there is no host-side reader and no fleet
29820
29885
  // to converge, so `classifyHostReach` returning `honors` for every host is
29821
29886
  // the literal truth here rather than the trap it is one flag above.
29887
+ },
29888
+ {
29889
+ key: "open-computer-use",
29890
+ description: "ENG-10133 (epic ENG-10127) - gates whether an agent gets the `open-computer-use` stdio MCP server, i.e. whether it can drive a human's macOS desktop at all. OFF (default) = the `.mcp.json` entry is not written, so the tools do not exist for the agent and `--allowedTools` never carries the wildcard (the allowlist is DERIVED from the server keys - see apps/cli/src/lib/claude-tools.ts, which is why there is no second lever to flip). ON = the entry is materialized for any agent that also holds the integration row; the flag is necessary, never sufficient. THE FLAG IS NOT THE SAFETY CONTROL AND MUST NOT BE READ AS ONE. Every forwarded call is gated per-action against a human-granted approval by packages/mcp/src/computer-use-gate.ts (ENG-10132); this flag decides whether the PATH EXISTS, the gate decides whether a call may travel it. Turning this on for an agent whose host runs a proxy build predating that gate hands it an ungated route to someone's desktop - which is why the gate ships in the same proxy binary rather than beside it, so there is no build in which the path exists and the gate does not. Org/agent-scoped rather than global: a desktop belongs to one person, and the blast radius of a wrong answer is that person's open windows, mail client and password manager. Deliberately NO envVar - a host-level env override would let a compromised or misconfigured host arm itself, and this is precisely the gate that must be armed centrally (ENG-8303 pin, ENG-7972 4KB cap).",
29891
+ flagType: "boolean",
29892
+ // Dark. There is no "today's behaviour" to preserve - nothing on the fleet
29893
+ // has this integration - so the safe direction is unambiguous.
29894
+ defaultValue: false,
29895
+ // Enforcement gate (ADR-0022 section 4). Arming it is "relaxing a security
29896
+ // control" in the most literal sense available in this codebase: it is the
29897
+ // difference between an agent that can and cannot move a human's mouse.
29898
+ // One confirmation is a cheap price for that.
29899
+ sensitive: true
29900
+ // Deliberately NOT public. The browser has no decision to make here; the
29901
+ // consumers are the host payload that builds `input.integrations` and the
29902
+ // grant route that refuses to install the row while the flag is off.
29822
29903
  }
29823
29904
  ];
29824
29905
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -40623,6 +40623,71 @@ var INTEGRATION_REGISTRY = [
40623
40623
  }
40624
40624
  }
40625
40625
  },
40626
+ {
40627
+ // ENG-10133 (epic ENG-10127). Drives a HUMAN'S macOS desktop — clicks,
40628
+ // keystrokes, window state — through `open-computer-use` running on that
40629
+ // Mac, reached over an SSH reverse tunnel the Mac itself opens.
40630
+ //
40631
+ // READ THIS BEFORE CHANGING ANY FIELD BELOW. Three properties are what make
40632
+ // this safe to ship at all, and each is easy to undo by accident:
40633
+ //
40634
+ // 1. Every forwarded call is gated per-action against a human-granted
40635
+ // approval (ENG-10132, packages/mcp/src/computer-use-gate.ts). The gate
40636
+ // lives INSIDE the proxy binary rather than beside it, so there is no
40637
+ // build in which the tools exist and the gate does not.
40638
+ // 2. The `open-computer-use` FLAG_REGISTRY flag decides whether the row is
40639
+ // forwarded to the host at all, and it is `sensitive` — arming it costs
40640
+ // a confirmation. The flag governs whether the PATH EXISTS; the gate
40641
+ // governs whether a call may travel it. Neither substitutes for the other.
40642
+ // 3. `beta` keeps it off every customer's picker until the operator runbook
40643
+ // (ENG-10135) exists. Setting up the Mac side — launchd tunnel, the
40644
+ // `from="127.0.0.1,::1"` pin on authorized_keys, Accessibility
40645
+ // permissions — is not something a connect dialog can do, and offering
40646
+ // it without those steps produces an integration that installs cleanly
40647
+ // and does nothing.
40648
+ //
40649
+ // NOT a `nativeMcp` spec: the entry needs a host-absolute proxy path and
40650
+ // per-install ssh config (user, port, remote command), neither of which the
40651
+ // ENG-5815 templating vocabulary can express. Rendered by
40652
+ // provisioning/computer-use-mcp.ts instead — see its header.
40653
+ id: "open-computer-use",
40654
+ name: "Computer Use (macOS)",
40655
+ category: "infrastructure",
40656
+ description: "Drive a macOS desktop by accessibility tree \u2014 read window state, click, type and press keys in any app. Every action requires a human approval granted per session and bound to one application.",
40657
+ // The credential is an OpenSSH private key, supplied by the operator who
40658
+ // set up the Mac. `api_key` is this codebase's "customer pastes a secret"
40659
+ // flow; there is no ssh-specific auth type and inventing one would buy
40660
+ // nothing the credential pipeline does not already do.
40661
+ supported_auth_types: ["api_key"],
40662
+ beta: true,
40663
+ // DELIBERATELY NOT `installable`, i.e. never in the Add Integration picker.
40664
+ // It joins augmented-admin / augmented-support / augmented-help-kb as a
40665
+ // GRANTED integration, and for a stronger version of their reason. A picker
40666
+ // entry promises self-service, and there is none to offer: the Mac side
40667
+ // needs a launchd tunnel, an authorized_keys entry pinned to loopback, an
40668
+ // SSH keypair and macOS Accessibility permission, none of which a connect
40669
+ // dialog can do. A customer who "installed" it from a picker would get a
40670
+ // dialog, paste something, and own a broken integration.
40671
+ //
40672
+ // It would also contradict the flag. `open-computer-use` is `sensitive`, so
40673
+ // arming it costs a deliberate confirmation — offering one-click install of
40674
+ // the thing behind it is incoherent.
40675
+ capabilities: [
40676
+ {
40677
+ id: "open-computer-use:read-screen",
40678
+ name: "Read Screen State",
40679
+ description: "List running applications and read a window's accessibility tree (element indices, labels, values). Screenshots are stripped by default and returned only on explicit request.",
40680
+ access: "read"
40681
+ },
40682
+ {
40683
+ id: "open-computer-use:control",
40684
+ name: "Control the Desktop",
40685
+ description: "Open apps, click, scroll, type text, press keys and set field values. Every call is refused unless a human has granted an approval for the target application.",
40686
+ access: "write"
40687
+ }
40688
+ ],
40689
+ docs_url: "https://github.com/anthropics/open-computer-use"
40690
+ },
40626
40691
  {
40627
40692
  // ENG-6195: admin-only debugging surface for Integrity Labs STAFF agents.
40628
40693
  // Provisions the @integrity-labs/augmented-admin-mcp stdio broker, which
@@ -43772,6 +43837,22 @@ var FLAG_REGISTRY = [
43772
43837
  // No `since` for the same reason: there is no host-side reader and no fleet
43773
43838
  // to converge, so `classifyHostReach` returning `honors` for every host is
43774
43839
  // the literal truth here rather than the trap it is one flag above.
43840
+ },
43841
+ {
43842
+ key: "open-computer-use",
43843
+ description: "ENG-10133 (epic ENG-10127) - gates whether an agent gets the `open-computer-use` stdio MCP server, i.e. whether it can drive a human's macOS desktop at all. OFF (default) = the `.mcp.json` entry is not written, so the tools do not exist for the agent and `--allowedTools` never carries the wildcard (the allowlist is DERIVED from the server keys - see apps/cli/src/lib/claude-tools.ts, which is why there is no second lever to flip). ON = the entry is materialized for any agent that also holds the integration row; the flag is necessary, never sufficient. THE FLAG IS NOT THE SAFETY CONTROL AND MUST NOT BE READ AS ONE. Every forwarded call is gated per-action against a human-granted approval by packages/mcp/src/computer-use-gate.ts (ENG-10132); this flag decides whether the PATH EXISTS, the gate decides whether a call may travel it. Turning this on for an agent whose host runs a proxy build predating that gate hands it an ungated route to someone's desktop - which is why the gate ships in the same proxy binary rather than beside it, so there is no build in which the path exists and the gate does not. Org/agent-scoped rather than global: a desktop belongs to one person, and the blast radius of a wrong answer is that person's open windows, mail client and password manager. Deliberately NO envVar - a host-level env override would let a compromised or misconfigured host arm itself, and this is precisely the gate that must be armed centrally (ENG-8303 pin, ENG-7972 4KB cap).",
43844
+ flagType: "boolean",
43845
+ // Dark. There is no "today's behaviour" to preserve - nothing on the fleet
43846
+ // has this integration - so the safe direction is unambiguous.
43847
+ defaultValue: false,
43848
+ // Enforcement gate (ADR-0022 section 4). Arming it is "relaxing a security
43849
+ // control" in the most literal sense available in this codebase: it is the
43850
+ // difference between an agent that can and cannot move a human's mouse.
43851
+ // One confirmation is a cheap price for that.
43852
+ sensitive: true
43853
+ // Deliberately NOT public. The browser has no decision to make here; the
43854
+ // consumers are the host payload that builds `input.integrations` and the
43855
+ // grant route that refuses to install the row while the flag is off.
43775
43856
  }
43776
43857
  ];
43777
43858
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -34771,6 +34771,71 @@ var INTEGRATION_REGISTRY = [
34771
34771
  }
34772
34772
  }
34773
34773
  },
34774
+ {
34775
+ // ENG-10133 (epic ENG-10127). Drives a HUMAN'S macOS desktop — clicks,
34776
+ // keystrokes, window state — through `open-computer-use` running on that
34777
+ // Mac, reached over an SSH reverse tunnel the Mac itself opens.
34778
+ //
34779
+ // READ THIS BEFORE CHANGING ANY FIELD BELOW. Three properties are what make
34780
+ // this safe to ship at all, and each is easy to undo by accident:
34781
+ //
34782
+ // 1. Every forwarded call is gated per-action against a human-granted
34783
+ // approval (ENG-10132, packages/mcp/src/computer-use-gate.ts). The gate
34784
+ // lives INSIDE the proxy binary rather than beside it, so there is no
34785
+ // build in which the tools exist and the gate does not.
34786
+ // 2. The `open-computer-use` FLAG_REGISTRY flag decides whether the row is
34787
+ // forwarded to the host at all, and it is `sensitive` — arming it costs
34788
+ // a confirmation. The flag governs whether the PATH EXISTS; the gate
34789
+ // governs whether a call may travel it. Neither substitutes for the other.
34790
+ // 3. `beta` keeps it off every customer's picker until the operator runbook
34791
+ // (ENG-10135) exists. Setting up the Mac side — launchd tunnel, the
34792
+ // `from="127.0.0.1,::1"` pin on authorized_keys, Accessibility
34793
+ // permissions — is not something a connect dialog can do, and offering
34794
+ // it without those steps produces an integration that installs cleanly
34795
+ // and does nothing.
34796
+ //
34797
+ // NOT a `nativeMcp` spec: the entry needs a host-absolute proxy path and
34798
+ // per-install ssh config (user, port, remote command), neither of which the
34799
+ // ENG-5815 templating vocabulary can express. Rendered by
34800
+ // provisioning/computer-use-mcp.ts instead — see its header.
34801
+ id: "open-computer-use",
34802
+ name: "Computer Use (macOS)",
34803
+ category: "infrastructure",
34804
+ description: "Drive a macOS desktop by accessibility tree \u2014 read window state, click, type and press keys in any app. Every action requires a human approval granted per session and bound to one application.",
34805
+ // The credential is an OpenSSH private key, supplied by the operator who
34806
+ // set up the Mac. `api_key` is this codebase's "customer pastes a secret"
34807
+ // flow; there is no ssh-specific auth type and inventing one would buy
34808
+ // nothing the credential pipeline does not already do.
34809
+ supported_auth_types: ["api_key"],
34810
+ beta: true,
34811
+ // DELIBERATELY NOT `installable`, i.e. never in the Add Integration picker.
34812
+ // It joins augmented-admin / augmented-support / augmented-help-kb as a
34813
+ // GRANTED integration, and for a stronger version of their reason. A picker
34814
+ // entry promises self-service, and there is none to offer: the Mac side
34815
+ // needs a launchd tunnel, an authorized_keys entry pinned to loopback, an
34816
+ // SSH keypair and macOS Accessibility permission, none of which a connect
34817
+ // dialog can do. A customer who "installed" it from a picker would get a
34818
+ // dialog, paste something, and own a broken integration.
34819
+ //
34820
+ // It would also contradict the flag. `open-computer-use` is `sensitive`, so
34821
+ // arming it costs a deliberate confirmation — offering one-click install of
34822
+ // the thing behind it is incoherent.
34823
+ capabilities: [
34824
+ {
34825
+ id: "open-computer-use:read-screen",
34826
+ name: "Read Screen State",
34827
+ description: "List running applications and read a window's accessibility tree (element indices, labels, values). Screenshots are stripped by default and returned only on explicit request.",
34828
+ access: "read"
34829
+ },
34830
+ {
34831
+ id: "open-computer-use:control",
34832
+ name: "Control the Desktop",
34833
+ description: "Open apps, click, scroll, type text, press keys and set field values. Every call is refused unless a human has granted an approval for the target application.",
34834
+ access: "write"
34835
+ }
34836
+ ],
34837
+ docs_url: "https://github.com/anthropics/open-computer-use"
34838
+ },
34774
34839
  {
34775
34840
  // ENG-6195: admin-only debugging surface for Integrity Labs STAFF agents.
34776
34841
  // Provisions the @integrity-labs/augmented-admin-mcp stdio broker, which
@@ -38327,6 +38392,22 @@ var FLAG_REGISTRY = [
38327
38392
  // No `since` for the same reason: there is no host-side reader and no fleet
38328
38393
  // to converge, so `classifyHostReach` returning `honors` for every host is
38329
38394
  // the literal truth here rather than the trap it is one flag above.
38395
+ },
38396
+ {
38397
+ key: "open-computer-use",
38398
+ description: "ENG-10133 (epic ENG-10127) - gates whether an agent gets the `open-computer-use` stdio MCP server, i.e. whether it can drive a human's macOS desktop at all. OFF (default) = the `.mcp.json` entry is not written, so the tools do not exist for the agent and `--allowedTools` never carries the wildcard (the allowlist is DERIVED from the server keys - see apps/cli/src/lib/claude-tools.ts, which is why there is no second lever to flip). ON = the entry is materialized for any agent that also holds the integration row; the flag is necessary, never sufficient. THE FLAG IS NOT THE SAFETY CONTROL AND MUST NOT BE READ AS ONE. Every forwarded call is gated per-action against a human-granted approval by packages/mcp/src/computer-use-gate.ts (ENG-10132); this flag decides whether the PATH EXISTS, the gate decides whether a call may travel it. Turning this on for an agent whose host runs a proxy build predating that gate hands it an ungated route to someone's desktop - which is why the gate ships in the same proxy binary rather than beside it, so there is no build in which the path exists and the gate does not. Org/agent-scoped rather than global: a desktop belongs to one person, and the blast radius of a wrong answer is that person's open windows, mail client and password manager. Deliberately NO envVar - a host-level env override would let a compromised or misconfigured host arm itself, and this is precisely the gate that must be armed centrally (ENG-8303 pin, ENG-7972 4KB cap).",
38399
+ flagType: "boolean",
38400
+ // Dark. There is no "today's behaviour" to preserve - nothing on the fleet
38401
+ // has this integration - so the safe direction is unambiguous.
38402
+ defaultValue: false,
38403
+ // Enforcement gate (ADR-0022 section 4). Arming it is "relaxing a security
38404
+ // control" in the most literal sense available in this codebase: it is the
38405
+ // difference between an agent that can and cannot move a human's mouse.
38406
+ // One confirmation is a cheap price for that.
38407
+ sensitive: true
38408
+ // Deliberately NOT public. The browser has no decision to make here; the
38409
+ // consumers are the host payload that builds `input.integrations` and the
38410
+ // grant route that refuses to install the row while the flag is off.
38330
38411
  }
38331
38412
  ];
38332
38413
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));