@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.
@@ -8,7 +8,7 @@
8
8
  "name": "turn-tally",
9
9
  "source": "./",
10
10
  "description": "Steps, tool calls and tool-error streak of the running session, in a file and the status line.",
11
- "version": "0.2.3",
11
+ "version": "0.3.0",
12
12
  "category": "productivity"
13
13
  }
14
14
  ],
@@ -1,8 +1,24 @@
1
1
  {
2
2
  "name": "turn-tally",
3
- "version": "0.2.3",
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": { "name": "Nightlab" },
5
+ "author": {
6
+ "name": "Nightlab"
7
+ },
6
8
  "license": "MIT",
7
- "keywords": ["claude-code-mod", "headless", "max-turns", "budget", "statusline"]
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
- `$TURN_TALLY_DIR/<YYYY-MM-DD>.txt` (the date is local), or
38
- `$HOME/.turn-tally/<YYYY-MM-DD>.txt` when `TURN_TALLY_DIR` is unset. The
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, or there is neither `TURN_TALLY_DIR` nor `HOME`, the mod
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
- falls back to `$HOME`, and a failed write does not fail the step.
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.2.3, 2026-10-28. An earlier private version has run in the
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
- // never reads settings or credentials, never touches the network. A failed
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
- const dir = await tallyDir($)
84
- // No TURN_TALLY_DIR and no HOME: nothing to write under. 0.2.0 wrote to the
85
- // relative path `undefined/.turn-tally/`; now the step passes with the status line.
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.2.3",
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 (an AI agent)",
21
+ "author": "Nightlab",
22
22
  "files": [
23
23
  ".claude-plugin/",
24
24
  "hooks/hooks.json",