@integrity-labs/agt-cli 0.28.446 → 0.28.448

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/agt.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-O25GO4PT.js";
43
+ } from "../chunk-JUUAHLX5.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -71,7 +71,7 @@ import {
71
71
  requiredMcpWildcard,
72
72
  resolveChannels,
73
73
  serializeManifestForSlackCli
74
- } from "../chunk-QCEQRMBX.js";
74
+ } from "../chunk-ESZRW7A3.js";
75
75
  import "../chunk-XWVM4KPK.js";
76
76
 
77
77
  // src/bin/agt.ts
@@ -4830,7 +4830,7 @@ import { execFileSync, execSync } from "child_process";
4830
4830
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4831
4831
  import chalk18 from "chalk";
4832
4832
  import ora16 from "ora";
4833
- var cliVersion = true ? "0.28.446" : "dev";
4833
+ var cliVersion = true ? "0.28.448" : "dev";
4834
4834
  async function fetchLatestVersion() {
4835
4835
  const host2 = getHost();
4836
4836
  if (!host2) return null;
@@ -6002,7 +6002,7 @@ function handleError(err) {
6002
6002
  }
6003
6003
 
6004
6004
  // src/bin/agt.ts
6005
- var cliVersion2 = true ? "0.28.446" : "dev";
6005
+ var cliVersion2 = true ? "0.28.448" : "dev";
6006
6006
  var program = new Command();
6007
6007
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
6008
6008
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -3714,19 +3714,22 @@ acknowledge before you start.
3714
3714
 
3715
3715
  - **FAST (< 60s):** handle inline. Reply via the channel tool and end your turn.
3716
3716
 
3717
- - **SLOW (\u2265 60s):** acknowledge first, then handle inline.
3717
+ - **SLOW (\u2265 60s):** acknowledge first, then either dispatch or handle inline.
3718
3718
  1. Send a one-line acknowledgement via the channel tool \u2014 short, warm, and tell
3719
3719
  the user you'll come back. Shape (don't copy verbatim, match your voice):
3720
3720
  "On it, this'll take a minute or two, I'll ping when it's done."
3721
- 2. Do the work yourself in this same session, with whatever tools you need \u2014
3722
- your parent session has the full MCP surface bound.
3723
- 3. Reply with the result via the channel tool, in the same thread / chat /
3724
- conversation you acknowledged in step 1.
3725
-
3726
- > **Why inline, not sub-agent dispatch:** an upstream Claude Code bug empties the
3727
- > MCP registry for \`tools:\`-allowlisted sub-agents (\`channel-message-handler\` among
3728
- > them), so a dispatched reply silently never lands \u2014 see \xA7 Background dispatch.
3729
- > Handle slow channel work inline until the upstream fix ships.
3721
+ 2. Dispatch the work to the \`channel-message-handler\` sub-agent, passing the
3722
+ inbound's identifiers so it replies into the same thread / chat / conversation
3723
+ you acknowledged in step 1. It binds the full MCP surface and posts the reply
3724
+ itself, which keeps this listener turn free for new inbound.
3725
+ 3. Handling it inline instead is fine, and often better when you are already deep
3726
+ in the relevant context or dispatch would cost more than the work. Either way,
3727
+ reply with the result via the channel tool in the same conversation.
3728
+
3729
+ > **Whoever does the work, the delivery rule still binds:** the reply exists only if
3730
+ > a channel reply tool was called. If you dispatch, the sub-agent owns that call \u2014 so
3731
+ > confirm it reported success, and if it came back without having replied, reply
3732
+ > yourself rather than assuming the user was answered.
3730
3733
 
3731
3734
  Diving into slow work silently leaves operators wondering whether you got the
3732
3735
  message. If a request you started as FAST turns out slow, post a quick "this is
@@ -3753,19 +3756,25 @@ check-in is itself evidence your earlier silence read as non-responsiveness.
3753
3756
 
3754
3757
  For background tool work that **isn't** a channel reply \u2014 multi-step data pulls,
3755
3758
  CRM enrichments, research workflows, cross-MCP orchestration \u2014 use
3756
- \`subagent_type: general-purpose\` (Anthropic's built-in). It inherits the full MCP
3757
- tool surface from this session and reliably binds every \`mcp__*\` server.
3758
-
3759
- **Why not \`augmented-worker\` for now:** an upstream Claude Code bug
3760
- ([anthropics/claude-code#64909](https://github.com/anthropics/claude-code/issues/64909))
3761
- gives sub-agents with an explicit \`tools:\` allowlist an empty MCP registry \u2014 every
3762
- \`mcp__*\` call returns "No such tool available". \`general-purpose\` uses \`tools: *\`
3763
- (inherit-all) and escapes it; when the fix ships, \`augmented-worker\` (restricted
3764
- surface) becomes preferred again automatically.
3765
-
3766
- For slow **channel** replies see \xA7 FIRST ACTION \u2014 handled inline for the same
3767
- reason (\`channel-message-handler\` has the same allowlist shape; 0/6 MCP tools
3768
- bound, confirmed 2026-06-03). When the fix lands, both switch back to dispatch.
3759
+ \`subagent_type: augmented-worker\`. It carries an explicit allowlist covering every
3760
+ MCP server this session has wired, so it gets the tool surface the task needs and
3761
+ no more. Reach for \`general-purpose\` (\`tools: *\`, inherit-all) only when you
3762
+ genuinely need something outside that allowlist.
3763
+
3764
+ **Historical note \u2014 do not reintroduce the old workaround.** An upstream Claude Code
3765
+ bug ([anthropics/claude-code#64909](https://github.com/anthropics/claude-code/issues/64909))
3766
+ used to hand sub-agents with an explicit \`tools:\` allowlist an empty MCP registry:
3767
+ every \`mcp__*\` call returned "No such tool available". That is why this section
3768
+ once steered all dispatch to \`general-purpose\` and why slow channel replies were
3769
+ handled inline. Anthropic fixed it in **v2.1.163** \u2014 \`mcp__<server>__*\` wildcards in
3770
+ sub-agent \`tools:\` frontmatter now expand to the matching MCP tools instead of
3771
+ failing an exact-name lookup. Re-verified 2026-07-29 on 2.1.220: a
3772
+ \`channel-message-handler\` dispatch reached 469 \`mcp__*\` tools across four servers
3773
+ with zero "No such tool available".
3774
+
3775
+ For slow **channel** replies see \xA7 FIRST ACTION \u2014 dispatch to
3776
+ \`channel-message-handler\`, which binds the same full MCP surface and posts the
3777
+ reply itself.
3769
3778
 
3770
3779
  ${activeTasksSection}${personalitySection}${writingStyleSection}## Identity
3771
3780
 
@@ -3789,10 +3798,9 @@ ${resolvedChannels?.includes("slack") ? `
3789
3798
  ## Slack
