@bramblex/codex-workbench 0.1.8 → 0.1.10

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 CHANGED
@@ -1,140 +1,199 @@
1
1
  # codex-workbench
2
2
 
3
- A small terminal workbench for browsing and managing Codex sessions.
3
+ > Terminal workbench for browsing, organizing, and resuming [Codex](https://github.com/openai/codex) sessions — locally and across SSH remotes.
4
4
 
5
- It reads local Codex session JSONL files, can aggregate compatible remote workbenches over SSH, groups sessions by source and project directory, and lets you inspect, rename, annotate, resume, fork, archive, unarchive, or delete sessions from either a command-line interface or an interactive terminal UI.
5
+ [![npm version](https://img.shields.io/npm/v/@bramblex/codex-workbench)](https://www.npmjs.com/package/@bramblex/codex-workbench)
6
+ [![license](https://img.shields.io/npm/l/@bramblex/codex-workbench)](LICENSE)
7
+ [![node](https://img.shields.io/node/v/@bramblex/codex-workbench)](package.json)
6
8
 
7
- ## Install
9
+ ---
8
10
 
9
- ```sh
11
+ ## What is it?
12
+
13
+ codex-workbench gives you a fast, keyboard-driven terminal UI over your Codex sessions. It reads session JSONL files from the Codex sessions directory and lets you **inspect, rename, annotate, fork, archive, hide, and delete** sessions without digging through `~/.codex/sessions/` by hand.
14
+
15
+ It also aggregates sessions from **remote machines over SSH** — so you can manage Codex sessions across all your servers from one terminal.
16
+
17
+ Run it without arguments to open the interactive TUI, or use the CLI subcommands for scripting and automation.
18
+
19
+ ---
20
+
21
+ ## Features
22
+
23
+ - **Interactive TUI** — three-pane layout: sources/projects → sessions → details
24
+ - **Remote SSH sources** — browse and manage sessions on distant machines with zero remote dependencies beyond `codex-workbench` itself
25
+ - **Session metadata** — assign custom names and notes, hide stale sessions without deleting them
26
+ - **One-key actions** — resume, fork, archive, or delete sessions from the keyboard
27
+ - **Directory picker** — navigate the filesystem to start new sessions in any project
28
+ - **JSON output** — pipe `list --json` into `jq` or other tools
29
+ - **Short aliases** — installed as both `codex-workbench` and `cwb`
30
+
31
+ ---
32
+
33
+ ## Quick start
34
+
35
+ ```bash
10
36
  npm install -g @bramblex/codex-workbench
11
37
  ```
12
38
 
13
- codex-workbench expects the Codex CLI to be available from your shell. You can check what executable will be used with:
39
+ Make sure Codex is available in your shell `PATH`. Verify everything is wired up:
14
40
 
15
- ```sh
41
+ ```bash
16
42
  codex-workbench doctor
17
43
  ```
18
44
 
19
- For local development:
45
+ Then open the workbench:
20
46
 
21
- ```sh
22
- npm install
47
+ ```bash
48
+ codex-workbench
49
+ # or just:
50
+ cwb
23
51
  ```
24
52
 
25
- Then run the CLI through Node:
53
+ ---
26
54
 
27
- ```sh
28
- node bin/codex-workbench --help
29
- ```
55
+ ## CLI commands
30
56
 
31
- To expose the `codex-workbench` command locally:
57
+ ### Browse sessions
32
58
 
33
- ```sh
34
- npm link
35
- codex-workbench list
59
+ ```bash
60
+ codex-workbench list # human-readable, grouped by source + project
61
+ codex-workbench list --json # machine-readable full output
62
+ codex-workbench list --json --compact # omit message history (faster for scripting)
63
+ codex-workbench list --cwd ~/projects/foo # filter to one working directory
64
+ codex-workbench list --all # include archived and hidden sessions
36
65
  ```
37
66
 
38
- ## Usage
67
+ ### Inspect a session
39
68
 
40
- ```sh
41
- codex-workbench [ui]
42
- codex-workbench doctor
43
- codex-workbench list [--json] [--compact] [--cwd <dir>] [--all]
69
+ ```bash
44
70
  codex-workbench show <session>
45
- codex-workbench rename <session> <name>
46
- codex-workbench note <session> <note>
47
- codex-workbench new [--cwd <dir>] [prompt...]
48
- codex-workbench dirs [--cwd <dir>] [--json]
49
- codex-workbench mkdir [--cwd <dir>] <name> [--json]
50
- codex-workbench resume <session> [prompt...]
51
- codex-workbench fork <session>
71
+ ```
72
+
73
+ `<session>` can be a full session id, a unique prefix, a saved custom name, or a session filename.
74
+
75
+ ### Manage sessions
76
+
77
+ ```bash
78
+ codex-workbench rename <session> "fix the auth bug"
79
+ codex-workbench note <session> "investigated JWT expiry, seems to be clock skew"
52
80
  codex-workbench archive <session>
53
81
  codex-workbench unarchive <session>
54
- codex-workbench hide <session>
82
+ codex-workbench hide <session> # remove from default list but keep on disk
55
83
  codex-workbench unhide <session>
56
- codex-workbench delete <session> [--force] [--file]
84
+ codex-workbench fork <session>
85
+ codex-workbench delete <session> --force
57
86
  ```
58
87
 
59
- Run without arguments to open the interactive UI:
88
+ ### Start and resume
60
89
 
61
- ```sh
62
- codex-workbench
90
+ ```bash
91
+ codex-workbench new --cwd ~/projects/foo "Summarize this repo"
92
+ codex-workbench resume <session> "what was the conclusion about the rate limiter?"
63
93
  ```
64
94
 
65
- The package also installs the short alias:
95
+ When you run `new` or `resume`, Codex takes over the terminal. When it exits, codex-workbench returns.
66
96
 
67
- ```sh
68
- cwb
97
+ ### Directories
98
+
99
+ ```bash
100
+ codex-workbench dirs --cwd ~/projects
101
+ codex-workbench dirs --json
102
+ codex-workbench mkdir ~/projects my-new-feature
69
103
  ```
70
104
 
71
- Use `list` to find sessions:
105
+ ### Diagnostics
72
106
 
73
- ```sh
74
- codex-workbench list
75
- codex-workbench list --json
76
- codex-workbench list --json --compact
77
- codex-workbench list --cwd /path/to/project
78
- codex-workbench list --all
107
+ ```bash
108
+ codex-workbench doctor
79
109
  ```
80
110
 
81
- Use `--compact` with `--json` when another tool only needs session summaries. It omits the full message history and keeps remote SSH listings small.
82
-
83
- Use `new` to start a fresh Codex session in a project directory:
111
+ ### Force-delete a broken session file
84
112
 
85
- ```sh
86
- codex-workbench new --cwd /path/to/project
87
- codex-workbench new --cwd /path/to/project "Summarize this repo"
113
+ ```bash
114
+ codex-workbench delete <session> --file
88
115
  ```
89
116
 
90
- Use `hide` for sessions that Codex itself can no longer resume, archive, or delete. Hidden sessions are removed from the default list but remain visible with `--all`:
117
+ Only use `--file` when Codex itself cannot remove the session. It deletes the JSONL file directly without going through the Codex CLI.
91
118
 
92
- ```sh
93
- codex-workbench hide <session>
94
- codex-workbench unhide <session>
95
- codex-workbench list --all
96
- ```
119
+ ---
97
120
 
98
- Use `delete --file` only for broken sessions that Codex can no longer remove. It deletes the local session JSONL file directly:
121
+ ## Interactive TUI
122
+
123
+ Run `cwb` with no arguments to open the TUI:
99
124
 
100
- ```sh
101
- codex-workbench delete <session> --file
125
+ ```
126
+ ┌─ Codex Workbench ───────────────────────────────────────────────────┐
127
+ │ 12/57 visible Local: ~/projects/api │
128
+ ├──────────────┬──────────────────────────────────────────────────────┤
129
+ │ > Sources │ > Sessions │
130
+ │ │ │
131
+ │ 0 All (57) │ a1b2c3d4e5f6g 23t 2025-03-15 14:22 fix auth bug │
132
+ │ = host-a (5) │ c8d9e0f1a2b3c 12t 2025-03-14 09:15 refactor db │
133
+ │ api (3) │ d4e5f6g7h8i9j 5t 2025-03-13 16:48 add tests │
134
+ │ web (2) │ ... │
135
+ │ = host-b (7) │ │
136
+ │ data (4) ├──────────────────────────────────────────────────────┤
137
+ │ infra (3) │ > Details │
138
+ │ │ │
139
+ │ │ fix auth bug │
140
+ │ │ id: a1b2c3d4e5f6g7... │
141
+ │ │ source: Local │
142
+ │ │ cwd: ~/projects/api │
143
+ │ │ ... │
144
+ ├──────────────┴──────────────────────────────────────────────────────┤
145
+ │ Sessions: ↑/↓ select Enter resume r rename n new d delete q quit│
146
+ └─────────────────────────────────────────────────────────────────────┘
102
147
  ```
103
148
 
104
- Use `doctor` to check which Codex executable the CLI will launch:
149
+ ### Keyboard shortcuts
105
150
 
106
- ```sh
107
- codex-workbench doctor
108
- ```
151
+ | Key | Action |
152
+ |-----|--------|
153
+ | `Enter` | Resume selected session in Codex |
154
+ | `Tab` / `S-Tab` | Switch focus between panes |
155
+ | `←` `→` / `h` `l` | Move between sources, sessions, and details |
156
+ | `↑` `↓` / `j` `k` | Move selection up/down |
157
+ | `0` | Show all sources |
158
+ | `1`–`9` | Jump to source |
159
+ | `[` `]` | Previous / next source |
160
+ | `n` | New session (picks directory from active project) |
161
+ | `f` | Fork selected session |
162
+ | `r` | Rename selected session |
163
+ | `o` | Add or edit note |
164
+ | `a` | Archive selected session |
165
+ | `d` | Delete selected session |
166
+ | `v` | Print session details to stdout and exit |
167
+ | `q` / `Esc` / `Ctrl+C` | Quit |
109
168
 
110
- Most commands accept a full session id, a unique prefix, a saved name, or a session filename.
169
+ ### Directory picker
111
170
 
112
- ## Interactive UI
171
+ When creating a new session, the directory picker opens:
113
172
 
114
- The UI groups sessions by source and working directory, with sources/projects on the left, sessions on the upper right, and details below. Local sessions render immediately, while remote SSH sources load in the background. When you start or resume a session, Codex temporarily takes over the terminal; when Codex exits, codex-workbench redraws the UI.
173
+ | Key | Action |
174
+ |-----|--------|
175
+ | `↑` `↓` / `j` `k` | Move selection |
176
+ | `←` / `h` | Go to parent directory |
177
+ | `→` / `l` | Enter child directory |
178
+ | `n` | Create a new subdirectory |
179
+ | `Enter` | Choose selected directory |
180
+ | `q` / `Esc` | Cancel |
115
181
 
116
- Common keys:
182
+ ---
117
183
 
118
- - `Enter`: resume the selected session in Codex
119
- - `n`: create a new project/session from Projects, or a new session from Sessions/Details
120
- - `f`: fork the selected session
121
- - `v`: print session details and exit
122
- - `r`: rename the selected session
123
- - `o`: add or edit a note
124
- - `a`: archive the selected session
125
- - `d`: delete the selected session
126
- - `Tab`: switch focus between projects, sessions, and details
127
- - `Left`/`Right` or `h`/`l`: move between panes
128
- - `0`: show all sources
129
- - `1`-`9`: jump to a source
130
- - `[`/`]`: switch to the previous or next source
131
- - `q`, `Esc`, or `Ctrl+C`: quit
184
+ ## Remote SSH sources
132
185
 
133
- In the directory picker, use `Up`/`Down` or `j`/`k` to move, `Left`/`h` for the parent directory, `Right`/`l` for the selected child directory, `n` to create a child directory, and `Enter` to choose the selected directory.
186
+ codex-workbench can show sessions from remote machines by running `cwb` over SSH.
134
187
 
135
- ## Remote Servers
188
+ ### Requirements
136
189
 
137
- codex-workbench can show remote sessions in the interactive UI by calling `cwb` over SSH. The remote server must have `codex-workbench` installed and the configured `cwb` command available to SSH non-interactive commands.
190
+ The remote machine must have `codex-workbench` installed and the `cwb` command available in the **non-interactive SSH PATH** (not just your interactive shell). Test it:
191
+
192
+ ```bash
193
+ ssh user@host 'cwb list --json'
194
+ ```
195
+
196
+ ### Configuration
138
197
 
139
198
  Create `~/.codex/codex-workbench.config.json`:
140
199
 
@@ -142,14 +201,14 @@ Create `~/.codex/codex-workbench.config.json`:
142
201
  {
143
202
  "servers": [
144
203
  {
145
- "id": "a",
146
- "label": "A server",
147
- "target": "user@example.com"
204
+ "id": "devbox",
205
+ "label": "Dev box",
206
+ "target": "user@dev.example.com"
148
207
  },
149
208
  {
150
- "id": "b",
151
- "label": "B server",
152
- "target": "b-host",
209
+ "id": "gpu",
210
+ "label": "GPU server",
211
+ "target": "gpu-host",
153
212
  "command": "/usr/local/bin/cwb",
154
213
  "sshArgs": ["-p", "2222"]
155
214
  }
@@ -157,46 +216,131 @@ Create `~/.codex/codex-workbench.config.json`:
157
216
  }
158
217
  ```
159
218
 
160
- The UI will render `Local`, `A server`, and `B server` as source groups. Remote list, rename, note, hide, directory browsing, new session, resume, fork, archive, and delete commands are executed as SSH calls to the remote `cwb`.
219
+ | Field | Required | Description |
220
+ |-------|----------|-------------|
221
+ | `target` | Yes | SSH destination (`user@host` or hostname) |
222
+ | `id` | No | Short identifier (defaults to sanitized target) |
223
+ | `label` | No | Display name in the UI |
224
+ | `command` | No | Path to `cwb` on the remote (default: `cwb`) |
225
+ | `sshArgs` | No | Extra SSH flags, e.g. `["-p", "2222"]` |
226
+
227
+ Remote sources appear alongside `Local` in the TUI and load asynchronously in the background. Most operations (rename, note, hide, new, resume, fork, archive, delete) are forwarded to the remote `cwb`.
228
+
229
+ ---
230
+
231
+ ## Environment variables
232
+
233
+ | Variable | Default | Description |
234
+ |----------|---------|-------------|
235
+ | `CODEX_HOME` | `~/.codex` | Codex data directory |
236
+ | `CODEX_SESSIONS_DIR` | `$CODEX_HOME/sessions` | Session JSONL files |
237
+ | `CODEX_WORKBENCH_META` | `$CODEX_HOME/codex-workbench.json` | Workbench metadata (names, notes) |
238
+ | `CODEX_WORKBENCH_CONFIG` | `$CODEX_HOME/codex-workbench.config.json` | SSH remote sources config |
239
+ | `CODEX_BIN` | auto-detected | Force a specific Codex executable |
240
+
241
+ By default, codex-workbench discovers the `codex` binary through your login shell's `PATH`. Set `CODEX_BIN` to override.
242
+
243
+ ---
244
+
245
+ ## Troubleshooting
161
246
 
162
- You can verify a remote source directly with:
247
+ ### "Could not find the codex executable"
163
248
 
164
- ```sh
165
- ssh user@example.com 'cwb list --json'
249
+ Run `codex-workbench doctor` to see where codex-workbench is looking. Common fixes:
250
+
251
+ - Run `npm install -g @openai/codex` to install Codex globally
252
+ - Set `CODEX_BIN=/path/to/codex` to point directly at the executable
253
+ - Make sure your shell profile (`~/.zshrc`, `~/.bashrc`) adds Codex to `PATH`
254
+
255
+ ### No sessions appear
256
+
257
+ Make sure you've run Codex at least once. Sessions are stored as `.jsonl` files under `$CODEX_SESSIONS_DIR`. Run `ls ~/.codex/sessions/` to verify.
258
+
259
+ ### Remote source shows an error
260
+
261
+ Verify the remote is reachable and has `cwb` in its non-interactive PATH:
262
+
263
+ ```bash
264
+ ssh user@host 'cwb list --json --compact'
166
265
  ```
167
266
 
168
- ## Environment
267
+ If that fails, set the `command` field in your config to the full path:
169
268
 
170
- ```sh
171
- CODEX_HOME # default: ~/.codex
172
- CODEX_SESSIONS_DIR # default: $CODEX_HOME/sessions
173
- CODEX_WORKBENCH_META # default: $CODEX_HOME/codex-workbench.json
174
- CODEX_WORKBENCH_CONFIG # default: $CODEX_HOME/codex-workbench.config.json
175
- CODEX_BIN # default: codex from shell PATH
269
+ ```json
270
+ { "command": "/home/user/.nvm/versions/node/v20/bin/cwb" }
176
271
  ```
177
272
 
178
- `CODEX_WORKBENCH_META` stores local workbench metadata such as custom names and notes. Session content remains in the Codex sessions directory.
273
+ ### TUI rendering issues
179
274
 
180
- `CODEX_WORKBENCH_CONFIG` points to the optional local configuration file for SSH remote sources.
275
+ codex-workbench uses [blessed](https://github.com/chjj/blessed) for terminal rendering. If you see garbled output, try a different terminal emulator (iTerm2, Kitty, WezTerm, and the built-in macOS Terminal all work well).
181
276
 
182
- By default, codex-workbench launches `codex` through your shell so your normal shell `PATH` applies. Set `CODEX_BIN` if you want to force a specific executable path.
277
+ ---
183
278
 
184
279
  ## Development
185
280
 
186
- ```sh
281
+ ```bash
282
+ git clone https://github.com/bramblex/codex-workbench.git
283
+ cd codex-workbench
284
+ npm install
285
+ ```
286
+
287
+ Run the CLI directly:
288
+
289
+ ```bash
290
+ node bin/codex-workbench --help
291
+ ```
292
+
293
+ Or link it locally:
294
+
295
+ ```bash
296
+ npm link
297
+ cwb list
298
+ ```
299
+
300
+ ### Project layout
301
+
302
+ ```
303
+ bin/codex-workbench # executable entry point
304
+ src/
305
+ cli.js # CLI argument parsing and command dispatch
306
+ cli-output.js # terminal output formatters
307
+ codex-bin.js # Codex binary discovery (PATH, shell, fallback)
308
+ config.js # environment-derived path constants
309
+ model/
310
+ session-store.js # session JSONL parsing and metadata persistence
311
+ format.js # id/time/text formatting helpers
312
+ directories.js # filesystem directory listing and creation
313
+ workbench-config.js # SSH remote source config loader
314
+ services/
315
+ codex-runner.js # spawn Codex processes (new, resume, fork, etc.)
316
+ session-sources.js # aggregates local + remote session lists
317
+ ssh-runner.js # runs cwb commands over SSH (sync + async)
318
+ ui/
319
+ blessed-compat.js # blessed terminfo compatibility patch
320
+ workbench.js # interactive TUI (blessed-based three-pane layout)
321
+ directory-picker.js # TUI filesystem directory picker
322
+ test/
323
+ smoke.js # end-to-end CLI smoke test
324
+ codex-bin.test.js # binary discovery unit tests
325
+ session-sources.test.js # session source aggregation tests
326
+ blessed-compat.test.js # terminfo patch verification
327
+ scripts/
328
+ pty-codex.js # PTY-based Codex runner prototype
329
+ tui-pty-codex.js # PTY + blessed integration prototype
330
+ blessed-xterm-codex.js # xterm + blessed integration prototype
331
+ ```
332
+
333
+ ### Tests
334
+
335
+ ```bash
187
336
  npm test
188
- npm pack --dry-run
189
337
  ```
190
338
 
191
- Project layout:
339
+ This runs syntax checks on all source files and executes the test suite.
192
340
 
193
- ```text
194
- bin/codex-workbench # executable entrypoint
195
- src/cli.js # thin CLI router
196
- src/cli-output.js # terminal output presenters
197
- src/codex-bin.js # Codex executable discovery
198
- src/model/ # session parsing, metadata, config, and format helpers
199
- src/services/ # Codex process runners and session source adapters
200
- src/ui/ # interactive UI and components
201
- test/ # smoke and service tests
341
+ ### Publishing
342
+
343
+ ```bash
344
+ npm pack --dry-run
345
+ npm publish --access public
202
346
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bramblex/codex-workbench",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Terminal workbench for browsing and managing local and SSH Codex sessions.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -69,6 +69,7 @@ async function runWorkbench() {
69
69
  mouse: true,
70
70
  keys: true,
71
71
  vi: false,
72
+ tags: true,
72
73
  scrollbar: { ch: ' ', track: { bg: 'black' }, style: { bg: 'green' } },
73
74
  style: {
74
75
  border: { fg: 'green' },
@@ -196,25 +197,28 @@ async function runWorkbench() {
196
197
  return index >= 0 && index < 9 ? String(index + 1) : '';
197
198
  };
198
199
 
200
+ const styledListLabel = (color, text) => `{${color}-fg}{bold}${blessed.escape(text)}{/}`;
201
+
199
202
  const machineLabel = (source, count) => {
200
203
  const shortcut = sourceShortcut(source);
201
204
  const prefix = shortcut ? `${shortcut} ` : '';
202
205
  const maxLabel = Math.max(8, projectWidth - 18);
203
206
  const text = `${prefix}${truncate(source.label, maxLabel)} (${count})`;
204
207
  const width = Math.max(12, projectWidth - 4);
205
- const head = `- ${text} `;
206
- return `${head}${'-'.repeat(width)}`.slice(0, width);
208
+ const head = `= ${text} `;
209
+ const line = `${head}${'='.repeat(width)}`.slice(0, width);
210
+ return styledListLabel('yellow', line);
207
211
  };
208
212
 
209
213
  const projectLabel = (group) => {
210
- if (group.kind === 'all') return `0 All (${sessions.length})`;
214
+ if (group.kind === 'all') return styledListLabel('white', `0 All (${sessions.length})`);
211
215
  if (group.kind === 'source') {
212
216
  const count = sessionsForSource(group.source.id).length;
213
217
  return machineLabel(group.source, count);
214
218
  }
215
219
  const count = sessions.filter((session) => session.sourceId === group.source.id && session.cwd === group.cwd).length;
216
220
  const base = path.basename(group.cwd) || group.cwd;
217
- return ` ${truncate(base, Math.max(10, projectWidth - 12))} (${count})`;
221
+ return ` ${blessed.escape(`${truncate(base, Math.max(10, projectWidth - 12))} (${count})`)}`;
218
222
  };
219
223
 
220
224
  const sessionLabel = (session) => {