termux-dev 1.4.2 → 1.4.4
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/assets/banner.svg +1 -1
- package/dist/cli/doctor.js +1 -1
- package/dist/cli/headless.js +1 -1
- package/dist/cli/index.js +6 -6
- package/dist/cli/prompt.js +88 -52
- package/dist/cli/server.js +1 -1
- package/dist/mcp/client.js +1 -1
- package/package.json +1 -1
package/assets/banner.svg
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<!-- Tagline & Badge -->
|
|
27
27
|
<text x="425" y="142" font-family="system-ui, -apple-system, sans-serif" font-size="14" font-weight="600" fill="#8b949e" text-anchor="middle" letter-spacing="3">
|
|
28
|
-
THE TERMINAL-NATIVE AI CODING AGENT <tspan fill="#00f2fe" font-weight="bold">v1.4.
|
|
28
|
+
THE TERMINAL-NATIVE AI CODING AGENT <tspan fill="#00f2fe" font-weight="bold">v1.4.4</tspan>
|
|
29
29
|
</text>
|
|
30
30
|
|
|
31
31
|
<!-- Top Accent Line -->
|
package/dist/cli/doctor.js
CHANGED
|
@@ -18,7 +18,7 @@ async function pingUrl(url) {
|
|
|
18
18
|
const req = https.get(url, {
|
|
19
19
|
timeout: 3000,
|
|
20
20
|
headers: {
|
|
21
|
-
'User-Agent': 'devx-doctor/1.4.
|
|
21
|
+
'User-Agent': 'devx-doctor/1.4.4'
|
|
22
22
|
}
|
|
23
23
|
}, (res) => {
|
|
24
24
|
res.resume(); // consume response data to free up memory and release socket
|
package/dist/cli/headless.js
CHANGED
|
@@ -35,7 +35,7 @@ export async function runHeadlessMode(userPrompt, config, options = {}) {
|
|
|
35
35
|
});
|
|
36
36
|
try {
|
|
37
37
|
if (!isQuiet && !isJson) {
|
|
38
|
-
console.log(pc.bold(pc.cyan(`⚡ devx v1.4.
|
|
38
|
+
console.log(pc.bold(pc.cyan(`⚡ devx v1.4.4 (headless) | ${planMode ? 'PLAN' : 'AGENT'} | ${config.model}`)));
|
|
39
39
|
console.log(pc.dim(`Task: ${userPrompt}\n`));
|
|
40
40
|
}
|
|
41
41
|
for await (const event of agent.run(abortController.signal)) {
|
package/dist/cli/index.js
CHANGED
|
@@ -484,7 +484,7 @@ function drawLogo() {
|
|
|
484
484
|
theme.colorFn(' █▀▀▄ █▀▀▀ █ █ █ █'),
|
|
485
485
|
theme.colorFn(' █ █ █▀▀▀ ▀▄▀ ▀▄▀ '),
|
|
486
486
|
theme.colorFn(' █▄▄▀ █▄▄▄ ▀ ▀ ▀ '),
|
|
487
|
-
' ' + theme.boldFn('v1.4.
|
|
487
|
+
' ' + theme.boldFn('v1.4.4'),
|
|
488
488
|
''
|
|
489
489
|
];
|
|
490
490
|
for (const line of logo) {
|
|
@@ -499,7 +499,7 @@ function drawLogo() {
|
|
|
499
499
|
indent + theme.colorFn('▀▀▀█▀▀▀ █▀▀▀ █▀▀█ █▄ ▄█ █ █ ▀▄ ▄▀ █▀▀▄ █▀▀▀ █ █'),
|
|
500
500
|
indent + theme.colorFn(' █ █▀▀▀ █▄▄▀ █ █ █ █ █ █ ▀▀ █ █ █▀▀▀ █ █'),
|
|
501
501
|
indent + theme.colorFn(' █ █▄▄▄ █ ▀▄ █ █ ▀▄▄▀ ▄▀ ▀▄ █▄▄▀ █▄▄▄ ▀▄▀ '),
|
|
502
|
-
indent + theme.boldFn('v1.4.
|
|
502
|
+
indent + theme.boldFn('v1.4.4'),
|
|
503
503
|
''
|
|
504
504
|
];
|
|
505
505
|
for (const line of logo) {
|
|
@@ -645,7 +645,7 @@ async function handleSettings(config) {
|
|
|
645
645
|
const maxIterLabel = maxIter >= 9999 ? 'Unlimited' : `${maxIter} steps`;
|
|
646
646
|
const currentTh = getCurrentTheme();
|
|
647
647
|
const choice = await select({
|
|
648
|
-
message: `${pc.bold('⚙️ Settings')} ${pc.dim(`(devx v1.4.
|
|
648
|
+
message: `${pc.bold('⚙️ Settings')} ${pc.dim(`(devx v1.4.4 • theme: ${currentTh.name})`)}`,
|
|
649
649
|
choices: [
|
|
650
650
|
{
|
|
651
651
|
name: `🎨 Color Theme: ${currentTh.emoji} ${currentTh.name}`,
|
|
@@ -686,7 +686,7 @@ async function handleSettings(config) {
|
|
|
686
686
|
description: 'Limit how many tool steps (file edits, terminal commands) agent can do per request'
|
|
687
687
|
},
|
|
688
688
|
{
|
|
689
|
-
name: `${currentTh.colorFn('✨ About devx')} ${pc.dim('(v1.4.
|
|
689
|
+
name: `${currentTh.colorFn('✨ About devx')} ${pc.dim('(v1.4.4 by ApvCode)')}`,
|
|
690
690
|
value: 'about',
|
|
691
691
|
description: 'Terminal-Native AI Coding Agent created by ApvCode (https://github.com/apvcode/Termux-Dev)'
|
|
692
692
|
},
|
|
@@ -702,7 +702,7 @@ async function handleSettings(config) {
|
|
|
702
702
|
continue;
|
|
703
703
|
}
|
|
704
704
|
if (choice === 'about') {
|
|
705
|
-
p.note(`⚡ devx v1.4.
|
|
705
|
+
p.note(`⚡ devx v1.4.4 — Terminal-Native AI Coding Agent\n` +
|
|
706
706
|
`🎨 Theme: ${currentTh.emoji} ${currentTh.name}\n` +
|
|
707
707
|
`👤 Author: ApvCode (https://github.com/apvcode)\n` +
|
|
708
708
|
`🌟 Repository: https://github.com/apvcode/Termux-Dev\n` +
|
|
@@ -771,7 +771,7 @@ export async function main() {
|
|
|
771
771
|
program
|
|
772
772
|
.name('devx')
|
|
773
773
|
.description('Terminal-native AI coding assistant and vibe-coding agent')
|
|
774
|
-
.version('1.4.
|
|
774
|
+
.version('1.4.4')
|
|
775
775
|
.option('-p, --prompt <task>', 'Run one-shot task non-interactively (headless mode)')
|
|
776
776
|
.option('-y, --yolo', 'Automatically approve all tool executions without confirmation')
|
|
777
777
|
.option('-m, --model <model>', 'Specify AI model to use for this execution')
|
package/dist/cli/prompt.js
CHANGED
|
@@ -43,6 +43,7 @@ export function askPrompt(opts = {}) {
|
|
|
43
43
|
let cursorPos = input.length;
|
|
44
44
|
let selectedIndex = 0;
|
|
45
45
|
let lastDropdownLines = 0;
|
|
46
|
+
let lastCursorLine = 0;
|
|
46
47
|
let disposed = false;
|
|
47
48
|
let historyIndex = GLOBAL_PROMPT_HISTORY.length;
|
|
48
49
|
let tempDraft = '';
|
|
@@ -229,7 +230,27 @@ export function askPrompt(opts = {}) {
|
|
|
229
230
|
}
|
|
230
231
|
dropdownLines.push(pc.dim('│') + ' ' + pc.dim('╰' + botBorderStr + '╯'));
|
|
231
232
|
}
|
|
232
|
-
//
|
|
233
|
+
// Calculate cursor position
|
|
234
|
+
// Calculate how many wrapped lines inputDisplay occupies
|
|
235
|
+
const plainAll = stripAnsi(pc.dim('│') + ' ' + formatInputWithBadges(input));
|
|
236
|
+
const allLines = plainAll.split('\n');
|
|
237
|
+
let totalInputLines = 0;
|
|
238
|
+
for (const l of allLines) {
|
|
239
|
+
totalInputLines += l.length === 0 ? 1 : Math.max(1, Math.floor((l.length - 1) / cols) + 1);
|
|
240
|
+
}
|
|
241
|
+
// Calculate where the cursor is inside inputDisplay
|
|
242
|
+
const plainBefore = stripAnsi(pc.dim('│') + ' ' + formatInputWithBadges(input.slice(0, cursorPos)));
|
|
243
|
+
const linesBefore = plainBefore.split('\n');
|
|
244
|
+
let curLine = 0;
|
|
245
|
+
for (let i = 0; i < linesBefore.length - 1; i++) {
|
|
246
|
+
const l = linesBefore[i];
|
|
247
|
+
curLine += l.length === 0 ? 1 : Math.max(1, Math.floor((l.length - 1) / cols) + 1);
|
|
248
|
+
}
|
|
249
|
+
const lastLineSegment = linesBefore[linesBefore.length - 1];
|
|
250
|
+
const wrapOffsetInLastLine = Math.floor(lastLineSegment.length / cols);
|
|
251
|
+
curLine += wrapOffsetInLastLine;
|
|
252
|
+
const curCol = lastLineSegment.length % cols;
|
|
253
|
+
// 1. Single-line fast path (flicker-free atomic render)
|
|
233
254
|
let inputDisplay = pc.dim('│') + ' ';
|
|
234
255
|
if (input.length === 0) {
|
|
235
256
|
const maxPlace = Math.max(12, cols - 8);
|
|
@@ -239,24 +260,34 @@ export function askPrompt(opts = {}) {
|
|
|
239
260
|
else {
|
|
240
261
|
inputDisplay += formatInputWithBadges(input);
|
|
241
262
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
263
|
+
if (totalInputLines === 1 && dropdownLines.length === 0 && lastCursorLine === 0 && lastDropdownLines === 0) {
|
|
264
|
+
process.stdout.write(`\r\x1b[2K${inputDisplay}`);
|
|
265
|
+
process.stdout.write(`\r\x1b[${curCol}C`);
|
|
266
|
+
lastCursorLine = 0;
|
|
267
|
+
lastDropdownLines = 0;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// 2. Multi-line / dropdown path: move to Line 0 and erase down
|
|
271
|
+
if (lastCursorLine > 0) {
|
|
272
|
+
process.stdout.write(`\x1b[${lastCursorLine}A`);
|
|
273
|
+
}
|
|
274
|
+
process.stdout.write('\r\x1b[J');
|
|
275
|
+
process.stdout.write(inputDisplay);
|
|
276
|
+
if (dropdownLines.length > 0) {
|
|
277
|
+
for (const dl of dropdownLines) {
|
|
278
|
+
process.stdout.write(`\n${dl}`);
|
|
253
279
|
}
|
|
254
|
-
// 3. Move cursor back UP to prompt line (line 0) at cursorPos column
|
|
255
|
-
process.stdout.write(`\x1b[${totalLinesToProcess}A\r\x1b[${3 + cursorPos}C`);
|
|
256
280
|
}
|
|
257
|
-
|
|
258
|
-
|
|
281
|
+
const totalBottomLine = (totalInputLines - 1) + dropdownLines.length;
|
|
282
|
+
const linesUp = totalBottomLine - curLine;
|
|
283
|
+
if (linesUp > 0) {
|
|
284
|
+
process.stdout.write(`\x1b[${linesUp}A`);
|
|
259
285
|
}
|
|
286
|
+
process.stdout.write('\r');
|
|
287
|
+
if (curCol > 0) {
|
|
288
|
+
process.stdout.write(`\x1b[${curCol}C`);
|
|
289
|
+
}
|
|
290
|
+
lastCursorLine = curLine;
|
|
260
291
|
lastDropdownLines = dropdownLines.length;
|
|
261
292
|
}
|
|
262
293
|
render();
|
|
@@ -272,13 +303,10 @@ export function askPrompt(opts = {}) {
|
|
|
272
303
|
process.stdin.pause();
|
|
273
304
|
}
|
|
274
305
|
function clearBoxAndExit(finalInput) {
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
process.stdout.write(`\n\x1b[2K`);
|
|
278
|
-
}
|
|
279
|
-
process.stdout.write(`\x1b[${lastDropdownLines}A\r`);
|
|
280
|
-
lastDropdownLines = 0;
|
|
306
|
+
if (lastCursorLine > 0) {
|
|
307
|
+
process.stdout.write(`\x1b[${lastCursorLine}A`);
|
|
281
308
|
}
|
|
309
|
+
process.stdout.write('\r\x1b[J');
|
|
282
310
|
const fullText = expandPastes(finalInput);
|
|
283
311
|
if (fullText.trim()) {
|
|
284
312
|
if (GLOBAL_PROMPT_HISTORY.length === 0 || GLOBAL_PROMPT_HISTORY[GLOBAL_PROMPT_HISTORY.length - 1] !== fullText.trim()) {
|
|
@@ -412,14 +440,10 @@ export function askPrompt(opts = {}) {
|
|
|
412
440
|
}
|
|
413
441
|
// Ctrl+C
|
|
414
442
|
if (str === '\x03' || (str.length === 1 && str.charCodeAt(0) === 3)) {
|
|
415
|
-
if (
|
|
416
|
-
|
|
417
|
-
process.stdout.write(`\n\x1b[2K`);
|
|
418
|
-
}
|
|
419
|
-
process.stdout.write(`\x1b[${lastDropdownLines}A\r`);
|
|
420
|
-
lastDropdownLines = 0;
|
|
443
|
+
if (lastCursorLine > 0) {
|
|
444
|
+
process.stdout.write(`\x1b[${lastCursorLine}A`);
|
|
421
445
|
}
|
|
422
|
-
process.stdout.write(
|
|
446
|
+
process.stdout.write('\r\x1b[J\n');
|
|
423
447
|
cleanup();
|
|
424
448
|
resolve('__CANCEL__');
|
|
425
449
|
return;
|
|
@@ -479,14 +503,10 @@ export function askPrompt(opts = {}) {
|
|
|
479
503
|
render();
|
|
480
504
|
}
|
|
481
505
|
else {
|
|
482
|
-
if (
|
|
483
|
-
|
|
484
|
-
process.stdout.write(`\n\x1b[2K`);
|
|
485
|
-
}
|
|
486
|
-
process.stdout.write(`\x1b[${lastDropdownLines}A\r`);
|
|
487
|
-
lastDropdownLines = 0;
|
|
506
|
+
if (lastCursorLine > 0) {
|
|
507
|
+
process.stdout.write(`\x1b[${lastCursorLine}A`);
|
|
488
508
|
}
|
|
489
|
-
process.stdout.write(
|
|
509
|
+
process.stdout.write('\r\x1b[J');
|
|
490
510
|
cleanup();
|
|
491
511
|
resolve(`__TOGGLE_MODE__:${input}`);
|
|
492
512
|
}
|
|
@@ -592,36 +612,52 @@ export function askPrompt(opts = {}) {
|
|
|
592
612
|
}
|
|
593
613
|
return;
|
|
594
614
|
}
|
|
595
|
-
// Backspace
|
|
596
|
-
if (str
|
|
597
|
-
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
615
|
+
// Backspace / DEL handling (handles single or multiple backspaces from mobile IME)
|
|
616
|
+
if (str.includes('\x08') || str.includes('\x7f')) {
|
|
617
|
+
for (let i = 0; i < str.length; i++) {
|
|
618
|
+
const ch = str[i];
|
|
619
|
+
if (ch === '\x08' || ch === '\x7f') {
|
|
620
|
+
if (cursorPos > 0) {
|
|
621
|
+
const spans = getTagSpans();
|
|
622
|
+
const endingSpan = spans.find(s => s.end === cursorPos);
|
|
623
|
+
if (endingSpan) {
|
|
624
|
+
input = input.slice(0, endingSpan.start) + input.slice(endingSpan.end);
|
|
625
|
+
cursorPos = endingSpan.start;
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
input = input.slice(0, cursorPos - 1) + input.slice(cursorPos);
|
|
629
|
+
cursorPos--;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
603
632
|
}
|
|
604
|
-
else {
|
|
605
|
-
|
|
606
|
-
cursorPos
|
|
633
|
+
else if (ch.charCodeAt(0) >= 32) {
|
|
634
|
+
const spans = getTagSpans();
|
|
635
|
+
const inside = spans.find(s => cursorPos > s.start && cursorPos < s.end);
|
|
636
|
+
if (inside)
|
|
637
|
+
cursorPos = inside.end;
|
|
638
|
+
input = input.slice(0, cursorPos) + ch + input.slice(cursorPos);
|
|
639
|
+
cursorPos++;
|
|
607
640
|
}
|
|
608
|
-
selectedIndex = 0;
|
|
609
|
-
render();
|
|
610
641
|
}
|
|
642
|
+
selectedIndex = 0;
|
|
643
|
+
render();
|
|
611
644
|
return;
|
|
612
645
|
}
|
|
613
646
|
// Ignore unknown escape sequences
|
|
614
647
|
if (str.startsWith('\x1b')) {
|
|
615
648
|
return;
|
|
616
649
|
}
|
|
617
|
-
// Normal character input -
|
|
650
|
+
// Normal character input - clean control characters
|
|
651
|
+
const cleanStr = str.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '');
|
|
652
|
+
if (!cleanStr)
|
|
653
|
+
return;
|
|
618
654
|
const spans = getTagSpans();
|
|
619
655
|
const inside = spans.find(s => cursorPos > s.start && cursorPos < s.end);
|
|
620
656
|
if (inside) {
|
|
621
657
|
cursorPos = inside.end;
|
|
622
658
|
}
|
|
623
|
-
input = input.slice(0, cursorPos) +
|
|
624
|
-
cursorPos +=
|
|
659
|
+
input = input.slice(0, cursorPos) + cleanStr + input.slice(cursorPos);
|
|
660
|
+
cursorPos += cleanStr.length;
|
|
625
661
|
selectedIndex = 0;
|
|
626
662
|
render();
|
|
627
663
|
}
|
package/dist/cli/server.js
CHANGED
|
@@ -139,7 +139,7 @@ function renderDirectoryHtml(dirPath, relPath, files, port) {
|
|
|
139
139
|
${parentLink}
|
|
140
140
|
${items || '<li style="padding: 20px; text-align: center; color: #6e7681;">No visible files in this directory</li>'}
|
|
141
141
|
</ul>
|
|
142
|
-
<div class="footer">devx v1.4.
|
|
142
|
+
<div class="footer">devx v1.4.4 • Terminal-Native AI Assistant</div>
|
|
143
143
|
</div>
|
|
144
144
|
</body>
|
|
145
145
|
</html>`;
|
package/dist/mcp/client.js
CHANGED
package/package.json
CHANGED