@integrity-labs/agt-cli 0.28.617 → 0.28.619

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-TYVQNCBU.js → chunk-P6KFZVKA.js} +36 -1
  3. package/dist/chunk-P6KFZVKA.js.map +1 -0
  4. package/dist/{chunk-6SJJM4FT.js → chunk-RXC3MTSN.js} +5 -2
  5. package/dist/chunk-RXC3MTSN.js.map +1 -0
  6. package/dist/{chunk-NJHZL7CZ.js → chunk-WY7QPFBK.js} +57 -4
  7. package/dist/chunk-WY7QPFBK.js.map +1 -0
  8. package/dist/{claude-pair-runtime-QCL2TB6N.js → claude-pair-runtime-3356FFTC.js} +2 -2
  9. package/dist/lib/manager-worker.js +121 -19
  10. package/dist/lib/manager-worker.js.map +1 -1
  11. package/dist/mcp/direct-chat-channel.js +35 -0
  12. package/dist/mcp/origami.js +35 -0
  13. package/dist/mcp/slack-channel.js +65 -6
  14. package/dist/mcp/telegram-channel.js +35 -0
  15. package/dist/{persistent-session-GM3EH2ZU.js → persistent-session-AGPLISL3.js} +3 -3
  16. package/dist/{responsiveness-probe-VSSJC3MN.js → responsiveness-probe-ITYPPSHM.js} +3 -3
  17. package/dist/{session-auth-dead-KOKVXPPQ.js → session-auth-dead-Y6ABNWNM.js} +2 -2
  18. package/package.json +1 -1
  19. package/dist/chunk-6SJJM4FT.js.map +0 -1
  20. package/dist/chunk-NJHZL7CZ.js.map +0 -1
  21. package/dist/chunk-TYVQNCBU.js.map +0 -1
  22. /package/dist/{claude-pair-runtime-QCL2TB6N.js.map → claude-pair-runtime-3356FFTC.js.map} +0 -0
  23. /package/dist/{persistent-session-GM3EH2ZU.js.map → persistent-session-AGPLISL3.js.map} +0 -0
  24. /package/dist/{responsiveness-probe-VSSJC3MN.js.map → responsiveness-probe-ITYPPSHM.js.map} +0 -0
  25. /package/dist/{session-auth-dead-KOKVXPPQ.js.map → session-auth-dead-Y6ABNWNM.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-GM3EH2ZU.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-AGPLISL3.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-QCL2TB6N.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-3356FFTC.js.map
@@ -34,6 +34,7 @@ import {
34
34
  liveProxyTokenVars,
35
35
  markQuarantinedForProbe,
36
36
  migrateAgentDirToIdKeyed,
37
+ mintAgentKey,
37
38
  pinAllowsUrgent,
38
39
  provision,
39
40
  provisionAutoKanbanProgressHook,
@@ -53,7 +54,7 @@ import {
53
54
  safeWriteJsonAtomic,
54
55
  setConfigHash,
55
56
  tripClass
56
- } from "../chunk-NJHZL7CZ.js";
57
+ } from "../chunk-WY7QPFBK.js";
57
58
  import {
58
59
  getProjectDir as getProjectDir2,
59
60
  getReadyTasks,
@@ -109,7 +110,7 @@ import {
109
110
  takeZombieDetection,
110
111
  toOpencodeModel,
111
112
  writeEgressAllowlist
112
- } from "../chunk-6SJJM4FT.js";
113
+ } from "../chunk-RXC3MTSN.js";
113
114
  import {
114
115
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
115
116
  AnchorSessionClient,
@@ -186,7 +187,7 @@ import {
186
187
  subagentActivityAgeSeconds,
187
188
  sumTranscriptUsageInWindow,
188
189
  transcriptActivityAgeSeconds
189
- } from "../chunk-TYVQNCBU.js";
190
+ } from "../chunk-P6KFZVKA.js";
190
191
  import {
191
192
  reapOrphanChannelMcps
192
193
  } from "../chunk-XWVM4KPK.js";
@@ -4696,6 +4697,13 @@ function classifyPollError(message) {
4696
4697
  return "other";
4697
4698
  }
4698
4699
 
4700
+ // src/lib/per-agent-key.ts
4701
+ async function resolvePerAgentApiKey(opts) {
4702
+ const isPool = opts.hostKind === "pool";
4703
+ if (!isPool && !opts.dedicatedEnabled) return null;
4704
+ return await opts.mint(opts.rawHostKey, opts.agentId);
4705
+ }
4706
+
4699
4707
  // src/lib/integration-context-render.ts
4700
4708
  var PLUGIN_CONTEXT_PLACEHOLDER_RE = /\{\{\s*context\.([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
4701
4709
  var TEAM_OVERRIDES_HEADER = "## Team Overrides\n\n> **The following overrides anything you've read above.** If any rule here conflicts with earlier instructions in this skill, follow what is written here. These are user-supplied directives that take precedence over the plugin's default guidance.\n";
@@ -8022,14 +8030,23 @@ var ALLOWED_MESSAGE_SUBTYPES = /* @__PURE__ */ new Set([
8022
8030
  "file_share",
8023
8031
  "thread_broadcast"
8024
8032
  ]);
8025
- function decideSlackMessageForward(evt) {
8033
+ function matchesThirdPartyGrant(evt, thirdPartyBots) {
8034
+ const botId = evt.bot_id;
8035
+ if (!botId || !thirdPartyBots?.length)
8036
+ return false;
8037
+ return thirdPartyBots.some((b) => b.bot_id === botId || b.bot_user_id === botId);
8038
+ }
8039
+ function decideSlackMessageForward(evt, thirdPartyBots) {
8026
8040
  if (evt.type !== "message") {
8027
8041
  return { forward: true };
8028
8042
  }
8043
+ const granted = matchesThirdPartyGrant(evt, thirdPartyBots);
8029
8044
  if (!ALLOWED_MESSAGE_SUBTYPES.has(evt.subtype)) {
8030
- return { forward: false, reason: "subtype" };
8045
+ if (!granted || evt.subtype !== "bot_message") {
8046
+ return { forward: false, reason: "subtype" };
8047
+ }
8031
8048
  }
8032
- if (!evt.user) {
8049
+ if (!evt.user && !granted) {
8033
8050
  return { forward: false, reason: "no_user" };
8034
8051
  }
8035
8052
  const hasText = typeof evt.text === "string" && evt.text.trim().length > 0;
@@ -8124,7 +8141,13 @@ function classifyPeerMessage(msg, cfg, self) {
8124
8141
  }
8125
8142
  const peer = cfg.peers.find((p) => p.bot_user_id === msg.user);
8126
8143
  if (!peer) {
8127
- const thirdParty = cfg.third_party_bots?.find((b) => b.bot_user_id === msg.user);
8144
+ const thirdParty = cfg.third_party_bots?.find((b) => {
8145
+ if (msg.user && b.bot_user_id === msg.user)
8146
+ return true;
8147
+ if (!msg.bot_id)
8148
+ return false;
8149
+ return b.bot_id === msg.bot_id || b.bot_user_id === msg.bot_id;
8150
+ });
8128
8151
  if (thirdParty) {
8129
8152
  if (cfg.peer_disabled_mode === "cross_team_only") {
8130
8153
  return { kind: "drop", reason: "peer_disabled_cross_team" };
@@ -8241,6 +8264,39 @@ function parsePeerGroupIdsEnv(raw) {
8241
8264
  return [];
8242
8265
  return raw.split(",").map((s) => s.trim()).filter(Boolean);
8243
8266
  }
8267
+ function parseThirdPartyBotsEnv(raw) {
8268
+ if (!raw || !raw.trim())
8269
+ return [];
8270
+ let parsed;
8271
+ try {
8272
+ parsed = JSON.parse(raw);
8273
+ } catch {
8274
+ return [];
8275
+ }
8276
+ if (!Array.isArray(parsed))
8277
+ return [];
8278
+ const out = [];
8279
+ for (const item of parsed) {
8280
+ if (!item || typeof item !== "object")
8281
+ continue;
8282
+ const rec = item;
8283
+ const botUserId = typeof rec["bot_user_id"] === "string" ? rec["bot_user_id"].trim() : "";
8284
+ if (!botUserId)
8285
+ continue;
8286
+ if (!Array.isArray(rec["channel_ids"]))
8287
+ continue;
8288
+ const channels = rec["channel_ids"].filter((c) => typeof c === "string" && c.trim() !== "").map((c) => c.trim());
8289
+ const label = typeof rec["label"] === "string" && rec["label"].trim() ? rec["label"].trim() : void 0;
8290
+ const botId = typeof rec["bot_id"] === "string" && rec["bot_id"].trim() ? rec["bot_id"].trim() : void 0;
8291
+ out.push({
8292
+ bot_user_id: botUserId,
8293
+ channel_ids: channels,
8294
+ ...botId ? { bot_id: botId } : {},
8295
+ ...label ? { label } : {}
8296
+ });
8297
+ }
8298
+ return out;
8299
+ }
8244
8300
  function parsePeerAgentModeEnv(raw) {
8245
8301
  if (raw === "listen" || raw === "respond")
8246
8302
  return raw;
@@ -8322,7 +8378,7 @@ function decideInboundAccess(input) {
8322
8378
  // ../../packages/core/dist/channels/governance/slack-sender-gate.js
8323
8379
  function evaluateSlackInboundGate(evt, deps) {
8324
8380
  const isBot = Boolean(evt.bot_id);
8325
- const content = decideSlackMessageForward(evt);
8381
+ const content = decideSlackMessageForward(evt, deps.peerConfig.third_party_bots);
8326
8382
  const spDecision = decideSenderPolicyForward(evt, deps.senderPolicy);
8327
8383
  const senderPolicy = spDecision.forward ? { forward: true } : { forward: false, reason: classifySlackPolicyBlock(evt, deps.senderPolicy) };
8328
8384
  const peer = isBot ? (() => {
@@ -8420,7 +8476,15 @@ function buildSlackPeerClassifierConfigFromEnv(env, opts) {
8420
8476
  peer_agent_mode: parsePeerAgentModeEnv(env["SLACK_PEER_AGENT_MODE"]),
8421
8477
  peer_group_ids: parsePeerGroupIdsEnv(env["SLACK_PEER_GROUP_IDS"]),
8422
8478
  peers: parsePeersEnv(env["SLACK_PEERS"], env["SLACK_PEERS_GATE"]),
8423
- peer_disabled_mode: parseSlackPeerDisabledModeEnv(env, opts?.onWarn)
8479
+ peer_disabled_mode: parseSlackPeerDisabledModeEnv(env, opts?.onWarn),
8480
+ // ENG-8669 follow-up: this builder never populated the third-party
8481
+ // allowlist. ENG-8669 read `SLACK_THIRD_PARTY_BOTS` only in the MCP
8482
+ // adapter's own inline config, so every consumer of THIS builder — the
8483
+ // opencode manager-side SenderGate among them — saw `third_party_bots`
8484
+ // as undefined and could not admit a third-party bot under any
8485
+ // configuration. The allowlist was wired into one of the two Slack ingress
8486
+ // paths. Reading it here makes the two agree.
8487
+ third_party_bots: parseThirdPartyBotsEnv(env["SLACK_THIRD_PARTY_BOTS"])
8424
8488
  };
8425
8489
  }
8426
8490
 
@@ -11330,7 +11394,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
11330
11394
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
11331
11395
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
11332
11396
  async function channelInboundActivityAgeSecondsFor(codeName) {
11333
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-VSSJC3MN.js");
11397
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-ITYPPSHM.js");
11334
11398
  const newest = newestPendingInboundActivityMtimeMs(dirname9(paneLogPath(codeName)));
11335
11399
  if (newest === null) return null;
11336
11400
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -11969,7 +12033,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
11969
12033
  var lastVersionCheckAt = 0;
11970
12034
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
11971
12035
  var lastResponsivenessProbeAt = 0;
11972
- var agtCliVersion = true ? "0.28.617" : "dev";
12036
+ var agtCliVersion = true ? "0.28.619" : "dev";
11973
12037
  function resolveBrewPath(execFileSync3) {
11974
12038
  try {
11975
12039
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -13276,7 +13340,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
13276
13340
  if (codeNames.length === 0) return;
13277
13341
  void (async () => {
13278
13342
  try {
13279
- const { collectDiagnostics } = await import("../persistent-session-GM3EH2ZU.js");
13343
+ const { collectDiagnostics } = await import("../persistent-session-AGPLISL3.js");
13280
13344
  await api.post("/host/heartbeat", {
13281
13345
  host_id: hostId,
13282
13346
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -13392,7 +13456,7 @@ async function pollCycleInner() {
13392
13456
  }
13393
13457
  try {
13394
13458
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
13395
- const { collectDiagnostics } = await import("../persistent-session-GM3EH2ZU.js");
13459
+ const { collectDiagnostics } = await import("../persistent-session-AGPLISL3.js");
13396
13460
  const diagCodeNames = [...agentState.persistentSessionAgents];
13397
13461
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor) : void 0;
13398
13462
  let tailscaleHostname;
@@ -13515,7 +13579,7 @@ async function pollCycleInner() {
13515
13579
  collectPanelessActivityProbes,
13516
13580
  getResponsivenessIntervalMs,
13517
13581
  occupancyQualificationClassifications
13518
- } = await import("../responsiveness-probe-VSSJC3MN.js");
13582
+ } = await import("../responsiveness-probe-ITYPPSHM.js");
13519
13583
  const probeIntervalMs = getResponsivenessIntervalMs();
13520
13584
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
13521
13585
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -13621,7 +13685,7 @@ async function pollCycleInner() {
13621
13685
  collectResponsivenessProbes,
13622
13686
  livePendingInboundOldestAgeSeconds,
13623
13687
  parkPendingInbound
13624
- } = await import("../responsiveness-probe-VSSJC3MN.js");
13688
+ } = await import("../responsiveness-probe-ITYPPSHM.js");
13625
13689
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
13626
13690
  const wedgeNow = /* @__PURE__ */ new Date();
13627
13691
  const liveAgents = agentState.persistentSessionAgents;
@@ -13777,7 +13841,7 @@ async function pollCycleInner() {
13777
13841
  }
13778
13842
  try {
13779
13843
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
13780
- const { probeSessionAuth } = await import("../session-auth-dead-KOKVXPPQ.js");
13844
+ const { probeSessionAuth } = await import("../session-auth-dead-Y6ABNWNM.js");
13781
13845
  const observations = [];
13782
13846
  const pendingCacheCommits = [];
13783
13847
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -16659,6 +16723,8 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
16659
16723
  let claudeAuthMode;
16660
16724
  let anthropicApiKey;
16661
16725
  let anthropicApiKeyFingerprint;
16726
+ let hostKind = null;
16727
+ let rawHostKey = null;
16662
16728
  try {
16663
16729
  const apiKey = getApiKey();
16664
16730
  if (!apiKey) {
@@ -16673,6 +16739,8 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
16673
16739
  claudeAuthMode = exchange.claudeAuthMode;
16674
16740
  anthropicApiKey = exchange.anthropicApiKey;
16675
16741
  anthropicApiKeyFingerprint = exchange.anthropicApiKeyFingerprint;
16742
+ hostKind = exchange.hostKind;
16743
+ rawHostKey = apiKey;
16676
16744
  } catch (err) {
16677
16745
  const msg = err.message;
16678
16746
  const healthyBefore = isSessionHealthy(codeName);
@@ -16923,6 +16991,37 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash17("sha256")
16923
16991
  refreshData.tools?.raw_content
16924
16992
  );
16925
16993
  egressAllowlistBySession.set(codeName, egressAllowlist);
16994
+ let perAgentApiKey = null;
16995
+ try {
16996
+ perAgentApiKey = await resolvePerAgentApiKey({
16997
+ hostKind,
16998
+ // Non-null on every path that reaches here: the auth block above returns
16999
+ // 'skipped-no-api-key' when getApiKey() is empty. `?? ''` keeps the types
17000
+ // honest without inventing a fallback credential — an empty key cannot
17001
+ // authenticate the mint, so it fails closed like any other bad key.
17002
+ rawHostKey: rawHostKey ?? "",
17003
+ agentId: agent.agent_id,
17004
+ dedicatedEnabled: hostFlagStore().getBoolean("per-agent-host-credentials"),
17005
+ mint: mintAgentKey
17006
+ });
17007
+ } catch (err) {
17008
+ const msg = err instanceof Error ? err.message : String(err);
17009
+ log(
17010
+ `[persistent-session] '${codeName}' (host_kind=${hostKind ?? "dedicated"}): per-agent key mint FAILED (${msg}) \u2014 refusing to spawn rather than fall back to the shared host key`
17011
+ );
17012
+ closeSessionRunForCode(codeName, "failed", "per-agent key mint failed");
17013
+ return {
17014
+ decision: "skipped-per-agent-key-mint-failed",
17015
+ spawnAttempted: false,
17016
+ sessionHealthyAfter: isSessionHealthy(codeName),
17017
+ detail: msg
17018
+ };
17019
+ }
17020
+ if (perAgentApiKey) {
17021
+ log(
17022
+ `[persistent-session] '${codeName}' (host_kind=${hostKind ?? "dedicated"}): injecting per-agent org-scoped key (ADR-0042 pt3b)`
17023
+ );
17024
+ }
16926
17025
  startPersistentSession({
16927
17026
  codeName,
16928
17027
  agentId: agent.agent_id,
@@ -16971,6 +17070,9 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash17("sha256")
16971
17070
  // this the flip reaches nothing running under Docker isolation.
16972
17071
  turnFailureNoticeEnabled: hostFlagStore().getBoolean("wedge-transient-notice"),
16973
17072
  egressAllowlist,
17073
+ // ADR-0042 pt3b (ENG-7607 / ENG-8992): this agent's own org-scoped key
17074
+ // (null when unarmed). The spawn env carries it as this agent's AGT_API_KEY.
17075
+ perAgentApiKey,
16974
17076
  log
16975
17077
  });
16976
17078
  agentState.persistentSessionAgents.add(codeName);
@@ -17266,7 +17368,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
17266
17368
  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}`));
17267
17369
  void (async () => {
17268
17370
  try {
17269
- const { collectDiagnostics } = await import("../persistent-session-GM3EH2ZU.js");
17371
+ const { collectDiagnostics } = await import("../persistent-session-AGPLISL3.js");
17270
17372
  await api.post("/host/heartbeat", {
17271
17373
  host_id: hostId,
17272
17374
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -17317,7 +17419,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
17317
17419
  }
17318
17420
  try {
17319
17421
  const hostId = await getHostId();
17320
- const { collectDiagnostics } = await import("../persistent-session-GM3EH2ZU.js");
17422
+ const { collectDiagnostics } = await import("../persistent-session-AGPLISL3.js");
17321
17423
  await api.post("/host/heartbeat", {
17322
17424
  host_id: hostId,
17323
17425
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -17913,7 +18015,7 @@ async function processClaudePairSessions(agents) {
17913
18015
  killPairSession,
17914
18016
  pairTmuxSession,
17915
18017
  finalizeClaudePairOnboarding
17916
- } = await import("../claude-pair-runtime-QCL2TB6N.js");
18018
+ } = await import("../claude-pair-runtime-3356FFTC.js");
17917
18019
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
17918
18020
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
17919
18021
  const killed = await killPairSession(pairTmuxSession(pairId));