@kulapard/pi-caveman 0.4.3 → 0.6.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/AGENTS.md CHANGED
@@ -4,22 +4,27 @@ Project memory. Non-obvious only.
4
4
 
5
5
  ## Architecture (do not rebuild)
6
6
 
7
- - `extensions/caveman.ts` = Pi extension. `extensions/caveman-core.ts` = pure SDK-free logic (`normalizeMode`, `modeInstructions`, `VALID_MODES`, regexes). Unit-testable without fake SDK.
8
- - Mode state **session-scoped**: `pi.appendEntry("caveman-mode", …)`, restored from `ctx.sessionManager.getBranch()` on `session_start`. New session always `off`. No cross-session config/env.
9
- - Activation = `before_agent_start` appends `modeInstructions(mode)`. Statusline = `ctx.ui.setStatus("caveman", …)` guarded by `hasUI`.
10
- - Extension `modeInstructions` = **canonical** activator. `skills/caveman/SKILL.md` = fallback for hosts loading skills but not extension. If both active, model sees both rule sets intentional redundancy, no de-dupe.
7
+ - `extensions/caveman.ts` = Pi extension. `extensions/caveman-core.ts` holds SDK-free logic (`normalizeMode`, `modeInstructions`, `VALID_MODES`, regexes). Testable without fake SDK.
8
+ - Mode state **session + project-scoped**: `pi.appendEntry("caveman-mode", …)` restores from `ctx.sessionManager.getBranch()` on `session_start`; since v0.4.3 `extensions/caveman-state.ts` reads/writes `.pi/caveman-mode.json`. Session entry overrides project default; missing state file → `off`. No global/env default.
9
+ - `before_agent_start` appends `modeInstructions(mode)`. Statusline = `ctx.ui.setStatus("caveman", …)` guarded by `hasUI`.
10
+ - Extension `modeInstructions` = **canonical** activator. `skills/caveman/SKILL.md` = fallback when extension not loaded. Both active model sees both rule sets; intentional redundancy, no de-dupe.
11
11
  - Pi 0.80.2 has **no `agents/` subagent mechanism**. `agents/cavecrew-*.md` = reference personas only; cavecrew optional/out-of-scope.
12
12
 
13
13
  ## Invariants
14
14
 
15
- - **SDK import `import type` only** in `extensions/*.ts`. JS tests run via `--experimental-strip-types`, erases type-only imports. Value import from `@earendil-works/pi-coding-agent` breaks tests — `tests/extension.test.mjs` asserts this.
16
- - **Verbatim preservation**: caveman-compress never changes code blocks, inline code, URLs, paths, commands, exact error strings. Skill instructs self-validate against original. Mismatch unfixable → restore from `.original` backup created in same invocation (stale backups rejected before compression).
17
- - `caveman-compress` is **prompt-only**: Pi agent compresses with own model + file tools, driven by `SKILL.md`. No Python, no external model CLI. Coverage = `tests/compress-docs.test.mjs`.
15
+ - **SDK import `import type` only** in `extensions/*.ts`. JS tests use `--experimental-strip-types`, erases type-only imports. Value import from `@earendil-works/pi-coding-agent` breaks tests — `tests/extension.test.mjs` asserts this.
16
+ - **Verbatim preservation**: caveman-compress never changes code blocks, inline code, URLs, paths, commands, exact error strings. Self-validate against original. Mismatch unfixable → restore from `.original` backup created in same invocation; stale backups rejected before compression.
17
+ - `caveman-compress` **prompt-only**: Pi agent compresses with own model + file tools, driven by `SKILL.md`. No Python, no external model CLI. Coverage = `tests/compress-docs.test.mjs`.
18
+ - `/caveman-compress` supports `--force`: overwrites existing `.original.<ext>` backup instead of aborting.
19
+
20
+ ## Releases
21
+
22
+ Tag push triggers npm publish via `.github/workflows/publish.yml`. On release, create GitHub Release with same tag; paste matching `CHANGELOG.md` section into notes.
18
23
 
19
24
  ## Changelog
20
25
 
