@nredd/pi-session-kit 0.0.0-stage → 0.4.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.
Files changed (52) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +191 -2
  3. package/dist/pi-stats-export.mjs +657 -0
  4. package/docs/stats-snapshots.md +122 -0
  5. package/package.json +55 -4
  6. package/src/child.ts +79 -0
  7. package/src/clock.ts +25 -0
  8. package/src/config.ts +64 -0
  9. package/src/diff/component.ts +214 -0
  10. package/src/diff/git.ts +289 -0
  11. package/src/diff/index.ts +65 -0
  12. package/src/diff/parse.ts +180 -0
  13. package/src/diff/view.ts +98 -0
  14. package/src/goal/index.ts +343 -0
  15. package/src/goal/state.ts +270 -0
  16. package/src/goal/subagents.ts +77 -0
  17. package/src/index.ts +52 -0
  18. package/src/loop/index.ts +151 -0
  19. package/src/loop/state.ts +107 -0
  20. package/src/monitor/README.md +12 -0
  21. package/src/monitor/coalescer.ts +76 -0
  22. package/src/monitor/index.ts +220 -0
  23. package/src/monitor/manager.ts +336 -0
  24. package/src/monitor/matcher.ts +113 -0
  25. package/src/monitor/messages.ts +93 -0
  26. package/src/monitor/output.ts +41 -0
  27. package/src/monitor/pidfiles.ts +415 -0
  28. package/src/monitor/process.ts +125 -0
  29. package/src/monitor/ring.ts +52 -0
  30. package/src/monitor/splitter.ts +57 -0
  31. package/src/monitor/types.ts +35 -0
  32. package/src/monitor/validate.ts +59 -0
  33. package/src/monitor/widget.ts +75 -0
  34. package/src/output.ts +25 -0
  35. package/src/rules/index.ts +94 -0
  36. package/src/rules/logic.ts +96 -0
  37. package/src/shared.ts +177 -0
  38. package/src/stats/aggregate.ts +287 -0
  39. package/src/stats/chart.ts +247 -0
  40. package/src/stats/cli.ts +50 -0
  41. package/src/stats/component.ts +496 -0
  42. package/src/stats/days.ts +46 -0
  43. package/src/stats/format.ts +49 -0
  44. package/src/stats/heatmap.ts +98 -0
  45. package/src/stats/index.ts +88 -0
  46. package/src/stats/library.ts +4 -0
  47. package/src/stats/load.ts +512 -0
  48. package/src/stats/palette.ts +22 -0
  49. package/src/stats/snapshot.ts +497 -0
  50. package/src/titles/aliases.ts +20 -0
  51. package/src/titles/index.ts +87 -0
  52. package/src/titles/logic.ts +160 -0
