@bramblex/codex-workbench 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +17 -1
  2. package/package.json +1 -1
  3. package/src/cli.js +42 -7
package/README.md CHANGED
@@ -48,7 +48,9 @@ codex-workbench resume <session> [prompt...]
48
48
  codex-workbench fork <session>
49
49
  codex-workbench archive <session>
50
50
  codex-workbench unarchive <session>
51
- codex-workbench delete <session> [--force]
51
+ codex-workbench hide <session>
52
+ codex-workbench unhide <session>
53
+ codex-workbench delete <session> [--force] [--file]
52
54
  ```
53
55
 
54
56
  Run without arguments to open the interactive UI:
@@ -72,6 +74,20 @@ codex-workbench list --cwd /path/to/project
72
74
  codex-workbench list --all
73
75
  ```
74
76
 
77
+ 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`:
78
+
79
+ ```sh
80
+ codex-workbench hide <session>
81
+ codex-workbench unhide <session>
82
+ codex-workbench list --all
83
+ ```
84
+
85
+ Use `delete --file` only for broken sessions that Codex can no longer remove. It deletes the local session JSONL file directly:
86
+
87
+ ```sh
88
+ codex-workbench delete <session> --file
89
+ ```
90
+
75
91
  Use `doctor` to check which Codex executable the CLI will launch:
76
92
 
77
93
  ```sh
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bramblex/codex-workbench",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Terminal workbench for browsing and managing local Codex sessions.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/cli.js CHANGED
@@ -27,7 +27,9 @@ Usage:
27
27
  codex-workbench fork <session>
28
28
  codex-workbench archive <session>
29
29
  codex-workbench unarchive <session>
30
- codex-workbench delete <session> [--force]
30
+ codex-workbench hide <session>
31
+ codex-workbench unhide <session>
32
+ codex-workbench delete <session> [--force] [--file]
31
33
 
32
34
  Environment:
33
35
  CODEX_HOME default: ~/.codex