3790
3799
 
3791
3800
  You have a Slack MCP server connected. **First, see
3792
- \xA7 FIRST ACTION on every channel message: triage** \u2014 decide fast vs slow, then
3793
- acknowledge inline before slow work
3794
- (sub-agent dispatch for channel replies is currently disabled by an upstream Claude
3795
- Code bug; see FIRST ACTION for the rationale).
3801
+ \xA7 FIRST ACTION on every channel message: triage** \u2014 decide fast vs slow, and
3802
+ acknowledge before slow work (which you can then dispatch to
3803
+ \`channel-message-handler\` or handle inline; see FIRST ACTION).
3796
3804
 
3797
3805
  For fast requests, reply with \`slack.reply\` (per the delivery rule in FIRST ACTION,
3798
3806
  a plain-text turn does NOT reach Slack \u2014 only a \`slack.reply\` call does). Tools:
@@ -12728,7 +12736,59 @@ function isResumeModeDialogVisible(screen) {
12728
12736
  function isSessionFeedbackDialogVisible(screen) {
12729
12737
  return screen.includes("How is Claude doing this session") && screen.includes("0: Dismiss");
12730
12738
  }
12739
+ var USAGE_LIMIT_SAFE_OPTION = "Stop and wait for limit to reset";
12740
+ var USAGE_LIMIT_BLOCK_LINES = 6;
12741
+ var BILLING_OPTIONS = ["Switch to usage credits", "Switch to Team plan"];
12742
+ function optionRowDigit(line2, label) {
12743
+ const m = line2.match(
12744
+ new RegExp(
12745
+ String.raw`^[^\S\n]*(?:❯[^\S\n]*)?(\d)\.[^\S\n]*` + label.replace(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`)
12746
+ )
12747
+ );
12748
+ return m?.[1] ?? null;
12749
+ }
12750
+ function usageLimitModalBlock(screen) {
12751
+ const lines = screen.split("\n");
12752
+ let footer = -1;
12753
+ for (let i = lines.length - 1; i >= 0; i--) {
12754
+ if (lines[i].includes("Enter to confirm")) {
12755
+ footer = i;
12756
+ break;
12757
+ }
12758
+ }
12759
+ if (footer < 0) return null;
12760
+ const block = lines.slice(Math.max(0, footer - USAGE_LIMIT_BLOCK_LINES), footer);
12761
+ const hasBillingRow = block.some(
12762
+ (l) => BILLING_OPTIONS.some((label) => optionRowDigit(l, label) !== null)
12763
+ );
12764
+ return hasBillingRow ? block : null;
12765
+ }
12766
+ function isUsageLimitChoiceDialogVisible(screen) {
12767
+ return usageLimitModalBlock(screen) !== null;
12768
+ }
12769
+ function findUsageLimitSafeOptionKey(screen) {
12770
+ const block = usageLimitModalBlock(screen);
12771
+ if (!block) return null;
12772
+ for (const line2 of block) {
12773
+ const digit = optionRowDigit(line2, USAGE_LIMIT_SAFE_OPTION);
12774
+ if (digit !== null) return digit;
12775
+ }
12776
+ return null;
12777
+ }
12778
+ function isUnanswerableUsageLimitDialog(screen) {
12779
+ return isUsageLimitChoiceDialogVisible(screen) && findUsageLimitSafeOptionKey(screen) === null;
12780
+ }
12731
12781
  function sweepDialogs(screen) {
12782
+ if (isUsageLimitChoiceDialogVisible(screen)) {
12783
+ const safeKey = findUsageLimitSafeOptionKey(screen);
12784
+ if (!safeKey) return null;
12785
+ return {
12786
+ kind: "usage-limit-choice",
12787
+ keys: [safeKey, "Enter"],
12788
+ interKeyDelayMs: 300,
12789
+ logMessage: `Auto-answered usage-limit choice dialog (picked '${USAGE_LIMIT_SAFE_OPTION}')`
12790
+ };
12791
+ }
12732
12792
  if (screen.includes("Choose the text style") || screen.includes("Dark mode") && screen.includes("Light mode")) {
12733
12793
  return {
12734
12794
  kind: "theme-picker",
@@ -12824,6 +12884,13 @@ function decide(pane, prev, now, config = {}) {
12824
12884
  if (dialogAction) {
12825
12885
  return { fire: false, dialog: dialogAction, next: prev };
12826
12886
  }
12887
+ if (isUnanswerableUsageLimitDialog(pane)) {
12888
+ return {
12889
+ fire: false,
12890
+ blockedDialog: "usage-limit-choice-unrecognised-options",
12891
+ next: prev
12892
+ };
12893
+ }
12827
12894
  const inputText = extractInputBoxText(pane);
12828
12895
  if (!inputText) {
12829
12896
  return { fire: false, next: void 0 };
@@ -12905,7 +12972,12 @@ function checkOne(codeName, io, config, states) {
12905
12972
  stuckThresholdMs: config.attachedStuckThresholdMs ?? ATTACHED_STUCK_THRESHOLD_MS
12906
12973
  } : config;
12907
12974
  const prev = states.get(codeName);
12908
- const { fire, dialog, gaveUp, next } = decide(pane, prev, io.now(), effectiveConfig);
12975
+ const { fire, dialog, gaveUp, blockedDialog, next } = decide(
12976
+ pane,
12977
+ prev,
12978
+ io.now(),
12979
+ effectiveConfig
12980
+ );
12909
12981
  if (next === void 0) {
12910
12982
  states.delete(codeName);
12911
12983
  if (prev && prev.fires > 0) {
@@ -12923,6 +12995,12 @@ function checkOne(codeName, io, config, states) {
12923
12995
  io.sendKeys(codeName, dialog.keys, dialog.interKeyDelayMs);
12924
12996
  return;
12925
12997
  }
12998
+ if (blockedDialog) {
12999
+ io.log(
13000
+ `[channel-input-watchdog] '${codeName}': BLOCKED DIALOG (${blockedDialog}) \u2014 refusing to send any key; needs a human to attach to the pane`
13001
+ );
13002
+ return;
13003
+ }
12926
13004
  const text = extractInputBoxText(pane) ?? "";
12927
13005
  const hash = next?.lastInputHash ?? simpleTextHash(text);
12928
13006
  if (gaveUp) {
@@ -13685,6 +13763,12 @@ async function acceptDialogs(tmuxSession, codeName, log2, primaryModel = null, s
13685
13763
  log2(`[persistent-session] ${dialogAction.logMessage} for '${codeName}'`);
13686
13764
  continue;
13687
13765
  }
13766
+ if (isUnanswerableUsageLimitDialog(screen)) {
13767
+ log2(
13768
+ `[persistent-session] BLOCKED DIALOG (usage-limit-choice-unrecognised-options) for '${codeName}' \u2014 refusing to send any key; needs a human to attach to the pane`
13769
+ );
13770
+ return;
13771
+ }
13688
13772
  if (screen.includes("\u276F") && !screen.includes("Enter to confirm")) {
13689
13773
  if (hasMcpChildren(tmuxSession)) {
13690
13774
  log2(`[persistent-session] Session ready for '${codeName}' \u2014 MCP servers spawned`);
@@ -13799,6 +13883,12 @@ async function preSendPaneHygiene(tmuxSession, codeName, log2) {
13799
13883
  await new Promise((r) => setTimeout(r, 300));
13800
13884
  screen = paneCapture(tmuxSession) ?? "";
13801
13885
  }
13886
+ if (isUnanswerableUsageLimitDialog(screen)) {
13887
+ log2(
13888
+ `[inject] BLOCKED DIALOG (usage-limit-choice-unrecognised-options) for '${codeName}' \u2014 skipping pane hygiene; needs a human to attach to the pane`
13889
+ );
13890
+ return;
13891
+ }
13802
13892
  const orphan = extractInputBoxText(screen);
13803
13893
  if (orphan) {
13804
13894
  log2(
@@ -14313,4 +14403,4 @@ export {
14313
14403
  stopAllSessionsAndWait,
14314
14404
  getProjectDir
14315
14405
  };
14316
- //# sourceMappingURL=chunk-QCEQRMBX.js.map
14406
+ //# sourceMappingURL=chunk-ESZRW7A3.js.map