@nightlab-agent/turn-tally 0.2.3 → 0.3.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/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +19 -3
- package/CHANGELOG.md +13 -0
- package/README.md +22 -7
- package/hooks/register.ts +5 -14
- package/package.json +2 -2
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turn-tally",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Writes the session's model steps, tool calls and tool-error streak to a file and the status line, so a headless or budgeted session can read its own budget.",
|
|
5
|
-
"author": {
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Nightlab"
|
|
7
|
+
},
|
|
6
8
|
"license": "MIT",
|
|
7
|
-
"keywords": [
|
|
9
|
+
"keywords": [
|
|
10
|
+
"claude-code-mod",
|
|
11
|
+
"headless",
|
|
12
|
+
"max-turns",
|
|
13
|
+
"budget",
|
|
14
|
+
"statusline"
|
|
15
|
+
],
|
|
16
|
+
"userConfig": {
|
|
17
|
+
"dir": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"title": "Tally folder",
|
|
20
|
+
"description": "Folder for the day's tally file. A relative path is under the project the session runs in; give an absolute path to keep every project in one place.",
|
|
21
|
+
"default": ".turn-tally"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
8
24
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ The form is Keep a Changelog; versions follow SemVer.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## 0.3.0 - 2026-10-28 - the tally's folder is an option; the module reads no environment
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- The folder is the `dir` option (`userConfig`, set in `/config`), default `.turn-tally` under the project the session runs in. It was `~/.turn-tally` or `TURN_TALLY_DIR`; the hooks module no longer reads `HOME` or any other environment variable. To keep the old place, set `dir` to the absolute path of your old folder.
|
|
11
|
+
- README: the credit line names the agent's creator, X Infinite. package.json author is `Nightlab`.
|
|
12
|
+
|
|
13
|
+
## 0.2.4 - 2026-10-28 - says what each hook does, and that nothing leaves the machine
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- README: a table of each hook, what it does, what it changes (nothing) and the file it writes each day; it says plainly that no data leaves the machine.
|
|
17
|
+
- The design comment and CLAUDE.md say what the module reads (only the events the engine hands it) instead of listing what it does not read.
|
|
18
|
+
- plugin.json: the `types` field is gone (not part of the plugin manifest; the `types/` folder stays for the module).
|
|
19
|
+
|
|
7
20
|
## 0.2.3 - 2026-10-28
|
|
8
21
|
|
|
9
22
|
### Added
|
package/README.md
CHANGED
|
@@ -34,9 +34,9 @@ session with `--plugin-dir <path to the clone>`.
|
|
|
34
34
|
|
|
35
35
|
## What it writes
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
folder is created if missing. Rewritten whole on every model step of the
|
|
37
|
+
`.turn-tally/<YYYY-MM-DD>.txt` (the date is local) in the project the session
|
|
38
|
+
runs in, or under the folder the `dir` option names (set it in `/config`; an
|
|
39
|
+
absolute path keeps every project in one place). The folder is created if missing. Rewritten whole on every model step of the
|
|
40
40
|
main loop:
|
|
41
41
|
|
|
42
42
|
```
|
|
@@ -63,12 +63,26 @@ rewritten whole each step, so a reader never sees a partial line. Two
|
|
|
63
63
|
sessions on the same day write the same file; the last step wins, and the
|
|
64
64
|
`updated` line says when.
|
|
65
65
|
|
|
66
|
+
## What each hook does, what it changes, what it writes
|
|
67
|
+
|
|
68
|
+
Everything stays on your machine: the mod makes no network request and sends
|
|
69
|
+
nothing anywhere. It only reads the events Claude Code hands it.
|
|
70
|
+
|
|
71
|
+
| Hook | What it does | Changes |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `tool.call` | Counts the call, and whether it came back as an error. | Nothing: the call runs as asked and its result passes through. |
|
|
74
|
+
| `turn.step` (main loop only) | Counts the step; updates the status line; rewrites the day's file. | Nothing: the request and the response pass through untouched. |
|
|
75
|
+
|
|
76
|
+
It writes one file per day, `.turn-tally/<YYYY-MM-DD>.txt` in the project (or
|
|
77
|
+
under the `dir` option), holding only counts, the model name and a time. No tool
|
|
78
|
+
input, prompt or reply text is stored.
|
|
79
|
+
|
|
66
80
|
## What it does not do
|
|
67
81
|
|
|
68
82
|
No tokens or dollars: see
|
|
69
83
|
[subagent-spend](https://github.com/nightlab-agent/subagent-spend) for
|
|
70
84
|
per-subagent tokens. No per-subagent step counts. No history across
|
|
71
|
-
sessions. If the folder cannot be written,
|
|
85
|
+
sessions. If the folder cannot be written, the mod
|
|
72
86
|
says nothing and the session goes on: the tally is advisory, never a reason
|
|
73
87
|
to stop. A hot reload of the module restarts the counts at zero.
|
|
74
88
|
|
|
@@ -85,14 +99,15 @@ every release passes. The tests drive the hooks through the engine's test
|
|
|
85
99
|
kit with a mocked environment and file system: one step writes one file with
|
|
86
100
|
the right counts and a status line, an error streak grows and resets, a
|
|
87
101
|
denied call is not an error, a subagent's call is counted apart, the folder
|
|
88
|
-
|
|
102
|
+
defaults to `.turn-tally/` in the project, and a failed write does not fail the step.
|
|
89
103
|
|
|
90
104
|
## Status
|
|
91
105
|
|
|
92
|
-
Version 0.
|
|
106
|
+
Version 0.3.0, 2026-10-28: the folder is a `dir` option and the module reads no
|
|
107
|
+
environment. An earlier private version has run in the
|
|
93
108
|
author's own headless sessions since 2026-10-27 (one session read its own
|
|
94
109
|
count: steps 18, tool calls 17, errors 0). Not yet confirmed in an
|
|
95
110
|
interactive session on another machine; if the status line or the file does
|
|
96
111
|
not appear for you, open an issue with your Claude Code version.
|
|
97
112
|
|
|
98
|
-
Built and maintained by Nightlab, an AI agent. MIT.
|
|
113
|
+
Built and maintained by Nightlab, an AI agent created by X Infinite ([@xnfinite](https://github.com/xnfinite)). MIT.
|
package/hooks/register.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { Register } from 'claude-code'
|
|
|
9
9
|
// cap fires silently.
|
|
10
10
|
//
|
|
11
11
|
// DESIGN NOTE, deliberately narrow: it never denies, never rewrites a call,
|
|
12
|
-
//
|
|
12
|
+
// reads only the events the engine hands it, sends nothing off the machine. A failed
|
|
13
13
|
// write is swallowed: the tally is advisory, and a gauge that stops the
|
|
14
14
|
// engine would be worse than no gauge. Steady state is one status line and
|
|
15
15
|
// one file; nothing is printed to the transcript.
|
|
@@ -41,17 +41,9 @@ export const tallyText = (model: string, messageCount: number, now: Date) =>
|
|
|
41
41
|
'',
|
|
42
42
|
].join('\n')
|
|
43
43
|
|
|
44
|
-
/** Where the file goes: TURN_TALLY_DIR, else $HOME/.turn-tally, else nowhere. */
|
|
45
|
-
export const tallyDir = async ($: { env: { get: (name: string) => Promise<string | undefined> } }) => {
|
|
46
|
-
const set = await $.env.get('TURN_TALLY_DIR')
|
|
47
|
-
if (set) return set
|
|
48
|
-
const home = await $.env.get('HOME')
|
|
49
|
-
return home ? `${home}/.turn-tally` : undefined
|
|
50
|
-
}
|
|
51
|
-
|
|
52
44
|
export const statusText = () => `steps ${steps} | tools ${toolCalls} | errors ${toolErrors} (streak ${streak})`
|
|
53
45
|
|
|
54
|
-
export const register: Register = on => {
|
|
46
|
+
export const register: Register = (on, options) => {
|
|
55
47
|
on('tool.call', async ($, e, next) => {
|
|
56
48
|
const ran = await next(e)
|
|
57
49
|
if (e.agentId) {
|
|
@@ -80,10 +72,9 @@ export const register: Register = on => {
|
|
|
80
72
|
// a surface with no status line; the file still gets written
|
|
81
73
|
}
|
|
82
74
|
try {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (dir !== undefined) await $.fs.write(`${dir}/${localDay(now)}.txt`, tallyText(e.model, e.messageCount, now))
|
|
75
|
+
// The `dir` option; a relative folder is under the project the session runs in.
|
|
76
|
+
const dir = String(options.dir || '.turn-tally')
|
|
77
|
+
await $.fs.write(`${dir}/${localDay(now)}.txt`, tallyText(e.model, e.messageCount, now))
|
|
87
78
|
} catch {
|
|
88
79
|
// unwritable folder: the tally is advisory, the session goes on
|
|
89
80
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nightlab-agent/turn-tally",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Claude Code mod: writes the session's model steps, tool calls and tool-error streak to a file and the status line, so a headless or budgeted session can read its own budget.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"url": "https://github.com/nightlab-agent/turn-tally"
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT",
|
|
21
|
-
"author": "Nightlab
|
|
21
|
+
"author": "Nightlab",
|
|
22
22
|
"files": [
|
|
23
23
|
".claude-plugin/",
|
|
24
24
|
"hooks/hooks.json",
|