21
- Every notable change must update `CHANGELOG.md` under `[Unreleased]`. Before finishing task, run `npm run changelog:check` to confirm changelog updated for files changed. CI runs same check on every PR.
26
+ Every notable change `CHANGELOG.md` `[Unreleased]`. Before finish, run `npm run changelog:check`. CI runs same check per PR.
22
27
 
23
- - `npm test` runs `pretest` (`npm run typecheck` → `tsc --noEmit`), then `node --test tests/**/*.test.mjs`. Typecheck failures fail test run.
28
+ - `npm test` = `pretest` (`npm run typecheck` → `tsc --noEmit`), then `node --test tests/**/*.test.mjs`. Typecheck failures fail test run.
24
29
  - Node `--test` glob expanded by runner, not shell. Directory-recursion `--test tests/` does **not** work on current Node — keep glob.
25
30
  - Tests are **phantom-reference guards** (`tests/stats-docs.test.mjs`, `tests/cavecrew-docs.test.mjs`, `tests/compress-docs.test.mjs`): docs must not mention Claude-Code hooks layer, plugin install path, `⛏` badge, Claude-only subagent presets, broken asset paths. Do not reintroduce.
package/CHANGELOG.md CHANGED
@@ -7,13 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] - 2026-06-29
11
+
12
+ ### Added
13
+
14
+ - Release notes reminder: when tagging a release, also create a GitHub Release with the same tag and paste the relevant `CHANGELOG.md` section into the release notes.
15
+
16
+ ### Changed
17
+
18
+ - Statusline no longer appends `ctx:XX%`; shows only `caveman:<mode>`.
19
+ - Re-compressed `AGENTS.md` with `/caveman-compress --force` to reduce session token load.
20
+
21
+ ### Repository
22
+
23
+ - `.gitignore` now excludes `.pi/caveman-mode.json` (project-scoped mode state).
24
+
25
+ ## [0.5.0] - 2026-06-29
26
+
27
+ ### Added
28
+
29
+ - `/caveman-compress` now accepts an optional `--force` flag. With `--force`, an existing `.original.<ext>` backup is overwritten instead of aborting.
30
+
10
31
  ### Changed
11
32
 
12
- - Caveman mode is now project-scoped: `.pi/caveman-mode.json` in the working
13
- directory persists the mode across new sessions, while session entries still
14
- override it for the current session. Falls back to `off` when no state exists.
15
- - Status bar now appends live context usage (`ctx:XX%`) when a caveman mode is
16
- active and Pi exposes usage data. Updates on mode changes and at each turn end.
33
+ - Updated README, AGENTS.md, caveman-help, and caveman-compress docs to reflect the project-scoped persistence added in v0.4.3 and the new `--force` flag.
17
34
 
18
35
  ## [0.4.2] - 2026-06-29
19
36
 
@@ -120,7 +137,9 @@ port of [caveman](https://github.com/JuliusBrussee/caveman).
120
137
  token, automatic provenance, a tag-equals-version guard, and a concurrency
121
138
  group).
122
139
 
123
- [Unreleased]: https://github.com/kulapard/pi-caveman/compare/v0.4.2...HEAD
140
+ [Unreleased]: https://github.com/kulapard/pi-caveman/compare/v0.6.0...HEAD
141
+ [0.6.0]: https://github.com/kulapard/pi-caveman/compare/v0.5.0...v0.6.0
142
+ [0.5.0]: https://github.com/kulapard/pi-caveman/compare/v0.4.2...v0.5.0
124
143
  [0.4.2]: https://github.com/kulapard/pi-caveman/compare/v0.4.1...v0.4.2
125
144
  [0.4.1]: https://github.com/kulapard/pi-caveman/compare/v0.4.0...v0.4.1
126
145
  [0.4.0]: https://github.com/kulapard/pi-caveman/compare/v0.3.0...v0.4.0
package/README.md CHANGED
@@ -92,7 +92,7 @@ session ends.
92
92
  | `/caveman-help` | Show the quick-reference card. |
93
93
  | `/caveman-commit [notes]` | Generate a terse Conventional Commit message. Does **not** commit. |
94
94
  | `/caveman-review [scope]` | One-line-per-finding code review comments. |
