@bramblex/codex-workbench 0.1.7 → 0.1.8

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
@@ -125,6 +125,9 @@ Common keys:
125
125
  - `d`: delete the selected session
126
126
  - `Tab`: switch focus between projects, sessions, and details
127
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
128
131
  - `q`, `Esc`, or `Ctrl+C`: quit
129
132
 
130
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bramblex/codex-workbench",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Terminal workbench for browsing and managing local and SSH Codex sessions.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -191,11 +191,26 @@ async function runWorkbench() {
191
191
  return `${group.source.label}: ${group.cwd}`;
192
192
  };
193
193
 
194
+ const sourceShortcut = (source) => {
195
+ const index = sources.findIndex((item) => item.id === source.id);
196
+ return index >= 0 && index < 9 ? String(index + 1) : '';
197
+ };
198
+
199
+ const machineLabel = (source, count) => {
200
+ const shortcut = sourceShortcut(source);
201
+ const prefix = shortcut ? `${shortcut} ` : '';
202
+ const maxLabel = Math.max(8, projectWidth - 18);
203
+ const text = `${prefix}${truncate(source.label, maxLabel)} (${count})`;
204
+ const width = Math.max(12, projectWidth - 4);
205
+ const head = `- ${text} `;
206
+ return `${head}${'-'.repeat(width)}`.slice(0, width);
207
+ };
208
+
194
209
  const projectLabel = (group) => {
195
- if (group.kind === 'all') return `All (${sessions.length})`;
210
+ if (group.kind === 'all') return `0 All (${sessions.length})`;
196
211
  if (group.kind === 'source') {
197
212
  const count = sessionsForSource(group.source.id).length;
198
- return `${truncate(group.source.label, Math.max(10, projectWidth - 6))} (${count})`;
213
+ return machineLabel(group.source, count);
199
214
  }
200
215
  const count = sessions.filter((session) => session.sourceId === group.source.id && session.cwd === group.cwd).length;
201
216
  const base = path.basename(group.cwd) || group.cwd;
@@ -410,11 +425,11 @@ async function runWorkbench() {
410
425
 
411
426
  const firstLine = message || 'Ready';
412
427
  if (projectFocused) {
413
- status.setContent(`${firstLine}\nProjects: ↑/↓ select project n new project →/Enter sessions Tab focus q quit`);
428
+ status.setContent(`${firstLine}\nSources: ↑/↓ select 0 all 1-9 machine [/] prev/next n new sessions q quit`);
414
429
  } else if (detailFocused) {
415
- status.setContent(`${firstLine}\nDetails: ↑/↓ scroll n new session ← sessions → projects Tab focus q quit`);
430
+ status.setContent(`${firstLine}\nDetails: ↑/↓ scroll 1-9 machine [/] prev/next n new ← sessions q quit`);
416
431
  } else {
417
- status.setContent(`${firstLine}\nSessions: ↑/↓ select Enter resume r rename n new session f fork v view o note a archive d delete q quit`);
432
+ status.setContent(`${firstLine}\nSessions: ↑/↓ select Enter resume 1-9 machine [/] prev/next r rename n new d delete`);
418
433
  }
419
434
  };
420
435
 
@@ -484,6 +499,35 @@ async function runWorkbench() {
484
499
  render();
485
500
  };
486
501
 
502
+ const selectSourceIndex = (sourceIndex) => {
503
+ const source = sources[sourceIndex];
504
+ if (!source) return;
505
+ const nextIndex = groups.findIndex((group) => group.kind === 'source' && group.source.id === source.id);
506
+ if (nextIndex === -1) return;
507
+ selectGroup(nextIndex);
508
+ setMessage(`Switched to ${source.label}.`);
509
+ render();
510
+ };
511
+
512
+ const currentSourceIndex = () => {
513
+ const group = currentGroup();
514
+ if (group.kind === 'source' || group.kind === 'project') {
515
+ return sources.findIndex((source) => source.id === group.source.id);
516
+ }
517
+ const session = selectedSession();
518
+ if (session) return sources.findIndex((source) => source.id === session.sourceId);
519
+ return -1;
520
+ };
521
+
522
+ const switchSource = (delta) => {
523
+ if (!sources.length) return;
524
+ const currentIndex = currentSourceIndex();
525
+ const nextIndex = currentIndex === -1
526
+ ? (delta > 0 ? 0 : sources.length - 1)
527
+ : (currentIndex + delta + sources.length) % sources.length;
528
+ selectSourceIndex(nextIndex);
529
+ };
530
+
487
531
  const runCodexAndReturn = (command, session, args = [], doneText = `${command} finished.`) => {
488
532
  screen.leave();
489
533
  let status = 0;
@@ -668,6 +712,30 @@ async function runWorkbench() {
668
712
  else focusPanel(detailBox, 'details');
669
713
  });
670
714
 
715
+ screen.key(['0'], () => {
716
+ if (promptOpen()) return;
717
+ selectGroup(0);
718
+ setMessage('Switched to all sources.');
719
+ render();
720
+ });
721
+
722
+ for (let i = 1; i <= 9; i += 1) {
723
+ screen.key([String(i)], () => {
724
+ if (promptOpen()) return;
725
+ selectSourceIndex(i - 1);
726
+ });
727
+ }
728
+
729
+ screen.key([']'], () => {
730
+ if (promptOpen()) return;
731
+ switchSource(1);
732
+ });
733
+
734
+ screen.key(['['], () => {
735
+ if (promptOpen()) return;
736
+ switchSource(-1);
737
+ });
738
+
671
739
  screen.key(['q', 'escape', 'C-c'], () => {
672
740
  if (promptOpen()) return;
673
741
  leaveScreen();