@rex_koh/subagent-budget-guard 0.1.0 → 0.1.1

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-budget-guard",
3
3
  "displayName": "Subagent Budget Guard",
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.1.0",
5
+ "version": "0.1.1",
6
6
  "author": {
7
7
  "name": "ClaudeSubAgentSuppressor"
8
8
  },
package/bin/verify.js CHANGED
@@ -4,6 +4,9 @@ import {
4
4
  runLiveVerification,
5
5
  runOfflineVerification
6
6
  } from '../lib/verifier.js';
7
+ import { pathExists } from '../lib/guard.js';
8
+ import { fileURLToPath } from 'node:url';
9
+ import path from 'node:path';
7
10
 
8
11
  function modeFromArgs() {
9
12
  if (process.argv.includes('--live')) return 'live';
@@ -12,10 +15,16 @@ function modeFromArgs() {
12
15
 
13
16
  async function main() {
14
17
  const mode = modeFromArgs();
18
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
19
+ const cwd = process.cwd();
20
+ const cwdLooksLikeMarketplace =
21
+ (await pathExists(path.join(cwd, '.claude-plugin', 'marketplace.json'))) ||
22
+ (await pathExists(path.join(cwd, 'plugins', 'subagent-budget-guard', '.claude-plugin', 'plugin.json')));
23
+ const repoRoot = cwdLooksLikeMarketplace ? cwd : packageRoot;
15
24
  const result =
16
25
  mode === 'live'
17
- ? await runLiveVerification({ repoRoot: process.cwd(), env: process.env })
18
- : await runOfflineVerification({ repoRoot: process.cwd(), env: process.env });
26
+ ? await runLiveVerification({ repoRoot, env: process.env })
27
+ : await runOfflineVerification({ repoRoot, env: process.env });
19
28
 
20
29
  process.stdout.write(`${formatVerificationResult(result)}\n`);
21
30
  process.exitCode = result.ok ? 0 : 1;
package/lib/verifier.js CHANGED
@@ -20,8 +20,31 @@ async function readJson(filePath) {
20
20
  return JSON.parse(text.replace(/^\uFEFF/, ''));
21
21
  }
22
22
 
23
- function pluginRoot(repoRoot) {
24
- return path.join(repoRoot, 'plugins', 'subagent-budget-guard');
23
+ async function resolveLayout(repoRoot) {
24
+ const packagePluginRoot = repoRoot;
25
+ const marketplacePluginRoot = path.join(repoRoot, 'plugins', 'subagent-budget-guard');
26
+
27
+ if (await pathExists(path.join(repoRoot, '.claude-plugin', 'marketplace.json'))) {
28
+ return {
29
+ repoRoot,
30
+ pluginRoot: marketplacePluginRoot,
31
+ hasMarketplace: true
32
+ };
33
+ }
34
+
35
+ if (await pathExists(path.join(packagePluginRoot, '.claude-plugin', 'plugin.json'))) {
36
+ return {
37
+ repoRoot,
38
+ pluginRoot: packagePluginRoot,
39
+ hasMarketplace: false
40
+ };
41
+ }
42
+
43
+ return {
44
+ repoRoot,
45
+ pluginRoot: marketplacePluginRoot,
46
+ hasMarketplace: false
47
+ };
25
48
  }
26
49
 
27
50
  async function withCheck(result, name, fn) {
@@ -48,23 +71,36 @@ export async function runOfflineVerification({
48
71
  checks: [],
49
72
  failures: []
50
73
  };
51
- const root = pluginRoot(repoRoot);
74
+ const layout = await resolveLayout(repoRoot);
75
+ const root = layout.pluginRoot;
52
76
 
53
- await withCheck(result, 'marketplace-manifest', async () => {
54
- const marketplacePath = path.join(repoRoot, '.claude-plugin', 'marketplace.json');
55
- const marketplace = await readJson(marketplacePath);
56
- assert(marketplace.name === 'subagent-budget-tools', 'marketplace name mismatch');
57
- assert(Array.isArray(marketplace.plugins), 'marketplace.plugins must be an array');
58
- const entry = marketplace.plugins.find((plugin) => plugin.name === 'subagent-budget-guard');
59
- assert(entry, 'subagent-budget-guard entry missing');
60
- assert(entry.source?.source === 'npm', 'marketplace source must use npm');
61
- assert(
62
- entry.source?.package === '@rex_koh/subagent-budget-guard',
63
- 'marketplace npm package mismatch'
64
- );
65
- assert(entry.source?.version === '0.1.0', 'marketplace npm version mismatch');
66
- return marketplacePath;
67
- });
77
+ if (layout.hasMarketplace) {
78
+ await withCheck(result, 'marketplace-manifest', async () => {
79
+ const marketplacePath = path.join(repoRoot, '.claude-plugin', 'marketplace.json');
80
+ const marketplace = await readJson(marketplacePath);
81
+ assert(marketplace.name === 'subagent-budget-tools', 'marketplace name mismatch');
82
+ assert(Array.isArray(marketplace.plugins), 'marketplace.plugins must be an array');
83
+ const entry = marketplace.plugins.find((plugin) => plugin.name === 'subagent-budget-guard');
84
+ assert(entry, 'subagent-budget-guard entry missing');
85
+ assert(entry.source?.source === 'npm', 'marketplace source must use npm');
86
+ assert(
87
+ entry.source?.package === '@rex_koh/subagent-budget-guard',
88
+ 'marketplace npm package mismatch'
89
+ );
90
+ assert(entry.source?.version === '0.1.1', 'marketplace npm version mismatch');
91
+ return marketplacePath;
92
+ });
93
+ } else {
94
+ await withCheck(result, 'package-root', async () => {
95
+ const packageJsonPath = path.join(root, 'package.json');
96
+ const packageJson = await readJson(packageJsonPath);
97
+ assert(
98
+ packageJson.name === '@rex_koh/subagent-budget-guard',
99
+ 'package root name mismatch'
100
+ );
101
+ return packageJsonPath;
102
+ });
103
+ }
68
104
 
69
105
  await withCheck(result, 'plugin-manifest-user-config', async () => {
70
106
  const manifestPath = path.join(root, '.claude-plugin', 'plugin.json');
@@ -303,7 +339,8 @@ export async function runLiveVerification({
303
339
  result.checks.push(...offline.checks);
304
340
  result.failures.push(...offline.failures);
305
341
 
306
- const root = pluginRoot(repoRoot);
342
+ const layout = await resolveLayout(repoRoot);
343
+ const root = layout.pluginRoot;
307
344
  const hasClaude = await commandExists('claude');
308
345
  if (!hasClaude) {
309
346
  result.warnings.push('claude executable was not found on PATH; skipped claude plugin validate and install-state checks.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex_koh/subagent-budget-guard",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",