@integrity-labs/agt-cli 0.28.441 → 0.28.443

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.
@@ -37627,8 +37627,31 @@ var DEFAULT_SCOPES = [
37627
37627
  // links an inbound Slack sender to their organization_people record (inbound
37628
37628
  // identity reconcile). Existing installs without it degrade gracefully - the
37629
37629
  // reconcile no-ops until the bot is re-authorised with the wider scope set.
37630
- "users:read.email",
37631
- "users.profile:write"
37630
+ "users:read.email"
37631
+ // ENG-8203: 'users.profile:write' is deliberately NOT here.
37632
+ //
37633
+ // It is registered with `token_type: 'user'` (ENG-4812 — Slack rejects it
37634
+ // under oauth_config.scopes.bot with `illegal_bot_scopes`). The MANIFEST
37635
+ // generator partitions on that flag; the OAuth install-URL builder does not —
37636
+ // `buildSlackAuthorizeUrl` puts every stored scope into `scope=` — so a
37637
+ // default-scoped OAuth install sent a user-only scope as a bot scope and
37638
+ // Slack rejected the whole authorization with "Invalid permissions
37639
+ // requested". That blocked EVERY new install on the default set.
37640
+ //
37641
+ // Removing it rather than routing it to `user_scope=` is deliberate: the
37642
+ // callback destructures `authed_user?: { id?: string }` and persists only the
37643
+ // BOT token (oauth-callback/route.ts:217,246). `authed_user.access_token` is
37644
+ // never read, so asking for the scope would put an extra consent screen in
37645
+ // front of the installing admin and then discard the token it returned.
37646
+ //
37647
+ // Nothing is lost. `users.profile.set` needs an `xoxp-` user token, which no
37648
+ // OAuth-installed agent has ever had — the bot-status/live-presence indicator
37649
+ // only ever worked where an operator pasted a user token into the wizard by
37650
+ // hand, and that path is untouched. The registry definition stays so existing
37651
+ // configs still render and the `token_type: 'user'` knowledge is preserved.
37652
+ //
37653
+ // Wiring the indicator for OAuth installs means persisting
37654
+ // `authed_user.access_token` first, THEN adding `user_scope=`. Separate work.
37632
37655
  ];
