termux-dev 1.4.17 → 1.4.19
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 +7 -7
- package/dist/cli/prompt.js +120 -22
- 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.19</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.19'
|
|
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.19 (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.19'),
|
|
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.19'),
|
|
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.19 • 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.19 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.19 — 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` +
|
|
@@ -798,7 +798,7 @@ export async function main() {
|
|
|
798
798
|
program
|
|
799
799
|
.name('devx')
|
|
800
800
|
.description('Terminal-native AI coding assistant and vibe-coding agent')
|
|
801
|
-
.version('1.4.
|
|
801
|
+
.version('1.4.19')
|
|
802
802
|
.option('-p, --prompt <task>', 'Run one-shot task non-interactively (headless mode)')
|
|
803
803
|
.option('-y, --yolo', 'Automatically approve all tool executions without confirmation')
|
|
804
804
|
.option('-m, --model <model>', 'Specify AI model to use for this execution')
|
|
@@ -936,7 +936,7 @@ export async function main() {
|
|
|
936
936
|
message: 'Are you sure you want to exit devx?',
|
|
937
937
|
initialValue: false
|
|
938
938
|
});
|
|
939
|
-
if (p.isCancel(confirmExit)
|
|
939
|
+
if (!p.isCancel(confirmExit) && confirmExit === true) {
|
|
940
940
|
resetTerminalTheme();
|
|
941
941
|
p.outro('Goodbye!');
|
|
942
942
|
break;
|
package/dist/cli/prompt.js
CHANGED
|
@@ -53,6 +53,7 @@ export function askPrompt(opts = {}) {
|
|
|
53
53
|
let input = opts.initialValue || '';
|
|
54
54
|
let cursorPos = input.length;
|
|
55
55
|
let selectedIndex = 0;
|
|
56
|
+
let lastRenderedDropdownLines = 0;
|
|
56
57
|
let historyIndex = GLOBAL_PROMPT_HISTORY.length;
|
|
57
58
|
let tempDraft = '';
|
|
58
59
|
const imageAttachments = [];
|
|
@@ -168,7 +169,80 @@ export function askPrompt(opts = {}) {
|
|
|
168
169
|
if (disposed)
|
|
169
170
|
return;
|
|
170
171
|
const cols = Math.max(20, process.stdout.columns || 40);
|
|
172
|
+
const rows = Math.max(8, process.stdout.rows || 20);
|
|
171
173
|
const items = getDropdownItems();
|
|
174
|
+
const dropdownLines = [];
|
|
175
|
+
if (items.length > 0) {
|
|
176
|
+
if (selectedIndex >= items.length)
|
|
177
|
+
selectedIndex = items.length - 1;
|
|
178
|
+
if (selectedIndex < 0)
|
|
179
|
+
selectedIndex = 0;
|
|
180
|
+
// Limit dropdown height gracefully so it always fits comfortably
|
|
181
|
+
const maxDropdownRows = Math.max(2, Math.min(rows - 3, 5));
|
|
182
|
+
const pageSize = Math.min(4, Math.max(2, Math.min(maxDropdownRows - 2, Math.floor(rows / 4))));
|
|
183
|
+
// Strict boundary: left margin (2) + box borders (2) + inner width <= cols - 4
|
|
184
|
+
// This mathematically prevents terminal auto-wrapping on narrow mobile screens
|
|
185
|
+
const boxWidth = Math.max(12, Math.min(cols - 6, 46));
|
|
186
|
+
const innerWidth = Math.max(8, boxWidth - 2);
|
|
187
|
+
const total = items.length;
|
|
188
|
+
let startIndex = 0;
|
|
189
|
+
if (total > pageSize) {
|
|
190
|
+
if (selectedIndex >= pageSize) {
|
|
191
|
+
startIndex = Math.min(selectedIndex - pageSize + 1, total - pageSize);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const endIndex = Math.min(startIndex + pageSize, total);
|
|
195
|
+
const hasMoreUp = startIndex > 0;
|
|
196
|
+
const hasMoreDown = endIndex < total;
|
|
197
|
+
let topBorderStr = '─'.repeat(innerWidth);
|
|
198
|
+
if (hasMoreUp) {
|
|
199
|
+
const mid = Math.max(0, Math.floor(innerWidth / 2) - 2);
|
|
200
|
+
topBorderStr = '─'.repeat(mid) + ' ▲ ' + '─'.repeat(Math.max(0, innerWidth - mid - 3));
|
|
201
|
+
}
|
|
202
|
+
let botBorderStr = '─'.repeat(innerWidth);
|
|
203
|
+
if (hasMoreDown) {
|
|
204
|
+
const mid = Math.max(0, Math.floor(innerWidth / 2) - 2);
|
|
205
|
+
botBorderStr = '─'.repeat(mid) + ' ▼ ' + '─'.repeat(Math.max(0, innerWidth - mid - 3));
|
|
206
|
+
}
|
|
207
|
+
dropdownLines.push(pc.dim('│ ') + pc.dim('╭' + topBorderStr + '╮') + '\x1b[0m');
|
|
208
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
209
|
+
const item = items[i];
|
|
210
|
+
const isSelected = i === selectedIndex;
|
|
211
|
+
const pointer = isSelected ? '› ' : ' ';
|
|
212
|
+
const avail = Math.max(4, innerWidth - pointer.length);
|
|
213
|
+
let rowText = '';
|
|
214
|
+
if (avail < 16) {
|
|
215
|
+
const labelStr = item.label.length > avail
|
|
216
|
+
? item.label.slice(0, avail - 1) + '…'
|
|
217
|
+
: item.label.padEnd(avail, ' ');
|
|
218
|
+
rowText = pointer + (isSelected ? theme.boldFn(labelStr) : labelStr);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
const labelMax = Math.min(12, Math.max(6, Math.floor(avail * 0.38)));
|
|
222
|
+
const labelStr = item.label.length > labelMax
|
|
223
|
+
? item.label.slice(0, labelMax - 1) + '…'
|
|
224
|
+
: item.label.padEnd(labelMax, ' ');
|
|
225
|
+
const descMax = Math.max(3, avail - labelMax - 1);
|
|
226
|
+
const descStr = item.desc.length > descMax
|
|
227
|
+
? item.desc.slice(0, descMax - 1) + '…'
|
|
228
|
+
: item.desc.padEnd(descMax, ' ');
|
|
229
|
+
rowText = pointer + (isSelected ? theme.boldFn(labelStr) : labelStr) + ' ' + pc.gray(descStr);
|
|
230
|
+
}
|
|
231
|
+
// Calculate visible plain length without ANSI
|
|
232
|
+
const plainLen = rowText.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '').length;
|
|
233
|
+
const padCount = Math.max(0, innerWidth - plainLen);
|
|
234
|
+
const fullRow = rowText + ' '.repeat(padCount);
|
|
235
|
+
if (isSelected) {
|
|
236
|
+
const cleanFull = fullRow.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
237
|
+
dropdownLines.push(pc.dim('│ ') + pc.dim('│') + theme.badgeFn(cleanFull) + pc.dim('│') + '\x1b[0m');
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
dropdownLines.push(pc.dim('│ ') + pc.dim('│') + fullRow + pc.dim('│') + '\x1b[0m');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
dropdownLines.push(pc.dim('│ ') + pc.dim('╰' + botBorderStr + '╯') + '\x1b[0m');
|
|
244
|
+
}
|
|
245
|
+
// 1. Format and write the Prompt line safely
|
|
172
246
|
let inputDisplay = pc.dim('│') + ' ';
|
|
173
247
|
let renderCursorCol = 3;
|
|
174
248
|
if (input.length === 0) {
|
|
@@ -178,28 +252,9 @@ export function askPrompt(opts = {}) {
|
|
|
178
252
|
renderCursorCol = 3;
|
|
179
253
|
}
|
|
180
254
|
else {
|
|
181
|
-
if (selectedIndex >= items.length)
|
|
182
|
-
selectedIndex = Math.max(0, items.length - 1);
|
|
183
|
-
if (selectedIndex < 0)
|
|
184
|
-
selectedIndex = 0;
|
|
185
|
-
const selected = items.length > 0 ? items[selectedIndex] : null;
|
|
186
|
-
// Calculate ghost autocomplete text & badge if available
|
|
187
|
-
let ghostText = '';
|
|
188
|
-
let hintBadge = '';
|
|
189
|
-
if (selected) {
|
|
190
|
-
if (input.startsWith('/') && selected.label.toLowerCase().startsWith(input.toLowerCase())) {
|
|
191
|
-
ghostText = selected.label.slice(input.length);
|
|
192
|
-
const remainingWidth = cols - (3 + input.length + ghostText.length + 8);
|
|
193
|
-
if (remainingWidth > 12) {
|
|
194
|
-
const maxDesc = Math.min(remainingWidth, 32);
|
|
195
|
-
const descStr = selected.desc.length > maxDesc ? selected.desc.slice(0, maxDesc - 1) + '…' : selected.desc;
|
|
196
|
-
hintBadge = ' ' + pc.dim('•') + ' ' + pc.gray(descStr);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
255
|
const maxInputLen = Math.max(10, cols - 6);
|
|
201
256
|
if (input.length <= maxInputLen) {
|
|
202
|
-
inputDisplay += formatInputWithBadges(input) +
|
|
257
|
+
inputDisplay += formatInputWithBadges(input) + '\x1b[0m';
|
|
203
258
|
renderCursorCol = 3 + cursorPos;
|
|
204
259
|
}
|
|
205
260
|
else {
|
|
@@ -212,8 +267,33 @@ export function askPrompt(opts = {}) {
|
|
|
212
267
|
renderCursorCol = 3 + (prefix ? 1 : 0) + (cursorPos - start);
|
|
213
268
|
}
|
|
214
269
|
}
|
|
215
|
-
// Write prompt line
|
|
216
|
-
process.stdout.write(`\x1b[0m\r\x1b[2K${inputDisplay}\x1b[0m
|
|
270
|
+
// Write prompt line
|
|
271
|
+
process.stdout.write(`\x1b[0m\r\x1b[2K${inputDisplay}\x1b[0m`);
|
|
272
|
+
// 2. Draw or update dropdown lines safely
|
|
273
|
+
if (dropdownLines.length > lastRenderedDropdownLines) {
|
|
274
|
+
// Allocate additional new lines that don't exist yet
|
|
275
|
+
for (let i = 0; i < lastRenderedDropdownLines; i++) {
|
|
276
|
+
process.stdout.write(`\x1b[1B\r\x1b[0m\x1b[2K${dropdownLines[i]}\x1b[0m`);
|
|
277
|
+
}
|
|
278
|
+
for (let i = lastRenderedDropdownLines; i < dropdownLines.length; i++) {
|
|
279
|
+
process.stdout.write(`\n\x1b[0m\x1b[2K${dropdownLines[i]}\x1b[0m`);
|
|
280
|
+
}
|
|
281
|
+
process.stdout.write(`\x1b[${dropdownLines.length}A`);
|
|
282
|
+
lastRenderedDropdownLines = dropdownLines.length;
|
|
283
|
+
}
|
|
284
|
+
else if (lastRenderedDropdownLines > 0) {
|
|
285
|
+
// Redraw over existing lines without allocating new ones (0 scrolling!)
|
|
286
|
+
for (let i = 0; i < lastRenderedDropdownLines; i++) {
|
|
287
|
+
process.stdout.write(`\x1b[1B\r\x1b[0m\x1b[2K`);
|
|
288
|
+
if (i < dropdownLines.length) {
|
|
289
|
+
process.stdout.write(`${dropdownLines[i]}\x1b[0m`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
process.stdout.write(`\x1b[${lastRenderedDropdownLines}A`);
|
|
293
|
+
lastRenderedDropdownLines = dropdownLines.length;
|
|
294
|
+
}
|
|
295
|
+
// 3. Position cursor on the prompt line
|
|
296
|
+
process.stdout.write(`\r\x1b[${renderCursorCol}C`);
|
|
217
297
|
}
|
|
218
298
|
render();
|
|
219
299
|
function cleanup() {
|
|
@@ -229,6 +309,13 @@ export function askPrompt(opts = {}) {
|
|
|
229
309
|
process.stdin.pause();
|
|
230
310
|
}
|
|
231
311
|
function clearBoxAndExit(finalInput) {
|
|
312
|
+
if (lastRenderedDropdownLines > 0) {
|
|
313
|
+
for (let i = 0; i < lastRenderedDropdownLines; i++) {
|
|
314
|
+
process.stdout.write(`\x1b[1B\r\x1b[0m\x1b[2K`);
|
|
315
|
+
}
|
|
316
|
+
process.stdout.write(`\x1b[${lastRenderedDropdownLines}A`);
|
|
317
|
+
lastRenderedDropdownLines = 0;
|
|
318
|
+
}
|
|
232
319
|
const fullText = expandPastes(finalInput);
|
|
233
320
|
if (fullText.trim()) {
|
|
234
321
|
if (GLOBAL_PROMPT_HISTORY.length === 0 ||
|
|
@@ -278,8 +365,19 @@ export function askPrompt(opts = {}) {
|
|
|
278
365
|
handlePaste(str);
|
|
279
366
|
return;
|
|
280
367
|
}
|
|
368
|
+
// Ignore EOF / Ctrl+D (\x04)
|
|
369
|
+
if (str === '\x04') {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
281
372
|
// Ctrl+C / SIGINT
|
|
282
373
|
if (str === '\x03') {
|
|
374
|
+
if (lastRenderedDropdownLines > 0) {
|
|
375
|
+
for (let i = 0; i < lastRenderedDropdownLines; i++) {
|
|
376
|
+
process.stdout.write(`\x1b[1B\r\x1b[0m\x1b[2K`);
|
|
377
|
+
}
|
|
378
|
+
process.stdout.write(`\x1b[${lastRenderedDropdownLines}A`);
|
|
379
|
+
lastRenderedDropdownLines = 0;
|
|
380
|
+
}
|
|
283
381
|
process.stdout.write(`\x1b[0m\r\x1b[2K\n`);
|
|
284
382
|
cleanup();
|
|
285
383
|
resolve('__CANCEL__');
|
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.19 • Terminal-Native AI Assistant</div>
|
|
143
143
|
</div>
|
|
144
144
|
</body>
|
|
145
145
|
</html>`;
|
package/dist/mcp/client.js
CHANGED
package/package.json
CHANGED