@ketchao/nextup 0.0.0-stage → 0.1.1
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/README.md +153 -2
- package/dist/cli.js +6509 -0
- package/package.json +35 -4
package/README.md
CHANGED
|
@@ -1,3 +1,154 @@
|
|
|
1
|
-
#
|
|
1
|
+
# nextup (placeholder name)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Next-step menu for coding agents. MVP: **Claude Code** and **Codex** (same hook protocol).
|
|
4
|
+
|
|
5
|
+
> The name is a placeholder. The reference screenshot is from a product called "Then", so that name should not be used.
|
|
6
|
+
|
|
7
|
+
After each substantial turn, it shows up to 4 contextual options (with a cost indicator). The user answers by typing the number in the normal Claude Code box.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
◆ What's next? Type a number · +1 2 = several
|
|
11
|
+
cost ▾
|
|
12
|
+
1 Commit changes ★ suggested ■□□ low
|
|
13
|
+
2 Review my changes ■■□ medium
|
|
14
|
+
3 Write tests ■■■ high
|
|
15
|
+
4 Leave it as is □□□ none
|
|
16
|
+
5 Something else (free text)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Try it (5 minutes)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install
|
|
23
|
+
npm test # 103 tests
|
|
24
|
+
npm run preview # see the menu without Claude (iterate the design here)
|
|
25
|
+
npm run preview -- --scenario failed --width 60
|
|
26
|
+
npm run build
|
|
27
|
+
|
|
28
|
+
# in a test repo, from the published package:
|
|
29
|
+
npm install -g @ketchao/nextup
|
|
30
|
+
nextup init --agent codex
|
|
31
|
+
claude # ask for a small change and watch what happens when it finishes
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`init --user` installs the hooks globally; `init --remove` removes them. The first time, it writes a `settings.json.nextup.bak` backup.
|
|
35
|
+
|
|
36
|
+
Try a hook without Claude:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cat fixtures/stop.json | NEXTUP_ALWAYS=1 node dist/cli.js hook stop
|
|
40
|
+
cat fixtures/prompt-submit.json | node dist/cli.js hook prompt-submit
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Try it with Codex (experimental)
|
|
44
|
+
|
|
45
|
+
`hook stop` and `hook prompt-submit` read and write the same JSON format Codex uses, so there is no new adapter: only the registration path changes.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node dist/cli.js init --agent codex # writes .codex/hooks.json (or --user for ~/.codex/hooks.json)
|
|
49
|
+
codex # then type /hooks and approve (trust) the 2 nextup hooks
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Notes:
|
|
53
|
+
- Codex ignores new or changed hooks until you review them with `/hooks`.
|
|
54
|
+
- On native Windows (Codex CLI 0.166.0, cmd) the hooks **do run**. The `systemMessage` shows up as "Hook · ..." with ANSI colors and alignment intact.
|
|
55
|
+
- The transcript reader (`transcript.ts`) is best effort and understands Claude Code and Codex formats. It only reads the current turn (the `UserPromptSubmit` hook marks where it starts). If something looks wrong, turn on `debug` and check `debug.jsonl`: the `stop-signals` entry shows the detected commands and exit codes, plus a summary of the lines read.
|
|
56
|
+
- Codex runs hooks from a background server that **does not inherit your environment variables**: use `~/.nextup/config.json` (below) or start `codex --no-daemon`.
|
|
57
|
+
|
|
58
|
+
## Configuration
|
|
59
|
+
|
|
60
|
+
Environment variables **or** the file `~/.nextup/config.json` (environment variables win):
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"language": "en",
|
|
65
|
+
"suggestions": 4,
|
|
66
|
+
"showCustomOption": true,
|
|
67
|
+
"showTokenEstimation": true,
|
|
68
|
+
"autoSuggest": true,
|
|
69
|
+
"backgroundCheck": true,
|
|
70
|
+
"consumption": "measured",
|
|
71
|
+
"providers": { "claude": true, "codex": true, "opencode": true },
|
|
72
|
+
"debug": false,
|
|
73
|
+
"theme": "default"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`suggestions` is the row cap, including "Leave it as is" (1–4). `showCustomOption` is the "Something else" row. `showTokenEstimation` is the cost column. `autoSuggest: false` stops new menus; a menu already on screen still accepts a number. `backgroundCheck` runs `npm test` (and `npm run lint` if it exists) before building the menu, with a short time cap: if 3 tests fail, the row says "3 tests failed, fix them". `false` turns that off. `consumption` is `measured` (real time: `1.5s`, or `—` if that action has not been measured yet) or `estimated` (low, medium, high, none). `providers` turns an agent off: Codex is recognized by a `.codex` path in the transcript. OpenCode has no adapter yet, so its flag is stored and does not cut anything off. `language` is the menu language when the prompt is not enough to tell (a number, an "ok", or a mix). The default is `en`. An existing `config.json` is not rewritten: switch it with `nextup config set language en`. A prompt that is a sentence in English shows the menu in English; a sentence in Spanish shows it in Spanish. `lang`, `mode`, `color`, `width`, `always`, and `disabled` still work. The environment overrides the file.
|
|
78
|
+
|
|
79
|
+
To view or change it without editing the JSON:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
nextup config
|
|
83
|
+
nextup config set autoSuggest false
|
|
84
|
+
nextup config set providers.codex false
|
|
85
|
+
nextup config set showCustomOption true
|
|
86
|
+
nextup config set suggestions 3
|
|
87
|
+
nextup config set theme blue
|
|
88
|
+
nextup config set language en
|
|
89
|
+
nextup config set consumption estimated
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Switches accept `true`/`false` (also `on`/`off` and `si`/`no`). In the agent box, without leaving Codex and without `nextup` on `PATH`:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
nextup theme blue
|
|
96
|
+
nextup config set consumption estimated
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The change is saved and the agent does not run it. It shows up on the next menu. `color` and `default` paint each row by cost. `blue`, `green`, `amber`, `pink`, `teal`, and `violet` paint the whole menu one color. `mono` leaves it uncolored. `azul`, `ambar`, `rosa`, and `cian` are accepted aliases. `nextup init` creates the file with everything on if it does not exist yet, and does not overwrite one you already have.
|
|
100
|
+
|
|
101
|
+
With `"debug": true`, each hook stores what it received and returned in `~/.nextup/state/debug.jsonl` (paths and text from your session; local only). Each menu also leaves a line in `~/.nextup/state/choices.jsonl`: whether you picked a number, left it as is, or typed something else. It does not store the sentence. If a row is offered three times on similar turns and you never pick it, it drops.
|
|
102
|
+
|
|
103
|
+
## How it works
|
|
104
|
+
|
|
105
|
+
1. **`Stop` hook**: reads the payload, gathers cheap signals (`git status` changes, `Bash` commands from the turn in the transcript, the final message), builds the menu, and shows it with `systemMessage`. Saves the pending menu in `~/.nextup/state/<session_id>.json`.
|
|
106
|
+
2. The user types the row number (`2`) or several at once (`+2 4`, `1 3`, `1 y 3`). The `+` is optional.
|
|
107
|
+
3. **`UserPromptSubmit` hook**: if a menu is pending and the reply is a selection, it injects the instructions as `additionalContext` (the hook cannot rewrite the prompt; Claude receives "3" plus the context that explains it). "Leave it as is" and "Something else" block the prompt and spend no tokens. Any other text discards the menu and passes through unchanged.
|
|
108
|
+
|
|
109
|
+
Design decisions (from the critique of the mock):
|
|
110
|
+
- **It does not suggest what already happened**: if the tests already passed, it does not offer to run them again.
|
|
111
|
+
- **It does not repeat what you just picked** (only for the next menu) **and it does not offer to run tests if the repo has none configured**: it suggests the commit instead.
|
|
112
|
+
- **0 to 4 options, and sometimes none**: no menu if nothing changed, or if the agent ended with a question.
|
|
113
|
+
- **The suggested row is never outward**: the schema (`SuggestionSchema`) rejects `recommended` + `outward` (push, deploy, ...).
|
|
114
|
+
- **The default menu paints the row**: green, amber, red, or gray by cost, and "Something else" in blue. The number sits on a lighter chip. `blue`, `green`, `amber`, `pink`, `teal`, and `violet` paint the whole menu one color. `mono` and `color: false` leave it plain text. The `☐` is not a checkbox: you pick with the number. In the agent box, with no slash: `nextup theme blue` (also `verde`, `azul`, `ambar`, `rosa`, `cian`). The slash command belongs to Codex and rejects `/nextup`.
|
|
115
|
+
|
|
116
|
+
## Spike: what to verify first
|
|
117
|
+
|
|
118
|
+
These four things are **not confirmed**; the design depends on them:
|
|
119
|
+
|
|
120
|
+
| # | Question | How to test | If it fails |
|
|
121
|
+
|---|----------|-------------|-------------|
|
|
122
|
+
| 1 | Does a Stop `systemMessage` show without blocking? | Run `claude`, ask for a change, look when it finishes | Use `NEXTUP_MODE=block` |
|
|
123
|
+
| 2 | Does it keep ANSI and line breaks? | Compare with `NEXTUP_COLOR=0` | Leave color off by default |
|
|
124
|
+
| 3 | Does Claude act well on `"3"` plus injected context? | Pick options several times | Strengthen the `additionalContext` text |
|
|
125
|
+
| 4 | Is the detected width correct? | Resize the terminal; try `NEXTUP_WIDTH` | Fixed or more compact width |
|
|
126
|
+
|
|
127
|
+
Also measure real turn latency (the hook starts in ~60 ms; the rules are local, so there is no model call today) and try the VS Code/Cursor extension, whose UI may show hooks differently from the terminal.
|
|
128
|
+
|
|
129
|
+
## Known limits
|
|
130
|
+
|
|
131
|
+
- The menu only looks at files whose diff changed this turn (baseline saved in `UserPromptSubmit`). If that mark is missing, it falls back to the full `git status`.
|
|
132
|
+
- The JSONL transcript is not a public contract: `transcript.ts` is best effort and degrades to "no signals".
|
|
133
|
+
- Test detection uses commands and exit codes from the transcript (real Codex format checked with `fixtures/codex-rollout-sample.jsonl`). If the failure looks environmental (EPERM, "Access is denied", ...), it is treated as *blocked*, not as "tests broken": the suggestion becomes review the diff. With no exit code, it falls back to a heuristic on the final message.
|
|
134
|
+
- No detection of headless runs (`claude -p`); if you later call `claude -p` from the hook, export `NEXTUP_INNER=1` on that call to avoid recursion.
|
|
135
|
+
- Claude and Codex share the hook protocol (`systemMessage` / `additionalContext`). OpenCode needs its own presenter (append to the prompt).
|
|
136
|
+
|
|
137
|
+
## Next steps
|
|
138
|
+
|
|
139
|
+
1. Pass the spike (table above) and use it for a week; record which options get picked.
|
|
140
|
+
2. `llm.ts`: 1 or 2 specific suggestions from a small model (API key or `claude -p`), keeping the deterministic rules as the base.
|
|
141
|
+
3. Measured cost (real duration of the last test run) instead of a fixed value per action type.
|
|
142
|
+
4. OpenCode presenter (append to the prompt). Claude and Codex already share `src/adapters/shared/`.
|
|
143
|
+
|
|
144
|
+
## Layout
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
src/core/ agent-independent: types (zod), rules, render, parser, state
|
|
148
|
+
src/adapters/shared/ hook protocol: payloads, transcript, context, Stop and UserPromptSubmit
|
|
149
|
+
src/adapters/claude/ install into .claude/settings.json
|
|
150
|
+
src/adapters/codex/ install into .codex/hooks.json (timeoutSec)
|
|
151
|
+
src/cli/ preview, init, config, hook entry
|
|
152
|
+
test/ parse, suggest, render, hooks (temp git repo), adapters
|
|
153
|
+
fixtures/ sample payloads
|
|
154
|
+
```
|