@rex_koh/subagent-budget-guard 0.5.3 → 0.5.4

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.
@@ -2,7 +2,7 @@
2
2
  "name": "subagent-cap",
3
3
  "displayName": "Subagent Cap",
4
4
  "description": "Hard-deny subagent launches, record verified subagent usage, and enforce a session budget against Claude Code's 5-hour rate-limit percentage.",
5
- "version": "0.5.3",
5
+ "version": "0.5.4",
6
6
  "author": {
7
7
  "name": "ClaudeSubAgentSuppressor"
8
8
  },
package/lib/guard.js CHANGED
@@ -538,6 +538,13 @@ function formatQueuedAgentContext(item, state, config) {
538
538
  ].join('\n');
539
539
  }
540
540
 
541
+ function formatQueuedAgentPendingReason(item, state, config) {
542
+ return [
543
+ 'Queued subagent pending. Do not start this Agent yet; retry the queued Agent task first.',
544
+ formatQueuedAgentContext(item, state, config)
545
+ ].join('\n\n');
546
+ }
547
+
541
548
  async function buildQueuedAgentNotice(sessionId, env, hookEventName) {
542
549
  const config = loadConfig(env);
543
550
  let context = null;
@@ -670,6 +677,30 @@ export async function handlePreToolUseAgent(input, env = process.env) {
670
677
  subagentType: input?.tool_input?.subagent_type || null
671
678
  });
672
679
  } else {
680
+ const queuedBeforeLaunch = nextQueuedAgent(state);
681
+ if (
682
+ config.enforcement_enabled &&
683
+ queuedBeforeLaunch &&
684
+ queuedBeforeLaunch.fingerprint !== agentFingerprint(input)
685
+ ) {
686
+ queuedItem = queueConcurrencyDeniedAgent(
687
+ state,
688
+ input,
689
+ 'Queued subagent pending; this Agent must wait for queued work to drain.'
690
+ );
691
+ const nextItem = nextQueuedAgent(state) || queuedBeforeLaunch;
692
+ reason = formatQueuedAgentPendingReason(nextItem, state, config);
693
+ state.subagents.denied += 1;
694
+ pushEvent(state, {
695
+ type: 'agent-denied',
696
+ reason,
697
+ queueId: queuedItem.queueId,
698
+ description: input?.tool_input?.description || null,
699
+ subagentType: input?.tool_input?.subagent_type || null
700
+ });
701
+ return state;
702
+ }
703
+
673
704
  const launchedQueuedItem = removeMatchingQueuedAgent(state, input);
674
705
  state.subagents.allowed += 1;
675
706
  pushEvent(state, {
@@ -818,7 +849,8 @@ export async function handleSubagentStop(input, env = process.env) {
818
849
  return state;
819
850
  });
820
851
 
821
- return { exitCode: 0, stdout: null, stderr: '' };
852
+ const notice = await buildQueuedAgentNotice(sessionId, env, 'SubagentStop');
853
+ return notice || { exitCode: 0, stdout: null, stderr: '' };
822
854
  }
823
855
 
824
856
  function taskDenyReason(state, config) {
package/lib/verifier.js CHANGED
@@ -111,7 +111,7 @@ export async function runOfflineVerification({
111
111
  entry.source?.package === '@rex_koh/subagent-budget-guard',
112
112
  'marketplace npm package mismatch'
113
113
  );
114
- assert(entry.source?.version === '0.5.3', 'marketplace npm version mismatch');
114
+ assert(entry.source?.version === '0.5.4', 'marketplace npm version mismatch');
115
115
  return marketplacePath;
116
116
  });
117
117
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex_koh/subagent-budget-guard",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Claude Code plugin that blocks subagents by default, records verified subagent usage, and enforces 5-hour usage budgets.",
5
5
  "license": "MIT",
6
6
  "author": "ClaudeSubAgentSuppressor",