@rex_koh/subagent-budget-guard 0.3.0 → 0.4.0

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.
@@ -1,8 +1,8 @@
1
1
  {
2
- "name": "agent-guard",
3
- "displayName": "Agent Guard",
2
+ "name": "subagent-cap",
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.3.0",
5
+ "version": "0.4.0",
6
6
  "author": {
7
7
  "name": "ClaudeSubAgentSuppressor"
8
8
  },
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Agent Guard
1
+ # Subagent Cap
2
2
 
3
3
  Claude Code plugin that guards subagent usage, records verified subagent tokens, and enforces a session budget against Claude Code's 5-hour usage percentage.
4
4
 
@@ -8,11 +8,11 @@ Recommended Claude Code install:
8
8
 
9
9
  ```text
10
10
  /plugin marketplace add rexkoh425/ClaudeSubAgentSuppressor
11
- /plugin install agent-guard@subagent-budget-tools
12
- /agent-guard:init
11
+ /plugin install subagent-cap@subagent-tools
12
+ /subagent-cap:init
13
13
  ```
14
14
 
15
- After `/agent-guard:init`, fully exit and reopen Claude Code so the statusLine bridge from `settings.json` is active. Some Claude Code builds do not provide an in-session plugin reload command.
15
+ After `/subagent-cap:init`, fully exit and reopen Claude Code so the statusLine bridge from `settings.json` is active. Some Claude Code builds do not provide an in-session plugin reload command.
16
16
 
17
17
  ## NPM Package
18
18
 
@@ -22,8 +22,8 @@ Claude Code plugin discovery is marketplace-based, so npm is mainly useful as a
22
22
 
23
23
  ```bash
24
24
  npm install -g @rex_koh/subagent-budget-guard
25
- agent-guard doctor --offline
26
- agent-guard status
25
+ subagent-cap doctor --offline
26
+ subagent-cap status
27
27
  ```
28
28
 
29
29
  Maintainer publish command:
@@ -38,7 +38,7 @@ Offline verification:
38
38
  node bin/verify.js --offline
39
39
  ```
40
40
 
41
- The plugin is strict before setup: `max_concurrent_subagents` defaults to `0`, so normal subagent launches are blocked unless raised. Run `/agent-guard:init` to choose defaults or custom values:
41
+ The plugin is strict before setup: `max_concurrent_subagents` defaults to `0`, so normal subagent launches are blocked unless raised. Run `/subagent-cap:init` to choose defaults or custom values:
42
42
 
43
43
  ```text
44
44
  max_concurrent_subagents=1
@@ -54,13 +54,13 @@ For existing installs, setup also removes obsolete `max_subagents_per_session` a
54
54
  The setup skill can ask for custom values. For direct terminal setup, use:
55
55
 
56
56
  ```bash
57
- agent-guard init
57
+ subagent-cap init
58
58
  ```
59
59
 
60
60
  Or pass explicit values:
61
61
 
62
62
  ```bash
63
- agent-guard init \
63
+ subagent-cap init \
64
64
  --config max_concurrent_subagents=2 \
65
65
  --config max_subagent_tokens_per_session=250000 \
66
66
  --config subagent_token_warning_threshold_percent=90 \
package/bin/setup.js CHANGED
@@ -15,7 +15,7 @@ const CONFIG_KEY_SET = new Set(CONFIG_KEYS);
15
15
 
16
16
  function usage() {
17
17
  return [
18
- 'Usage: agent-guard init [--defaults] [--interactive] [--config key=value ...]',
18
+ 'Usage: subagent-cap init [--defaults] [--interactive] [--config key=value ...]',
19
19
  '',
20
20
  'Config keys:',
21
21
  ...CONFIG_KEYS.map((key) => ` ${key} (default ${SETUP_CONFIG[key]})`)
@@ -121,7 +121,7 @@ async function main() {
121
121
 
122
122
  process.stdout.write(
123
123
  [
124
- 'Agent Guard statusLine bridge installed.',
124
+ 'Subagent Cap statusLine bridge installed.',
125
125
  'Plugin config applied:',
126
126
  ` max_concurrent_subagents=${result.pluginConfigOptions.max_concurrent_subagents}`,
127
127
  ` max_subagent_tokens_per_session=${result.pluginConfigOptions.max_subagent_tokens_per_session}`,
@@ -22,16 +22,16 @@ const COMMANDS = Object.freeze({
22
22
 
23
23
  function usage() {
24
24
  return [
25
- 'Usage: agent-guard <command> [options]',
25
+ 'Usage: subagent-cap <command> [options]',
26
26
  '',
27
27
  'Commands:',
28
28
  ...Object.entries(COMMANDS).map(([name, info]) => ` ${name.padEnd(8)} ${info.help}`),
29
29
  '',
30
30
  'Examples:',
31
- ' agent-guard init',
32
- ' agent-guard init --defaults',
33
- ' agent-guard status',
34
- ' agent-guard doctor --offline'
31
+ ' subagent-cap init',
32
+ ' subagent-cap init --defaults',
33
+ ' subagent-cap status',
34
+ ' subagent-cap doctor --offline'
35
35
  ].join('\n');
36
36
  }
37
37
 
package/lib/guard.js CHANGED
@@ -17,9 +17,8 @@ import { fileURLToPath } from 'node:url';
17
17
 
18
18
  const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
19
19
 
20
- export const PLUGIN_NAME = 'agent-guard';
21
- export const PLUGIN_ID = 'agent-guard@subagent-budget-tools';
22
- export const LEGACY_PLUGIN_ID = 'subagent-budget-guard@subagent-budget-tools';
20
+ export const PLUGIN_NAME = 'subagent-cap';
21
+ export const PLUGIN_ID = 'subagent-cap@subagent-tools';
23
22
 
24
23
  export const DEFAULT_CONFIG = Object.freeze({
25
24
  max_concurrent_subagents: 0,
@@ -88,9 +87,7 @@ function readSettingsOptions(env) {
88
87
  try {
89
88
  const text = readFileSync(settingsPath, 'utf8');
90
89
  const settings = JSON.parse(text.replace(/^\uFEFF/, ''));
91
- const options =
92
- settings?.pluginConfigs?.[PLUGIN_ID]?.options ||
93
- settings?.pluginConfigs?.[LEGACY_PLUGIN_ID]?.options;
90
+ const options = settings?.pluginConfigs?.[PLUGIN_ID]?.options;
94
91
  return isPlainObject(options) ? options : {};
95
92
  } catch (error) {
96
93
  if (error.code === 'ENOENT') return {};
@@ -760,7 +757,7 @@ export function formatReport(report) {
760
757
  const { state, config, summary } = report;
761
758
  const fiveHour = state.rateLimits.fiveHour;
762
759
  const lines = [
763
- `Agent Guard report for ${report.sessionId}`,
760
+ `Subagent Cap report for ${report.sessionId}`,
764
761
  `Enforcement: ${config.enforcement_enabled ? 'enabled' : 'disabled'}`,
765
762
  `Subagents: allowed ${state.subagents.allowed}, denied ${state.subagents.denied}, active ${state.subagents.active}, lifecycle starts ${state.subagents.lifecycleStarted}, lifecycle stops ${state.subagents.lifecycleStopped}`,
766
763
  `Verified usage: ${summary.verifiedTokenLabel}, ${state.subagents.totalToolUseCount} subagent tool calls, ${state.subagents.totalDurationMs} ms`,
@@ -776,7 +773,7 @@ export function formatReport(report) {
776
773
  );
777
774
  } else {
778
775
  lines.push(
779
- '5-hour latest: unavailable. Run /agent-guard:init so the statusLine bridge can capture rate_limits.five_hour.used_percentage.'
776
+ '5-hour latest: unavailable. Run /subagent-cap:init so the statusLine bridge can capture rate_limits.five_hour.used_percentage.'
780
777
  );
781
778
  }
782
779
 
@@ -822,12 +819,9 @@ function applySetupPluginConfig(
822
819
  settings.pluginConfigs = {};
823
820
  }
824
821
 
825
- const legacyEntry = isPlainObject(settings.pluginConfigs[LEGACY_PLUGIN_ID])
826
- ? settings.pluginConfigs[LEGACY_PLUGIN_ID]
827
- : {};
828
822
  const currentEntry = isPlainObject(settings.pluginConfigs[pluginId])
829
823
  ? settings.pluginConfigs[pluginId]
830
- : legacyEntry;
824
+ : {};
831
825
  const currentOptions = isPlainObject(currentEntry.options)
832
826
  ? currentEntry.options
833
827
  : {};
@@ -846,10 +840,6 @@ function applySetupPluginConfig(
846
840
  ...currentEntry,
847
841
  options: nextOptions
848
842
  };
849
- if (pluginId !== LEGACY_PLUGIN_ID) {
850
- delete settings.pluginConfigs[LEGACY_PLUGIN_ID];
851
- }
852
-
853
843
  return nextOptions;
854
844
  }
855
845
 
package/lib/verifier.js CHANGED
@@ -102,16 +102,16 @@ export async function runOfflineVerification({
102
102
  await withCheck(result, 'marketplace-manifest', async () => {
103
103
  const marketplacePath = path.join(repoRoot, '.claude-plugin', 'marketplace.json');
104
104
  const marketplace = await readJson(marketplacePath);
105
- assert(marketplace.name === 'subagent-budget-tools', 'marketplace name mismatch');
105
+ assert(marketplace.name === 'subagent-tools', 'marketplace name mismatch');
106
106
  assert(Array.isArray(marketplace.plugins), 'marketplace.plugins must be an array');
107
- const entry = marketplace.plugins.find((plugin) => plugin.name === 'agent-guard');
108
- assert(entry, 'agent-guard entry missing');
107
+ const entry = marketplace.plugins.find((plugin) => plugin.name === 'subagent-cap');
108
+ assert(entry, 'subagent-cap entry missing');
109
109
  assert(entry.source?.source === 'npm', 'marketplace source must use npm');
110
110
  assert(
111
111
  entry.source?.package === '@rex_koh/subagent-budget-guard',
112
112
  'marketplace npm package mismatch'
113
113
  );
114
- assert(entry.source?.version === '0.3.0', 'marketplace npm version mismatch');
114
+ assert(entry.source?.version === '0.4.0', 'marketplace npm version mismatch');
115
115
  return marketplacePath;
116
116
  });
117
117
  } else {
@@ -129,7 +129,7 @@ export async function runOfflineVerification({
129
129
  await withCheck(result, 'plugin-manifest-no-install-config', async () => {
130
130
  const manifestPath = path.join(root, '.claude-plugin', 'plugin.json');
131
131
  const manifest = await readJson(manifestPath);
132
- assert(manifest.name === 'agent-guard', 'plugin name mismatch');
132
+ assert(manifest.name === 'subagent-cap', 'plugin name mismatch');
133
133
  assert(
134
134
  manifest.hooks === undefined,
135
135
  'manifest.hooks must be omitted for default hooks/hooks.json to avoid duplicate loading'
@@ -168,7 +168,7 @@ export async function runOfflineVerification({
168
168
  await withCheck(result, 'script-paths', async () => {
169
169
  const scripts = [
170
170
  'bin/hook.js',
171
- 'bin/agent-guard.js',
171
+ 'bin/subagent-cap.js',
172
172
  'bin/statusline.js',
173
173
  'bin/setup.js',
174
174
  'bin/report.js',
@@ -407,12 +407,12 @@ export async function runLiveVerification({
407
407
  const list = await runCommand('claude', ['plugin', 'list'], { cwd: repoRoot });
408
408
  assert(list.code === 0, list.stderr || list.stdout || 'claude plugin list failed');
409
409
  assert(
410
- list.stdout.includes('agent-guard'),
411
- 'agent-guard is not installed'
410
+ list.stdout.includes('subagent-cap'),
411
+ 'subagent-cap is not installed'
412
412
  );
413
413
  assert(
414
- !/agent-guard@subagent-budget-tools[\s\S]*failed to load/i.test(list.stdout),
415
- 'agent-guard is installed but failed to load'
414
+ !/subagent-cap@subagent-tools[\s\S]*failed to load/i.test(list.stdout),
415
+ 'subagent-cap is installed but failed to load'
416
416
  );
417
417
  return 'claude plugin list returned output';
418
418
  });
@@ -426,7 +426,7 @@ export async function runLiveVerification({
426
426
  typeof settings.statusLine?.command === 'string' &&
427
427
  settings.statusLine.command.includes('statusline.js') &&
428
428
  settings.statusLine.command.includes('--data'),
429
- 'statusLine bridge is not installed; run /agent-guard:init'
429
+ 'statusLine bridge is not installed; run /subagent-cap:init'
430
430
  );
431
431
  return settings.statusLine.command;
432
432
  });
@@ -437,7 +437,7 @@ export async function runLiveVerification({
437
437
 
438
438
  export function formatVerificationResult(result) {
439
439
  const lines = [
440
- `Agent Guard ${result.mode} verification`,
440
+ `Subagent Cap ${result.mode} verification`,
441
441
  result.ok ? 'PASS' : 'FAIL'
442
442
  ];
443
443
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex_koh/subagent-budget-guard",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
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",
@@ -32,7 +32,7 @@
32
32
  "LICENSE"
33
33
  ],
34
34
  "bin": {
35
- "agent-guard": "bin/agent-guard.js"
35
+ "subagent-cap": "bin/subagent-cap.js"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -41,7 +41,7 @@
41
41
  "test": "node --test test/*.test.js",
42
42
  "verify:offline": "node bin/verify.js --offline",
43
43
  "verify:live": "node bin/verify.js --live",
44
- "prepack": "node --check bin/hook.js && node --check bin/statusline.js && node --check bin/setup.js && node --check bin/report.js && node --check bin/verify.js && node --check bin/agent-guard.js && node --check lib/guard.js && node --check lib/verifier.js"
44
+ "prepack": "node --check bin/hook.js && node --check bin/statusline.js && node --check bin/setup.js && node --check bin/report.js && node --check bin/verify.js && node --check bin/subagent-cap.js && node --check lib/guard.js && node --check lib/verifier.js"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=20"
@@ -1,8 +1,8 @@
1
1
  ---
2
- description: Initialize Agent Guard settings and the statusLine bridge.
2
+ description: Initialize Subagent Cap settings and the statusLine bridge.
3
3
  ---
4
4
 
5
- # Init Agent Guard
5
+ # Init Subagent Cap
6
6
 
7
7
  Ask the user whether to use recommended defaults or custom values.
8
8
 
@@ -20,13 +20,13 @@ enforcement_enabled=true
20
20
  If they choose defaults, run:
21
21
 
22
22
  ```bash
23
- node "${CLAUDE_PLUGIN_ROOT}/bin/agent-guard.js" init --defaults
23
+ node "${CLAUDE_PLUGIN_ROOT}/bin/subagent-cap.js" init --defaults
24
24
  ```
25
25
 
26
26
  If they choose custom values, ask for each value. Accept a blank answer as the default, then run:
27
27
 
28
28
  ```bash
29
- node "${CLAUDE_PLUGIN_ROOT}/bin/agent-guard.js" init \
29
+ node "${CLAUDE_PLUGIN_ROOT}/bin/subagent-cap.js" init \
30
30
  --config max_concurrent_subagents=<value> \
31
31
  --config max_subagent_tokens_per_session=<value> \
32
32
  --config subagent_token_warning_threshold_percent=<value> \
@@ -40,5 +40,5 @@ Then tell the user to fully exit and reopen Claude Code, then interact once so t
40
40
  For optional terminal verification, run:
41
41
 
42
42
  ```bash
43
- node "${CLAUDE_PLUGIN_ROOT}/bin/agent-guard.js" doctor --live
43
+ node "${CLAUDE_PLUGIN_ROOT}/bin/subagent-cap.js" doctor --live
44
44
  ```