@integrity-labs/agt-cli 0.28.962 → 0.28.964

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.
@@ -20,7 +20,7 @@ import {
20
20
  rotateDailySession,
21
21
  sessionFileExists,
22
22
  todayLocalIso
23
- } from "./chunk-D3FGOGI2.js";
23
+ } from "./chunk-SMZQHDO7.js";
24
24
  import {
25
25
  classifyUnanswerablePane,
26
26
  findUsageLimitResetHint,
@@ -5575,4 +5575,4 @@ export {
5575
5575
  stopAllSessionsAndWait,
5576
5576
  getProjectDir
5577
5577
  };
5578
- //# sourceMappingURL=chunk-MNARTDPO.js.map
5578
+ //# sourceMappingURL=chunk-WVOB2TIP.js.map
@@ -236,7 +236,7 @@ async function spawnPairSession(session) {
236
236
  return { ok: true };
237
237
  } catch {
238
238
  }
239
- const { resolveClaudeBinary } = await import("./persistent-session-22PIKH3S.js");
239
+ const { resolveClaudeBinary } = await import("./persistent-session-TZO2JPCC.js");
240
240
  const claudeBin = resolveClaudeBinary();
241
241
  const pairEnv = {
242
242
  ...process.env,
@@ -558,4 +558,4 @@ export {
558
558
  startClaudePair,
559
559
  submitClaudePairCode
560
560
  };
561
- //# sourceMappingURL=claude-pair-runtime-6DGCWXRM.js.map
561
+ //# sourceMappingURL=claude-pair-runtime-QEVUC7L4.js.map
@@ -63,7 +63,7 @@ import {
63
63
  safeWriteJsonAtomic,
64
64
  setConfigHash,
65
65
  tripClass
66
- } from "../chunk-37AUMVY3.js";
66
+ } from "../chunk-JCAQEJYK.js";
67
67
  import {
68
68
  getProjectDir as getProjectDir2,
69
69
  getReadyTasks,
@@ -140,7 +140,7 @@ import {
140
140
  takeZombieDetection,
141
141
  toOpencodeModel,
142
142
  writeEgressAllowlist
143
- } from "../chunk-MNARTDPO.js";
143
+ } from "../chunk-WVOB2TIP.js";
144
144
  import {
145
145
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
146
146
  AnchorSessionClient,
@@ -236,7 +236,7 @@ import {
236
236
  subagentActivityAgeSeconds,
237
237
  sumTranscriptUsageInWindow,
238
238
  transcriptActivityAgeSeconds
239
- } from "../chunk-D3FGOGI2.js";
239
+ } from "../chunk-SMZQHDO7.js";
240
240
  import "../chunk-DHWNVVX4.js";
241
241
  import {
242
242
  reapOrphanChannelMcps
@@ -13262,7 +13262,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
13262
13262
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
13263
13263
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
13264
13264
  async function channelInboundActivityAgeSecondsFor(codeName) {
13265
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-3HPANEK6.js");
13265
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-DW7SMQGE.js");
13266
13266
  const newest = newestPendingInboundActivityMtimeMs(dirname11(paneLogPath(codeName)));
13267
13267
  if (newest === null) return null;
13268
13268
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -13947,7 +13947,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13947
13947
  var lastVersionCheckAt = 0;
13948
13948
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13949
13949
  var lastResponsivenessProbeAt = 0;
13950
- var agtCliVersion = true ? "0.28.962" : "dev";
13950
+ var agtCliVersion = true ? "0.28.964" : "dev";
13951
13951
  function resolveBrewPath(execFileSync2) {
13952
13952
  try {
13953
13953
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -15549,7 +15549,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
15549
15549
  if (codeNames.length === 0) return;
15550
15550
  void (async () => {
15551
15551
  try {
15552
- const { collectDiagnostics } = await import("../persistent-session-22PIKH3S.js");
15552
+ const { collectDiagnostics } = await import("../persistent-session-TZO2JPCC.js");
15553
15553
  await api.post("/host/heartbeat", {
15554
15554
  host_id: hostId,
15555
15555
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -15691,7 +15691,7 @@ async function pollCycleInner() {
15691
15691
  }
15692
15692
  try {
15693
15693
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
15694
- const { collectDiagnostics } = await import("../persistent-session-22PIKH3S.js");
15694
+ const { collectDiagnostics } = await import("../persistent-session-TZO2JPCC.js");
15695
15695
  const diagCodeNames = [...agentState.persistentSessionAgents];
15696
15696
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
15697
15697
  let tailscaleHostname;
@@ -15867,7 +15867,7 @@ async function pollCycleInner() {
15867
15867
  collectPanelessActivityProbes,
15868
15868
  getResponsivenessIntervalMs,
15869
15869
  occupancyQualificationClassifications
15870
- } = await import("../responsiveness-probe-3HPANEK6.js");
15870
+ } = await import("../responsiveness-probe-DW7SMQGE.js");
15871
15871
  const probeIntervalMs = getResponsivenessIntervalMs();
15872
15872
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
15873
15873
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -15984,7 +15984,7 @@ async function pollCycleInner() {
15984
15984
  collectResponsivenessProbes,
15985
15985
  livePendingInboundOldestAgeSeconds,
15986
15986
  parkPendingInbound
15987
- } = await import("../responsiveness-probe-3HPANEK6.js");
15987
+ } = await import("../responsiveness-probe-DW7SMQGE.js");
15988
15988
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
15989
15989
  const wedgeNow = /* @__PURE__ */ new Date();
15990
15990
  const liveAgents = agentState.persistentSessionAgents;
@@ -16140,7 +16140,7 @@ async function pollCycleInner() {
16140
16140
  }
16141
16141
  try {
16142
16142
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
16143
- const { probeSessionAuth } = await import("../session-auth-dead-FAIJPJUK.js");
16143
+ const { probeSessionAuth } = await import("../session-auth-dead-5D3XND6M.js");
16144
16144
  const observations = [];
16145
16145
  const pendingCacheCommits = [];
16146
16146
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -20416,7 +20416,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
20416
20416
  try {
20417
20417
  const freshId = rotateSessionForWedge(codeName);
20418
20418
  consecutiveWedgeCycles.delete(codeName);
20419
- const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-3HPANEK6.js");
20419
+ const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-DW7SMQGE.js");
20420
20420
  const { parked, deadLettered } = parkForRestart(codeName, /* @__PURE__ */ new Date());
20421
20421
  const parkNote = parked > 0 ? `, ${parked} inbound parked` : "";
20422
20422
  const deadNote = deadLettered > 0 ? `, ${deadLettered} undeliverable dead-lettered` : "";
@@ -20459,7 +20459,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
20459
20459
  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}`));
20460
20460
  void (async () => {
20461
20461
  try {
20462
- const { collectDiagnostics } = await import("../persistent-session-22PIKH3S.js");
20462
+ const { collectDiagnostics } = await import("../persistent-session-TZO2JPCC.js");
20463
20463
  await api.post("/host/heartbeat", {
20464
20464
  host_id: hostId,
20465
20465
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -20510,7 +20510,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
20510
20510
  }
20511
20511
  try {
20512
20512
  const hostId = await getHostId();
20513
- const { collectDiagnostics } = await import("../persistent-session-22PIKH3S.js");
20513
+ const { collectDiagnostics } = await import("../persistent-session-TZO2JPCC.js");
20514
20514
  await api.post("/host/heartbeat", {
20515
20515
  host_id: hostId,
20516
20516
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -21152,7 +21152,7 @@ async function processClaudePairSessions(agents) {
21152
21152
  killPairSession,
21153
21153
  pairTmuxSession,
21154
21154
  finalizeClaudePairOnboarding
21155
- } = await import("../claude-pair-runtime-6DGCWXRM.js");
21155
+ } = await import("../claude-pair-runtime-QEVUC7L4.js");
21156
21156
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
21157
21157
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
21158
21158
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -32977,12 +32977,12 @@ var composio_approved_egress_default = {
32977
32977
  "id, so comparing ids would red on the safe case - which is precisely the case Part 2's",
32978
32978
  "EIP adoption exists to create.",
32979
32979
  "",
32980
- "WHEN ENG-9426 LANDS THIS GOES RED UNTIL IT IS UPDATED. That is the forcing function",
32981
- "working, not a fault. ENG-9426 adds a NAT in ap-southeast-2b, i.e. a THIRD egress",
32982
- "address: add it here in the same change that lands it, or the detector correctly",
32980
+ "ANY NEW HOSTS-ACCOUNT EGRESS ADDRESS TURNS THE DETECTOR RED UNTIL IT IS ADDED HERE.",
32981
+ "That is the forcing function working, not a fault: ENG-9426's 2b NAT was added in the",
32982
+ "same change that created it. Do the same for the next one, or the detector correctly",
32983
32983
  "reports that hosts are leaving from an address no key allows. Do not loosen the check.",
32984
- "",
32985
- " crossing to 2a and stop dying with it. The address does not exist until",
32984
+ "A CONTROL-PLANE address gets no such forcing function - the detector never sees that",
32985
+ "account at all - which is why the bridge note below is written out by hand instead.",
32986
32986
  "",
32987
32987
  "15.135.204.192 IS GONE AND MUST NOT BE RE-ADDED (ENG-9426, 2026-09-15).",
32988
32988
  "The dev NAT was retired and that address was RELEASED back to the AWS pool, so it can",
@@ -32996,8 +32996,24 @@ var composio_approved_egress_default = {
32996
32996
  "delete-time options from the STATE recorded at the resource's last registration, and by",
32997
32997
  "the time this ran the resource was no longer in the program at all - so the state still",
32998
32998
  "said 'delete normally'. retainOnDelete has to land in a deploy that STILL DECLARES the",
32999
- "resource before it protects anything. The two prod EIPs above are protected, because",
33000
- "this apply registered them with the option set."
32999
+ "resource before it protects anything. The two prod hosts EIPs listed below are protected, because",
33000
+ "this apply registered them with the option set.",
33001
+ "",
33002
+ "TWO BRIDGE ADDRESSES ARE STILL MISSING FROM THIS FILE (ENG-9684, 2026-09-15).",
33003
+ "The control-plane egress bridge is being deployed to prod with a managed multi-AZ NAT,",
33004
+ "which allocates two more Elastic IPs - in the CONTROL PLANE account (109039361030), not",
33005
+ "the hosts account. They are not listed here yet because they do not exist until that",
33006
+ "deploy runs; read them from SSM at",
33007
+ "/augmented/prod/secrets/COMPOSIO_EGRESS_IPS (comma-separated, ready to paste) and add",
33008
+ "them here in the same change that arms anything.",
33009
+ "",
33010
+ "THE DETECTOR CANNOT VERIFY THOSE TWO, AND THAT IS CORRECT, NOT A BUG.",
33011
+ "ComposioEgressAddressDrift enumerates ONE account - the hosts account - so it compares",
33012
+ "only the addresses instances there actually route through. Bridge addresses will sit in",
33013
+ "this set unmatched and unflagged. Do NOT 'fix' that by trimming this file to what the",
33014
+ "detector checks: the file records what the ALLOWLIST must hold, which is a superset of",
33015
+ "what any one account scan can see. Trimming it would make the allowlist incomplete,",
33016
+ "which is a fleet-wide 401 rather than a tidy file."
33001
33017
  ],
33002
33018
  account: "711726113003",
33003
33019
  homeRegion: "ap-southeast-2",
package/dist/mcp/index.js CHANGED
@@ -25578,12 +25578,12 @@ var composio_approved_egress_default = {
25578
25578
  "id, so comparing ids would red on the safe case - which is precisely the case Part 2's",
25579
25579
  "EIP adoption exists to create.",
25580
25580
  "",
25581
- "WHEN ENG-9426 LANDS THIS GOES RED UNTIL IT IS UPDATED. That is the forcing function",
25582
- "working, not a fault. ENG-9426 adds a NAT in ap-southeast-2b, i.e. a THIRD egress",
25583
- "address: add it here in the same change that lands it, or the detector correctly",
25581
+ "ANY NEW HOSTS-ACCOUNT EGRESS ADDRESS TURNS THE DETECTOR RED UNTIL IT IS ADDED HERE.",
25582
+ "That is the forcing function working, not a fault: ENG-9426's 2b NAT was added in the",
25583
+ "same change that created it. Do the same for the next one, or the detector correctly",
25584
25584
  "reports that hosts are leaving from an address no key allows. Do not loosen the check.",
25585
- "",
25586
- " crossing to 2a and stop dying with it. The address does not exist until",
25585
+ "A CONTROL-PLANE address gets no such forcing function - the detector never sees that",
25586
+ "account at all - which is why the bridge note below is written out by hand instead.",
25587
25587
  "",
25588
25588
  "15.135.204.192 IS GONE AND MUST NOT BE RE-ADDED (ENG-9426, 2026-09-15).",
25589
25589
  "The dev NAT was retired and that address was RELEASED back to the AWS pool, so it can",
@@ -25597,8 +25597,24 @@ var composio_approved_egress_default = {
25597
25597
  "delete-time options from the STATE recorded at the resource's last registration, and by",
25598
25598
  "the time this ran the resource was no longer in the program at all - so the state still",
25599
25599
  "said 'delete normally'. retainOnDelete has to land in a deploy that STILL DECLARES the",
25600
- "resource before it protects anything. The two prod EIPs above are protected, because",
25601
- "this apply registered them with the option set."
25600
+ "resource before it protects anything. The two prod hosts EIPs listed below are protected, because",
25601
+ "this apply registered them with the option set.",
25602
+ "",
25603
+ "TWO BRIDGE ADDRESSES ARE STILL MISSING FROM THIS FILE (ENG-9684, 2026-09-15).",
25604
+ "The control-plane egress bridge is being deployed to prod with a managed multi-AZ NAT,",
25605
+ "which allocates two more Elastic IPs - in the CONTROL PLANE account (109039361030), not",
25606
+ "the hosts account. They are not listed here yet because they do not exist until that",
25607
+ "deploy runs; read them from SSM at",
25608
+ "/augmented/prod/secrets/COMPOSIO_EGRESS_IPS (comma-separated, ready to paste) and add",
25609
+ "them here in the same change that arms anything.",
25610
+ "",
25611
+ "THE DETECTOR CANNOT VERIFY THOSE TWO, AND THAT IS CORRECT, NOT A BUG.",
25612
+ "ComposioEgressAddressDrift enumerates ONE account - the hosts account - so it compares",
25613
+ "only the addresses instances there actually route through. Bridge addresses will sit in",
25614
+ "this set unmatched and unflagged. Do NOT 'fix' that by trimming this file to what the",
25615
+ "detector checks: the file records what the ALLOWLIST must hold, which is a superset of",
25616
+ "what any one account scan can see. Trimming it would make the allowlist incomplete,",
25617
+ "which is a fleet-wide 401 rather than a tidy file."
25602
25618
  ],
25603
25619
  account: "711726113003",
25604
25620
  homeRegion: "ap-southeast-2",
@@ -39729,12 +39729,12 @@ var composio_approved_egress_default = {
39729
39729
  "id, so comparing ids would red on the safe case - which is precisely the case Part 2's",
39730
39730
  "EIP adoption exists to create.",
39731
39731
  "",
39732
- "WHEN ENG-9426 LANDS THIS GOES RED UNTIL IT IS UPDATED. That is the forcing function",
39733
- "working, not a fault. ENG-9426 adds a NAT in ap-southeast-2b, i.e. a THIRD egress",
39734
- "address: add it here in the same change that lands it, or the detector correctly",
39732
+ "ANY NEW HOSTS-ACCOUNT EGRESS ADDRESS TURNS THE DETECTOR RED UNTIL IT IS ADDED HERE.",
39733
+ "That is the forcing function working, not a fault: ENG-9426's 2b NAT was added in the",
39734
+ "same change that created it. Do the same for the next one, or the detector correctly",
39735
39735
  "reports that hosts are leaving from an address no key allows. Do not loosen the check.",
39736
- "",
39737
- " crossing to 2a and stop dying with it. The address does not exist until",
39736
+ "A CONTROL-PLANE address gets no such forcing function - the detector never sees that",
39737
+ "account at all - which is why the bridge note below is written out by hand instead.",
39738
39738
  "",
39739
39739
  "15.135.204.192 IS GONE AND MUST NOT BE RE-ADDED (ENG-9426, 2026-09-15).",
39740
39740
  "The dev NAT was retired and that address was RELEASED back to the AWS pool, so it can",
@@ -39748,8 +39748,24 @@ var composio_approved_egress_default = {
39748
39748
  "delete-time options from the STATE recorded at the resource's last registration, and by",
39749
39749
  "the time this ran the resource was no longer in the program at all - so the state still",
39750
39750
  "said 'delete normally'. retainOnDelete has to land in a deploy that STILL DECLARES the",
39751
- "resource before it protects anything. The two prod EIPs above are protected, because",
39752
- "this apply registered them with the option set."
39751
+ "resource before it protects anything. The two prod hosts EIPs listed below are protected, because",
39752
+ "this apply registered them with the option set.",
39753
+ "",
39754
+ "TWO BRIDGE ADDRESSES ARE STILL MISSING FROM THIS FILE (ENG-9684, 2026-09-15).",
39755
+ "The control-plane egress bridge is being deployed to prod with a managed multi-AZ NAT,",
39756
+ "which allocates two more Elastic IPs - in the CONTROL PLANE account (109039361030), not",
39757
+ "the hosts account. They are not listed here yet because they do not exist until that",
39758
+ "deploy runs; read them from SSM at",
39759
+ "/augmented/prod/secrets/COMPOSIO_EGRESS_IPS (comma-separated, ready to paste) and add",
39760
+ "them here in the same change that arms anything.",
39761
+ "",
39762
+ "THE DETECTOR CANNOT VERIFY THOSE TWO, AND THAT IS CORRECT, NOT A BUG.",
39763
+ "ComposioEgressAddressDrift enumerates ONE account - the hosts account - so it compares",
39764
+ "only the addresses instances there actually route through. Bridge addresses will sit in",
39765
+ "this set unmatched and unflagged. Do NOT 'fix' that by trimming this file to what the",
39766
+ "detector checks: the file records what the ALLOWLIST must hold, which is a superset of",
39767
+ "what any one account scan can see. Trimming it would make the allowlist incomplete,",
39768
+ "which is a fleet-wide 401 rather than a tidy file."
39753
39769
  ],
39754
39770
  account: "711726113003",
39755
39771
  homeRegion: "ap-southeast-2",
@@ -33946,12 +33946,12 @@ var composio_approved_egress_default = {
33946
33946
  "id, so comparing ids would red on the safe case - which is precisely the case Part 2's",
33947
33947
  "EIP adoption exists to create.",
33948
33948
  "",
33949
- "WHEN ENG-9426 LANDS THIS GOES RED UNTIL IT IS UPDATED. That is the forcing function",
33950
- "working, not a fault. ENG-9426 adds a NAT in ap-southeast-2b, i.e. a THIRD egress",
33951
- "address: add it here in the same change that lands it, or the detector correctly",
33949
+ "ANY NEW HOSTS-ACCOUNT EGRESS ADDRESS TURNS THE DETECTOR RED UNTIL IT IS ADDED HERE.",
33950
+ "That is the forcing function working, not a fault: ENG-9426's 2b NAT was added in the",
33951
+ "same change that created it. Do the same for the next one, or the detector correctly",
33952
33952
  "reports that hosts are leaving from an address no key allows. Do not loosen the check.",
33953
- "",
33954
- " crossing to 2a and stop dying with it. The address does not exist until",
33953
+ "A CONTROL-PLANE address gets no such forcing function - the detector never sees that",
33954
+ "account at all - which is why the bridge note below is written out by hand instead.",
33955
33955
  "",
33956
33956
  "15.135.204.192 IS GONE AND MUST NOT BE RE-ADDED (ENG-9426, 2026-09-15).",
33957
33957
  "The dev NAT was retired and that address was RELEASED back to the AWS pool, so it can",
@@ -33965,8 +33965,24 @@ var composio_approved_egress_default = {
33965
33965
  "delete-time options from the STATE recorded at the resource's last registration, and by",
33966
33966
  "the time this ran the resource was no longer in the program at all - so the state still",
33967
33967
  "said 'delete normally'. retainOnDelete has to land in a deploy that STILL DECLARES the",
33968
- "resource before it protects anything. The two prod EIPs above are protected, because",
33969
- "this apply registered them with the option set."
33968
+ "resource before it protects anything. The two prod hosts EIPs listed below are protected, because",
33969
+ "this apply registered them with the option set.",
33970
+ "",
33971
+ "TWO BRIDGE ADDRESSES ARE STILL MISSING FROM THIS FILE (ENG-9684, 2026-09-15).",
33972
+ "The control-plane egress bridge is being deployed to prod with a managed multi-AZ NAT,",
33973
+ "which allocates two more Elastic IPs - in the CONTROL PLANE account (109039361030), not",
33974
+ "the hosts account. They are not listed here yet because they do not exist until that",
33975
+ "deploy runs; read them from SSM at",
33976
+ "/augmented/prod/secrets/COMPOSIO_EGRESS_IPS (comma-separated, ready to paste) and add",
33977
+ "them here in the same change that arms anything.",
33978
+ "",
33979
+ "THE DETECTOR CANNOT VERIFY THOSE TWO, AND THAT IS CORRECT, NOT A BUG.",
33980
+ "ComposioEgressAddressDrift enumerates ONE account - the hosts account - so it compares",
33981
+ "only the addresses instances there actually route through. Bridge addresses will sit in",
33982
+ "this set unmatched and unflagged. Do NOT 'fix' that by trimming this file to what the",
33983
+ "detector checks: the file records what the ALLOWLIST must hold, which is a superset of",
33984
+ "what any one account scan can see. Trimming it would make the allowlist incomplete,",
33985
+ "which is a fleet-wide 401 rather than a tidy file."
33970
33986
  ],
33971
33987
  account: "711726113003",
33972
33988
  homeRegion: "ap-southeast-2",
@@ -33964,12 +33964,12 @@ var composio_approved_egress_default = {
33964
33964
  "id, so comparing ids would red on the safe case - which is precisely the case Part 2's",
33965
33965
  "EIP adoption exists to create.",
33966
33966
  "",
33967
- "WHEN ENG-9426 LANDS THIS GOES RED UNTIL IT IS UPDATED. That is the forcing function",
33968
- "working, not a fault. ENG-9426 adds a NAT in ap-southeast-2b, i.e. a THIRD egress",
33969
- "address: add it here in the same change that lands it, or the detector correctly",
33967
+ "ANY NEW HOSTS-ACCOUNT EGRESS ADDRESS TURNS THE DETECTOR RED UNTIL IT IS ADDED HERE.",
33968
+ "That is the forcing function working, not a fault: ENG-9426's 2b NAT was added in the",
33969
+ "same change that created it. Do the same for the next one, or the detector correctly",
33970
33970
  "reports that hosts are leaving from an address no key allows. Do not loosen the check.",
33971
- "",
33972
- " crossing to 2a and stop dying with it. The address does not exist until",
33971
+ "A CONTROL-PLANE address gets no such forcing function - the detector never sees that",
33972
+ "account at all - which is why the bridge note below is written out by hand instead.",
33973
33973
  "",
33974
33974
  "15.135.204.192 IS GONE AND MUST NOT BE RE-ADDED (ENG-9426, 2026-09-15).",
33975
33975
  "The dev NAT was retired and that address was RELEASED back to the AWS pool, so it can",
@@ -33983,8 +33983,24 @@ var composio_approved_egress_default = {
33983
33983
  "delete-time options from the STATE recorded at the resource's last registration, and by",
33984
33984
  "the time this ran the resource was no longer in the program at all - so the state still",
33985
33985
  "said 'delete normally'. retainOnDelete has to land in a deploy that STILL DECLARES the",
33986
- "resource before it protects anything. The two prod EIPs above are protected, because",
33987
- "this apply registered them with the option set."
33986
+ "resource before it protects anything. The two prod hosts EIPs listed below are protected, because",
33987
+ "this apply registered them with the option set.",
33988
+ "",
33989
+ "TWO BRIDGE ADDRESSES ARE STILL MISSING FROM THIS FILE (ENG-9684, 2026-09-15).",
33990
+ "The control-plane egress bridge is being deployed to prod with a managed multi-AZ NAT,",
33991
+ "which allocates two more Elastic IPs - in the CONTROL PLANE account (109039361030), not",
33992
+ "the hosts account. They are not listed here yet because they do not exist until that",
33993
+ "deploy runs; read them from SSM at",
33994
+ "/augmented/prod/secrets/COMPOSIO_EGRESS_IPS (comma-separated, ready to paste) and add",
33995
+ "them here in the same change that arms anything.",
33996
+ "",
33997
+ "THE DETECTOR CANNOT VERIFY THOSE TWO, AND THAT IS CORRECT, NOT A BUG.",
33998
+ "ComposioEgressAddressDrift enumerates ONE account - the hosts account - so it compares",
33999
+ "only the addresses instances there actually route through. Bridge addresses will sit in",
34000
+ "this set unmatched and unflagged. Do NOT 'fix' that by trimming this file to what the",
34001
+ "detector checks: the file records what the ALLOWLIST must hold, which is a superset of",
34002
+ "what any one account scan can see. Trimming it would make the allowlist incomplete,",
34003
+ "which is a fleet-wide 401 rather than a tidy file."
33988
34004
  ],
33989
34005
  account: "711726113003",
33990
34006
  homeRegion: "ap-southeast-2",
package/dist/mcp/xero.js CHANGED
@@ -114353,6 +114353,16 @@ function pickTenantId(tenants, desired) {
114353
114353
  return desired;
114354
114354
  }
114355
114355
 
114356
+ // src/helpers/tenant-context.ts
114357
+ import { AsyncLocalStorage } from "async_hooks";
114358
+ var store = new AsyncLocalStorage();
114359
+ function runWithTenant(tenantId, fn) {
114360
+ return store.run({ tenantId }, fn);
114361
+ }
114362
+ function currentCallTenant() {
114363
+ return store.getStore()?.tenantId;
114364
+ }
114365
+
114356
114366
  // src/clients/broker-credential-client.ts
114357
114367
  function makeError(status, message, needsReauth = false) {
114358
114368
  const err = new Error(message);
@@ -114437,7 +114447,11 @@ var BrokerCredentialClient = class {
114437
114447
  tenantId: res.data.tenant_id ?? null,
114438
114448
  expiresAt: res.data.expires_at ?? null,
114439
114449
  grantedScopes: res.data.granted_scopes ?? null,
114440
- effectiveScopes: res.data.effective_scopes ?? null
114450
+ effectiveScopes: res.data.effective_scopes ?? null,
114451
+ allowedTenants: Array.isArray(res.data.allowed_tenants) ? res.data.allowed_tenants.filter((t) => typeof t?.tenant_id === "string" && t.tenant_id.trim() !== "").map((t) => ({
114452
+ tenantId: t.tenant_id.trim(),
114453
+ tenantName: typeof t.tenant_name === "string" ? t.tenant_name : null
114454
+ })) : null
114441
114455
  };
114442
114456
  } catch (err) {
114443
114457
  if (err.status !== void 0) throw err;
@@ -114512,12 +114526,44 @@ if (!broker_mode && !bearer_token && (!client_id || !client_secret)) {
114512
114526
  throw Error("Environment Variables not set - please check your .env file");
114513
114527
  }
114514
114528
  var MCPXeroClient = class extends import_xero_node.XeroClient {
114515
- tenantId;
114516
- shortCode;
114529
+ pinnedTenantId = "";
114530
+ // CS-1739: one short code per organisation, since a call can now target any
114531
+ // allowed organisation and a deep link must point at the right one.
114532
+ shortCodes = /* @__PURE__ */ new Map();
114533
+ /** CS-1739: the organisations the platform allows for this login (broker mode). */
114534
+ /**
114535
+ * CS-1739: the operator's organisation list from the broker.
114536
+ * null = the platform sent none (older API, or a non-broker install), so
114537
+ * the single pinned tenant applies;
114538
+ * [] = an EXPLICIT empty list (nothing intersected), which must refuse
114539
+ * every call rather than fall back to the pin. CodeRabbit on #6188:
114540
+ * collapsing both to [] let a call run against the pinned tenant
114541
+ * despite the operator allowing nothing.
114542
+ */
114543
+ allowedTenants = null;
114517
114544
  constructor(config2) {
114518
114545
  super(config2);
114519
- this.tenantId = "";
114520
- this.shortCode = "";
114546
+ }
114547
+ /**
114548
+ * The tenant for the CURRENT tool call when one was chosen (CS-1739), else
114549
+ * the pinned tenant. Handlers keep reading `xeroClient.tenantId` unchanged.
114550
+ */
114551
+ get tenantId() {
114552
+ return currentCallTenant() ?? this.pinnedTenantId;
114553
+ }
114554
+ set tenantId(value) {
114555
+ this.pinnedTenantId = value;
114556
+ }
114557
+ /**
114558
+ * CS-1739: the organisations a tool call may target. The broker's list when
114559
+ * it sent one; otherwise the single pinned tenant (older API / non-broker).
114560
+ */
114561
+ async getAllowedTenants() {
114562
+ await this.authenticate();
114563
+ if (this.allowedTenants !== null) return this.allowedTenants;
114564
+ if (!this.pinnedTenantId) return [];
114565
+ const match = (this.tenants ?? []).find((t) => t?.tenantId === this.pinnedTenantId);
114566
+ return [{ tenantId: this.pinnedTenantId, tenantName: match?.tenantName ?? null }];
114521
114567
  }
114522
114568
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
114523
114569
  async updateTenants(fullOrgDetails) {
@@ -114537,10 +114583,11 @@ var MCPXeroClient = class extends import_xero_node.XeroClient {
114537
114583
  return organisation;
114538
114584
  }
114539
114585
  async getShortCode() {
114540
- if (!this.shortCode) {
114586
+ const key = this.tenantId;
114587
+ if (!this.shortCodes.has(key)) {
114541
114588
  try {
114542
114589
  const organisation = await this.getOrganisation();
114543
- this.shortCode = organisation.shortCode ?? "";
114590
+ this.shortCodes.set(key, organisation.shortCode ?? "");
114544
114591
  } catch (error2) {
114545
114592
  const err = ensureError(error2);
114546
114593
  throw new Error(
@@ -114548,7 +114595,7 @@ var MCPXeroClient = class extends import_xero_node.XeroClient {
114548
114595
  );
114549
114596
  }
114550
114597
  }
114551
- return this.shortCode;
114598
+ return this.shortCodes.get(key);
114552
114599
  }
114553
114600
  };
114554
114601
  var CustomConnectionsXeroClient = class extends MCPXeroClient {
@@ -114681,6 +114728,7 @@ var BrokerBearerTokenXeroClient = class extends MCPXeroClient {
114681
114728
  this.setTokenSet({
114682
114729
  access_token: cred.accessToken
114683
114730
  });
114731
+ this.allowedTenants = cred.allowedTenants ?? null;
114684
114732
  if (cred.tenantId) {
114685
114733
  this.tenantId = cred.tenantId;
114686
114734
  } else {
@@ -120844,6 +120892,100 @@ var UpdateTools = [
120844
120892
  update_repeating_invoice_tool_default
120845
120893
  ];
120846
120894
 
120895
+ // src/tools/list/list-organisations.tool.ts
120896
+ var ListOrganisationsTool = CreateXeroTool(
120897
+ "list-organisations",
120898
+ "Lists the Xero organisations this agent is allowed to use, with each organisation's tenant_id. Pass one of these tenant_id values to any Xero tool to target that organisation. Read-only.",
120899
+ {},
120900
+ async () => {
120901
+ try {
120902
+ const allowed = await xeroClient.getAllowedTenants();
120903
+ if (allowed.length === 0) {
120904
+ return {
120905
+ content: [{ type: "text", text: "No Xero organisation is selected for this agent. Ask an admin to choose one in the console." }],
120906
+ isError: true
120907
+ };
120908
+ }
120909
+ const lines = allowed.map(
120910
+ (t, i) => `${i + 1}. ${t.tenantName ?? "(name unknown)"} - tenant_id: ${t.tenantId}${i === 0 ? " (default)" : ""}`
120911
+ );
120912
+ return {
120913
+ content: [{ type: "text", text: `Xero organisations this agent may use:
120914
+ ${lines.join("\n")}` }]
120915
+ };
120916
+ } catch (error2) {
120917
+ return {
120918
+ content: [{ type: "text", text: `Could not list Xero organisations: ${ensureError(error2).message}` }],
120919
+ isError: true
120920
+ };
120921
+ }
120922
+ }
120923
+ );
120924
+ var list_organisations_tool_default = ListOrganisationsTool;
120925
+
120926
+ // src/helpers/resolve-call-tenant.ts
120927
+ function describe(allowed) {
120928
+ return allowed.map((t) => t.tenantName ? `${t.tenantName} (${t.tenantId})` : t.tenantId).join(", ");
120929
+ }
120930
+ function resolveCallTenant(allowed, requested) {
120931
+ const wanted = typeof requested === "string" ? requested.trim() : "";
120932
+ if (allowed !== null && allowed.length === 0) {
120933
+ return {
120934
+ ok: false,
120935
+ message: "This agent has no Xero organisations selected, so no Xero call can run. Ask an admin to choose the organisations for this integration."
120936
+ };
120937
+ }
120938
+ if (allowed === null) {
120939
+ if (wanted) {
120940
+ return {
120941
+ ok: false,
120942
+ message: `tenant_id ${wanted} cannot be used: this Xero connection has no organisation list to check it against.`
120943
+ };
120944
+ }
120945
+ return { ok: true, tenantId: void 0 };
120946
+ }
120947
+ if (wanted) {
120948
+ if (allowed.some((t) => t.tenantId === wanted)) return { ok: true, tenantId: wanted };
120949
+ return {
120950
+ ok: false,
120951
+ message: `tenant_id ${wanted} is not one of the Xero organisations this agent may use: ${describe(allowed)}.`
120952
+ };
120953
+ }
120954
+ if (allowed.length === 1) return { ok: true, tenantId: allowed[0].tenantId };
120955
+ return {
120956
+ ok: false,
120957
+ message: `This agent can use more than one Xero organisation, so pass tenant_id. Allowed: ${describe(allowed)}. Call list-organisations to see them.`
120958
+ };
120959
+ }
120960
+
120961
+ // src/tools/tenant-scope.ts
120962
+ var TENANT_ID_ARG_DESCRIPTION = "Optional. The Xero organisation id (tenant) to use. Needed only when this agent can use more than one Xero organisation; call list-organisations to see them. Defaults to the only allowed organisation.";
120963
+ function errorResult(text) {
120964
+ return { content: [{ type: "text", text }], isError: true };
120965
+ }
120966
+ function withTenantScope(tool) {
120967
+ const schema = tool.schema ?? {};
120968
+ if ("tenant_id" in schema) return tool;
120969
+ return {
120970
+ ...tool,
120971
+ schema: { ...schema, tenant_id: external_exports.string().optional().describe(TENANT_ID_ARG_DESCRIPTION) },
120972
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
120973
+ handler: (async (args, extra) => {
120974
+ const { tenant_id: requested, ...rest } = args ?? {};
120975
+ let allowed;
120976
+ try {
120977
+ allowed = await xeroClient.getAllowedTenants();
120978
+ } catch (error2) {
120979
+ return errorResult(`Could not resolve the Xero organisations for this agent: ${ensureError(error2).message}`);
120980
+ }
120981
+ const choice = resolveCallTenant(allowed, typeof requested === "string" ? requested : void 0);
120982
+ if (!choice.ok) return errorResult(choice.message);
120983
+ const call = () => tool.handler(rest, extra);
120984
+ return choice.tenantId === void 0 ? call() : runWithTenant(choice.tenantId, call);
120985
+ })
120986
+ };
120987
+ }
120988
+
120847
120989
  // src/tools/tool-factory.ts
120848
120990
  function writesGoViaBroker() {
120849
120991
  const raw = (process.env.XERO_WRITES_VIA_BROKER ?? "").trim().toLowerCase();
@@ -120877,15 +121019,17 @@ function ToolFactory(server, effectiveScopes = null) {
120877
121019
  "xero-mcp-server: agent policy excludes payroll scopes \u2014 payroll tools not registered (ENG-7824)."
120878
121020
  );
120879
121021
  }
120880
- GetTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
120881
- ListTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
120882
- AttachmentTools.map((tool) => tool()).forEach(
121022
+ const listOrganisations = list_organisations_tool_default();
121023
+ server.tool(listOrganisations.name, listOrganisations.description, listOrganisations.schema, listOrganisations.handler);
121024
+ GetTools.map((tool) => tool()).filter((tool) => allow(tool.name)).map(withTenantScope).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
121025
+ ListTools.map((tool) => tool()).filter((tool) => allow(tool.name)).map(withTenantScope).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
121026
+ AttachmentTools.map((tool) => tool()).map(withTenantScope).forEach(
120883
121027
  (tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler)
120884
121028
  );
120885
121029
  if (readOnly) return;
120886
- DeleteTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
120887
- CreateTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
120888
- UpdateTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
121030
+ DeleteTools.map((tool) => tool()).filter((tool) => allow(tool.name)).map(withTenantScope).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
121031
+ CreateTools.map((tool) => tool()).filter((tool) => allow(tool.name)).map(withTenantScope).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
121032
+ UpdateTools.map((tool) => tool()).filter((tool) => allow(tool.name)).map(withTenantScope).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
120889
121033
  }
120890
121034
 
120891
121035
  // src/index.ts
@@ -62,8 +62,8 @@ import {
62
62
  writeDirectChatSessionState,
63
63
  writeEgressAllowlist,
64
64
  writePersistentClaudeWrapper
65
- } from "./chunk-MNARTDPO.js";
66
- import "./chunk-D3FGOGI2.js";
65
+ } from "./chunk-WVOB2TIP.js";
66
+ import "./chunk-SMZQHDO7.js";
67
67
  import "./chunk-DHWNVVX4.js";
68
68
  import "./chunk-XWVM4KPK.js";
69
69
  export {
@@ -131,4 +131,4 @@ export {
131
131
  writeEgressAllowlist,
132
132
  writePersistentClaudeWrapper
133
133
  };
134
- //# sourceMappingURL=persistent-session-22PIKH3S.js.map
134
+ //# sourceMappingURL=persistent-session-TZO2JPCC.js.map