termux-dev 1.4.3 → 1.4.5
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/assets/preview_work1.png +0 -0
- 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 +121 -79
- 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.5</tspan>
|
|
29
29
|
</text>
|
|
30
30
|
|
|
31
31
|
<!-- Top Accent Line -->
|
|
Binary file
|
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.5'
|
|
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.5 (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.5'),
|
|
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.5'),
|
|
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.5 • 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.5 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.5 — 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.5')
|
|
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
|
@@ -202,13 +202,11 @@ export function askPrompt(opts = {}) {
|
|
|
202
202
|
const availWidth = innerBoxWidth - 2;
|
|
203
203
|
let row = '';
|
|
204
204
|
if (availWidth < 20) {
|
|
205
|
-
// Very narrow mobile screen: show command name only
|
|
206
205
|
const labelStr = item.label.length > availWidth ? item.label.slice(0, availWidth - 1) + '…' : item.label.padEnd(availWidth);
|
|
207
206
|
const plain = pointer + labelStr;
|
|
208
207
|
row = isSelected ? theme.badgeFn(plain) : (pointer + theme.boldFn(labelStr));
|
|
209
208
|
}
|
|
210
209
|
else {
|
|
211
|
-
// Show command name and truncated description
|
|
212
210
|
const labelMax = Math.min(15, Math.floor(availWidth * 0.45));
|
|
213
211
|
const labelStr = item.label.length > labelMax ? item.label.slice(0, labelMax - 1) + '…' : item.label.padEnd(labelMax);
|
|
214
212
|
const descMax = availWidth - labelMax - 1;
|
|
@@ -221,7 +219,6 @@ export function askPrompt(opts = {}) {
|
|
|
221
219
|
row = `${pointer}${theme.boldFn(labelStr)} ${pc.gray(descStr)}`;
|
|
222
220
|
}
|
|
223
221
|
}
|
|
224
|
-
// Safety guarantee: exact visible width must match innerBoxWidth
|
|
225
222
|
const currentLen = stripAnsi(row).length;
|
|
226
223
|
if (currentLen < innerBoxWidth) {
|
|
227
224
|
row += ' '.repeat(innerBoxWidth - currentLen);
|
|
@@ -230,59 +227,78 @@ export function askPrompt(opts = {}) {
|
|
|
230
227
|
}
|
|
231
228
|
dropdownLines.push(pc.dim('│') + ' ' + pc.dim('╰' + botBorderStr + '╯'));
|
|
232
229
|
}
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
let
|
|
230
|
+
// === SCROLLING SINGLE-LINE INPUT (never wraps, works on all terminals) ===
|
|
231
|
+
const prefix = pc.dim('│') + ' ';
|
|
232
|
+
const prefixLen = 3; // visible width of "│ "
|
|
233
|
+
// Reserve 1 char safety margin so terminal never auto-wraps
|
|
234
|
+
const maxVisible = cols - prefixLen - 1;
|
|
235
|
+
let lineContent;
|
|
236
|
+
let screenCursorCol;
|
|
240
237
|
if (input.length === 0) {
|
|
241
|
-
|
|
242
|
-
const displayPlace = placeholder.length >
|
|
243
|
-
|
|
238
|
+
// Show placeholder
|
|
239
|
+
const displayPlace = placeholder.length > maxVisible ? placeholder.slice(0, maxVisible - 1) + '…' : placeholder;
|
|
240
|
+
lineContent = prefix + pc.dim(displayPlace);
|
|
241
|
+
screenCursorCol = prefixLen;
|
|
242
|
+
}
|
|
243
|
+
else if (input.length <= maxVisible) {
|
|
244
|
+
// Input fits on screen entirely
|
|
245
|
+
lineContent = prefix + formatInputWithBadges(input);
|
|
246
|
+
screenCursorCol = prefixLen + cursorPos;
|
|
244
247
|
}
|
|
245
248
|
else {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
process.stdout.write(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
249
|
+
// Scrolling window: show a slice of input around cursor
|
|
250
|
+
const scrollPad = Math.floor(maxVisible / 3);
|
|
251
|
+
let winStart = 0;
|
|
252
|
+
if (cursorPos > maxVisible - scrollPad) {
|
|
253
|
+
winStart = cursorPos - (maxVisible - scrollPad);
|
|
254
|
+
}
|
|
255
|
+
if (winStart > input.length - maxVisible) {
|
|
256
|
+
winStart = Math.max(0, input.length - maxVisible);
|
|
257
|
+
}
|
|
258
|
+
const winEnd = Math.min(winStart + maxVisible, input.length);
|
|
259
|
+
let visibleSlice = input.slice(winStart, winEnd);
|
|
260
|
+
// Add scroll indicators
|
|
261
|
+
if (winStart > 0) {
|
|
262
|
+
visibleSlice = '…' + visibleSlice.slice(1);
|
|
263
|
+
}
|
|
264
|
+
if (winEnd < input.length) {
|
|
265
|
+
visibleSlice = visibleSlice.slice(0, -1) + '…';
|
|
266
|
+
}
|
|
267
|
+
lineContent = prefix + formatInputWithBadges(visibleSlice);
|
|
268
|
+
screenCursorCol = prefixLen + (cursorPos - winStart);
|
|
269
|
+
// Clamp cursor position for scroll indicator adjustments
|
|
270
|
+
if (winStart > 0 && cursorPos === winStart) {
|
|
271
|
+
screenCursorCol = prefixLen + 1;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Pad line to exactly cols-1 to overwrite any stale characters
|
|
275
|
+
const visLen = stripAnsi(lineContent).length;
|
|
276
|
+
if (visLen < cols - 1) {
|
|
277
|
+
lineContent += ' '.repeat(cols - 1 - visLen);
|
|
278
|
+
}
|
|
279
|
+
// Move cursor up past any previous dropdown lines, then clear and redraw
|
|
280
|
+
if (lastDropdownLines > 0) {
|
|
281
|
+
process.stdout.write(`\x1b[${lastDropdownLines}A`);
|
|
282
|
+
}
|
|
283
|
+
// Write input line (always exactly 1 physical line, no wrap)
|
|
284
|
+
process.stdout.write(`\r\x1b[2K${lineContent}`);
|
|
285
|
+
// Write dropdown lines below
|
|
286
|
+
for (let i = 0; i < Math.max(dropdownLines.length, lastDropdownLines); i++) {
|
|
287
|
+
if (i < dropdownLines.length) {
|
|
288
|
+
process.stdout.write(`\n\x1b[2K${dropdownLines[i]}`);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
process.stdout.write(`\n\x1b[2K`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Move cursor back up to the input line
|
|
295
|
+
const totalBelow = Math.max(dropdownLines.length, lastDropdownLines);
|
|
296
|
+
if (totalBelow > 0) {
|
|
297
|
+
process.stdout.write(`\x1b[${totalBelow}A`);
|
|
298
|
+
}
|
|
299
|
+
// Position cursor at the correct column
|
|
300
|
+
process.stdout.write(`\r\x1b[${screenCursorCol}C`);
|
|
301
|
+
lastCursorLine = 0; // Always line 0 now
|
|
286
302
|
lastDropdownLines = dropdownLines.length;
|
|
287
303
|
}
|
|
288
304
|
render();
|
|
@@ -298,10 +314,14 @@ export function askPrompt(opts = {}) {
|
|
|
298
314
|
process.stdin.pause();
|
|
299
315
|
}
|
|
300
316
|
function clearBoxAndExit(finalInput) {
|
|
301
|
-
|
|
302
|
-
|
|
317
|
+
// Clear dropdown lines below
|
|
318
|
+
if (lastDropdownLines > 0) {
|
|
319
|
+
for (let i = 0; i < lastDropdownLines; i++) {
|
|
320
|
+
process.stdout.write(`\n\x1b[2K`);
|
|
321
|
+
}
|
|
322
|
+
process.stdout.write(`\x1b[${lastDropdownLines}A`);
|
|
303
323
|
}
|
|
304
|
-
process.stdout.write(
|
|
324
|
+
process.stdout.write(`\r\x1b[2K`);
|
|
305
325
|
const fullText = expandPastes(finalInput);
|
|
306
326
|
if (fullText.trim()) {
|
|
307
327
|
if (GLOBAL_PROMPT_HISTORY.length === 0 || GLOBAL_PROMPT_HISTORY[GLOBAL_PROMPT_HISTORY.length - 1] !== fullText.trim()) {
|
|
@@ -309,7 +329,7 @@ export function askPrompt(opts = {}) {
|
|
|
309
329
|
}
|
|
310
330
|
}
|
|
311
331
|
const lines = fullText.split('\n');
|
|
312
|
-
process.stdout.write(
|
|
332
|
+
process.stdout.write(`${pc.dim('│')} ${formatInputWithBadges(lines[0])}\n`);
|
|
313
333
|
for (let i = 1; i < lines.length; i++) {
|
|
314
334
|
process.stdout.write(pc.dim('│') + ' ' + lines[i] + '\n');
|
|
315
335
|
}
|
|
@@ -435,10 +455,13 @@ export function askPrompt(opts = {}) {
|
|
|
435
455
|
}
|
|
436
456
|
// Ctrl+C
|
|
437
457
|
if (str === '\x03' || (str.length === 1 && str.charCodeAt(0) === 3)) {
|
|
438
|
-
if (
|
|
439
|
-
|
|
458
|
+
if (lastDropdownLines > 0) {
|
|
459
|
+
for (let i = 0; i < lastDropdownLines; i++) {
|
|
460
|
+
process.stdout.write(`\n\x1b[2K`);
|
|
461
|
+
}
|
|
462
|
+
process.stdout.write(`\x1b[${lastDropdownLines}A`);
|
|
440
463
|
}
|
|
441
|
-
process.stdout.write('\r\x1b[
|
|
464
|
+
process.stdout.write('\r\x1b[2K\n');
|
|
442
465
|
cleanup();
|
|
443
466
|
resolve('__CANCEL__');
|
|
444
467
|
return;
|
|
@@ -498,10 +521,13 @@ export function askPrompt(opts = {}) {
|
|
|
498
521
|
render();
|
|
499
522
|
}
|
|
500
523
|
else {
|
|
501
|
-
if (
|
|
502
|
-
|
|
524
|
+
if (lastDropdownLines > 0) {
|
|
525
|
+
for (let i = 0; i < lastDropdownLines; i++) {
|
|
526
|
+
process.stdout.write(`\n\x1b[2K`);
|
|
527
|
+
}
|
|
528
|
+
process.stdout.write(`\x1b[${lastDropdownLines}A`);
|
|
503
529
|
}
|
|
504
|
-
process.stdout.write('\r\x1b[
|
|
530
|
+
process.stdout.write('\r\x1b[2K');
|
|
505
531
|
cleanup();
|
|
506
532
|
resolve(`__TOGGLE_MODE__:${input}`);
|
|
507
533
|
}
|
|
@@ -607,36 +633,52 @@ export function askPrompt(opts = {}) {
|
|
|
607
633
|
}
|
|
608
634
|
return;
|
|
609
635
|
}
|
|
610
|
-
// Backspace
|
|
611
|
-
if (str
|
|
612
|
-
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
636
|
+
// Backspace / DEL handling (handles single or multiple backspaces from mobile IME)
|
|
637
|
+
if (str.includes('\x08') || str.includes('\x7f')) {
|
|
638
|
+
for (let i = 0; i < str.length; i++) {
|
|
639
|
+
const ch = str[i];
|
|
640
|
+
if (ch === '\x08' || ch === '\x7f') {
|
|
641
|
+
if (cursorPos > 0) {
|
|
642
|
+
const spans = getTagSpans();
|
|
643
|
+
const endingSpan = spans.find(s => s.end === cursorPos);
|
|
644
|
+
if (endingSpan) {
|
|
645
|
+
input = input.slice(0, endingSpan.start) + input.slice(endingSpan.end);
|
|
646
|
+
cursorPos = endingSpan.start;
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
input = input.slice(0, cursorPos - 1) + input.slice(cursorPos);
|
|
650
|
+
cursorPos--;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
618
653
|
}
|
|
619
|
-
else {
|
|
620
|
-
|
|
621
|
-
cursorPos
|
|
654
|
+
else if (ch.charCodeAt(0) >= 32) {
|
|
655
|
+
const spans = getTagSpans();
|
|
656
|
+
const inside = spans.find(s => cursorPos > s.start && cursorPos < s.end);
|
|
657
|
+
if (inside)
|
|
658
|
+
cursorPos = inside.end;
|
|
659
|
+
input = input.slice(0, cursorPos) + ch + input.slice(cursorPos);
|
|
660
|
+
cursorPos++;
|
|
622
661
|
}
|
|
623
|
-
selectedIndex = 0;
|
|
624
|
-
render();
|
|
625
662
|
}
|
|
663
|
+
selectedIndex = 0;
|
|
664
|
+
render();
|
|
626
665
|
return;
|
|
627
666
|
}
|
|
628
667
|
// Ignore unknown escape sequences
|
|
629
668
|
if (str.startsWith('\x1b')) {
|
|
630
669
|
return;
|
|
631
670
|
}
|
|
632
|
-
// Normal character input -
|
|
671
|
+
// Normal character input - clean control characters
|
|
672
|
+
const cleanStr = str.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '');
|
|
673
|
+
if (!cleanStr)
|
|
674
|
+
return;
|
|
633
675
|
const spans = getTagSpans();
|
|
634
676
|
const inside = spans.find(s => cursorPos > s.start && cursorPos < s.end);
|
|
635
677
|
if (inside) {
|
|
636
678
|
cursorPos = inside.end;
|
|
637
679
|
}
|
|
638
|
-
input = input.slice(0, cursorPos) +
|
|
639
|
-
cursorPos +=
|
|
680
|
+
input = input.slice(0, cursorPos) + cleanStr + input.slice(cursorPos);
|
|
681
|
+
cursorPos += cleanStr.length;
|
|
640
682
|
selectedIndex = 0;
|
|
641
683
|
render();
|
|
642
684
|
}
|
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.5 • Terminal-Native AI Assistant</div>
|
|
143
143
|
</div>
|
|
144
144
|
</body>
|
|
145
145
|
</html>`;
|
package/dist/mcp/client.js
CHANGED
package/package.json
CHANGED