95
- | `/caveman-compress <file>` | Compress a prose file via the caveman-compress skill. |
95
+ | `/caveman-compress <file> [--force]` | Compress a prose file via the caveman-compress skill. `--force` overwrites an existing `.original` backup. |
96
96
  | `/caveman-stats` | Load the stats skill (an on-demand, model-driven estimate). |
97
97
 
98
98
  ## Natural-language activation
@@ -105,18 +105,18 @@ switches mode on phrases like:
105
105
  - **Deactivate:** "stop caveman", "normal mode", "disable caveman" → turns it
106
106
  off.
107
107
 
108
- ## Session-scoped behavior
108
+ ## Session and project-scoped behavior
109
109
 
110
- Mode state is **session-scoped**. It is stored as a session entry and restored
111
- across a `/reload` within the same session, but a **new session always starts
112
- with caveman off** — by design. There is no cross-session config file or global
113
- default that auto-enables it.
110
+ Mode state is stored as a session entry, so it survives a `/reload` within the
111
+ same session. Since v0.4.3 it is also persisted per project in
112
+ `.pi/caveman-mode.json`, so a **new session in the same project directory**
113
+ restores the last used mode. A session entry always overrides the project
114
+ default, and a project without a state file falls back to `off`.
114
115
 
115
116
  ## Statusline indicator
116
117
 
117
118
  When a UI is attached, the statusline shows the active mode as
118
- `caveman:<mode>` (for example `caveman:ultra`). When caveman is off the indicator
119
- is cleared.
119
+ `caveman:<mode>` (for example `caveman:ultra`). When caveman is off the indicator is cleared.
120
120
 
121
121
  ## Compression vs. upstream MCP shrink
122
122
 
@@ -20,7 +20,7 @@ Commands:
20
20
  - /caveman-help — show this card.
21
21
  - /caveman-commit [notes] — generate Conventional Commit message. Does not commit.
22
22
  - /caveman-review [scope] — terse review comments.
23
- - /caveman-compress <file> — compress prose file via caveman-compress skill.
23
+ - /caveman-compress <file> [--force] — compress prose file via caveman-compress skill. --force overwrites an existing .original backup.
24
24
  - /caveman-stats — load stats skill/help.
25
25
 
26
26
  Mode persists across sessions in the same project via \`.pi/caveman-mode.json\`, and
@@ -32,13 +32,7 @@ export default function cavemanExtension(pi: ExtensionAPI) {
32
32
 
33
33
  function setStatus(ctx?: ExtensionContext) {
34
34
  if (!ctx?.hasUI) return;
35
- const usage = ctx.getContextUsage?.();
36
- const suffix =
37
- usage?.percent != null ? ` ctx:${Math.round(usage.percent)}%` : "";
38
- ctx.ui.setStatus(
39
- "caveman",
40
- mode === "off" ? undefined : `caveman:${mode}${suffix}`,
41
- );
35
+ ctx.ui.setStatus("caveman", mode === "off" ? undefined : `caveman:${mode}`);
42
36
  }
43
37
 
44
38
  function persistMode(nextMode: StoredMode, ctx?: ExtensionContext) {
@@ -121,14 +115,20 @@ export default function cavemanExtension(pi: ExtensionAPI) {
121
115
  });
122
116
 
123
117
  pi.registerCommand("caveman-compress", {
124
- description: "Compress prose/memory file into caveman style",
118
+ description:
119
+ "Compress prose/memory file into caveman style (optional --force)",
125
120
  handler: async (args, ctx) => {
126
- const target = args?.trim();
121
+ const raw = args?.trim() ?? "";
122
+ const tokens = raw.split(/\s+/).filter(Boolean);
123
+ const force = tokens.includes("--force");
124
+ const target = tokens.filter((t) => t !== "--force").join(" ");
127
125
  if (!target) {
128
- ctx.ui.notify("Usage: /caveman-compress <file>", "error");
126
+ ctx.ui.notify("Usage: /caveman-compress <file> [--force]", "error");
129
127
  return;
130
128
  }
131
- pi.sendUserMessage(`/skill:caveman-compress ${target}`);
129
+ pi.sendUserMessage(
130
+ `/skill:caveman-compress ${target}${force ? " --force" : ""}`,
131
+ );
132
132
  },
133
133
  });
134
134
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kulapard/pi-caveman",
3
- "version": "0.4.3",
3
+ "version": "0.6.0",
4
4
  "description": "Caveman for Pi: ultra-compressed agent output that preserves technical substance. Six intensity modes, slash commands, natural-language activation, and a session statusline.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -25,7 +25,7 @@ AGENTS.md ← compressed (the agent reads this — fewer tokens every s
25
25
  AGENTS.original.md ← human-readable backup (snapshot taken at first compression)
26
26
  ```
