chore: ignore reviewers and superpowers docs
- commit
- 4d937f1f49026cc9d27d29b7754381d944d7a174
- author
- brice · · 2026-08-04 09:32 UTC
- parent
- ae5a835
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +2 -389
M .gitignore +2 -0
| @@ -73,4 +73,6 @@ logs/ | |||
| 73 | 73 | .tmp/ | |
| 74 | 74 | tmp/ | |
| 75 | 75 | .agent-reviews/ | |
| 76 | + | .codereview/ | |
| 77 | + | docs/superpowers/ | |
| 76 | 78 | npm/ | |
| @@ -73,4 +73,6 @@ logs/ | |||||
| 73 | .tmp/ | 73 | .tmp/ | ||
| 74 | tmp/ | 74 | tmp/ | ||
| 75 | .agent-reviews/ | 75 | .agent-reviews/ | ||
| 76 | + | .codereview/ | |||
| 77 | + | docs/superpowers/ | |||
| 76 | npm/ | 78 | npm/ | ||
D docs/superpowers/plans/2026-07-28-configurable-auto-compact-threshold.md +0 -239
| @@ -1,239 +0,0 @@ | |||
| 1 | - | # Configurable Auto-Compact Threshold Implementation Plan | |
| 2 | - | ||
| 3 | - | > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. | |
| 4 | - | ||
| 5 | - | **Goal:** Add persisted auto-compaction threshold presets to the interactive TUI settings. | |
| 6 | - | ||
| 7 | - | **Architecture:** Keep automatic triggering in `packages/agent/modes`. Thread an optional integer percentage from persisted `agent.Config` into `modes.InteractiveConfig`, normalize missing or invalid values to 85%, and let zero disable only percentage-based triggers. Reuse the settings dialog's existing fixed-option picker and settings-store persistence path. | |
| 8 | - | ||
| 9 | - | **Tech Stack:** Go, standard library, Zot's existing TUI settings dialog, JSON configuration. | |
| 10 | - | ||
| 11 | - | ## Global Constraints | |
| 12 | - | ||
| 13 | - | - Supported values are `0` (off), `70`, `80`, `85`, and `90`. | |
| 14 | - | - Missing or invalid persisted values resolve to `85`. | |
| 15 | - | - Disabling the threshold does not disable manual compaction or HTTP 413 recovery. | |
| 16 | - | - Do not add dependencies or change non-interactive compaction behavior. | |
| 17 | - | - Preserve unrelated working-tree changes and stage only this feature. | |
| 18 | - | ||
| 19 | - | --- | |
| 20 | - | ||
| 21 | - | ### Task 1: Configuration and threshold decision | |
| 22 | - | ||
| 23 | - | **Files:** | |
| 24 | - | - Modify: `packages/agent/config.go` | |
| 25 | - | - Modify: `packages/agent/modes/interactive.go` | |
| 26 | - | - Create: `packages/agent/modes/auto_compact_test.go` | |
| 27 | - | - Modify: `packages/agent/cli.go` | |
| 28 | - | ||
| 29 | - | **Interfaces:** | |
| 30 | - | - Produces: `Config.AutoCompactThreshold *int` | |
| 31 | - | - Produces: `InteractiveConfig.AutoCompactThreshold *int` | |
| 32 | - | - Produces: `normalizeAutoCompactThreshold(*int) int` | |
| 33 | - | - Produces: `shouldAutoCompact(inputTokens, contextWindow, thresholdPercent int) bool` | |
| 34 | - | ||
| 35 | - | - [ ] **Step 1: Write failing normalization and decision tests** | |
| 36 | - | ||
| 37 | - | Add table-driven tests proving nil and invalid values resolve to 85, supported presets survive unchanged, zero disables percentage checks, and 70/80/85/90 trigger exactly at their boundaries. | |
| 38 | - | ||
| 39 | - | ```go | |
| 40 | - | func TestNormalizeAutoCompactThreshold(t *testing.T) { | |
| 41 | - | tests := []struct { | |
| 42 | - | name string | |
| 43 | - | value *int | |
| 44 | - | want int | |
| 45 | - | }{ | |
| 46 | - | {name: "missing", value: nil, want: 85}, | |
| 47 | - | {name: "off", value: intPtr(0), want: 0}, | |
| 48 | - | {name: "seventy", value: intPtr(70), want: 70}, | |
| 49 | - | {name: "invalid", value: intPtr(42), want: 85}, | |
| 50 | - | } | |
| 51 | - | // Assert normalizeAutoCompactThreshold(test.value) == test.want. | |
| 52 | - | } | |
| 53 | - | ||
| 54 | - | func TestShouldAutoCompactUsesConfiguredThreshold(t *testing.T) { | |
| 55 | - | if shouldAutoCompact(84, 100, 85) { | |
| 56 | - | t.Fatal("84% must remain below an 85% threshold") | |
| 57 | - | } | |
| 58 | - | if !shouldAutoCompact(85, 100, 85) { | |
| 59 | - | t.Fatal("85% must trigger an 85% threshold") | |
| 60 | - | } | |
| 61 | - | if shouldAutoCompact(100, 100, 0) { | |
| 62 | - | t.Fatal("off must disable percentage-triggered compaction") | |
| 63 | - | } | |
| 64 | - | } | |
| 65 | - | ``` | |
| 66 | - | ||
| 67 | - | - [ ] **Step 2: Run tests and verify RED** | |
| 68 | - | ||
| 69 | - | Run: | |
| 70 | - | ||
| 71 | - | ```sh | |
| 72 | - | go test ./packages/agent/modes -run 'TestNormalizeAutoCompactThreshold|TestShouldAutoCompactUsesConfiguredThreshold' -count=1 | |
| 73 | - | ``` | |
| 74 | - | ||
| 75 | - | Expected: compilation failure because the normalization and decision helpers do not exist. | |
| 76 | - | ||
| 77 | - | - [ ] **Step 3: Add optional configuration and minimal helpers** | |
| 78 | - | ||
| 79 | - | Add `AutoCompactThreshold *int` with JSON name `auto_compact_threshold` to both configuration structs. Implement normalization for exactly `0`, `70`, `80`, `85`, and `90`, defaulting all other values to `85`. Replace the hard-coded fraction check with the normalized percentage helper and pass the config field through `cli.go`. | |
| 80 | - | ||
| 81 | - | - [ ] **Step 4: Run focused tests and verify GREEN** | |
| 82 | - | ||
| 83 | - | Run: | |
| 84 | - | ||
| 85 | - | ```sh | |
| 86 | - | go test ./packages/agent/modes -run 'TestNormalizeAutoCompactThreshold|TestShouldAutoCompactUsesConfiguredThreshold' -count=1 | |
| 87 | - | ``` | |
| 88 | - | ||
| 89 | - | Expected: PASS. | |
| 90 | - | ||
| 91 | - | ### Task 2: Persistence and TUI preset picker | |
| 92 | - | ||
| 93 | - | **Files:** | |
| 94 | - | - Modify: `packages/agent/settings_store.go` | |
| 95 | - | - Modify: `packages/agent/settings_store_test.go` | |
| 96 | - | - Modify: `packages/agent/modes/interactive.go` | |
| 97 | - | - Modify: `packages/agent/modes/auto_compact_test.go` | |
| 98 | - | ||
| 99 | - | **Interfaces:** | |
| 100 | - | - Extends: `SettingsStore.SetAutoCompactThreshold(percent int) error` | |
| 101 | - | - Consumes: `normalizeAutoCompactThreshold(*int) int` | |
| 102 | - | ||
| 103 | - | - [ ] **Step 1: Write failing persistence and settings-item tests** | |
| 104 | - | ||
| 105 | - | Add a settings-store test that writes `70` into an isolated `$ZOT_HOME` and verifies `auto_compact_threshold` plus an unrelated config field. Add a modes test that opens settings with missing configuration and verifies the option values are `0`, `70`, `80`, `85`, `90` with `85` selected. | |
| 106 | - | ||
| 107 | - | ```go | |
| 108 | - | func TestConfigSettingsStorePersistsAutoCompactThreshold(t *testing.T) { | |
| 109 | - | t.Setenv("ZOT_HOME", t.TempDir()) | |
| 110 | - | if err := SaveConfig(Config{Theme: "dark"}); err != nil { | |
| 111 | - | t.Fatal(err) | |
| 112 | - | } | |
| 113 | - | if err := (configSettingsStore{}).SetAutoCompactThreshold(70); err != nil { | |
| 114 | - | t.Fatal(err) | |
| 115 | - | } | |
| 116 | - | cfg, err := LoadConfig() | |
| 117 | - | if err != nil { | |
| 118 | - | t.Fatal(err) | |
| 119 | - | } | |
| 120 | - | if cfg.AutoCompactThreshold == nil || *cfg.AutoCompactThreshold != 70 { | |
| 121 | - | t.Fatalf("auto_compact_threshold = %v, want 70", cfg.AutoCompactThreshold) | |
| 122 | - | } | |
| 123 | - | if cfg.Theme != "dark" { | |
| 124 | - | t.Fatalf("unrelated config changed: theme = %q, want dark", cfg.Theme) | |
| 125 | - | } | |
| 126 | - | } | |
| 127 | - | ``` | |
| 128 | - | ||
| 129 | - | - [ ] **Step 2: Run tests and verify RED** | |
| 130 | - | ||
| 131 | - | Run: | |
| 132 | - | ||
| 133 | - | ```sh | |
| 134 | - | go test ./packages/agent ./packages/agent/modes -run 'AutoCompactThreshold|SettingsDialog.*AutoCompact' -count=1 | |
| 135 | - | ``` | |
| 136 | - | ||
| 137 | - | Expected: compilation or assertion failure because persistence and the picker row do not exist. | |
| 138 | - | ||
| 139 | - | - [ ] **Step 3: Implement persistence and live setting application** | |
| 140 | - | ||
| 141 | - | Add the settings-store method, fixed picker options, choice resolution, action routing, integer parsing, live `InteractiveConfig` update, and status message. Persist only values exposed by the picker; normalize the live value defensively before use. | |
| 142 | - | ||
| 143 | - | - [ ] **Step 4: Run focused tests and verify GREEN** | |
| 144 | - | ||
| 145 | - | Run: | |
| 146 | - | ||
| 147 | - | ```sh | |
| 148 | - | go test ./packages/agent ./packages/agent/modes -run 'AutoCompactThreshold|SettingsDialog.*AutoCompact' -count=1 | |
| 149 | - | ``` | |
| 150 | - | ||
| 151 | - | Expected: PASS. | |
| 152 | - | ||
| 153 | - | ### Task 3: Documentation and full verification | |
| 154 | - | ||
| 155 | - | **Files:** | |
| 156 | - | - Modify: `README.md` | |
| 157 | - | - Review: `docs/superpowers/specs/2026-07-28-configurable-auto-compact-threshold-design.md` | |
| 158 | - | - Review: `docs/superpowers/plans/2026-07-28-configurable-auto-compact-threshold.md` | |
| 159 | - | ||
| 160 | - | **Interfaces:** | |
| 161 | - | - Documents: `auto_compact_threshold` | |
| 162 | - | - Documents: `/settings` presets and `off` semantics | |
| 163 | - | ||
| 164 | - | - [ ] **Step 1: Update user documentation** | |
| 165 | - | ||
| 166 | - | Document `off`, `70%`, `80%`, `85%` default, and `90%` in the `/settings` section. Update `/compact` to state that threshold-based auto-compaction is configurable and that payload-too-large recovery remains active when the percentage trigger is off. | |
| 167 | - | ||
| 168 | - | - [ ] **Step 2: Format changed Go files** | |
| 169 | - | ||
| 170 | - | Run: | |
| 171 | - | ||
| 172 | - | ```sh | |
| 173 | - | gofmt -w packages/agent/config.go packages/agent/settings_store.go packages/agent/settings_store_test.go packages/agent/cli.go packages/agent/modes/interactive.go packages/agent/modes/auto_compact_test.go | |
| 174 | - | ``` | |
| 175 | - | ||
| 176 | - | - [ ] **Step 3: Run the complete test suite** | |
| 177 | - | ||
| 178 | - | Run: | |
| 179 | - | ||
| 180 | - | ```sh | |
| 181 | - | go test ./... | |
| 182 | - | ``` | |
| 183 | - | ||
| 184 | - | Expected: PASS. | |
| 185 | - | ||
| 186 | - | - [ ] **Step 4: Run static analysis** | |
| 187 | - | ||
| 188 | - | Run: | |
| 189 | - | ||
| 190 | - | ```sh | |
| 191 | - | go vet ./... | |
| 192 | - | ``` | |
| 193 | - | ||
| 194 | - | Expected: PASS. | |
| 195 | - | ||
| 196 | - | - [ ] **Step 5: Inspect the final change** | |
| 197 | - | ||
| 198 | - | Run: | |
| 199 | - | ||
| 200 | - | ```sh | |
| 201 | - | git diff --check | |
| 202 | - | git status --short | |
| 203 | - | git diff | |
| 204 | - | ``` | |
| 205 | - | ||
| 206 | - | Confirm only the configuration, TUI, tests, README, design, and plan belong to the feature. | |
| 207 | - | ||
| 208 | - | ### Task 4: Publish the pull request | |
| 209 | - | ||
| 210 | - | **Files:** | |
| 211 | - | - Stage only the files listed in Tasks 1-3. | |
| 212 | - | ||
| 213 | - | **Interfaces:** | |
| 214 | - | - Produces: branch `codex/configurable-auto-compact-threshold` | |
| 215 | - | - Produces: one feature commit and a ready GitHub pull request | |
| 216 | - | ||
| 217 | - | - [ ] **Step 1: Create the feature branch** | |
| 218 | - | ||
| 219 | - | ```sh | |
| 220 | - | git switch -c codex/configurable-auto-compact-threshold | |
| 221 | - | ``` | |
| 222 | - | ||
| 223 | - | - [ ] **Step 2: Stage explicit feature paths and review** | |
| 224 | - | ||
| 225 | - | Stage only the implementation, tests, README, design, and plan. Review `git diff --cached --check` and `git diff --cached`. | |
| 226 | - | ||
| 227 | - | - [ ] **Step 3: Commit** | |
| 228 | - | ||
| 229 | - | ```sh | |
| 230 | - | git commit -m "Make auto-compact threshold configurable" | |
| 231 | - | ``` | |
| 232 | - | ||
| 233 | - | - [ ] **Step 4: Push the branch** | |
| 234 | - | ||
| 235 | - | Push to the appropriate writable GitHub remote with upstream tracking. | |
| 236 | - | ||
| 237 | - | - [ ] **Step 5: Open a ready pull request** | |
| 238 | - | ||
| 239 | - | Target the upstream default branch. Include the behavior, compatibility, user impact, and exact validation commands in the PR body. | |
| @@ -1,239 +0,0 @@ | |||||
| 1 | - | # Configurable Auto-Compact Threshold Implementation Plan | |||
| 2 | - | ||||
| 3 | - | > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. | |||
| 4 | - | ||||
| 5 | - | **Goal:** Add persisted auto-compaction threshold presets to the interactive TUI settings. | |||
| 6 | - | ||||
| 7 | - | **Architecture:** Keep automatic triggering in `packages/agent/modes`. Thread an optional integer percentage from persisted `agent.Config` into `modes.InteractiveConfig`, normalize missing or invalid values to 85%, and let zero disable only percentage-based triggers. Reuse the settings dialog's existing fixed-option picker and settings-store persistence path. | |||
| 8 | - | ||||
| 9 | - | **Tech Stack:** Go, standard library, Zot's existing TUI settings dialog, JSON configuration. | |||
| 10 | - | ||||
| 11 | - | ## Global Constraints | |||
| 12 | - | ||||
| 13 | - | - Supported values are `0` (off), `70`, `80`, `85`, and `90`. | |||
| 14 | - | - Missing or invalid persisted values resolve to `85`. | |||
| 15 | - | - Disabling the threshold does not disable manual compaction or HTTP 413 recovery. | |||
| 16 | - | - Do not add dependencies or change non-interactive compaction behavior. | |||
| 17 | - | - Preserve unrelated working-tree changes and stage only this feature. | |||
| 18 | - | ||||
| 19 | - | --- | |||
| 20 | - | ||||
| 21 | - | ### Task 1: Configuration and threshold decision | |||
| 22 | - | ||||
| 23 | - | **Files:** | |||
| 24 | - | - Modify: `packages/agent/config.go` | |||
| 25 | - | - Modify: `packages/agent/modes/interactive.go` | |||
| 26 | - | - Create: `packages/agent/modes/auto_compact_test.go` | |||
| 27 | - | - Modify: `packages/agent/cli.go` | |||
| 28 | - | ||||
| 29 | - | **Interfaces:** | |||
| 30 | - | - Produces: `Config.AutoCompactThreshold *int` | |||
| 31 | - | - Produces: `InteractiveConfig.AutoCompactThreshold *int` | |||
| 32 | - | - Produces: `normalizeAutoCompactThreshold(*int) int` | |||
| 33 | - | - Produces: `shouldAutoCompact(inputTokens, contextWindow, thresholdPercent int) bool` | |||
| 34 | - | ||||
| 35 | - | - [ ] **Step 1: Write failing normalization and decision tests** | |||
| 36 | - | ||||
| 37 | - | Add table-driven tests proving nil and invalid values resolve to 85, supported presets survive unchanged, zero disables percentage checks, and 70/80/85/90 trigger exactly at their boundaries. | |||
| 38 | - | ||||
| 39 | - | ```go | |||
| 40 | - | func TestNormalizeAutoCompactThreshold(t *testing.T) { | |||
| 41 | - | tests := []struct { | |||
| 42 | - | name string | |||
| 43 | - | value *int | |||
| 44 | - | want int | |||
| 45 | - | }{ | |||
| 46 | - | {name: "missing", value: nil, want: 85}, | |||
| 47 | - | {name: "off", value: intPtr(0), want: 0}, | |||
| 48 | - | {name: "seventy", value: intPtr(70), want: 70}, | |||
| 49 | - | {name: "invalid", value: intPtr(42), want: 85}, | |||
| 50 | - | } | |||
| 51 | - | // Assert normalizeAutoCompactThreshold(test.value) == test.want. | |||
| 52 | - | } | |||
| 53 | - | ||||
| 54 | - | func TestShouldAutoCompactUsesConfiguredThreshold(t *testing.T) { | |||
| 55 | - | if shouldAutoCompact(84, 100, 85) { | |||
| 56 | - | t.Fatal("84% must remain below an 85% threshold") | |||
| 57 | - | } | |||
| 58 | - | if !shouldAutoCompact(85, 100, 85) { | |||
| 59 | - | t.Fatal("85% must trigger an 85% threshold") | |||
| 60 | - | } | |||
| 61 | - | if shouldAutoCompact(100, 100, 0) { | |||
| 62 | - | t.Fatal("off must disable percentage-triggered compaction") | |||
| 63 | - | } | |||
| 64 | - | } | |||
| 65 | - | ``` | |||
| 66 | - | ||||
| 67 | - | - [ ] **Step 2: Run tests and verify RED** | |||
| 68 | - | ||||
| 69 | - | Run: | |||
| 70 | - | ||||
| 71 | - | ```sh | |||
| 72 | - | go test ./packages/agent/modes -run 'TestNormalizeAutoCompactThreshold|TestShouldAutoCompactUsesConfiguredThreshold' -count=1 | |||
| 73 | - | ``` | |||
| 74 | - | ||||
| 75 | - | Expected: compilation failure because the normalization and decision helpers do not exist. | |||
| 76 | - | ||||
| 77 | - | - [ ] **Step 3: Add optional configuration and minimal helpers** | |||
| 78 | - | ||||
| 79 | - | Add `AutoCompactThreshold *int` with JSON name `auto_compact_threshold` to both configuration structs. Implement normalization for exactly `0`, `70`, `80`, `85`, and `90`, defaulting all other values to `85`. Replace the hard-coded fraction check with the normalized percentage helper and pass the config field through `cli.go`. | |||
| 80 | - | ||||
| 81 | - | - [ ] **Step 4: Run focused tests and verify GREEN** | |||
| 82 | - | ||||
| 83 | - | Run: | |||
| 84 | - | ||||
| 85 | - | ```sh | |||
| 86 | - | go test ./packages/agent/modes -run 'TestNormalizeAutoCompactThreshold|TestShouldAutoCompactUsesConfiguredThreshold' -count=1 | |||
| 87 | - | ``` | |||
| 88 | - | ||||
| 89 | - | Expected: PASS. | |||
| 90 | - | ||||
| 91 | - | ### Task 2: Persistence and TUI preset picker | |||
| 92 | - | ||||
| 93 | - | **Files:** | |||
| 94 | - | - Modify: `packages/agent/settings_store.go` | |||
| 95 | - | - Modify: `packages/agent/settings_store_test.go` | |||
| 96 | - | - Modify: `packages/agent/modes/interactive.go` | |||
| 97 | - | - Modify: `packages/agent/modes/auto_compact_test.go` | |||
| 98 | - | ||||
| 99 | - | **Interfaces:** | |||
| 100 | - | - Extends: `SettingsStore.SetAutoCompactThreshold(percent int) error` | |||
| 101 | - | - Consumes: `normalizeAutoCompactThreshold(*int) int` | |||
| 102 | - | ||||
| 103 | - | - [ ] **Step 1: Write failing persistence and settings-item tests** | |||
| 104 | - | ||||
| 105 | - | Add a settings-store test that writes `70` into an isolated `$ZOT_HOME` and verifies `auto_compact_threshold` plus an unrelated config field. Add a modes test that opens settings with missing configuration and verifies the option values are `0`, `70`, `80`, `85`, `90` with `85` selected. | |||
| 106 | - | ||||
| 107 | - | ```go | |||
| 108 | - | func TestConfigSettingsStorePersistsAutoCompactThreshold(t *testing.T) { | |||
| 109 | - | t.Setenv("ZOT_HOME", t.TempDir()) | |||
| 110 | - | if err := SaveConfig(Config{Theme: "dark"}); err != nil { | |||
| 111 | - | t.Fatal(err) | |||
| 112 | - | } | |||
| 113 | - | if err := (configSettingsStore{}).SetAutoCompactThreshold(70); err != nil { | |||
| 114 | - | t.Fatal(err) | |||
| 115 | - | } | |||
| 116 | - | cfg, err := LoadConfig() | |||
| 117 | - | if err != nil { | |||
| 118 | - | t.Fatal(err) | |||
| 119 | - | } | |||
| 120 | - | if cfg.AutoCompactThreshold == nil || *cfg.AutoCompactThreshold != 70 { | |||
| 121 | - | t.Fatalf("auto_compact_threshold = %v, want 70", cfg.AutoCompactThreshold) | |||
| 122 | - | } | |||
| 123 | - | if cfg.Theme != "dark" { | |||
| 124 | - | t.Fatalf("unrelated config changed: theme = %q, want dark", cfg.Theme) | |||
| 125 | - | } | |||
| 126 | - | } | |||
| 127 | - | ``` | |||
| 128 | - | ||||
| 129 | - | - [ ] **Step 2: Run tests and verify RED** | |||
| 130 | - | ||||
| 131 | - | Run: | |||
| 132 | - | ||||
| 133 | - | ```sh | |||
| 134 | - | go test ./packages/agent ./packages/agent/modes -run 'AutoCompactThreshold|SettingsDialog.*AutoCompact' -count=1 | |||
| 135 | - | ``` | |||
| 136 | - | ||||
| 137 | - | Expected: compilation or assertion failure because persistence and the picker row do not exist. | |||
| 138 | - | ||||
| 139 | - | - [ ] **Step 3: Implement persistence and live setting application** | |||
| 140 | - | ||||
| 141 | - | Add the settings-store method, fixed picker options, choice resolution, action routing, integer parsing, live `InteractiveConfig` update, and status message. Persist only values exposed by the picker; normalize the live value defensively before use. | |||
| 142 | - | ||||
| 143 | - | - [ ] **Step 4: Run focused tests and verify GREEN** | |||
| 144 | - | ||||
| 145 | - | Run: | |||
| 146 | - | ||||
| 147 | - | ```sh | |||
| 148 | - | go test ./packages/agent ./packages/agent/modes -run 'AutoCompactThreshold|SettingsDialog.*AutoCompact' -count=1 | |||
| 149 | - | ``` | |||
| 150 | - | ||||
| 151 | - | Expected: PASS. | |||
| 152 | - | ||||
| 153 | - | ### Task 3: Documentation and full verification | |||
| 154 | - | ||||
| 155 | - | **Files:** | |||
| 156 | - | - Modify: `README.md` | |||
| 157 | - | - Review: `docs/superpowers/specs/2026-07-28-configurable-auto-compact-threshold-design.md` | |||
| 158 | - | - Review: `docs/superpowers/plans/2026-07-28-configurable-auto-compact-threshold.md` | |||
| 159 | - | ||||
| 160 | - | **Interfaces:** | |||
| 161 | - | - Documents: `auto_compact_threshold` | |||
| 162 | - | - Documents: `/settings` presets and `off` semantics | |||
| 163 | - | ||||
| 164 | - | - [ ] **Step 1: Update user documentation** | |||
| 165 | - | ||||
| 166 | - | Document `off`, `70%`, `80%`, `85%` default, and `90%` in the `/settings` section. Update `/compact` to state that threshold-based auto-compaction is configurable and that payload-too-large recovery remains active when the percentage trigger is off. | |||
| 167 | - | ||||
| 168 | - | - [ ] **Step 2: Format changed Go files** | |||
| 169 | - | ||||
| 170 | - | Run: | |||
| 171 | - | ||||
| 172 | - | ```sh | |||
| 173 | - | gofmt -w packages/agent/config.go packages/agent/settings_store.go packages/agent/settings_store_test.go packages/agent/cli.go packages/agent/modes/interactive.go packages/agent/modes/auto_compact_test.go | |||
| 174 | - | ``` | |||
| 175 | - | ||||
| 176 | - | - [ ] **Step 3: Run the complete test suite** | |||
| 177 | - | ||||
| 178 | - | Run: | |||
| 179 | - | ||||
| 180 | - | ```sh | |||
| 181 | - | go test ./... | |||
| 182 | - | ``` | |||
| 183 | - | ||||
| 184 | - | Expected: PASS. | |||
| 185 | - | ||||
| 186 | - | - [ ] **Step 4: Run static analysis** | |||
| 187 | - | ||||
| 188 | - | Run: | |||
| 189 | - | ||||
| 190 | - | ```sh | |||
| 191 | - | go vet ./... | |||
| 192 | - | ``` | |||
| 193 | - | ||||
| 194 | - | Expected: PASS. | |||
| 195 | - | ||||
| 196 | - | - [ ] **Step 5: Inspect the final change** | |||
| 197 | - | ||||
| 198 | - | Run: | |||
| 199 | - | ||||
| 200 | - | ```sh | |||
| 201 | - | git diff --check | |||
| 202 | - | git status --short | |||
| 203 | - | git diff | |||
| 204 | - | ``` | |||
| 205 | - | ||||
| 206 | - | Confirm only the configuration, TUI, tests, README, design, and plan belong to the feature. | |||
| 207 | - | ||||
| 208 | - | ### Task 4: Publish the pull request | |||
| 209 | - | ||||
| 210 | - | **Files:** | |||
| 211 | - | - Stage only the files listed in Tasks 1-3. | |||
| 212 | - | ||||
| 213 | - | **Interfaces:** | |||
| 214 | - | - Produces: branch `codex/configurable-auto-compact-threshold` | |||
| 215 | - | - Produces: one feature commit and a ready GitHub pull request | |||
| 216 | - | ||||
| 217 | - | - [ ] **Step 1: Create the feature branch** | |||
| 218 | - | ||||
| 219 | - | ```sh | |||
| 220 | - | git switch -c codex/configurable-auto-compact-threshold | |||
| 221 | - | ``` | |||
| 222 | - | ||||
| 223 | - | - [ ] **Step 2: Stage explicit feature paths and review** | |||
| 224 | - | ||||
| 225 | - | Stage only the implementation, tests, README, design, and plan. Review `git diff --cached --check` and `git diff --cached`. | |||
| 226 | - | ||||
| 227 | - | - [ ] **Step 3: Commit** | |||
| 228 | - | ||||
| 229 | - | ```sh | |||
| 230 | - | git commit -m "Make auto-compact threshold configurable" | |||
| 231 | - | ``` | |||
| 232 | - | ||||
| 233 | - | - [ ] **Step 4: Push the branch** | |||
| 234 | - | ||||
| 235 | - | Push to the appropriate writable GitHub remote with upstream tracking. | |||
| 236 | - | ||||
| 237 | - | - [ ] **Step 5: Open a ready pull request** | |||
| 238 | - | ||||
| 239 | - | Target the upstream default branch. Include the behavior, compatibility, user impact, and exact validation commands in the PR body. | |||
D docs/superpowers/specs/2026-07-28-configurable-auto-compact-threshold-design.md +0 -73
| @@ -1,73 +0,0 @@ | |||
| 1 | - | # Configurable Auto-Compact Threshold | |
| 2 | - | ||
| 3 | - | ## Goal | |
| 4 | - | ||
| 5 | - | Let users choose when Zot automatically compacts an interactive transcript from the existing `/settings` dialog, while preserving the current 85% behavior by default. | |
| 6 | - | ||
| 7 | - | ## User Experience | |
| 8 | - | ||
| 9 | - | Add a top-level `/settings` option named **auto-compact threshold** with these choices: | |
| 10 | - | ||
| 11 | - | - `off` | |
| 12 | - | - `70%` | |
| 13 | - | - `80%` | |
| 14 | - | - `85%` (default) | |
| 15 | - | - `90%` | |
| 16 | - | ||
| 17 | - | Changing the option takes effect for the next turn without restarting Zot. | |
| 18 | - | ||
| 19 | - | The `off` choice disables context-percentage triggers before and after turns. It does not disable: | |
| 20 | - | ||
| 21 | - | - manual `/compact` | |
| 22 | - | - explicit RPC or SDK compaction | |
| 23 | - | - automatic compaction and retry after an HTTP 413 or equivalent payload-too-large response | |
| 24 | - | ||
| 25 | - | ## Configuration | |
| 26 | - | ||
| 27 | - | Persist the selected percentage in `$ZOT_HOME/config.json` as: | |
| 28 | - | ||
| 29 | - | ```json | |
| 30 | - | { | |
| 31 | - | "auto_compact_threshold": 85 | |
| 32 | - | } | |
| 33 | - | ``` | |
| 34 | - | ||
| 35 | - | The field is an optional integer percentage: | |
| 36 | - | ||
| 37 | - | - A missing field resolves to `85` for backward compatibility. | |
| 38 | - | - `0` represents `off`. | |
| 39 | - | - Valid non-zero values are `70`, `80`, `85`, and `90`. | |
| 40 | - | - Any other persisted value resolves to `85` at runtime. | |
| 41 | - | - When a user selects a setting in the TUI, Zot writes only one of the supported values. | |
| 42 | - | ||
| 43 | - | ## Implementation Boundaries | |
| 44 | - | ||
| 45 | - | The interactive host continues to own automatic triggering. `core.Agent.Compact`, RPC, SDK, bot, print, and JSON mode behavior remain unchanged. | |
| 46 | - | ||
| 47 | - | Replace the hard-coded `0.85` comparison with a helper that resolves the configured integer percentage and compares the most recent context usage against the model's advertised context window. A resolved value of `0` returns false for percentage-based checks. | |
| 48 | - | ||
| 49 | - | The payload-too-large recovery path continues to invoke automatic compaction independently of the configured percentage. | |
| 50 | - | ||
| 51 | - | The settings dialog uses its existing fixed-option picker. No free-form numeric input or new dialog control is introduced. | |
| 52 | - | ||
| 53 | - | ## Error Handling | |
| 54 | - | ||
| 55 | - | Configuration writes use the existing settings-store error path and show failures in the TUI status area. An invalid value already present in `config.json` does not prevent startup; Zot falls back to 85%. | |
| 56 | - | ||
| 57 | - | ## Tests | |
| 58 | - | ||
| 59 | - | Add focused tests covering: | |
| 60 | - | ||
| 61 | - | - missing configuration resolves to 85% | |
| 62 | - | - every supported preset resolves correctly | |
| 63 | - | - invalid persisted values resolve to 85% | |
| 64 | - | - `off` suppresses percentage-triggered compaction | |
| 65 | - | - threshold comparison uses the selected percentage | |
| 66 | - | - the settings store persists the selected integer | |
| 67 | - | - the settings dialog exposes all presets with 85% selected by default | |
| 68 | - | ||
| 69 | - | Run the focused package tests during development, then `gofmt`, `go test ./...`, `go vet ./...`, `git diff --check`, and final status/diff inspection. | |
| 70 | - | ||
| 71 | - | ## Documentation | |
| 72 | - | ||
| 73 | - | Update the README sections for `/settings` and `/compact` to list the presets, default, immediate application, and the fact that `off` does not disable payload-too-large recovery. | |
| @@ -1,73 +0,0 @@ | |||||
| 1 | - | # Configurable Auto-Compact Threshold | |||
| 2 | - | ||||
| 3 | - | ## Goal | |||
| 4 | - | ||||
| 5 | - | Let users choose when Zot automatically compacts an interactive transcript from the existing `/settings` dialog, while preserving the current 85% behavior by default. | |||
| 6 | - | ||||
| 7 | - | ## User Experience | |||
| 8 | - | ||||
| 9 | - | Add a top-level `/settings` option named **auto-compact threshold** with these choices: | |||
| 10 | - | ||||
| 11 | - | - `off` | |||
| 12 | - | - `70%` | |||
| 13 | - | - `80%` | |||
| 14 | - | - `85%` (default) | |||
| 15 | - | - `90%` | |||
| 16 | - | ||||
| 17 | - | Changing the option takes effect for the next turn without restarting Zot. | |||
| 18 | - | ||||
| 19 | - | The `off` choice disables context-percentage triggers before and after turns. It does not disable: | |||
| 20 | - | ||||
| 21 | - | - manual `/compact` | |||
| 22 | - | - explicit RPC or SDK compaction | |||
| 23 | - | - automatic compaction and retry after an HTTP 413 or equivalent payload-too-large response | |||
| 24 | - | ||||
| 25 | - | ## Configuration | |||
| 26 | - | ||||
| 27 | - | Persist the selected percentage in `$ZOT_HOME/config.json` as: | |||
| 28 | - | ||||
| 29 | - | ```json | |||
| 30 | - | { | |||
| 31 | - | "auto_compact_threshold": 85 | |||
| 32 | - | } | |||
| 33 | - | ``` | |||
| 34 | - | ||||
| 35 | - | The field is an optional integer percentage: | |||
| 36 | - | ||||
| 37 | - | - A missing field resolves to `85` for backward compatibility. | |||
| 38 | - | - `0` represents `off`. | |||
| 39 | - | - Valid non-zero values are `70`, `80`, `85`, and `90`. | |||
| 40 | - | - Any other persisted value resolves to `85` at runtime. | |||
| 41 | - | - When a user selects a setting in the TUI, Zot writes only one of the supported values. | |||
| 42 | - | ||||
| 43 | - | ## Implementation Boundaries | |||
| 44 | - | ||||
| 45 | - | The interactive host continues to own automatic triggering. `core.Agent.Compact`, RPC, SDK, bot, print, and JSON mode behavior remain unchanged. | |||
| 46 | - | ||||
| 47 | - | Replace the hard-coded `0.85` comparison with a helper that resolves the configured integer percentage and compares the most recent context usage against the model's advertised context window. A resolved value of `0` returns false for percentage-based checks. | |||
| 48 | - | ||||
| 49 | - | The payload-too-large recovery path continues to invoke automatic compaction independently of the configured percentage. | |||
| 50 | - | ||||
| 51 | - | The settings dialog uses its existing fixed-option picker. No free-form numeric input or new dialog control is introduced. | |||
| 52 | - | ||||
| 53 | - | ## Error Handling | |||
| 54 | - | ||||
| 55 | - | Configuration writes use the existing settings-store error path and show failures in the TUI status area. An invalid value already present in `config.json` does not prevent startup; Zot falls back to 85%. | |||
| 56 | - | ||||
| 57 | - | ## Tests | |||
| 58 | - | ||||
| 59 | - | Add focused tests covering: | |||
| 60 | - | ||||
| 61 | - | - missing configuration resolves to 85% | |||
| 62 | - | - every supported preset resolves correctly | |||
| 63 | - | - invalid persisted values resolve to 85% | |||
| 64 | - | - `off` suppresses percentage-triggered compaction | |||
| 65 | - | - threshold comparison uses the selected percentage | |||
| 66 | - | - the settings store persists the selected integer | |||
| 67 | - | - the settings dialog exposes all presets with 85% selected by default | |||
| 68 | - | ||||
| 69 | - | Run the focused package tests during development, then `gofmt`, `go test ./...`, `go vet ./...`, `git diff --check`, and final status/diff inspection. | |||
| 70 | - | ||||
| 71 | - | ## Documentation | |||
| 72 | - | ||||
| 73 | - | Update the README sections for `/settings` and `/compact` to list the presets, default, immediate application, and the fact that `off` does not disable payload-too-large recovery. | |||
D docs/superpowers/specs/2026-08-04-terminal-alerts-design.md +0 -77
| @@ -1,77 +0,0 @@ | |||
| 1 | - | # Terminal Alerts and Extension Bells | |
| 2 | - | ||
| 3 | - | ## Goal | |
| 4 | - | ||
| 5 | - | Provide a reusable host alert boundary for the interactive terminal. The first alert kind is a terminal bell, emitted as `\a` only by the interactive host. | |
| 6 | - | ||
| 7 | - | The same alert policy serves the main agent session and trusted, user-installed extensions that need to draw attention to an interactive question or panel. | |
| 8 | - | ||
| 9 | - | ## User Experience | |
| 10 | - | ||
| 11 | - | The main interactive session emits one bell after a submitted main-agent run becomes idle and the paced final response has finished rendering when the outcome needs attention: | |
| 12 | - | ||
| 13 | - | - normal final answer | |
| 14 | - | - output-limit/truncated response | |
| 15 | - | - non-recoverable provider error | |
| 16 | - | - rescue dialog opened after a recoverable provider error | |
| 17 | - | ||
| 18 | - | The bell is suppressed for explicit cancellation, automatic compaction/retry, and work immediately followed by another queued turn. `/btw`, Telegram, SDK, JSON, print, stream, RPC, and swarm-agent modes do not write raw terminal bell bytes. | |
| 19 | - | ||
| 20 | - | Users can disable both main-agent and extension terminal alerts from `/settings`. Alerts are enabled by default when the configuration field is missing. | |
| 21 | - | ||
| 22 | - | ## Public Extension Surface | |
| 23 | - | ||
| 24 | - | Extensions send a fire-and-forget structured alert frame: | |
| 25 | - | ||
| 26 | - | ```json | |
| 27 | - | {"type":"alert","kind":"bell","reason":"question_ready"} | |
| 28 | - | ``` | |
| 29 | - | ||
| 30 | - | The Go extension SDK exposes the equivalent `Extension.Alert(AlertRequest)` method. The host-side alert hook is optional so existing `HostHooks` embedders remain compatible. `kind` is initially `bell`; `reason` is semantic metadata and is not rendered as terminal text. Extensions never provide raw terminal bytes, ANSI sequences, counts, or sound patterns. | |
| 31 | - | ||
| 32 | - | The host owns the output policy. Interactive mode writes a standalone BEL byte through its injected `tui.Terminal`; non-interactive hosts remain byte-clean and may ignore or translate the request. | |
| 33 | - | ||
| 34 | - | ## Configuration | |
| 35 | - | ||
| 36 | - | Persist the shared policy in `$ZOT_HOME/config.json`: | |
| 37 | - | ||
| 38 | - | ```json | |
| 39 | - | {"terminal_alerts_enabled": true} | |
| 40 | - | ``` | |
| 41 | - | ||
| 42 | - | The optional boolean resolves as follows: | |
| 43 | - | ||
| 44 | - | - missing or `null`: enabled | |
| 45 | - | - `true`: enabled | |
| 46 | - | - `false`: disabled | |
| 47 | - | ||
| 48 | - | The setting applies immediately to the current interactive session and persists for future sessions. | |
| 49 | - | ||
| 50 | - | ## Lifecycle Boundary | |
| 51 | - | ||
| 52 | - | The main-agent alert is scheduled from the interactive `startTurnRequest` completion path, not from `core.Agent` events. `EvTurnEnd` is one model step and `EvDone` is not emitted on every error path. The final outcome is tracked from both the last turn event and the returned `Prompt`/`Continue` error. | |
| 53 | - | ||
| 54 | - | A pending main-agent alert waits for the streaming pacer to drain `streamPending`. If a new queued/recovery turn begins before the drain completes, the pending alert is discarded. The bell is emitted only after the host is truly idle. | |
| 55 | - | ||
| 56 | - | ## Extension Routing | |
| 57 | - | ||
| 58 | - | `packages/agent/extproto` defines the alert wire frame. `packages/agent/extensions` routes it through the optional `AlertHostHooks` extension to `HostHooks`. Interactive mode applies the shared setting and terminal output. RPC mode translates extension alerts into an `ext_alert` JSON event; print, stream, JSON, Telegram, and other non-interactive hosts do not write BEL to their data streams. | |
| 59 | - | ||
| 60 | - | Unknown alert kinds are ignored by the interactive renderer. The wire shape is additive and permits future host alert kinds without exposing terminal implementation details. | |
| 61 | - | ||
| 62 | - | ## Tests | |
| 63 | - | ||
| 64 | - | Cover: | |
| 65 | - | ||
| 66 | - | - BEL writes as a standalone byte through an injected writer | |
| 67 | - | - extension SDK emits the structured alert frame | |
| 68 | - | - extension manager routes alert frames to host hooks | |
| 69 | - | - disabled terminal alerts suppress both main and extension alerts | |
| 70 | - | - missing configuration enables alerts | |
| 71 | - | - main completion alerts wait for paced output to drain | |
| 72 | - | - cancellation, recovery, queue, and side-chat paths do not produce an unwanted main bell | |
| 73 | - | - RPC alert translation does not emit raw BEL | |
| 74 | - | ||
| 75 | - | ## Documentation | |
| 76 | - | ||
| 77 | - | Document the `/settings` terminal-alert toggle and the extension alert frame/SDK method in `README.md` and `docs/extensions.md`. State that terminal bells depend on terminal emulator settings and may be audible, visual, or suppressed by the host terminal. | |
| @@ -1,77 +0,0 @@ | |||||
| 1 | - | # Terminal Alerts and Extension Bells | |||
| 2 | - | ||||
| 3 | - | ## Goal | |||
| 4 | - | ||||
| 5 | - | Provide a reusable host alert boundary for the interactive terminal. The first alert kind is a terminal bell, emitted as `\a` only by the interactive host. | |||
| 6 | - | ||||
| 7 | - | The same alert policy serves the main agent session and trusted, user-installed extensions that need to draw attention to an interactive question or panel. | |||
| 8 | - | ||||
| 9 | - | ## User Experience | |||
| 10 | - | ||||
| 11 | - | The main interactive session emits one bell after a submitted main-agent run becomes idle and the paced final response has finished rendering when the outcome needs attention: | |||
| 12 | - | ||||
| 13 | - | - normal final answer | |||
| 14 | - | - output-limit/truncated response | |||
| 15 | - | - non-recoverable provider error | |||
| 16 | - | - rescue dialog opened after a recoverable provider error | |||
| 17 | - | ||||
| 18 | - | The bell is suppressed for explicit cancellation, automatic compaction/retry, and work immediately followed by another queued turn. `/btw`, Telegram, SDK, JSON, print, stream, RPC, and swarm-agent modes do not write raw terminal bell bytes. | |||
| 19 | - | ||||
| 20 | - | Users can disable both main-agent and extension terminal alerts from `/settings`. Alerts are enabled by default when the configuration field is missing. | |||
| 21 | - | ||||
| 22 | - | ## Public Extension Surface | |||
| 23 | - | ||||
| 24 | - | Extensions send a fire-and-forget structured alert frame: | |||
| 25 | - | ||||
| 26 | - | ```json | |||
| 27 | - | {"type":"alert","kind":"bell","reason":"question_ready"} | |||
| 28 | - | ``` | |||
| 29 | - | ||||
| 30 | - | The Go extension SDK exposes the equivalent `Extension.Alert(AlertRequest)` method. The host-side alert hook is optional so existing `HostHooks` embedders remain compatible. `kind` is initially `bell`; `reason` is semantic metadata and is not rendered as terminal text. Extensions never provide raw terminal bytes, ANSI sequences, counts, or sound patterns. | |||
| 31 | - | ||||
| 32 | - | The host owns the output policy. Interactive mode writes a standalone BEL byte through its injected `tui.Terminal`; non-interactive hosts remain byte-clean and may ignore or translate the request. | |||
| 33 | - | ||||
| 34 | - | ## Configuration | |||
| 35 | - | ||||
| 36 | - | Persist the shared policy in `$ZOT_HOME/config.json`: | |||
| 37 | - | ||||
| 38 | - | ```json | |||
| 39 | - | {"terminal_alerts_enabled": true} | |||
| 40 | - | ``` | |||
| 41 | - | ||||
| 42 | - | The optional boolean resolves as follows: | |||
| 43 | - | ||||
| 44 | - | - missing or `null`: enabled | |||
| 45 | - | - `true`: enabled | |||
| 46 | - | - `false`: disabled | |||
| 47 | - | ||||
| 48 | - | The setting applies immediately to the current interactive session and persists for future sessions. | |||
| 49 | - | ||||
| 50 | - | ## Lifecycle Boundary | |||
| 51 | - | ||||
| 52 | - | The main-agent alert is scheduled from the interactive `startTurnRequest` completion path, not from `core.Agent` events. `EvTurnEnd` is one model step and `EvDone` is not emitted on every error path. The final outcome is tracked from both the last turn event and the returned `Prompt`/`Continue` error. | |||
| 53 | - | ||||
| 54 | - | A pending main-agent alert waits for the streaming pacer to drain `streamPending`. If a new queued/recovery turn begins before the drain completes, the pending alert is discarded. The bell is emitted only after the host is truly idle. | |||
| 55 | - | ||||
| 56 | - | ## Extension Routing | |||
| 57 | - | ||||
| 58 | - | `packages/agent/extproto` defines the alert wire frame. `packages/agent/extensions` routes it through the optional `AlertHostHooks` extension to `HostHooks`. Interactive mode applies the shared setting and terminal output. RPC mode translates extension alerts into an `ext_alert` JSON event; print, stream, JSON, Telegram, and other non-interactive hosts do not write BEL to their data streams. | |||
| 59 | - | ||||
| 60 | - | Unknown alert kinds are ignored by the interactive renderer. The wire shape is additive and permits future host alert kinds without exposing terminal implementation details. | |||
| 61 | - | ||||
| 62 | - | ## Tests | |||
| 63 | - | ||||
| 64 | - | Cover: | |||
| 65 | - | ||||
| 66 | - | - BEL writes as a standalone byte through an injected writer | |||
| 67 | - | - extension SDK emits the structured alert frame | |||
| 68 | - | - extension manager routes alert frames to host hooks | |||
| 69 | - | - disabled terminal alerts suppress both main and extension alerts | |||
| 70 | - | - missing configuration enables alerts | |||
| 71 | - | - main completion alerts wait for paced output to drain | |||
| 72 | - | - cancellation, recovery, queue, and side-chat paths do not produce an unwanted main bell | |||
| 73 | - | - RPC alert translation does not emit raw BEL | |||
| 74 | - | ||||
| 75 | - | ## Documentation | |||
| 76 | - | ||||
| 77 | - | Document the `/settings` terminal-alert toggle and the extension alert frame/SDK method in `README.md` and `docs/extensions.md`. State that terminal bells depend on terminal emulator settings and may be audible, visual, or suppressed by the host terminal. | |||