termux-dev 1.4.5 → 1.4.6

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.5</tspan>
28
+ THE TERMINAL-NATIVE AI CODING AGENT <tspan fill="#00f2fe" font-weight="bold">v1.4.6</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.5'
21
+ 'User-Agent': 'devx-doctor/1.4.6'
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.5 (headless) | ${planMode ? 'PLAN' : 'AGENT'} | ${config.model}`)));
38
+ console.log(pc.bold(pc.cyan(`⚡ devx v1.4.6 (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.5'),
487
+ ' ' + theme.boldFn('v1.4.6'),
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.5'),
502
+ indent + theme.boldFn('v1.4.6'),
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.5 • theme: ${currentTh.name})`)}`,
648
+ message: `${pc.bold('⚙️ Settings')} ${pc.dim(`(devx v1.4.6 • 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.5 by ApvCode)')}`,
689
+ name: `${currentTh.colorFn('✨ About devx')} ${pc.dim('(v1.4.6 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.5 — Terminal-Native AI Coding Agent\n` +
705
+ p.note(`⚡ devx v1.4.6 — 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.5')
774
+ .version('1.4.6')
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')
@@ -42,8 +42,7 @@ export function askPrompt(opts = {}) {
42
42
  let input = opts.initialValue || '';
43
43
  let cursorPos = input.length;
44
44
  let selectedIndex = 0;
45
- let lastDropdownLines = 0;
46
- let lastCursorLine = 0;
45
+ let lastTotalLines = 0;
47
46
  let disposed = false;
48
47
  let historyIndex = GLOBAL_PROMPT_HISTORY.length;
49
48
  let tempDraft = '';
@@ -156,19 +155,49 @@ export function askPrompt(opts = {}) {
156
155
  function stripAnsi(str) {
157
156
  return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
158
157
  }
158
+ // Helper: clear all previously rendered lines and move cursor to line 0
159
+ function clearPreviousRender() {
160
+ if (lastTotalLines > 1) {
161
+ process.stdout.write(`\x1b[${lastTotalLines - 1}A`);
162
+ }
163
+ for (let i = 0; i < lastTotalLines; i++) {
164
+ process.stdout.write(`\r\x1b[2K`);
165
+ if (i < lastTotalLines - 1)
166
+ process.stdout.write('\n');
167
+ }
168
+ if (lastTotalLines > 1) {
169
+ process.stdout.write(`\x1b[${lastTotalLines - 1}A`);
170
+ }
171
+ }
159
172
  function render() {
160
173
  if (disposed)
161
174
  return;
162
175
  const items = getDropdownItems();
163
- const dropdownLines = [];
164
176
  const cols = Math.max(28, process.stdout.columns || 80);
165
177
  const rows = Math.max(8, process.stdout.rows || 24);
178
+ const prefixLen = 3;
179
+ const maxPerLine = Math.max(10, cols - prefixLen - 1);
180
+ const allLines = [];
181
+ let inputLineCount = 0;
182
+ if (input.length === 0) {
183
+ const displayPlace = placeholder.length > maxPerLine ? placeholder.slice(0, maxPerLine - 1) + '…' : placeholder;
184
+ allLines.push(pc.dim('│') + ' ' + pc.dim(displayPlace));
185
+ inputLineCount = 1;
186
+ }
187
+ else {
188
+ let pos = 0;
189
+ while (pos < input.length) {
190
+ const chunk = input.slice(pos, pos + maxPerLine);
191
+ allLines.push(pc.dim('│') + ' ' + formatInputWithBadges(chunk));
192
+ pos += maxPerLine;
193
+ }
194
+ inputLineCount = allLines.length;
195
+ }
166
196
  if (items.length > 0) {
167
197
  if (selectedIndex >= items.length)
168
198
  selectedIndex = 0;
169
199
  if (selectedIndex < 0)
170
200
  selectedIndex = items.length - 1;
171
- // Ensure inner box width strictly fits: innerBoxWidth + 5 <= cols - 2
172
201
  const innerBoxWidth = Math.max(16, Math.min(cols - 8, 54));
173
202
  const isNarrowOrShort = rows <= 16 || cols < 50;
174
203
  const pageSize = isNarrowOrShort
@@ -194,7 +223,7 @@ export function askPrompt(opts = {}) {
194
223
  const mid = Math.max(0, Math.floor(innerBoxWidth / 2) - 2);
195
224
  botBorderStr = '─'.repeat(mid) + ' ▼ ' + '─'.repeat(Math.max(0, innerBoxWidth - mid - 3));
196
225
  }
197
- dropdownLines.push(pc.dim('│') + ' ' + pc.dim('╭' + topBorderStr + '╮'));
226
+ allLines.push(pc.dim('│') + ' ' + pc.dim('╭' + topBorderStr + '╮'));
198
227
  for (let i = startIndex; i < endIndex; i++) {
199
228
  const item = items[i];
200
229
  const isSelected = i === selectedIndex;
@@ -223,83 +252,33 @@ export function askPrompt(opts = {}) {
223
252
  if (currentLen < innerBoxWidth) {
224
253
  row += ' '.repeat(innerBoxWidth - currentLen);
225
254
  }
226
- dropdownLines.push(pc.dim('│') + ' ' + pc.dim('│') + row + pc.dim('│'));
255
+ allLines.push(pc.dim('│') + ' ' + pc.dim('│') + row + pc.dim('│'));
227
256
  }
228
- dropdownLines.push(pc.dim('│') + ' ' + pc.dim('╰' + botBorderStr + '╯'));
229
- }
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;
237
- if (input.length === 0) {
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;
257
+ allLines.push(pc.dim('│') + ' ' + pc.dim('╰' + botBorderStr + '╯'));
247
258
  }
248
- else {
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);
259
+ clearPreviousRender();
260
+ const maxLinesToWrite = Math.max(allLines.length, lastTotalLines);
261
+ for (let i = 0; i < maxLinesToWrite; i++) {
262
+ process.stdout.write('\r\x1b[2K');
263
+ if (i < allLines.length) {
264
+ process.stdout.write(allLines[i]);
254
265
  }
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;
266
+ if (i < maxLinesToWrite - 1) {
267
+ process.stdout.write('\n');
272
268
  }
273
269
  }
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
- }
270
+ const cursorInputLine = input.length === 0 ? 0 : Math.min(Math.floor(cursorPos / maxPerLine), inputLineCount - 1);
271
+ const cursorCol = input.length === 0 ? prefixLen : prefixLen + (cursorPos % maxPerLine);
272
+ const currentLine = maxLinesToWrite - 1;
273
+ const moveUp = currentLine - cursorInputLine;
274
+ if (moveUp > 0) {
275
+ process.stdout.write(`\x1b[${moveUp}A`);
293
276
  }
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`);
277
+ process.stdout.write('\r');
278
+ if (cursorCol > 0) {
279
+ process.stdout.write(`\x1b[${cursorCol}C`);
298
280
  }
299
- // Position cursor at the correct column
300
- process.stdout.write(`\r\x1b[${screenCursorCol}C`);
301
- lastCursorLine = 0; // Always line 0 now
302
- lastDropdownLines = dropdownLines.length;
281
+ lastTotalLines = allLines.length;
303
282
  }
304
283
  render();
305
284
  function cleanup() {
@@ -314,14 +293,8 @@ export function askPrompt(opts = {}) {
314
293
  process.stdin.pause();
315
294
  }
316
295
  function clearBoxAndExit(finalInput) {
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`);
323
- }
324
- process.stdout.write(`\r\x1b[2K`);
296
+ clearPreviousRender();
297
+ process.stdout.write('\r\x1b[2K');
325
298
  const fullText = expandPastes(finalInput);
326
299
  if (fullText.trim()) {
327
300
  if (GLOBAL_PROMPT_HISTORY.length === 0 || GLOBAL_PROMPT_HISTORY[GLOBAL_PROMPT_HISTORY.length - 1] !== fullText.trim()) {
@@ -455,12 +428,7 @@ export function askPrompt(opts = {}) {
455
428
  }
456
429
  // Ctrl+C
457
430
  if (str === '\x03' || (str.length === 1 && str.charCodeAt(0) === 3)) {
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`);
463
- }
431
+ clearPreviousRender();
464
432
  process.stdout.write('\r\x1b[2K\n');
465
433
  cleanup();
466
434
  resolve('__CANCEL__');
@@ -521,12 +489,7 @@ export function askPrompt(opts = {}) {
521
489
  render();
522
490
  }
523
491
  else {
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`);
529
- }
492
+ clearPreviousRender();
530
493
  process.stdout.write('\r\x1b[2K');
531
494
  cleanup();
532
495
  resolve(`__TOGGLE_MODE__:${input}`);
@@ -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.5 &bull; Terminal-Native AI Assistant</div>
142
+ <div class="footer">devx v1.4.6 &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.5'
66
+ version: '1.4.6'
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.5",
3
+ "version": "1.4.6",
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",