termux-dev 1.4.18 → 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 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.18</tspan>
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 -->
@@ -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.18'
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
@@ -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.18 (headless) | ${planMode ? 'PLAN' : 'AGENT'} | ${config.model}`)));
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.18'),
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.18'),
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.18 • theme: ${currentTh.name})`)}`,
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.18 by ApvCode)')}`,
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.18 — Terminal-Native AI Coding Agent\n` +
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.18')
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) || confirmExit) {
939
+ if (!p.isCancel(confirmExit) && confirmExit === true) {
940
940
  resetTerminalTheme();
941
941
  p.outro('Goodbye!');
942
942
  break;
@@ -178,9 +178,12 @@ export function askPrompt(opts = {}) {
178
178
  if (selectedIndex < 0)
179
179
  selectedIndex = 0;
180
180
  // Limit dropdown height gracefully so it always fits comfortably
181
- const maxDropdownRows = Math.max(2, Math.min(rows - 3, 6));
181
+ const maxDropdownRows = Math.max(2, Math.min(rows - 3, 5));
182
182
  const pageSize = Math.min(4, Math.max(2, Math.min(maxDropdownRows - 2, Math.floor(rows / 4))));
183
- const innerBoxWidth = Math.max(10, Math.min(cols - 8, 48));
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);
184
187
  const total = items.length;
185
188
  let startIndex = 0;
186
189
  if (total > pageSize) {
@@ -191,52 +194,53 @@ export function askPrompt(opts = {}) {
191
194
  const endIndex = Math.min(startIndex + pageSize, total);
192
195
  const hasMoreUp = startIndex > 0;
193
196
  const hasMoreDown = endIndex < total;
194
- let topBorderStr = '─'.repeat(innerBoxWidth);
197
+ let topBorderStr = '─'.repeat(innerWidth);
195
198
  if (hasMoreUp) {
196
- const mid = Math.max(0, Math.floor(innerBoxWidth / 2) - 2);
197
- topBorderStr = '─'.repeat(mid) + ' ▲ ' + '─'.repeat(Math.max(0, innerBoxWidth - mid - 3));
199
+ const mid = Math.max(0, Math.floor(innerWidth / 2) - 2);
200
+ topBorderStr = '─'.repeat(mid) + ' ▲ ' + '─'.repeat(Math.max(0, innerWidth - mid - 3));
198
201
  }
199
- let botBorderStr = '─'.repeat(innerBoxWidth);
202
+ let botBorderStr = '─'.repeat(innerWidth);
200
203
  if (hasMoreDown) {
201
- const mid = Math.max(0, Math.floor(innerBoxWidth / 2) - 2);
202
- botBorderStr = '─'.repeat(mid) + ' ▼ ' + '─'.repeat(Math.max(0, innerBoxWidth - mid - 3));
204
+ const mid = Math.max(0, Math.floor(innerWidth / 2) - 2);
205
+ botBorderStr = '─'.repeat(mid) + ' ▼ ' + '─'.repeat(Math.max(0, innerWidth - mid - 3));
203
206
  }
204
- dropdownLines.push(pc.dim('│') + ' ' + pc.dim('╭' + topBorderStr + '╮') + '\x1b[0m');
207
+ dropdownLines.push(pc.dim('│ ') + pc.dim('╭' + topBorderStr + '╮') + '\x1b[0m');
205
208
  for (let i = startIndex; i < endIndex; i++) {
206
209
  const item = items[i];
207
210
  const isSelected = i === selectedIndex;
208
211
  const pointer = isSelected ? '› ' : ' ';
209
- const availWidth = innerBoxWidth;
210
- let row = '';
211
- if (availWidth < 20) {
212
- const labelStr = item.label.length > availWidth - 2
213
- ? item.label.slice(0, availWidth - 3) + '…'
214
- : item.label.padEnd(availWidth - 2, ' ');
215
- const plain = (pointer + labelStr).padEnd(availWidth, ' ').slice(0, availWidth);
216
- row = isSelected
217
- ? theme.badgeFn(plain) + '\x1b[0m'
218
- : pointer + theme.boldFn(labelStr) + '\x1b[0m';
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
219
  }
220
220
  else {
221
- const labelMax = Math.min(13, Math.max(6, Math.floor(availWidth * 0.35)));
221
+ const labelMax = Math.min(12, Math.max(6, Math.floor(avail * 0.38)));
222
222
  const labelStr = item.label.length > labelMax
223
223
  ? item.label.slice(0, labelMax - 1) + '…'
224
224
  : item.label.padEnd(labelMax, ' ');
225
- const descMax = Math.max(4, availWidth - labelMax - pointer.length - 1);
225
+ const descMax = Math.max(3, avail - labelMax - 1);
226
226
  const descStr = item.desc.length > descMax
227
227
  ? item.desc.slice(0, descMax - 1) + '…'
228
228
  : item.desc.padEnd(descMax, ' ');
229
- const plain = (pointer + labelStr + ' ' + descStr).padEnd(availWidth, ' ').slice(0, availWidth);
230
- if (isSelected) {
231
- row = theme.badgeFn(plain) + '\x1b[0m';
232
- }
233
- else {
234
- row = `${pointer}${theme.boldFn(labelStr)} ${pc.gray(descStr)}\x1b[0m`;
235
- }
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');
236
241
  }
237
- dropdownLines.push(pc.dim('│') + ' ' + pc.dim('│') + row + pc.dim('│') + '\x1b[0m');
238
242
  }
239
- dropdownLines.push(pc.dim('│') + ' ' + pc.dim('╰' + botBorderStr + '╯') + '\x1b[0m');
243
+ dropdownLines.push(pc.dim('│ ') + pc.dim('╰' + botBorderStr + '╯') + '\x1b[0m');
240
244
  }
241
245
  // 1. Format and write the Prompt line safely
242
246
  let inputDisplay = pc.dim('│') + ' ';
@@ -361,6 +365,10 @@ export function askPrompt(opts = {}) {
361
365
  handlePaste(str);
362
366
  return;
363
367
  }
368
+ // Ignore EOF / Ctrl+D (\x04)
369
+ if (str === '\x04') {
370
+ return;
371
+ }
364
372
  // Ctrl+C / SIGINT
365
373
  if (str === '\x03') {
366
374
  if (lastRenderedDropdownLines > 0) {
@@ -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.18 &bull; Terminal-Native AI Assistant</div>
142
+ <div class="footer">devx v1.4.19 &bull; Terminal-Native AI Assistant</div>
143
143
  </div>
144
144
  </body>
145
145
  </html>`;
@@ -63,7 +63,7 @@ export class MCPClient {
63
63
  capabilities: {},
64
64
  clientInfo: {
65
65
  name: 'devx',
66
- version: '1.4.18'
66
+ version: '1.4.19'
67
67
  }
68
68
  });
69
69
  if (!initResult) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termux-dev",
3
- "version": "1.4.18",
3
+ "version": "1.4.19",
4
4
  "description": "Ultra-fast, terminal-native AI coding assistant and agent built for Android Termux, Windows, macOS, and Linux.",
5
5
  "main": "dist/cli/index.js",
6
6
  "type": "module",