termux-dev 1.9.8 → 1.9.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 +4 -0
- package/assets/banner.svg +1 -1
- package/assets/preview.svg +1 -1
- package/dist/cli/typeahead.js +32 -8
- package/dist/cli/width.js +32 -0
- package/dist/core/types.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,10 @@ Built specifically for **Android Termux**, **Windows**, **macOS**, and **Linux**
|
|
|
22
22
|
|
|
23
23
|
<br/><br/>
|
|
24
24
|
|
|
25
|
+
<a href="assets/demo.mp4"><img src="assets/demo.gif" alt="devx demo: plan, build, test, preview with a QR code" width="880" /></a>
|
|
26
|
+
|
|
27
|
+
<br/>
|
|
28
|
+
|
|
25
29
|
<img src="assets/preview.svg" alt="The devx terminal interface" width="880" />
|
|
26
30
|
|
|
27
31
|
</div>
|
package/assets/banner.svg
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<rect width="1000" height="280" fill="url(#bg)"/>
|
|
17
17
|
</g>
|
|
18
18
|
<rect x="1.5" y="1.5" width="997" height="277" rx="18" fill="none" stroke="#23252c" stroke-width="1.5"/>
|
|
19
|
-
<text x="500.0" y="70" text-anchor="middle" font-family="'Inter',system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif" font-size="13" font-weight="600" letter-spacing="5" fill="#7d8896">THE TERMINAL-NATIVE AI CODING AGENT<tspan dx="16" fill="#2fe3ee" font-weight="700">v1.9.
|
|
19
|
+
<text x="500.0" y="70" text-anchor="middle" font-family="'Inter',system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif" font-size="13" font-weight="600" letter-spacing="5" fill="#7d8896">THE TERMINAL-NATIVE AI CODING AGENT<tspan dx="16" fill="#2fe3ee" font-weight="700">v1.9.9</tspan></text>
|
|
20
20
|
<g>
|
|
21
21
|
<text x="500.0" y="178" text-anchor="middle" font-family="'JetBrains Mono','Fira Code','SF Mono',ui-monospace,Menlo,Consolas,'DejaVu Sans Mono',monospace" font-size="112" font-weight="800" letter-spacing="14" fill="#2fe3ee">DEVX</text>
|
|
22
22
|
</g>
|
package/assets/preview.svg
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<rect x="595.2" y="574.0" width="243.2" height="19" fill="#000000"/>
|
|
33
33
|
<text x="44.8" y="62.0" class="t" fill="#b794f6">▌</text>
|
|
34
34
|
<text x="61.6" y="62.0" class="t b" fill="#f4f7fb">devx</text>
|
|
35
|
-
<text x="112.0" y="62.0" class="t" fill="#5f6b7a">v1.9.
|
|
35
|
+
<text x="112.0" y="62.0" class="t" fill="#5f6b7a">v1.9.9</text>
|
|
36
36
|
<text x="61.6" y="106.0" class="t" fill="#5f6b7a">model</text>
|
|
37
37
|
<text x="128.8" y="106.0" class="t" fill="#e5eaf1">deepseek-v4.1-flash · think high</text>
|
|
38
38
|
<text x="406.0" y="106.0" class="t" fill="#5f6b7a">/model</text>
|
package/dist/cli/typeahead.js
CHANGED
|
@@ -3,7 +3,7 @@ import os from 'os';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { extendedKeysOff, extendedKeysOn, isNewlineKey, normalizeKey, splitKeys } from './keys.js';
|
|
5
5
|
import { buildPromptFrame, palette } from './ui.js';
|
|
6
|
-
import { displayWidth, truncateWidth } from './width.js';
|
|
6
|
+
import { columnAfter, displayWidth, truncateWidth } from './width.js';
|
|
7
7
|
import { t } from '../core/i18n.js';
|
|
8
8
|
/** The down arrow in every form a terminal may send it: `ESC [ B`, `ESC O B` (application mode), `ESC [ 1 ; mods B` (with modifier fields). */
|
|
9
9
|
const DOWN_ARROW = /^\x1b(?:\[|O)(?:1;[\d:]+)?B$/;
|
|
@@ -153,6 +153,8 @@ export class TurnComposer {
|
|
|
153
153
|
state = { text: '', cursor: 0 };
|
|
154
154
|
queue = [];
|
|
155
155
|
lines = [];
|
|
156
|
+
/** The column the output cursor is in: the frame is drawn under it and the cursor comes back to this column. */
|
|
157
|
+
col = 0;
|
|
156
158
|
original = null;
|
|
157
159
|
timer = null;
|
|
158
160
|
/** Called on ctrl+p (thinking) and ctrl+o (tool output). */
|
|
@@ -207,6 +209,7 @@ export class TurnComposer {
|
|
|
207
209
|
this.active = true;
|
|
208
210
|
this.suspended = false;
|
|
209
211
|
this.shown = false;
|
|
212
|
+
this.col = 0;
|
|
210
213
|
this.original = this.out.write.bind(this.out);
|
|
211
214
|
this.out.write = ((chunk, encoding, cb) => this.through(chunk, encoding, cb));
|
|
212
215
|
this.write(extendedKeysOn() + this.drawSeq());
|
|
@@ -298,17 +301,27 @@ export class TurnComposer {
|
|
|
298
301
|
/** The write that replaces the terminal's own for the length of the turn. */
|
|
299
302
|
through(chunk, encoding, cb) {
|
|
300
303
|
const raw = this.original;
|
|
301
|
-
|
|
304
|
+
const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');
|
|
305
|
+
if (!this.active || this.suspended) {
|
|
306
|
+
this.advanceColumn(text);
|
|
302
307
|
return raw(chunk, encoding, cb);
|
|
308
|
+
}
|
|
309
|
+
// The old frame is wiped from the column the cursor is in now; the new one comes back to the column the text ends in.
|
|
310
|
+
const erase = this.eraseSeq();
|
|
311
|
+
this.advanceColumn(text);
|
|
303
312
|
if (typeof chunk === 'string') {
|
|
304
313
|
// The callback form `write(chunk, cb)` has the callback in the second place.
|
|
305
|
-
return raw(
|
|
314
|
+
return raw(erase + chunk + this.drawSeq(), encoding, cb);
|
|
306
315
|
}
|
|
307
|
-
raw(
|
|
316
|
+
raw(erase);
|
|
308
317
|
const result = raw(chunk, encoding, cb);
|
|
309
318
|
raw(this.drawSeq());
|
|
310
319
|
return result;
|
|
311
320
|
}
|
|
321
|
+
/** Where the cursor is after this text (also while a card has the screen, so that the frame comes back to the right column). */
|
|
322
|
+
advanceColumn(text) {
|
|
323
|
+
this.col = columnAfter(this.col, text, this.out.columns ?? 80);
|
|
324
|
+
}
|
|
312
325
|
write(text) {
|
|
313
326
|
if (text)
|
|
314
327
|
(this.original ?? this.out.write.bind(this.out))(text);
|
|
@@ -339,14 +352,25 @@ export class TurnComposer {
|
|
|
339
352
|
oneRow(line) {
|
|
340
353
|
return line.replace(/[\r\n\x00-\x08\x0b-\x1a\x1c-\x1f]+/g, ' ');
|
|
341
354
|
}
|
|
342
|
-
/**
|
|
355
|
+
/** Puts the cursor back in the column of the output, on the row it is on. */
|
|
356
|
+
backToColumn() {
|
|
357
|
+
const cols = Math.max(1, this.out.columns ?? 80);
|
|
358
|
+
return `\x1b[${Math.min(this.col, cols - 1) + 1}G`;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Wipes the frame: everything under the cursor row. The cursor stays on its text.
|
|
362
|
+
*
|
|
363
|
+
* Only relative moves are used, no saved cursor (ESC 7 / ESC 8): the saved position is a screen row,
|
|
364
|
+
* and when the window changes size in the middle of a write (the keyboard of a phone comes and goes)
|
|
365
|
+
* some terminals do not move it with the text, and the cursor comes back to the wrong row.
|
|
366
|
+
*/
|
|
343
367
|
eraseSeq() {
|
|
344
368
|
if (!this.shown)
|
|
345
369
|
return '';
|
|
346
370
|
this.shown = false;
|
|
347
371
|
// The erase starts from plain attributes: a style left on by the text above (an underline, a
|
|
348
372
|
// background) would be painted into every row it wipes (stripes across the screen).
|
|
349
|
-
return '\
|
|
373
|
+
return '\x1b[0m\x1b[1B\r\x1b[J\x1b[1A' + this.backToColumn();
|
|
350
374
|
}
|
|
351
375
|
/** Draws the frame under the cursor row and puts the cursor back where the text goes on. */
|
|
352
376
|
drawSeq() {
|
|
@@ -358,9 +382,9 @@ export class TurnComposer {
|
|
|
358
382
|
// The real cursor only marks where the output goes on. Whatever showed it in the meantime
|
|
359
383
|
// (an approval card, a spinner that stopped) must not leave it blinking under the output.
|
|
360
384
|
// ESC D moves down (scrolling at the bottom edge) and keeps the column; then back up.
|
|
361
|
-
let seq = '\x1b[?25l' + '\x1bD'.repeat(n) + `\x1b[${n}A
|
|
385
|
+
let seq = '\x1b[?25l' + '\x1bD'.repeat(n) + `\x1b[${n}A`;
|
|
362
386
|
for (const line of lines)
|
|
363
387
|
seq += `\x1b[0m\x1b[1B\r\x1b[2K${line}\x1b[0m`;
|
|
364
|
-
return seq +
|
|
388
|
+
return seq + `\x1b[${n}A` + this.backToColumn();
|
|
365
389
|
}
|
|
366
390
|
}
|
package/dist/cli/width.js
CHANGED
|
@@ -289,3 +289,35 @@ export function rowsToTop(lineWidths, cursorRow, cursorCol, cols) {
|
|
|
289
289
|
rows += Math.max(1, Math.ceil(lineWidths[i] / width));
|
|
290
290
|
return rows + Math.floor(Math.max(0, cursorCol) / width);
|
|
291
291
|
}
|
|
292
|
+
/**
|
|
293
|
+
* The column (0-based, in cells) the cursor is in after `text` is written starting at column `col`
|
|
294
|
+
* of a terminal `cols` wide. Escape sequences take no room; a line break and a carriage return go
|
|
295
|
+
* to column 0; a character that does not fit wraps to the next row. A cursor that has just filled
|
|
296
|
+
* the last column is reported as `cols` (the terminal holds it there until the next character).
|
|
297
|
+
*/
|
|
298
|
+
export function columnAfter(col, text, cols) {
|
|
299
|
+
const width = Math.max(1, cols);
|
|
300
|
+
let at = Math.max(0, Math.min(col, width));
|
|
301
|
+
const plain = text.replace(ANSI, '').replace(/\x1b[0-9A-Za-z=>]/g, '');
|
|
302
|
+
for (const ch of plain) {
|
|
303
|
+
if (ch === '\n' || ch === '\r') {
|
|
304
|
+
at = 0;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (ch === '\b') {
|
|
308
|
+
at = Math.max(0, at - 1);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (ch === '\t') {
|
|
312
|
+
at = Math.min(width - 1, (Math.floor(at / 8) + 1) * 8);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const w = codePointWidth(ch.codePointAt(0));
|
|
316
|
+
if (w === 0)
|
|
317
|
+
continue;
|
|
318
|
+
if (at + w > width)
|
|
319
|
+
at = 0;
|
|
320
|
+
at += w;
|
|
321
|
+
}
|
|
322
|
+
return at;
|
|
323
|
+
}
|
package/dist/core/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const DEVX_VERSION = '1.9.
|
|
1
|
+
export const DEVX_VERSION = '1.9.9';
|
package/package.json
CHANGED