27
27
 
28
- Original never lost — first compression writes a verbatim backup. To edit and re-compress, **edit `AGENTS.md` itself**, then delete or rename the existing `AGENTS.original.md` so the next `/caveman-compress` can create a fresh backup.
28
+ Original never lost — first compression writes a verbatim backup. To edit and re-compress, **edit `AGENTS.md` itself**, then delete or rename the existing `AGENTS.original.md` so the next `/caveman-compress` can create a fresh backup. Or use `/caveman-compress AGENTS.md --force` to overwrite the existing backup in one step.
29
29
 
30
30
  ## Benchmarks
31
31
 
@@ -77,7 +77,7 @@ its own model and file tools — there is no separate tool or language to instal
77
77
  ## Usage
78
78
 
79
79
  ```
80
- /caveman-compress <filepath>
80
+ /caveman-compress <filepath> [--force]
81
81
  ```
82
82
 
83
83
  Examples:
@@ -87,6 +87,7 @@ Examples:
87
87
  /caveman-compress CLAUDE.md
88
88
  /caveman-compress docs/preferences.md
89
89
  /caveman-compress todos.md
90
+ /caveman-compress AGENTS.md --force
90
91
  ```
91
92
 
92
93
  ### What files work
@@ -4,7 +4,7 @@ description: >
4
4
  Compress natural language memory files (AGENTS.md, CLAUDE.md, todos, preferences) into caveman
5
5
  format to save input tokens. Preserves all technical substance, code, URLs, and structure.
6
6
  Compressed version overwrites the original file. Human-readable backup saved as FILE.original.<ext> (same extension as the source).
7
- Trigger: /caveman-compress FILEPATH or "compress memory file"
7
+ Trigger: /caveman-compress FILEPATH [--force]
8
8
  ---
9
9
 
10
10
  # Caveman Compress
@@ -15,16 +15,19 @@ Compress natural language files (`AGENTS.md`, `CLAUDE.md`, todos, preferences) i
15
15
 
16
16
  ## Trigger
17
17
 
18
- `/caveman-compress <filepath>` or when user asks to compress a memory file.
18
+ `/caveman-compress <filepath>` or when user asks to compress a memory file. Append `--force` to overwrite an existing `.original.<ext>` backup instead of aborting.
19
19
 
20
20
  ## Process
21
21
 
22
- You (the Pi agent) perform the compression directly — there is no separate tool to run. Given `/caveman-compress <filepath>`:
22
+ You (the Pi agent) perform the compression directly — there is no separate tool to run. Given `/caveman-compress <filepath>` (optionally with `--force`):
23
23
 
24
24
  1. **Skip backups.** If the path ends in `.original.<ext>` or, for extensionless files, in `.original` (e.g. `AGENTS.original.md`, `NOTES.original`), stop — never compress a backup file.
25
25
  2. **Check it is compressible** per **Boundaries** below: prose files (`.md`, `.txt`, `.rst`, `.typ`, `.typst`, `.tex`, or extensionless natural language). If it is code/config (`.py`, `.js`, `.ts`, `.json`, `.yaml`, …) or larger than ~500 KB, report it is out of scope and stop.
26
26
  3. **Read** the file's full contents.
27
- 4. **Back up the original.** If a `.original`/`.original.<ext>` backup already exists, **abort** and tell the user to remove or rename the stale backup before re-compressing. Otherwise write a verbatim copy to `<filename>.original.<ext>` (or `<filename>.original` for extensionless files) before any rewrite.
27
+ 4. **Back up the original.** If a `.original`/`.original.<ext>` backup already exists:
28
+ - Without `--force`, **abort** and tell the user to remove or rename the stale backup before re-compressing.
29
+ - With `--force`, overwrite the existing backup with a verbatim copy of the current source before any rewrite.
30
+ If no backup exists, write a verbatim copy to `<filename>.original.<ext>` (or `<filename>.original` for extensionless files) before any rewrite.
28
31
  5. **Rewrite** the file in place, applying the **Compression Rules** below. Treat code blocks, inline code, URLs, paths, commands, headings, and table structure as read-only regions.
29
32
  6. **Self-validate** against the contents you read in step 3: every protected token — fenced and inline code, URLs, file paths, heading text, table structure, dates/version numbers — must be byte-for-byte identical. If any changed, fix just that region; if you cannot make it identical, restore the file from the backup you wrote in step 4 and report the failure rather than leave a corrupted file.
30
33
  7. **Report** the result: bytes before/after and the approximate reduction.
@@ -4,7 +4,13 @@ Quick-reference card. One shot, no mode change.
4
4
 
5
5
  ## What it does
6
6
 
7
- Prints a cheat sheet of all caveman modes, sibling skills, deactivation triggers, and how mode lasts for the session (set with `/caveman`, resets to `off` on a new session — no config file or env var). One-shot display — does not flip the active mode, write flag files, or persist anything. Use when you forget the slash commands.
7
+ Prints a cheat sheet of all caveman modes, sibling skills, deactivation
8
+ triggers, and how mode persists: it is stored as a session entry (survives
9
+ `/reload`), and since v0.4.3 it is also saved per project in
10
+ `.pi/caveman-mode.json` (a new session in the same project directory restores
11
+ the last mode). No config file? Falls back to `off`. One-shot display — does not
12
+ flip the active mode, write flag files, or persist anything. Use when you forget
13
+ the slash commands.
8
14
 
9
15
  ## How to invoke
10
16
 
@@ -29,7 +29,7 @@ Mode stick until changed or session end.
29
29
  |-------|---------|-----------|
30
30
  | **caveman-commit** | `/caveman-commit` | Terse commit messages. Conventional Commits. ≤50 char subject. |
31
31
  | **caveman-review** | `/caveman-review` | One-line PR comments: `L42: bug: user null. Add guard.` |
32
- | **caveman-compress** | `/caveman-compress <file>` | Compress .md files to caveman prose. Saves ~46% input tokens. |
32
+ | **caveman-compress** | `/caveman-compress <file> [--force]` | Compress .md files to caveman prose. Saves ~46% input tokens. `--force` overwrites stale backup. |
33
33
  | **caveman-stats** | `/caveman-stats` | On-demand, model-driven estimate of tokens saved this session. |
34
34
  | **caveman-help** | `/caveman-help` | This card. |
35
35
 
@@ -41,12 +41,16 @@ Say "stop caveman" or "normal mode". Resume anytime with `/caveman`.
41
41
 
42
42
  Keep user's language by default. User write Portuguese → reply Portuguese caveman. Compress the style, not the language. Technical terms, code, commands, commit types, and exact error strings stay verbatim unless user ask for translation.
43
43
 
44
- ## Mode lasts the session
44
+ ## Mode persistence
45
45
 
46
- `/caveman` (no argument) = `full`. Pick another with `/caveman ultra`, `/caveman lite`, etc.
46
+ Mode set per session entry, so it survives `/reload`. Since v0.4.3 it is also
47
+ saved per project in `.pi/caveman-mode.json`; a new session in the same project
48
+ directory restores the last mode. Session entry overrides project default. No
49
+ config file? Falls back to `off`.
47
50
 
48
- Mode set per session. New session start → mode `off`; activate again with `/caveman`. No config file, no env var — the `/caveman` command is the only switch.
51
+ `/caveman` (no argument) = `full`. Pick another with `/caveman ultra`,
52
+ `/caveman lite`, etc. Say "stop caveman" or "normal mode" to turn off.
49
53
 
50
54
  ## More
51
55
 
52
- Full docs: https://github.com/kulapard/pi-caveman
56
+ Full docs: <https://github.com/kulapard/pi-caveman>