@bramblex/codex-workbench 0.1.7 → 0.1.9

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.9",
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' },
@@ -191,15 +192,33 @@ async function runWorkbench() {
191
192
  return `${group.source.label}: ${group.cwd}`;
192
193
  };
193
194
 
195
+ const sourceShortcut = (source) => {
196
+ const index = sources.findIndex((item) => item.id === source.id);
197
+ return index >= 0 && index < 9 ? String(index + 1) : '';
198
+ };
199
+
200
+ const styledListLabel = (color, text) => `{${color}-fg}{bold}${blessed.escape(text)}{/}`;
201
+
202
+ const machineLabel = (source, count) => {
203
+ const shortcut = sourceShortcut(source);
204
+ const prefix = shortcut ? `${shortcut} ` : '';
205
+ const maxLabel = Math.max(8, projectWidth - 18);
206
+ const text = `${prefix}${truncate(source.label, maxLabel)} (${count})`;
207
+ const width = Math.max(12, projectWidth - 4);
208
+ const head = `= ${text} `;
209
+ const line = `${head}${'='.repeat(width)}`.slice(0, width);
210
+ return styledListLabel('yellow', line);
211
+ };
212
+
194
213
  const projectLabel = (group) => {
195
- if (group.kind === 'all') return `All (${sessions.length})`;
214
+ if (group.kind === 'all') return styledListLabel('white', `0 All (${sessions.length})`);
196
215
  if (group.kind === 'source') {
197
216
  const count = sessionsForSource(group.source.id).length;
198
- return `${truncate(group.source.label, Math.max(10, projectWidth - 6))} (${count})`;
217
+ return machineLabel(group.source, count);
199
218
  }
200
219
  const count = sessions.filter((session) => session.sourceId === group.source.id && session.cwd === group.cwd).length;
201
220
  const base = path.basename(group.cwd) || group.cwd;
202
- return ` ${truncate(base, Math.max(10, projectWidth - 12))} (${count})`;
221
+ return ` ${blessed.escape(`${truncate(base, Math.max(10, projectWidth - 12))} (${count})`)}`;
203
222
  };
204
223
 
205
224
  const sessionLabel = (session) => {
@@ -410,11 +429,11 @@ async function runWorkbench() {
410
429
 
411
430
  const firstLine = message || 'Ready';
412
431
  if (projectFocused) {
413
- status.setContent(`${firstLine}\nProjects: ↑/↓ select project n new project →/Enter sessions Tab focus q quit`);
432
+ status.setContent(`${firstLine}\nSources: ↑/↓ select 0 all 1-9 machine [/] prev/next n new sessions q quit`);
414
433
  } else if (detailFocused) {
415
- status.setContent(`${firstLine}\nDetails: ↑/↓ scroll n new session ← sessions → projects Tab focus q quit`);
434
+ status.setContent(`${firstLine}\nDetails: ↑/↓ scroll 1-9 machine [/] prev/next n new ← sessions q quit`);
416
435
  } 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`);
436
+ status.setContent(`${firstLine}\nSessions: ↑/↓ select Enter resume 1-9 machine [/] prev/next r rename n new d delete`);
418
437
  }
419
438
  };
420
439
 
@@ -484,6 +503,35 @@ async function runWorkbench() {
484
503
  render();
485
504
  };
486
505
 
506
+ const selectSourceIndex = (sourceIndex) => {
507
+ const source = sources[sourceIndex];
508
+ if (!source) return;
509
+ const nextIndex = groups.findIndex((group) => group.kind === 'source' && group.source.id === source.id);
510
+ if (nextIndex === -1) return;
511
+ selectGroup(nextIndex);
512
+ setMessage(`Switched to ${source.label}.`);
513
+ render();
514
+ };
515
+
516
+ const currentSourceIndex = () => {
517
+ const group = currentGroup();
518
+ if (group.kind === 'source' || group.kind === 'project') {
519
+ return sources.findIndex((source) => source.id === group.source.id);
520
+ }
521
+ const session = selectedSession();
522
+ if (session) return sources.findIndex((source) => source.id === session.sourceId);
523
+ return -1;
524
+ };
525
+
526
+ const switchSource = (delta) => {
527
+ if (!sources.length) return;
528
+ const currentIndex = currentSourceIndex();
529
+ const nextIndex = currentIndex === -1
530
+ ? (delta > 0 ? 0 : sources.length - 1)
531
+ : (currentIndex + delta + sources.length) % sources.length;
532
+ selectSourceIndex(nextIndex);
533
+ };
534
+
487
535
  const runCodexAndReturn = (command, session, args = [], doneText = `${command} finished.`) => {
488
536
  screen.leave();
489
537
  let status = 0;
@@ -668,6 +716,30 @@ async function runWorkbench() {
668
716
  else focusPanel(detailBox, 'details');
669
717
  });
670
718
 
719
+ screen.key(['0'], () => {
720
+ if (promptOpen()) return;
721
+ selectGroup(0);
722
+ setMessage('Switched to all sources.');
723
+ render();
724
+ });
725
+
726
+ for (let i = 1; i <= 9; i += 1) {
727
+ screen.key([String(i)], () => {
728
+ if (promptOpen()) return;
729
+ selectSourceIndex(i - 1);
730
+ });
731
+ }
732
+
733
+ screen.key([']'], () => {
734
+ if (promptOpen()) return;
735
+ switchSource(1);
736
+ });
737
+
738
+ screen.key(['['], () => {
739
+ if (promptOpen()) return;
740
+ switchSource(-1);
741
+ });
742
+
671
743
  screen.key(['q', 'escape', 'C-c'], () => {
672
744
  if (promptOpen()) return;
673
745
  leaveScreen();