37633
37656
  var SLACK_SCOPE_PRESETS = {
37634
37657
  minimal: [
@@ -39782,6 +39805,14 @@ var BANNER_PATTERNS = [
39782
39805
  ];
39783
39806
  var MS_PER_DAY = 24 * 60 * 60 * 1e3;
39784
39807
 
39808
+ // ../core/dist/claude-code-usage/rate-limit-classifier.js
39809
+ var UNKNOWN_RATE_LIMIT = Object.freeze({
39810
+ verdict: "unknown",
39811
+ atMs: null,
39812
+ resetsAt: null,
39813
+ text: null
39814
+ });
39815
+
39785
39816
  // ../core/dist/kanban/state-machine.js
39786
39817
  var KANBAN_STATUSES = [
39787
39818
  "backlog",
@@ -40404,6 +40435,33 @@ var FLAG_REGISTRY = [
40404
40435
  // projectDefinition, so setting it does not roll FLAGS_SCHEMA_VERSION.
40405
40436
  since: "0.28.421"
40406
40437
  },
40438
+ {
40439
+ key: "usage-limit-reactive-notice",
40440
+ description: "Report a Claude Code usage cap REACTIVELY instead of predicting it (ENG-8201). Today the manager guesses from the agent transcript that the next turn will be refused, writes a marker, and every channel MCP refuses to dispatch on the strength of that guess - so a wrong guess is a swallowed message, and because the notice is throttled per (channel, sender) while the DROP is not, the usual symptom is total silence rather than a wrong reply. A refused turn actually costs nothing (rejected in under a second, zero tokens) and Claude Code records it with the reset time in it, so there is no need to guess: dispatch, and report the refusal if one comes back. off = today behaviour (pre-dispatch marker gate, no watcher). shadow = still gate on the marker, but ALSO watch dispatched messages and log the refusal that would have been reported - measures the true-positive rate with no user-visible change. enforce = stop reading the marker before dispatch; every admitted human message reaches the agent and a refusal is answered in-thread with the reset time from the error itself. Read live from the heartbeat flags-cache (or the env override).",
40441
+ flagType: "enum",
40442
+ allowedValues: ["off", "shadow", "enforce"],
40443
+ // Ships dark: off preserves today's gate byte-for-byte. shadow is a free
40444
+ // local log line (the watch is a transcript read, no model spend), so it is a
40445
+ // cheap soak; enforce changes what reaches the agent, so it is the audited
40446
+ // per-org flip.
40447
+ defaultValue: "off",
40448
+ // Enum override AGT_USAGE_LIMIT_REACTIVE_MODE (off|shadow|enforce), resolved
40449
+ // by resolveUsageLimitReactiveMode in the channel-server bundle.
40450
+ envVar: "AGT_USAGE_LIMIT_REACTIVE_MODE",
40451
+ // enforce sends a message to an agent the host currently believes is capped -
40452
+ // a deliberate availability trade (the refusal is free, but it is still a
40453
+ // dispatch the operator previously suppressed), so flipping toward it is an
40454
+ // audited change (ADR-0022 sensitive-flag confirm).
40455
+ sensitive: true
40456
+ // ENG-8149: `since` is the agt-cli version that first carries
40457
+ // resolveUsageLimitReactiveMode + the MCP watcher. It cannot be known before
40458
+ // this lands (the auto-publish patch-bumps on merge), and an undefined
40459
+ // `since` makes the flip-reach modal claim FULL reach - true for flags that
40460
+ // predate the reach work, wrong for a NEW host-read flag whose reader older
40461
+ // hosts simply do not have. Backfilled by a follow-up commit once the
40462
+ // publishing run reports the version. Excluded from projectDefinition, so
40463
+ // setting it does not roll FLAGS_SCHEMA_VERSION.
40464
+ },
40407
40465
  {
40408
40466
  key: "slack-hot-thread-guard",
40409
40467
  description: "Server-side hot-thread guard on the slack.reply surface (ENG-7462). Prevents an agent posting a NEW top-level Slack message when it meant to reply inside the thread it is already working in - a prompt/memory rule proved insufficient (the agent had the rule and still slipped). When a reply would otherwise post to channel ROOT (no thread_ts / message_ts / inbound_id, no active kanban card) and the agent has a recent active thread in that channel (its last bot-posted thread, from the persisted trackedThreads cache, within a freshness window), the reply is redirected into that thread. proactive:true no longer implies channel root; posting at root becomes a deliberate action (the to_channel_root flag, or the thread_ts:null sentinel). off = guard never runs, replies with no coords root exactly as today (ships dark). shadow = compute + log the would-redirect but STILL post to root (measure the fire rate before acting). enforce = apply the redirect (a soft-block: redirect + inform, never a hard rejection). Read live from the heartbeat flags-cache (or the env override); enforce is a deliberate per-org flip after a shadow soak.",
@@ -31558,8 +31558,31 @@ var DEFAULT_SCOPES = [
31558
31558
  // links an inbound Slack sender to their organization_people record (inbound
31559
31559
  // identity reconcile). Existing installs without it degrade gracefully - the
31560
31560
  // reconcile no-ops until the bot is re-authorised with the wider scope set.
31561
- "users:read.email",
31562
- "users.profile:write"
31561
+ "users:read.email"
31562
+ // ENG-8203: 'users.profile:write' is deliberately NOT here.
31563
+ //
31564
+ // It is registered with `token_type: 'user'` (ENG-4812 — Slack rejects it
31565
+ // under oauth_config.scopes.bot with `illegal_bot_scopes`). The MANIFEST
31566
+ // generator partitions on that flag; the OAuth install-URL builder does not —
31567
+ // `buildSlackAuthorizeUrl` puts every stored scope into `scope=` — so a
31568
+ // default-scoped OAuth install sent a user-only scope as a bot scope and
31569
+ // Slack rejected the whole authorization with "Invalid permissions
31570
+ // requested". That blocked EVERY new install on the default set.
31571
+ //
31572
+ // Removing it rather than routing it to `user_scope=` is deliberate: the
31573
+ // callback destructures `authed_user?: { id?: string }` and persists only the
31574
+ // BOT token (oauth-callback/route.ts:217,246). `authed_user.access_token` is
31575
+ // never read, so asking for the scope would put an extra consent screen in
31576
+ // front of the installing admin and then discard the token it returned.
31577
+ //
31578
+ // Nothing is lost. `users.profile.set` needs an `xoxp-` user token, which no
31579
+ // OAuth-installed agent has ever had — the bot-status/live-presence indicator
31580
+ // only ever worked where an operator pasted a user token into the wizard by
31581
+ // hand, and that path is untouched. The registry definition stays so existing
31582
+ // configs still render and the `token_type: 'user'` knowledge is preserved.
31583
+ //
31584
+ // Wiring the indicator for OAuth installs means persisting
31585
+ // `authed_user.access_token` first, THEN adding `user_scope=`. Separate work.
31563
31586
  ];
31564
31587
  var SLACK_SCOPE_PRESETS = {
31565
31588
  minimal: [
@@ -33749,6 +33772,14 @@ function buildUsageLimitReplyText(limitedUntil) {
33749
33772
  return `Your agent has hit its Claude Code usage limit until ${formatUtcClock(limitedUntil)}. It'll pick back up once the limit resets \u2014 please try again after then.`;
33750
33773
  }
33751
33774
 
33775
+ // ../core/dist/claude-code-usage/rate-limit-classifier.js
33776
+ var UNKNOWN_RATE_LIMIT = Object.freeze({
33777
+ verdict: "unknown",
33778
+ atMs: null,
33779
+ resetsAt: null,
33780
+ text: null
33781
+ });
33782
+
33752
33783
  // ../core/dist/account-enforcement/marker.js
33753
33784
  var ACCOUNT_ENFORCEMENT_MARKER_FILENAME = "account-enforcement.json";
33754
33785
  var ACCOUNT_ENFORCEMENT_MARKER_VERSION = 1;
@@ -34393,6 +34424,33 @@ var FLAG_REGISTRY = [
34393
34424
  // projectDefinition, so setting it does not roll FLAGS_SCHEMA_VERSION.
34394
34425
  since: "0.28.421"
34395
34426
  },
34427
+ {
34428
+ key: "usage-limit-reactive-notice",
34429
+ description: "Report a Claude Code usage cap REACTIVELY instead of predicting it (ENG-8201). Today the manager guesses from the agent transcript that the next turn will be refused, writes a marker, and every channel MCP refuses to dispatch on the strength of that guess - so a wrong guess is a swallowed message, and because the notice is throttled per (channel, sender) while the DROP is not, the usual symptom is total silence rather than a wrong reply. A refused turn actually costs nothing (rejected in under a second, zero tokens) and Claude Code records it with the reset time in it, so there is no need to guess: dispatch, and report the refusal if one comes back. off = today behaviour (pre-dispatch marker gate, no watcher). shadow = still gate on the marker, but ALSO watch dispatched messages and log the refusal that would have been reported - measures the true-positive rate with no user-visible change. enforce = stop reading the marker before dispatch; every admitted human message reaches the agent and a refusal is answered in-thread with the reset time from the error itself. Read live from the heartbeat flags-cache (or the env override).",
34430
+ flagType: "enum",
34431
+ allowedValues: ["off", "shadow", "enforce"],
34432
+ // Ships dark: off preserves today's gate byte-for-byte. shadow is a free
34433
+ // local log line (the watch is a transcript read, no model spend), so it is a
34434
+ // cheap soak; enforce changes what reaches the agent, so it is the audited
34435
+ // per-org flip.
34436
+ defaultValue: "off",
34437
+ // Enum override AGT_USAGE_LIMIT_REACTIVE_MODE (off|shadow|enforce), resolved
34438
+ // by resolveUsageLimitReactiveMode in the channel-server bundle.
34439
+ envVar: "AGT_USAGE_LIMIT_REACTIVE_MODE",
34440
+ // enforce sends a message to an agent the host currently believes is capped -
34441
+ // a deliberate availability trade (the refusal is free, but it is still a
34442
+ // dispatch the operator previously suppressed), so flipping toward it is an
34443
+ // audited change (ADR-0022 sensitive-flag confirm).
34444
+ sensitive: true
34445
+ // ENG-8149: `since` is the agt-cli version that first carries
34446
+ // resolveUsageLimitReactiveMode + the MCP watcher. It cannot be known before
34447
+ // this lands (the auto-publish patch-bumps on merge), and an undefined
34448
+ // `since` makes the flip-reach modal claim FULL reach - true for flags that
34449
+ // predate the reach work, wrong for a NEW host-read flag whose reader older
34450
+ // hosts simply do not have. Backfilled by a follow-up commit once the
34451
+ // publishing run reports the version. Excluded from projectDefinition, so
34452
+ // setting it does not roll FLAGS_SCHEMA_VERSION.
34453
+ },
34396
34454
  {
34397
34455
  key: "slack-hot-thread-guard",
34398
34456
  description: "Server-side hot-thread guard on the slack.reply surface (ENG-7462). Prevents an agent posting a NEW top-level Slack message when it meant to reply inside the thread it is already working in - a prompt/memory rule proved insufficient (the agent had the rule and still slipped). When a reply would otherwise post to channel ROOT (no thread_ts / message_ts / inbound_id, no active kanban card) and the agent has a recent active thread in that channel (its last bot-posted thread, from the persisted trackedThreads cache, within a freshness window), the reply is redirected into that thread. proactive:true no longer implies channel root; posting at root becomes a deliberate action (the to_channel_root flag, or the thread_ts:null sentinel). off = guard never runs, replies with no coords root exactly as today (ships dark). shadow = compute + log the would-redirect but STILL post to root (measure the fire rate before acting). enforce = apply the redirect (a soft-block: redirect + inform, never a hard rejection). Read live from the heartbeat flags-cache (or the env override); enforce is a deliberate per-org flip after a shadow soak.",
@@ -31860,8 +31860,31 @@ var DEFAULT_SCOPES = [
31860
31860
  // links an inbound Slack sender to their organization_people record (inbound
31861
31861
  // identity reconcile). Existing installs without it degrade gracefully - the
31862
31862
  // reconcile no-ops until the bot is re-authorised with the wider scope set.
31863
- "users:read.email",
31864
- "users.profile:write"
31863
+ "users:read.email"
31864
+ // ENG-8203: 'users.profile:write' is deliberately NOT here.
31865
+ //
31866
+ // It is registered with `token_type: 'user'` (ENG-4812 — Slack rejects it
31867
+ // under oauth_config.scopes.bot with `illegal_bot_scopes`). The MANIFEST
31868
+ // generator partitions on that flag; the OAuth install-URL builder does not —
31869
+ // `buildSlackAuthorizeUrl` puts every stored scope into `scope=` — so a
31870
+ // default-scoped OAuth install sent a user-only scope as a bot scope and
31871
+ // Slack rejected the whole authorization with "Invalid permissions
31872
+ // requested". That blocked EVERY new install on the default set.
31873
+ //
31874
+ // Removing it rather than routing it to `user_scope=` is deliberate: the
31875
+ // callback destructures `authed_user?: { id?: string }` and persists only the
31876
+ // BOT token (oauth-callback/route.ts:217,246). `authed_user.access_token` is
31877
+ // never read, so asking for the scope would put an extra consent screen in
31878
+ // front of the installing admin and then discard the token it returned.
31879
+ //
31880
+ // Nothing is lost. `users.profile.set` needs an `xoxp-` user token, which no
31881
+ // OAuth-installed agent has ever had — the bot-status/live-presence indicator
31882
+ // only ever worked where an operator pasted a user token into the wizard by
31883
+ // hand, and that path is untouched. The registry definition stays so existing
31884
+ // configs still render and the `token_type: 'user'` knowledge is preserved.
31885
+ //
31886
+ // Wiring the indicator for OAuth installs means persisting
31887
+ // `authed_user.access_token` first, THEN adding `user_scope=`. Separate work.
31865
31888
  ];
31866
31889
  var SLACK_SCOPE_PRESETS = {
31867
31890
  minimal: [
@@ -34051,6 +34074,14 @@ function buildUsageLimitReplyText(limitedUntil) {
34051
34074
  return `Your agent has hit its Claude Code usage limit until ${formatUtcClock(limitedUntil)}. It'll pick back up once the limit resets \u2014 please try again after then.`;
34052
34075
  }
34053
34076
 
34077
+ // ../core/dist/claude-code-usage/rate-limit-classifier.js
34078
+ var UNKNOWN_RATE_LIMIT = Object.freeze({
34079
+ verdict: "unknown",
34080
+ atMs: null,
34081
+ resetsAt: null,
34082
+ text: null
34083
+ });
34084
+
34054
34085
  // ../core/dist/account-enforcement/marker.js
34055
34086
  var ACCOUNT_ENFORCEMENT_MARKER_FILENAME = "account-enforcement.json";
34056
34087
  var ACCOUNT_ENFORCEMENT_MARKER_VERSION = 1;
@@ -34695,6 +34726,33 @@ var FLAG_REGISTRY = [
34695
34726
  // projectDefinition, so setting it does not roll FLAGS_SCHEMA_VERSION.
34696
34727
  since: "0.28.421"
34697
34728
  },
34729
+ {
34730
+ key: "usage-limit-reactive-notice",
34731
+ description: "Report a Claude Code usage cap REACTIVELY instead of predicting it (ENG-8201). Today the manager guesses from the agent transcript that the next turn will be refused, writes a marker, and every channel MCP refuses to dispatch on the strength of that guess - so a wrong guess is a swallowed message, and because the notice is throttled per (channel, sender) while the DROP is not, the usual symptom is total silence rather than a wrong reply. A refused turn actually costs nothing (rejected in under a second, zero tokens) and Claude Code records it with the reset time in it, so there is no need to guess: dispatch, and report the refusal if one comes back. off = today behaviour (pre-dispatch marker gate, no watcher). shadow = still gate on the marker, but ALSO watch dispatched messages and log the refusal that would have been reported - measures the true-positive rate with no user-visible change. enforce = stop reading the marker before dispatch; every admitted human message reaches the agent and a refusal is answered in-thread with the reset time from the error itself. Read live from the heartbeat flags-cache (or the env override).",
34732
+ flagType: "enum",
34733
+ allowedValues: ["off", "shadow", "enforce"],
34734
+ // Ships dark: off preserves today's gate byte-for-byte. shadow is a free
34735
+ // local log line (the watch is a transcript read, no model spend), so it is a
34736
+ // cheap soak; enforce changes what reaches the agent, so it is the audited
34737
+ // per-org flip.
34738
+ defaultValue: "off",
34739
+ // Enum override AGT_USAGE_LIMIT_REACTIVE_MODE (off|shadow|enforce), resolved
34740
+ // by resolveUsageLimitReactiveMode in the channel-server bundle.
34741
+ envVar: "AGT_USAGE_LIMIT_REACTIVE_MODE",
34742
+ // enforce sends a message to an agent the host currently believes is capped -
34743
+ // a deliberate availability trade (the refusal is free, but it is still a
34744
+ // dispatch the operator previously suppressed), so flipping toward it is an
34745
+ // audited change (ADR-0022 sensitive-flag confirm).
34746
+ sensitive: true
34747
+ // ENG-8149: `since` is the agt-cli version that first carries
34748
+ // resolveUsageLimitReactiveMode + the MCP watcher. It cannot be known before
34749
+ // this lands (the auto-publish patch-bumps on merge), and an undefined
34750
+ // `since` makes the flip-reach modal claim FULL reach - true for flags that
34751
+ // predate the reach work, wrong for a NEW host-read flag whose reader older
34752
+ // hosts simply do not have. Backfilled by a follow-up commit once the
34753
+ // publishing run reports the version. Excluded from projectDefinition, so
34754
+ // setting it does not roll FLAGS_SCHEMA_VERSION.
34755
+ },
34698
34756
  {
34699
34757
  key: "slack-hot-thread-guard",
34700
34758
  description: "Server-side hot-thread guard on the slack.reply surface (ENG-7462). Prevents an agent posting a NEW top-level Slack message when it meant to reply inside the thread it is already working in - a prompt/memory rule proved insufficient (the agent had the rule and still slipped). When a reply would otherwise post to channel ROOT (no thread_ts / message_ts / inbound_id, no active kanban card) and the agent has a recent active thread in that channel (its last bot-posted thread, from the persisted trackedThreads cache, within a freshness window), the reply is redirected into that thread. proactive:true no longer implies channel root; posting at root becomes a deliberate action (the to_channel_root flag, or the thread_ts:null sentinel). off = guard never runs, replies with no coords root exactly as today (ships dark). shadow = compute + log the would-redirect but STILL post to root (measure the fire rate before acting). enforce = apply the redirect (a soft-block: redirect + inform, never a hard rejection). Read live from the heartbeat flags-cache (or the env override); enforce is a deliberate per-org flip after a shadow soak.",
@@ -36,7 +36,7 @@ import {
36
36
  writeDirectChatSessionState,
37
37
  writeEgressAllowlist,
38
38
  writePersistentClaudeWrapper
39
- } from "./chunk-NQP2W2RD.js";
39
+ } from "./chunk-IQX7TMYZ.js";
40
40
  import "./chunk-XWVM4KPK.js";
41
41
  export {
42
42
  EGRESS_BASELINE_DOMAINS,
@@ -77,4 +77,4 @@ export {
77
77
  writeEgressAllowlist,
78
78
  writePersistentClaudeWrapper
79
79
  };
80
- //# sourceMappingURL=persistent-session-PWLMLDVX.js.map
80
+ //# sourceMappingURL=persistent-session-6SCIPYQI.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-NQP2W2RD.js";
3
+ } from "./chunk-IQX7TMYZ.js";
4
4
  import "./chunk-XWVM4KPK.js";
5
5
 
6
6
  // src/lib/responsiveness-probe.ts
@@ -471,4 +471,4 @@ export {
471
471
  readAndResetSlackReplyBindingClassifications,
472
472
  readAndResetSlackReplyTargetClassifications
473
473
  };
474
- //# sourceMappingURL=responsiveness-probe-ZKUDFRIU.js.map
474
+ //# sourceMappingURL=responsiveness-probe-WHDWK62P.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.441",
3
+ "version": "0.28.443",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {