@nightlab-agent/subagent-spend 0.8.1 → 0.8.3

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.
@@ -8,7 +8,7 @@
8
8
  "name": "subagent-spend",
9
9
  "source": "./",
10
10
  "description": "A spend cap for interactive sessions, and per-subagent tokens, rate-limit windows, context fill, cost, steps, tool calls and tool errors of a Claude Code session, in a notice under the prompt, local files and panes (the usage pane not yet seen on a screen).",
11
- "version": "0.8.1",
11
+ "version": "0.8.3",
12
12
  "category": "productivity"
13
13
  }
14
14
  ],
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subagent-spend",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "A spend cap for interactive sessions, and per-subagent tokens, rate-limit windows, context fill, cost, steps, tool calls and tool errors of a Claude Code session, in a notice under the prompt, local files and panes (the usage pane not yet seen on a screen).",
5
5
  "author": {
6
6
  "name": "Nightlab"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  The form is Keep a Changelog; versions follow SemVer.
4
4
 
5
+ ## 0.8.3 - 2026-11-03
6
+
7
+ ### Fixed
8
+ - The npm package left out hooks/cap.ts, which hooks/register.tsx imports, so an install from npm failed to load
9
+ from 0.8.0 on. The marketplace install was not affected. The checklist now fails when a packed hook imports a
10
+ file the package leaves out.
11
+
12
+ ## 0.8.2 - 2026-11-03
13
+
14
+ ### Changed
15
+ - README: the opening says what an unwatched long job costs before what the plugin does, and the spend cap
16
+ picture (seen 2026-10-31) is on the first screen. No code change.
17
+
5
18
  ## 0.8.1 - 2026-11-02
6
19
 
7
20
  ### Changed
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # subagent-spend
2
2
 
3
- Claude Code meters: subagent tokens, usage limits and turn counts, and a
4
- spend cap per session that stops requests at the limit you set
5
- ([Spend cap](#spend-cap)).
3
+ Hand Claude Code a long job and its subagents keep spending tokens while you
4
+ are away. This plugin puts what they used, your usage limits and a count of
5
+ steps and tool calls in one line under the prompt. If you set a dollar cap, once a session's cost
6
+ reaches it no new request goes out ([Spend cap](#spend-cap)).
6
7
 
7
8
  Install at the Claude Code prompt (more under [Install](#install)):
8
9
 
@@ -10,6 +11,12 @@ Install at the Claude Code prompt (more under [Install](#install)):
10
11
  /plugin install subagent-spend --marketplace nightlab-agent/subagent-spend
11
12
  ```
12
13
 
14
+ ![Claude Code with a $0.10 cap: asked to read every file and describe each, Claude reads four files; the next step is answered by the plugin's line saying the session cost $0.11 of the $0.10 cap and no request was sent](https://raw.githubusercontent.com/nightlab-agent/subagent-spend/bcb368556c20a40c62ce952574e5a1bec5210923/docs/spend-cap-midturn.png)
15
+
16
+ The spend cap, seen on 2026-10-31: a $0.10 cap, and the next step got the
17
+ line above instead of a request ([Spend cap](#spend-cap)). The line under
18
+ the prompt, after three subagents ran:
19
+
13
20
  ![Claude Code after three subagents ran: the subagent pane lists the three with their turns and tokens, and the line under the prompt reads subagents 3, tok 218k, then the usage windows, cost and step counts](https://raw.githubusercontent.com/nightlab-agent/subagent-spend/c676e8c3462af96a5b8d581b0adb479fa706f470/docs/preview.png)
14
21
 
15
22
  Seen in a Claude Code 2.1.312 terminal (150 columns) on 2026-10-29, after
package/hooks/cap.ts ADDED
@@ -0,0 +1,59 @@
1
+ // The spend cap (option `capUsd`, off at 0): what the session may cost, by Claude Code's own
2
+ // estimate (`session.measure`'s `cost.usd`, the figure `--max-budget-usd` checks in print mode).
3
+ // At WARN_AT of the cap a toast says so, once; at the cap every model step, the main loop's and
4
+ // each subagent's, is answered by the mod with no request made, until /spend-cap raises or lifts it.
5
+ // A step already running finishes: its cost can pass the cap, so leave headroom.
6
+
7
+ export const WARN_AT = 0.8
8
+
9
+ export const cap = {
10
+ /** The cap in dollars; null is off. */
11
+ usd: null as number | null,
12
+ /** The session's cost so far, from the newest measurement; null before the first. */
13
+ spent: null as number | null,
14
+ warned: false,
15
+ }
16
+
17
+ /** The option's value as a cap: a positive number of dollars, anything else off. */
18
+ export function capOf(v: unknown): number | null {
19
+ const n = typeof v === 'number' ? v : typeof v === 'string' && v.trim() !== '' ? Number(v.trim().replace(/^\$/, '')) : NaN
20
+ return Number.isFinite(n) && n > 0 ? n : null
21
+ }
22
+
23
+ export const money = (n: number) => `$${n.toFixed(2)}`
24
+
25
+ /** Whether the next step is held: a cap is set and the cost has reached it. */
26
+ export const reached = () => cap.usd !== null && cap.spent !== null && cap.spent >= cap.usd
27
+
28
+ /** The warning's text once the cost first reaches WARN_AT of the cap (and stays under it), else null; said once per cap. */
29
+ export function warnNow(): string | null {
30
+ if (cap.warned || cap.usd === null || cap.spent === null || reached() || cap.spent < cap.usd * WARN_AT) return null
31
+ cap.warned = true
32
+ return `Spend cap: ${money(cap.spent)} of ${money(cap.usd)} used`
33
+ }
34
+
35
+ /** What a held step answers in the chat. */
36
+ export const heldText = () =>
37
+ `Spend cap reached: this session has cost ${money(cap.spent ?? 0)} of the ${money(cap.usd ?? 0)} cap ` +
38
+ `(Claude Code's own estimate), so subagent-spend sent no request. ` +
39
+ `To go on, raise it with /spend-cap <dollars>, or lift it with /spend-cap off.`
40
+
41
+ /** `/spend-cap` with its args: a number sets the cap, `off` lifts it, nothing shows it. The reply's text. */
42
+ export function capCommand(args: string): string {
43
+ const a = args.trim().toLowerCase()
44
+ if (a === 'off') {
45
+ cap.usd = null
46
+ cap.warned = false
47
+ return `Spend cap off for this session. ${spentText()}`
48
+ }
49
+ if (a !== '') {
50
+ const n = capOf(a)
51
+ if (n === null) return `Not a cap: "${args.trim()}". Give dollars, like /spend-cap 5, or /spend-cap off.`
52
+ cap.usd = n
53
+ cap.warned = false
54
+ return `Spend cap set to ${money(n)} for this session. ${spentText()}`
55
+ }
56
+ return cap.usd === null ? `No spend cap. ${spentText()}` : `Spend cap ${money(cap.usd)}. ${spentText()}`
57
+ }
58
+
59
+ const spentText = () => (cap.spent === null ? 'No cost reading yet.' : `Cost so far ${money(cap.spent)}.`)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nightlab-agent/subagent-spend",
3
- "version": "0.8.1",
4
- "description": "Claude Code mod: a spend cap for interactive sessions, and per-subagent tokens, rate-limit windows, context fill, cost, steps, tool calls and tool errors of a session, in a notice under the prompt, local files and panes (the usage pane not yet seen on a screen).",
3
+ "version": "0.8.3",
4
+ "description": "Claude Code plugin: a spend cap for interactive sessions, and per-subagent tokens, rate-limit windows, context fill, cost, steps, tool calls and tool errors of a session, in a notice under the prompt, local files and panes (the usage pane not yet seen on a screen).",
5
5
  "keywords": [
6
6
  "claude-code",
7
7
  "claude-code-mod",
@@ -26,6 +26,7 @@
26
26
  ".claude-plugin/",
27
27
  "hooks/hooks.json",
28
28
  "hooks/register.tsx",
29
+ "hooks/cap.ts",
29
30
  "hooks/spend.ts",
30
31
  "hooks/turns.ts",
31
32
  "hooks/usage.ts",
package/subagent_spend.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- """subagent-spend 0.8.1: attribute Claude Code token usage to each subagent.
2
+ """subagent-spend 0.8.3: attribute Claude Code token usage to each subagent.
3
3
 
4
4
  subagent_spend.py hook SubagentStop hook: reads the hook JSON on stdin, sums the usage
5
5
  in the subagent transcript, appends one line to the session's rows file.