@rex_koh/subagent-budget-guard 0.4.0 → 0.5.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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -0
- package/bin/subagent-cap.js +5 -0
- package/bin/view.js +31 -0
- package/lib/guard.js +33 -0
- package/lib/verifier.js +2 -1
- package/package.json +4 -3
|
@@ -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
|
+
"version": "0.5.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ClaudeSubAgentSuppressor"
|
|
8
8
|
},
|
package/README.md
CHANGED
|
@@ -24,8 +24,11 @@ Claude Code plugin discovery is marketplace-based, so npm is mainly useful as a
|
|
|
24
24
|
npm install -g @rex_koh/subagent-budget-guard
|
|
25
25
|
subagent-cap doctor --offline
|
|
26
26
|
subagent-cap status
|
|
27
|
+
sub-agent-view
|
|
27
28
|
```
|
|
28
29
|
|
|
30
|
+
`sub-agent-view` prints the latest session's recorded subagents with per-subagent status, type, description, verified token count, duration, model, and tool-call count. Use `sub-agent-view --session <session-id>` for a specific saved session, or `sub-agent-view --json` for machine-readable output. The same view is also available as `subagent-cap view`.
|
|
31
|
+
|
|
29
32
|
Maintainer publish command:
|
|
30
33
|
|
|
31
34
|
```bash
|
package/bin/subagent-cap.js
CHANGED
|
@@ -14,6 +14,10 @@ const COMMANDS = Object.freeze({
|
|
|
14
14
|
script: 'report.js',
|
|
15
15
|
help: 'show the current guard report'
|
|
16
16
|
},
|
|
17
|
+
view: {
|
|
18
|
+
script: 'view.js',
|
|
19
|
+
help: 'show recorded subagent tokens and duration'
|
|
20
|
+
},
|
|
17
21
|
doctor: {
|
|
18
22
|
script: 'verify.js',
|
|
19
23
|
help: 'verify the install without spending Claude quota'
|
|
@@ -31,6 +35,7 @@ function usage() {
|
|
|
31
35
|
' subagent-cap init',
|
|
32
36
|
' subagent-cap init --defaults',
|
|
33
37
|
' subagent-cap status',
|
|
38
|
+
' subagent-cap view',
|
|
34
39
|
' subagent-cap doctor --offline'
|
|
35
40
|
].join('\n');
|
|
36
41
|
}
|
package/bin/view.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { buildReport, formatSubagentView } from '../lib/guard.js';
|
|
3
|
+
|
|
4
|
+
function argValue(name) {
|
|
5
|
+
const index = process.argv.indexOf(name);
|
|
6
|
+
if (index === -1) return null;
|
|
7
|
+
return process.argv[index + 1] || null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async function main() {
|
|
11
|
+
const asJson = process.argv.includes('--json');
|
|
12
|
+
const sessionId = argValue('--session');
|
|
13
|
+
const report = await buildReport(sessionId, process.env);
|
|
14
|
+
const view = {
|
|
15
|
+
plugin: report.plugin,
|
|
16
|
+
sessionId: report.sessionId,
|
|
17
|
+
spawnedSubagents: report.state.subagents.runs.length,
|
|
18
|
+
verifiedTokens: report.state.subagents.verifiedTokens,
|
|
19
|
+
totalDurationMs: report.state.subagents.totalDurationMs,
|
|
20
|
+
subagents: report.state.subagents.runs
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
process.stdout.write(
|
|
24
|
+
asJson ? `${JSON.stringify(view, null, 2)}\n` : `${formatSubagentView(report)}\n`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
main().catch((error) => {
|
|
29
|
+
process.stderr.write(`sub-agent-view failed: ${error.stack || error.message}\n`);
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
});
|
package/lib/guard.js
CHANGED
|
@@ -780,6 +780,39 @@ export function formatReport(report) {
|
|
|
780
780
|
return lines.join('\n');
|
|
781
781
|
}
|
|
782
782
|
|
|
783
|
+
function formatDuration(ms) {
|
|
784
|
+
const value = Number(ms || 0);
|
|
785
|
+
if (value >= 1000) return `${(value / 1000).toFixed(value % 1000 === 0 ? 0 : 1)}s`;
|
|
786
|
+
return `${value}ms`;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
export function formatSubagentView(report) {
|
|
790
|
+
const runs = report.state.subagents.runs;
|
|
791
|
+
const lines = [
|
|
792
|
+
`Sub-agent view for ${report.sessionId}`,
|
|
793
|
+
`Spawned subagents: ${runs.length}`,
|
|
794
|
+
`Verified tokens: ${formatCount(report.state.subagents.verifiedTokens)}`,
|
|
795
|
+
`Total duration: ${formatDuration(report.state.subagents.totalDurationMs)}`
|
|
796
|
+
];
|
|
797
|
+
|
|
798
|
+
if (runs.length === 0) {
|
|
799
|
+
lines.push('No subagents recorded for this session.');
|
|
800
|
+
return lines.join('\n');
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
for (const [index, run] of runs.entries()) {
|
|
804
|
+
const type = run.subagentType || 'unknown';
|
|
805
|
+
const description = run.description ? ` "${run.description}"` : '';
|
|
806
|
+
lines.push(`#${index + 1} ${run.status} ${type}${description}`);
|
|
807
|
+
lines.push(` tokens: ${run.verified ? `${formatCount(run.totalTokens)} verified` : 'pending'}`);
|
|
808
|
+
lines.push(` duration: ${formatDuration(run.totalDurationMs)}`);
|
|
809
|
+
lines.push(` model: ${run.resolvedModel || 'unknown'}`);
|
|
810
|
+
lines.push(` tools: ${Number(run.totalToolUseCount || 0)}`);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
return lines.join('\n');
|
|
814
|
+
}
|
|
815
|
+
|
|
783
816
|
function quoteShellArg(value) {
|
|
784
817
|
const normalized = String(value).replace(/\\/g, '/').replace(/"/g, '\\"');
|
|
785
818
|
return `"${normalized}"`;
|
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.
|
|
114
|
+
assert(entry.source?.version === '0.5.0', 'marketplace npm version mismatch');
|
|
115
115
|
return marketplacePath;
|
|
116
116
|
});
|
|
117
117
|
} else {
|
|
@@ -172,6 +172,7 @@ export async function runOfflineVerification({
|
|
|
172
172
|
'bin/statusline.js',
|
|
173
173
|
'bin/setup.js',
|
|
174
174
|
'bin/report.js',
|
|
175
|
+
'bin/view.js',
|
|
175
176
|
'bin/verify.js',
|
|
176
177
|
'lib/guard.js',
|
|
177
178
|
'lib/verifier.js',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rex_koh/subagent-budget-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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,8 @@
|
|
|
32
32
|
"LICENSE"
|
|
33
33
|
],
|
|
34
34
|
"bin": {
|
|
35
|
-
"subagent-cap": "bin/subagent-cap.js"
|
|
35
|
+
"subagent-cap": "bin/subagent-cap.js",
|
|
36
|
+
"sub-agent-view": "bin/view.js"
|
|
36
37
|
},
|
|
37
38
|
"publishConfig": {
|
|
38
39
|
"access": "public"
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"test": "node --test test/*.test.js",
|
|
42
43
|
"verify:offline": "node bin/verify.js --offline",
|
|
43
44
|
"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/subagent-cap.js && node --check lib/guard.js && node --check lib/verifier.js"
|
|
45
|
+
"prepack": "node --check bin/hook.js && node --check bin/statusline.js && node --check bin/setup.js && node --check bin/report.js && node --check bin/view.js && node --check bin/verify.js && node --check bin/subagent-cap.js && node --check lib/guard.js && node --check lib/verifier.js"
|
|
45
46
|
},
|
|
46
47
|
"engines": {
|
|
47
48
|
"node": ">=20"
|