termux-dev 1.4.1 → 1.4.3

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.1</tspan>
28
+ THE TERMINAL-NATIVE AI CODING AGENT <tspan fill="#00f2fe" font-weight="bold">v1.4.3</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.1'
21
+ 'User-Agent': 'devx-doctor/1.4.3'
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.1 (headless) | ${planMode ? 'PLAN' : 'AGENT'} | ${config.model}`)));
38
+ console.log(pc.bold(pc.cyan(`⚡ devx v1.4.3 (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.1'),
487
+ ' ' + theme.boldFn('v1.4.3'),
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.1'),
502
+ indent + theme.boldFn('v1.4.3'),
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.1 • theme: ${currentTh.name})`)}`,
648
+ message: `${pc.bold('⚙️ Settings')} ${pc.dim(`(devx v1.4.3 • 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.1 by ApvCode)')}`,
689
+ name: `${currentTh.colorFn('✨ About devx')} ${pc.dim('(v1.4.3 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.1 — Terminal-Native AI Coding Agent\n` +
705
+ p.note(`⚡ devx v1.4.3 — 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.1')
774
+ .version('1.4.3')
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')
@@ -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,12 @@ export function askPrompt(opts = {}) {
229
230
  }
230
231
  dropdownLines.push(pc.dim('│') + ' ' + pc.dim('╰' + botBorderStr + '╯'));
231
232
  }
232
- // 1. Draw/update input line (line 0)
233
+ // 1. Move cursor back to Line 0 from lastCursorLine and erase everything down
234
+ if (lastCursorLine > 0) {
235
+ process.stdout.write(`\x1b[${lastCursorLine}A`);
236
+ }
237
+ process.stdout.write('\r\x1b[J');
238
+ // 2. Prepare and write input display
233
239
  let inputDisplay = pc.dim('│') + ' ';
234
240
  if (input.length === 0) {
235
241
  const maxPlace = Math.max(12, cols - 8);
@@ -239,24 +245,44 @@ export function askPrompt(opts = {}) {
239
245
  else {
240
246
  inputDisplay += formatInputWithBadges(input);
241
247
  }
242
- process.stdout.write(`\r\x1b[2K${inputDisplay}`);
243
- // 2. Draw dropdown lines below, and clear any leftover old lines
244
- const totalLinesToProcess = Math.max(dropdownLines.length, lastDropdownLines);
245
- if (totalLinesToProcess > 0) {
246
- for (let i = 0; i < totalLinesToProcess; i++) {
247
- if (i < dropdownLines.length) {
248
- process.stdout.write(`\n\x1b[2K${dropdownLines[i]}`);
249
- }
250
- else {
251
- process.stdout.write(`\n\x1b[2K`);
252
- }
248
+ process.stdout.write(inputDisplay);
249
+ // 3. Write dropdown lines below input if present
250
+ if (dropdownLines.length > 0) {
251
+ for (const dl of dropdownLines) {
252
+ process.stdout.write(`\n${dl}`);
253
253
  }
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
- }
257
- else {
258
- process.stdout.write(`\r\x1b[${3 + cursorPos}C`);
259
254
  }
255
+ // 4. Calculate cursor position
256
+ // Calculate how many wrapped lines inputDisplay occupies
257
+ const plainAll = stripAnsi(inputDisplay);
258
+ const allLines = plainAll.split('\n');
259
+ let totalInputLines = 0;
260
+ for (const l of allLines) {
261
+ totalInputLines += l.length === 0 ? 1 : Math.max(1, Math.floor((l.length - 1) / cols) + 1);
262
+ }
263
+ // Calculate where the cursor is inside inputDisplay
264
+ const plainBefore = stripAnsi(pc.dim('│') + ' ' + formatInputWithBadges(input.slice(0, cursorPos)));
265
+ const linesBefore = plainBefore.split('\n');
266
+ let curLine = 0;
267
+ for (let i = 0; i < linesBefore.length - 1; i++) {
268
+ const l = linesBefore[i];
269
+ curLine += l.length === 0 ? 1 : Math.max(1, Math.floor((l.length - 1) / cols) + 1);
270
+ }
271
+ const lastLineSegment = linesBefore[linesBefore.length - 1];
272
+ const wrapOffsetInLastLine = Math.floor(lastLineSegment.length / cols);
273
+ curLine += wrapOffsetInLastLine;
274
+ const curCol = lastLineSegment.length % cols;
275
+ // Current line after writing dropdown is: (totalInputLines - 1) + dropdownLines.length
276
+ const totalBottomLine = (totalInputLines - 1) + dropdownLines.length;
277
+ const linesUp = totalBottomLine - curLine;
278
+ if (linesUp > 0) {
279
+ process.stdout.write(`\x1b[${linesUp}A`);
280
+ }
281
+ process.stdout.write('\r');
282
+ if (curCol > 0) {
283
+ process.stdout.write(`\x1b[${curCol}C`);
284
+ }
285
+ lastCursorLine = curLine;
260
286
  lastDropdownLines = dropdownLines.length;
261
287
  }
262
288
  render();
@@ -272,13 +298,10 @@ export function askPrompt(opts = {}) {
272
298
  process.stdin.pause();
273
299
  }
274
300
  function clearBoxAndExit(finalInput) {
275
- if (lastDropdownLines > 0) {
276
- for (let i = 0; i < lastDropdownLines; i++) {
277
- process.stdout.write(`\n\x1b[2K`);
278
- }
279
- process.stdout.write(`\x1b[${lastDropdownLines}A\r`);
280
- lastDropdownLines = 0;
301
+ if (lastCursorLine > 0) {
302
+ process.stdout.write(`\x1b[${lastCursorLine}A`);
281
303
  }
304
+ process.stdout.write('\r\x1b[J');
282
305
  const fullText = expandPastes(finalInput);
283
306
  if (fullText.trim()) {
284
307
  if (GLOBAL_PROMPT_HISTORY.length === 0 || GLOBAL_PROMPT_HISTORY[GLOBAL_PROMPT_HISTORY.length - 1] !== fullText.trim()) {
@@ -412,14 +435,10 @@ export function askPrompt(opts = {}) {
412
435
  }
413
436
  // Ctrl+C
414
437
  if (str === '\x03' || (str.length === 1 && str.charCodeAt(0) === 3)) {
415
- if (lastDropdownLines > 0) {
416
- for (let i = 0; i < lastDropdownLines; i++) {
417
- process.stdout.write(`\n\x1b[2K`);
418
- }
419
- process.stdout.write(`\x1b[${lastDropdownLines}A\r`);
420
- lastDropdownLines = 0;
438
+ if (lastCursorLine > 0) {
439
+ process.stdout.write(`\x1b[${lastCursorLine}A`);
421
440
  }
422
- process.stdout.write(`\r\x1b[2K\n`);
441
+ process.stdout.write('\r\x1b[J\n');
423
442
  cleanup();
424
443
  resolve('__CANCEL__');
425
444
  return;
@@ -479,14 +498,10 @@ export function askPrompt(opts = {}) {
479
498
  render();
480
499
  }
481
500
  else {
482
- if (lastDropdownLines > 0) {
483
- for (let i = 0; i < lastDropdownLines; i++) {
484
- process.stdout.write(`\n\x1b[2K`);
485
- }
486
- process.stdout.write(`\x1b[${lastDropdownLines}A\r`);
487
- lastDropdownLines = 0;
501
+ if (lastCursorLine > 0) {
502
+ process.stdout.write(`\x1b[${lastCursorLine}A`);
488
503
  }
489
- process.stdout.write(`\r\x1b[2K`);
504
+ process.stdout.write('\r\x1b[J');
490
505
  cleanup();
491
506
  resolve(`__TOGGLE_MODE__:${input}`);
492
507
  }
@@ -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.1 &bull; Terminal-Native AI Assistant</div>
142
+ <div class="footer">devx v1.4.3 &bull; Terminal-Native AI Assistant</div>
143
143
  </div>
144
144
  </body>
145
145
  </html>`;
@@ -119,14 +119,14 @@ export async function performSelfUpdate(latestVersion) {
119
119
  process.stdout.write(`\r ${pc.cyan(frames[fIdx++ % frames.length])} ${pc.dim(`npm install -g termux-dev@latest`)} `);
120
120
  }, 80);
121
121
  try {
122
- execSync('npm install -g termux-dev@latest', { stdio: 'pipe' });
122
+ execSync('npm install -g termux-dev@latest --prefer-online', { stdio: 'pipe' });
123
123
  clearInterval(interval);
124
124
  process.stdout.write(`\r ${pc.green('✔')} ${pc.bold(pc.white(`Successfully updated termux-dev to v${latestVersion} via npm!`))}\n`);
125
125
  }
126
126
  catch (err) {
127
127
  clearInterval(interval);
128
128
  process.stdout.write(`\r ${pc.red('✖')} ${pc.red(`Update failed: ${err.message}`)}\n`);
129
- console.log(pc.yellow(`\n💡 To update manually, run: ${pc.bold('npm install -g termux-dev')}`));
129
+ console.log(pc.yellow(`\n💡 To update manually, run: ${pc.bold('npm install -g termux-dev@latest')}`));
130
130
  return false;
131
131
  }
132
132
  }
@@ -63,7 +63,7 @@ export class MCPClient {
63
63
  capabilities: {},
64
64
  clientInfo: {
65
65
  name: 'devx',
66
- version: '1.4.1'
66
+ version: '1.4.3'
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.1",
3
+ "version": "1.4.3",
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",