tsunami-code 3.11.8 → 3.12.0
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/index.js +12 -6
- package/lib/ui.js +54 -1
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from './lib/memory.js';
|
|
27
27
|
import { listMemories, readMemory, saveMemory, deleteMemory, getMemdirPath } from './lib/memdir.js';
|
|
28
28
|
|
|
29
|
-
const VERSION = '3.
|
|
29
|
+
const VERSION = '3.12.0';
|
|
30
30
|
const CONFIG_DIR = join(os.homedir(), '.tsunami-code');
|
|
31
31
|
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
32
32
|
const DEFAULT_SERVER = 'https://radiometric-reita-amuck.ngrok-free.dev';
|
|
@@ -830,12 +830,18 @@ async function run() {
|
|
|
830
830
|
case 'mode': {
|
|
831
831
|
const m = rest[0]?.toLowerCase();
|
|
832
832
|
if (!m) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
833
|
+
// Interactive arrow-key picker
|
|
834
|
+
const currentIdx = PERM_MODES.indexOf(permMode);
|
|
835
|
+
const selected = await ui.selectFromList(PERM_MODES, currentIdx >= 0 ? currentIdx : 0, blue(' Select permission mode:'));
|
|
836
|
+
if (selected) {
|
|
837
|
+
permMode = selected;
|
|
838
|
+
planMode = selected === 'readonly';
|
|
839
|
+
ui.setPlanMode(planMode);
|
|
840
|
+
updateModeLabel();
|
|
841
|
+
console.log(green(`\n Mode: ${selected}\n`));
|
|
842
|
+
} else {
|
|
843
|
+
console.log(dim(' Cancelled.\n'));
|
|
837
844
|
}
|
|
838
|
-
console.log(dim('\n Usage: /mode <name>\n'));
|
|
839
845
|
break;
|
|
840
846
|
}
|
|
841
847
|
if (!PERM_MODES.includes(m)) {
|
package/lib/ui.js
CHANGED
|
@@ -281,6 +281,59 @@ export function createUI({ planMode: initPlanMode = false, onLine, onTab, onExit
|
|
|
281
281
|
});
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
+
// ── selectFromList — arrow-key interactive picker ─────────────────────────
|
|
285
|
+
function selectFromList(items, initialIdx = 0, header = null) {
|
|
286
|
+
return new Promise((resolve) => {
|
|
287
|
+
let idx = initialIdx;
|
|
288
|
+
const n = items.length;
|
|
289
|
+
const extra = header ? 2 : 0; // header line + blank line
|
|
290
|
+
|
|
291
|
+
if (header) process.stdout.write(`\n${header}\n\n`);
|
|
292
|
+
|
|
293
|
+
function render(isFirst) {
|
|
294
|
+
if (!isFirst) process.stdout.write(`\x1b[${n}A`);
|
|
295
|
+
for (let i = 0; i < n; i++) {
|
|
296
|
+
const active = i === idx;
|
|
297
|
+
const label = active ? ` ${cyan('❯')} ${items[i]}` : ` ${dim(items[i])}`;
|
|
298
|
+
process.stdout.write(`\x1b[2K${label}\n`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
render(true);
|
|
303
|
+
|
|
304
|
+
function clearList() {
|
|
305
|
+
// Erase list + header
|
|
306
|
+
const total = n + extra;
|
|
307
|
+
process.stdout.write(`\x1b[${n}A`); // back to top of list
|
|
308
|
+
for (let i = 0; i < n; i++) process.stdout.write(`\x1b[2K\n`);
|
|
309
|
+
process.stdout.write(`\x1b[${n}A`); // cursor to top of list
|
|
310
|
+
if (extra) {
|
|
311
|
+
process.stdout.write(`\x1b[${extra}A`); // back past header
|
|
312
|
+
for (let i = 0; i < extra; i++) process.stdout.write(`\x1b[2K\n`);
|
|
313
|
+
process.stdout.write(`\x1b[${extra}A`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
lineHandler = (key) => {
|
|
318
|
+
if (key === '\x1b[A') {
|
|
319
|
+
idx = (idx - 1 + n) % n;
|
|
320
|
+
render(false);
|
|
321
|
+
} else if (key === '\x1b[B') {
|
|
322
|
+
idx = (idx + 1) % n;
|
|
323
|
+
render(false);
|
|
324
|
+
} else if (key === '\r' || key === '\n') {
|
|
325
|
+
lineHandler = null;
|
|
326
|
+
clearList();
|
|
327
|
+
resolve(items[idx]);
|
|
328
|
+
} else if (key === '\x1b' || key === '\x03') {
|
|
329
|
+
lineHandler = null;
|
|
330
|
+
clearList();
|
|
331
|
+
resolve(null);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
284
337
|
function readChar(promptText) {
|
|
285
338
|
return new Promise((resolve) => {
|
|
286
339
|
process.stdout.write(promptText);
|
|
@@ -374,7 +427,7 @@ export function createUI({ planMode: initPlanMode = false, onLine, onTab, onExit
|
|
|
374
427
|
return {
|
|
375
428
|
start, pause, resume,
|
|
376
429
|
setPlanMode, setContinuation, setModelLabel, setModeLabel,
|
|
377
|
-
readLine, readChar,
|
|
430
|
+
readLine, readChar, selectFromList,
|
|
378
431
|
wasInterrupted, stop, exitUI,
|
|
379
432
|
};
|
|
380
433
|
}
|