@@ -175,7 +177,7 @@ function truncate(text, width) {
175
177
 
176
178
  function printList(sessions, opts = {}) {
177
179
  const filtered = sessions.filter((session) => {
178
- if (!opts.all && session.archived) return false;
180
+ if (!opts.all && (session.archived || session.hidden)) return false;
179
181
  if (opts.cwd) return path.resolve(session.cwd) === path.resolve(opts.cwd);
180
182
  return true;
181
183
  });
@@ -192,7 +194,7 @@ function printList(sessions, opts = {}) {
192
194
  console.log(`\n${cwd}`);
193
195
  for (const session of group) {
194
196
  const label = session.name || truncate(session.first || session.last || '(no prompt)', 56);
195
- const flags = [session.archived ? 'archived' : '', session.note ? 'note' : ''].filter(Boolean).join(',');
197
+ const flags = [session.archived ? 'archived' : '', session.hidden ? 'hidden' : '', session.note ? 'note' : ''].filter(Boolean).join(',');
196
198
  console.log(` ${shortId(session.id)} ${localTime(session.updatedAt)} ${String(session.turns).padStart(2)} turns ${flags ? `[${flags}] ` : ''}${label}`);
197
199
  }
198
200
  }
@@ -200,7 +202,7 @@ function printList(sessions, opts = {}) {
200
202
  }
201
203
 
202
204
  function printShow(session) {
203
- console.log(`${session.name || '(unnamed)'} ${session.archived ? '[archived]' : ''}`);
205
+ console.log(`${session.name || '(unnamed)'} ${session.archived ? '[archived]' : ''}${session.hidden ? '[hidden]' : ''}`);
204
206
  console.log(`id: ${session.id}`);
205
207
  console.log(`cwd: ${session.cwd}`);
206
208
  console.log(`started: ${localTime(session.startedAt)}`);
@@ -244,6 +246,18 @@ function updateMetadata(session, patch) {
244
246
  writeJson(META_PATH, meta);
245
247
  }
246
248
 
249
+ function removeMetadata(session) {
250
+ const meta = loadMeta();
251
+ delete meta.sessions[session.id];
252
+ meta.updatedAt = new Date().toISOString();
253
+ writeJson(META_PATH, meta);
254
+ }
255
+
256
+ function deleteSessionFile(session) {
257
+ fs.unlinkSync(session.file);
258
+ removeMetadata(session);
259
+ }
260
+
247
261
  function usableCwd(dir) {
248
262
  const candidates = [dir, process.cwd(), HOME];
249
263
  for (const candidate of candidates) {
@@ -303,6 +317,7 @@ function parseFlags(args) {
303
317
  if (arg === '--json') out.json = true;
304
318
  else if (arg === '--all') out.all = true;
305
319
  else if (arg === '--force') out.force = true;
320
+ else if (arg === '--file') out.file = true;
306
321
  else if (arg === '--cwd') {
307
322
  if (i + 1 >= args.length) throw new Error('--cwd requires a directory.');
308
323
  out.cwd = args[++i];
@@ -524,7 +539,7 @@ async function ui() {
524
539
  const promptOpen = () => prompt.visible || question.visible;
525
540
 
526
541
  const reload = () => {
527
- sessions = listSessions().filter((s) => !s.archived);
542
+ sessions = listSessions().filter((s) => !s.archived && !s.hidden);
528
543
  groups = ['All', ...new Set(sessions.map((s) => s.cwd))];
529
544
  if (groupIndex >= groups.length) groupIndex = Math.max(0, groups.length - 1);
530
545
  const visible = currentSessions();
@@ -594,6 +609,7 @@ async function ui() {
594
609
  }
595
610
  if (status === 0) refreshAfterAction(doneText);
596
611
  else refreshAfterAction(`${command} exited with code ${status}.`, true);
612
+ return status;
597
613
  };
598
614
 
599
615
  const runAction = async (action) => {
@@ -712,7 +728,20 @@ async function ui() {
712
728
  setMessage('Delete cancelled.');
713
729
  return render();
714
730
  }
715
- runCodexAndReturn('delete', session, ['--force'], `Deleted ${shortId(session.id)}.`);
731
+ const status = runCodexAndReturn('delete', session, ['--force'], `Deleted ${shortId(session.id)}.`);
732
+ if (status !== 0) {
733
+ const removeFile = await askConfirm(`Codex could not delete ${shortId(session.id)}. Delete its session file?`);
734
+ if (removeFile) {
735
+ deleteSessionFile(session);
736
+ refreshAfterAction(`Deleted file for ${shortId(session.id)}.`);
737
+ return;
738
+ }
739
+ const hideSession = await askConfirm(`Hide ${shortId(session.id)} from workbench instead?`);
740
+ if (hideSession) {
741
+ updateMetadata(session, { hidden: true });
742
+ refreshAfterAction(`Hidden ${shortId(session.id)}.`);
743
+ }
744
+ }
716
745
  }));
717
746
 
718
747
  sessionsList.focus();
@@ -739,7 +768,13 @@ async function main() {
739
768
  if (cmd === 'fork') return codexCommand('fork', resolveSession(flags._[0], sessions), [], true);
740
769
  if (cmd === 'archive') return codexCommand('archive', resolveSession(flags._[0], sessions));
741
770
  if (cmd === 'unarchive') return codexCommand('unarchive', resolveSession(flags._[0], sessions));
742
- if (cmd === 'delete') return codexCommand('delete', resolveSession(flags._[0], sessions), flags.force ? ['--force'] : []);
771
+ if (cmd === 'hide') return updateMetadata(resolveSession(flags._[0], sessions), { hidden: true });
772
+ if (cmd === 'unhide') return updateMetadata(resolveSession(flags._[0], sessions), { hidden: false });
773
+ if (cmd === 'delete') {
774
+ const session = resolveSession(flags._[0], sessions);
775
+ if (flags.file) return deleteSessionFile(session);
776
+ return codexCommand('delete', session, flags.force ? ['--force'] : []);
777
+ }
743
778
 
744
779
  usage();
745
780
  process.exitCode = 2;