package/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Redd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction,
7
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
8
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
17
+ OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,192 @@
1
- # Temporary Holding Version
1
+ # pi-session-kit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Published to npm as `@nredd/pi-session-kit` (public). Each version is cut by the monorepo `Publish` workflow from a signed `@nredd/pi-session-kit@<version>` tag, with npm provenance and a GitHub release carrying the tarball, checksums and manifest (`docs/releases.md`). `0.4.0` adds `createSessionKit(options)` (explicit `config`, `agentDir`, `monitorRoot`, injectable `clock` and `spawnMonitor`; the default export is unchanged) and fixes leaderless orphan-group sweeps at `ps` start-time resolution.
4
+ Use the [monorepo development commands](https://github.com/nredd/pi-harness/blob/main/README.md). The Git install and standalone harness
5
+ references below describe the legacy deployment, not installation or candidate verification of
6
+ this package.
7
+
8
+ ## Standalone use
9
+
10
+ The packed tarball is self-contained: Pi host modules (`@earendil-works/pi-*`, `typebox`) are `*` peers supplied by Pi, there are no runtime dependencies and no sibling plugin is required. Verified by installing the tarball alone and running it in exact stock Pi 1.3.0 (see the repository's `docs/package-contracts.md`). Optional fork integrations (subagents, Plan mode) are absent in that setup; the exercised behavior does not need them.
11
+
12
+ Session-scoped pi extensions for tmux users. No daemon, supervisor, core patch or cross-pane
13
+ registry. Each runtime owns its goal, loops and monitors; persisted goal state follows the active
14
+ session branch. Closing pi stops its work.
15
+
16
+ ## Install and config
17
+
18
+ ```sh
19
+ pi install npm:@nredd/pi-session-kit@0.4.0
20
+ ```
21
+
22
+ Optional `~/.pi/agent/pi-session-kit.json` (respects `PI_CODING_AGENT_DIR`):
23
+
24
+ ```json
25
+ {
26
+ "titles": { "enabled": true, "model": "anthropic/claude-haiku-5-5" },
27
+ "rules": { "enabled": true },
28
+ "goal": { "enabled": true },
29
+ "loop": { "enabled": true },
30
+ "monitor": { "enabled": true },
31
+ "diff": { "enabled": true },
32
+ "stats": { "enabled": true }
33
+ }
34
+ ```
35
+
36
+ Every module defaults on. Malformed config reports a diagnostic and uses defaults. SDK hosts can use
37
+ `createSessionKit({ config, agentDir, monitorRoot })` from `src/index.ts`: explicit `config` avoids
38
+ loading the config file, `agentDir` scopes config/rules/title aliases, and `monitorRoot` isolates
39
+ monitor pidfiles and orphan sweeps. Optional `clock` (`now`, cancellable `setTimeout`/`setInterval`)
40
+ and `spawnMonitor` seams control scheduling and child lifetime in SDK tests; the real manager,
41
+ ring, coalescer, regex worker and host follow-up queue still run. Controlled stdout callbacks resolve
42
+ after matching/ingestion; native pipe events need not await them. Omitted options keep the CLI defaults. No daemon or
43
+ persistent cron is installed. Deferred-tool configurations need `goal_update` in `neverDefer`
44
+ (without forcing it active), and `monitor_read` in `alwaysActive` and `neverDefer` for Plan mode.
45
+
46
+ ## Goal and loop
47
+
48
+ - `/goal <objective> [--turns N] [--tokens N]`: keep working toward an explicit objective. Default
49
+ budget: 30 parent turns. Token accounting uses reported usage. `status`, `pause`, `resume` and
50
+ `clear` manage it; the footer chip shows turn and token consumption.
51
+ - `goal_update({status: "complete" | "blocked", evidence})`: complete requires nonempty evidence.
52
+ This is a self-report, not an independent verifier; it does not replace tests or todo evidence.
53
+ - The settle nudge respects existing continuations, background-agent delivery and Plan permissions.
54
+ Abort, settled provider error, budgets and a Plan-mode excursion pause/stop it. Resume restores a
55
+ goal paused. Quota recovery is left to the router; a parked dispatch or direct refusal pauses
56
+ goals and loops, cancels goal wake timers, and requires explicit resume. Goal resume is refused
57
+ while a quota-parked dispatch remains. A settled provider failure also pauses rather than spinning.
58
+ - `/loop <interval> <prompt> [--max N]`: repeat a prompt in the current conversation, unlike
59
+ `Agent({schedule: ...})`, which launches fresh children. Minimum interval 30s; maximum 50 runs.
60
+ `list` and `stop [id|all]` manage loops. Busy ticks are skipped, never queued. Plan mode and an
61
+ active goal suspend ticks; settled errors pause loops. Loops are not persisted across restarts.
62
+
63
+ ## Monitor
64
+
65
+ - `monitor_start({argv, name, match?, wake?, timeout_s?})`: run an argv command with stdin closed,
66
+ no implicit shell. Five active monitors maximum, one-hour default timeout. Explicitly passing a
67
+ shell remains arbitrary command execution; this is not a sandbox.
68
+ - `monitor_read({id, since?})`: numbered output since a cursor. Ring buffers retain 2000 lines.
69
+ - `monitor_stop({id})`, `/monitor list`, `/monitor stop <id|all>`: stop and inspect owned monitors.
70
+ - Output batches every two seconds with bounded pending storage and dropped-line reporting. Passive
71
+ batches do not start turns; regex matches, exit and `wake: true` can wake the agent.
72
+ - Children run in process groups: SIGTERM, then SIGKILL. Exit cleanup and pidfiles cover orderly quit
73
+ and later recovery after SIGKILL. Files live at
74
+ `$TMPDIR/pi-monitors-<uid>/<sessionId>.<ownerPid>/<monitorId>.json`. Startup checks dead-owner
75
+ records, including a resumed session, and validates process identity before signalling. It never
76
+ sweeps a live owner's monitors. Two panes resuming the same session have separate directories.
77
+ A group whose leader already exited is reaped only when a member started at spawn anchors it: its
78
+ `ps lstart` must read under one second after, or under two before, the recorded spawn (`lstart` is
79
+ a whole-second floor). A member that reads a second or more after the spawn cannot authenticate a
80
+ possibly reused group, so its record is kept, not signalled. Within that window a later-born member
81
+ in a reused group is indistinguishable; the dead leader, matching group and session, and no prior
82
+ members bound that case, they do not exclude it.
83
+ - Plan mode admits only `monitor_read`; start and stop are mutating tools. Ordinary tool hooks apply
84
+ to the tool call, but a custom argv tool does not automatically inherit Bash-specific policies.
85
+
86
+ ## Diff
87
+
88
+ `/diff [ref]` opens a read-only file/patch overlay. Default: staged and working changes against HEAD,
89
+ with untracked files listed. `j/k` or arrows scroll, `n/p` select files, `g/G` and PageUp/PageDown
90
+ navigate, `q` or Escape closes. Output is capped. Invalid refs and non-repositories produce clear
91
+ errors. Print mode emits a stat (pi currently redirects extension stdout to stderr); JSON emits a
92
+ non-triggering display message. The overlay is TUI-only and works in Plan mode.
93
+
94
+ ## Stats
95
+
96
+ `/stats` is Claude Code's `/stats` pane over fresh local sessions plus imported machine snapshots,
97
+ split by provider and model. It NEVER performs network I/O. Machine coverage and the last successful
98
+ remote import are shown; unsynced machines show `local-only` / `never synced`. Invalid or missing
99
+ snapshots retain last-good data and show `incomplete coverage`. Overview: an activity heatmap (one column per week), headline numbers (favorite model, total tokens,
100
+ sessions, longest session, active days, streaks, cache tokens, notional cost) and the token chart.
101
+ Models: the chart, then every model grouped under its provider with in/out/cache/cost, two-up from
102
+ 80 columns. Tab switches tabs, `r` cycles All / 7d / 30d / 5h / 24h (default All), `m`/`M` cycle the filter
103
+ (All, each provider, each `provider/model`), `j/k` or arrows scroll, `q` or Escape closes.
104
+
105
+ - The chart is an asciichart-style line plot (`╭╮╰╯`), one line per provider under All, else the top
106
+ three models. Where lines overlap they merge into junctions (`┴┬├┤┼`) so every line stays
107
+ connected; the larger series keeps the colour. Line colours start at the theme's `accent` hue,
108
+ saturated, with hues spread evenly over the lines drawn (two providers get opposite hues), so
109
+ muted themes still separate them. The heatmap and the chart span 75% of the pane, with the same right edge; the heatmap shows as
110
+ many weeks as fit, never less than a year when the pane allows. Days sum into 1/2/3/7/14/30-day buckets (longer
111
+ when needed) so the range fits the width; short ranges are interpolated, not stepped. Y ticks land
112
+ on round values with little headroom. Height follows the pane in whole tick steps (5 to 40 rows):
113
+ Overview grows the chart into the rows it has left, Models gives it about half.
114
+ - Rolling 5h/24h use the original call timestamps in zero-filled one-hour UTC buckets, with
115
+ partial edges labeled. Labels use viewer-local time and UTC offsets, including repeated DST
116
+ hours. The same rolling filter feeds chart/model/overview totals; future calls are ignored in
117
+ every range. Long ranges retain the daily chart and activity heatmap.
118
+ - Tokens = input + output + cache read + cache write. Anthropic reports almost every prompt token
119
+ as a cache read or write while Codex reports it as input, so anything less undercounts agentic
120
+ use by orders of magnitude. Cost is pi's recorded list price: notional on a subscription.
121
+ - Counted: assistant messages, under the provider/model that answered. Not counted: tool-result
122
+ usage (pi-subagents' parent-side report; its child sessions already hold those calls), compaction
123
+ usage, `router/*` rows, `faux` and zero-usage rows. A `/fork` or cross-machine copy counts once.
124
+ Preserved assistant entry IDs distinguish equal-value events. Legacy records use the old tuple
125
+ identity and are discarded when an identified counterpart exists. Raw names drive dedup;
126
+ only display text is sanitized.
127
+ - Subagent children (parent link plus a `<type>#<8 hex>` name, or the matching persisted child
128
+ marker, including renamed children) count toward tokens but not
129
+ Sessions. A filter narrows Sessions to the sessions that used the filtered models.
130
+ - Source: `*.jsonl` under `$PI_CODING_AGENT_SESSION_DIR` or `<agentDir>/sessions`. Cache:
131
+ `<agentDir>/pi-session-kit/stats-cache.json`, re-parsing only files whose size or mtime changed;
132
+ deleted sessions keep counting; machine views also retain history from previously configured
133
+ session roots. Version 1 caches migrate without dropping deleted-file records; available files
134
+ are reparsed for preserved IDs. A corrupt record is dropped and rebuilt. Lines that are not JSON
135
+ objects show as `! N unreadable lines`.
136
+ - Print mode prints a per-model table and coverage; JSON emits a display message. Works in Plan mode.
137
+ - After `make install` at the monorepo root, `npm run build:stats-export --workspace @nredd/pi-session-kit`
138
+ reproduces `dist/pi-stats-export.mjs` inside this package. Copy this standalone Node 22+ artifact
139
+ to another machine: neither Pi nor the loaded session-kit extension is needed at runtime.
140
+ `node ARTIFACT export --agent-dir DIR --output OUT` writes ONLY `OUT/machines/<UUID>/`.
141
+ `node ARTIFACT import --agent-dir DIR --input REPO` validates all machines and atomically
142
+ publishes the local global cache. Both emit one JSON object on success; partial imports emit
143
+ JSON and diagnostics with a nonzero exit. No Git/network operations are part of the CLI.
144
+ Schema, identity, atomicity and harness API details: [here](docs/stats-snapshots.md).
145
+
146
+ ## Titles and rules
147
+
148
+ - Titles: one attempt after the first eligible TUI run of an unnamed persisted session. Default
149
+ candidates are Haiku 5.5, validated enterprise alias candidates (including the legacy Haiku 4.5
150
+ logical key), then GPT 6 Luna. `titles.model` overrides the preferred candidate. No silent retry
151
+ after provider failure; explicit names and session switches win races. Children, headless runs,
152
+ no-session runs and active planning are skipped. Output is capped at six words/60 characters;
153
+ shorter names are accepted.
154
+ - Rules: Markdown files in `.pi/rules/` and the agent directory's `rules/`, with YAML frontmatter
155
+ `paths: ["src/**/*.ts"]`. No `paths`, no injection. Successful read/edit/write results receive
156
+ matching rules once per context lifetime. Compaction resets deduplication. Eight rules per turn,
157
+ 4096 UTF-8 bytes per appended block. The system prompt is not rewritten. Rules injected after an
158
+ edit inform subsequent work, not the edit already performed.
159
+
160
+ ## Subagents and verification
161
+
162
+ `pi-subagents` exposes no public child-context marker. The kit recognises its generated
163
+ `<type>#<8 hex>` session names; this is a compatibility heuristic, not a security boundary.
164
+ Commands/continuations are guarded. At `session_start`, parent-only goal/monitor tools are
165
+ re-registered with Pi's `hidden` exposure: child scoping and deferred promotion cannot reactivate
166
+ their schemas or nested-call capabilities. Tool-call and execute guards also deny child calls,
167
+ even after a child renames itself and reloads. Initial child binding persists a
168
+ `session-kit:child` entry with its session id; reload reads the active branch, not a generic
169
+ parent-session link (fresh Plan sessions also have parents). Replacement sessions do not inherit
170
+ cached identity or another session's marker. Goal/monitor factories register the shared identity
171
+ hook before their rebuild hooks, without querying an unbound runtime during factory loading.
172
+ No private subagent marker is imported. Existing tool permissions are not widened.
173
+
174
+ A prior settle handler's continuation (including a todo reminder) suppresses the goal nudge;
175
+ the kit does not append a second reminder or request another continuation.
176
+
177
+ `test/scenarios/` drives the real kit through core's in-process session harness under Vitest and Bun,
178
+ covering goals, file-backed restore, child rename/reload, read-rule injection, titles,
179
+ monitor output/wakes/cursors/caps/timeouts and loop scheduling with same-cwd session isolation.
180
+ The interactive host/VirtualTerminal covers `/diff`, `/stats` and real `/name`, including width/resize
181
+ matrices, chart glyph ports/colours and file-backed titles. Stats histories use a fixed clock;
182
+ `createSessionKit({ agentDir, clock })` scopes both offline loading and displayed time ranges.
183
+ Terminal fixtures route input chunks through pi-tui's real `StdinBuffer`, matching ProcessTerminal's
184
+ keypress splitting (complete keys only; lone Escape is flushed immediately). Stats scroll-to-clamp
185
+ checks batch input and settle once; intermediate-frame checks still settle per step. Both hourly
186
+ tabs and exact provider totals remain covered at every width. Each stats-view body owns its fixture
187
+ and disposes it in `finally`, so runner timeout teardown cannot race a still-running callback.
188
+ Monitor scenarios use a shared fake clock and controlled children; native `test/monitor/` keeps real
189
+ workers/processes, and process-group kill/orphan recovery stays in the assembled integration tier.
190
+ `npm run check` runs Biome, TypeScript, the full Vitest suite and `bun test test/scenarios` (Bun 1.3.14).
191
+ Cross-extension Plan/subagent/todo interactions and OS terminal boundaries remain in the integration tier;
192
+ `docs/verification-rebuild.md` at the monorepo root tracks their destinations.