termux-dev 1.3.0 → 1.4.1
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/README.md +2 -0
- package/assets/banner.svg +1 -1
- package/assets/preview.png +0 -0
- package/dist/cli/doctor.js +8 -2
- package/dist/cli/headless.js +1 -1
- package/dist/cli/index.js +207 -188
- package/dist/cli/prompt.js +48 -15
- package/dist/cli/server.js +1 -1
- package/dist/cli/updater.js +0 -6
- package/dist/core/commands.js +3 -3
- package/dist/core/history.js +10 -0
- package/dist/core/loop.js +5 -1
- package/dist/core/models.js +1 -1
- package/dist/core/pricing.js +1 -1
- package/dist/core/usage.js +21 -21
- package/dist/mcp/client.js +218 -0
- package/dist/mcp/manager.js +196 -0
- package/dist/mcp/types.js +1 -0
- package/dist/permissions/guard.js +34 -10
- package/dist/providers/openai.js +14 -5
- package/dist/tools/bash.js +7 -0
- package/dist/tools/fs.js +1 -1
- package/dist/tools/index.js +4 -2
- package/dist/tools/web.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -131,6 +131,7 @@ Type `/` in the prompt to open the autocomplete command palette:
|
|
|
131
131
|
| :--- | :--- |
|
|
132
132
|
| **`/plan`** | Switch to **PLAN** mode (architect & requirements planner) |
|
|
133
133
|
| **`/agent`** | Switch to **AGENT** mode (coder & autonomous executor) |
|
|
134
|
+
| **`/mcp`** | Manage Model Context Protocol (MCP) servers & external tools (`/mcp reload`) |
|
|
134
135
|
| **`/usage`** | View live network bandwidth (KB/MB), token costs, and API request counts |
|
|
135
136
|
| **`/export`** | Export session conversation to a clean GitHub-Flavored Markdown transcript |
|
|
136
137
|
| **`/theme`** | Switch UI color theme (Cyan, Purple, Matrix, Amber, Crimson, Monochrome) |
|
|
@@ -282,6 +283,7 @@ devx
|
|
|
282
283
|
| :--- | :--- |
|
|
283
284
|
| **`/plan`** | Переключиться в режим архитектора (**PLAN**) |
|
|
284
285
|
| **`/agent`** | Переключиться в режим исполнителя (**AGENT**) |
|
|
286
|
+
| **`/mcp`** | Управление MCP-серверами и внешними инструментами (`/mcp reload`) |
|
|
285
287
|
| **`/usage`** | Показать сетевой трафик (КБ/МБ), токены, число запросов и расходы ($) |
|
|
286
288
|
| **`/export`** | Экспортировать сессию диалога в чистый GitHub Markdown файл |
|
|
287
289
|
| **`/theme`** | Сменить цветовую тему (Cyan, Purple, Matrix, Amber, Crimson, Monochrome) |
|
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.
|
|
28
|
+
THE TERMINAL-NATIVE AI CODING AGENT <tspan fill="#00f2fe" font-weight="bold">v1.4.1</tspan>
|
|
29
29
|
</text>
|
|
30
30
|
|
|
31
31
|
<!-- Top Accent Line -->
|
package/assets/preview.png
CHANGED
|
Binary file
|
package/dist/cli/doctor.js
CHANGED
|
@@ -15,8 +15,14 @@ function checkCmd(cmd) {
|
|
|
15
15
|
}
|
|
16
16
|
async function pingUrl(url) {
|
|
17
17
|
return new Promise((resolve) => {
|
|
18
|
-
const req = https.get(url, {
|
|
19
|
-
|
|
18
|
+
const req = https.get(url, {
|
|
19
|
+
timeout: 3000,
|
|
20
|
+
headers: {
|
|
21
|
+
'User-Agent': 'devx-doctor/1.4.1'
|
|
22
|
+
}
|
|
23
|
+
}, (res) => {
|
|
24
|
+
res.resume(); // consume response data to free up memory and release socket
|
|
25
|
+
resolve(res.statusCode !== undefined && res.statusCode < 500);
|
|
20
26
|
});
|
|
21
27
|
req.on('error', () => resolve(false));
|
|
22
28
|
req.on('timeout', () => {
|
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.
|
|
38
|
+
console.log(pc.bold(pc.cyan(`⚡ devx v1.4.1 (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
|
@@ -31,6 +31,7 @@ import { runHeadlessMode } from './headless.js';
|
|
|
31
31
|
import { CustomCommandManager } from '../core/commands.js';
|
|
32
32
|
import { UsageTracker } from '../core/usage.js';
|
|
33
33
|
import { SessionExporter } from './export.js';
|
|
34
|
+
import { MCPManager } from '../mcp/manager.js';
|
|
34
35
|
const CONFIG_PATH = path.join(os.homedir(), '.devxrc.json');
|
|
35
36
|
function maskApiKey(key) {
|
|
36
37
|
if (!key)
|
|
@@ -360,40 +361,41 @@ async function loadConfig(interactive = true) {
|
|
|
360
361
|
catch { }
|
|
361
362
|
}
|
|
362
363
|
const effectiveConfig = { ...globalConfig };
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
364
|
+
const cwd = process.cwd();
|
|
365
|
+
let isTrusted = globalConfig.trustedProjects?.[cwd];
|
|
366
|
+
// Workspace & Project Trust Check on first time opening this directory
|
|
367
|
+
if (isTrusted === undefined) {
|
|
368
|
+
if (interactive) {
|
|
369
|
+
console.log('');
|
|
370
|
+
p.log.warn(pc.bold(pc.yellow(`🛡️ [WORKSPACE TRUST] First time opening this workspace:`)));
|
|
371
|
+
console.log(pc.dim(` Directory: ${cwd}`));
|
|
372
|
+
if (localConfig) {
|
|
371
373
|
if (localConfig.autoApprove === true) {
|
|
372
|
-
console.log(pc.yellow(` • Auto-approval (YOLO mode)
|
|
374
|
+
console.log(pc.yellow(` • Local .devx.json requests Auto-approval (YOLO mode)`));
|
|
373
375
|
}
|
|
374
376
|
if (localConfig.bashAllowlist) {
|
|
375
|
-
console.log(pc.yellow(` • Bash allowlist: ${localConfig.bashAllowlist.join(', ')}`));
|
|
376
|
-
}
|
|
377
|
-
console.log(pc.dim(` Repository: ${cwd}`));
|
|
378
|
-
const answer = await p.confirm({
|
|
379
|
-
message: 'Do you trust this repository and allow its elevated permissions?',
|
|
380
|
-
initialValue: false
|
|
381
|
-
});
|
|
382
|
-
isTrusted = answer === true;
|
|
383
|
-
globalConfig.trustedProjects = globalConfig.trustedProjects || {};
|
|
384
|
-
globalConfig.trustedProjects[cwd] = isTrusted;
|
|
385
|
-
await saveConfig(globalConfig);
|
|
386
|
-
if (isTrusted) {
|
|
387
|
-
p.log.success(pc.green('Repository marked as trusted. Elevated permissions applied.'));
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
p.log.info(pc.cyan('Repository not trusted. Elevated permissions ignored.'));
|
|
377
|
+
console.log(pc.yellow(` • Local .devx.json requests Bash allowlist: ${localConfig.bashAllowlist.join(', ')}`));
|
|
391
378
|
}
|
|
392
379
|
}
|
|
393
|
-
|
|
394
|
-
|
|
380
|
+
const answer = await p.confirm({
|
|
381
|
+
message: 'Do you trust this workspace and allow agent operations?',
|
|
382
|
+
initialValue: true
|
|
383
|
+
});
|
|
384
|
+
if (p.isCancel(answer) || answer !== true) {
|
|
385
|
+
resetTerminalTheme();
|
|
386
|
+
p.outro(pc.yellow('Workspace not trusted. Exiting devx.'));
|
|
387
|
+
process.exit(0);
|
|
395
388
|
}
|
|
389
|
+
globalConfig.trustedProjects = globalConfig.trustedProjects || {};
|
|
390
|
+
globalConfig.trustedProjects[cwd] = true;
|
|
391
|
+
await saveConfig(globalConfig);
|
|
392
|
+
p.log.success(pc.green('Workspace marked as trusted. Full capabilities enabled.'));
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
isTrusted = false; // Never auto-trust in non-interactive headless mode
|
|
396
396
|
}
|
|
397
|
+
}
|
|
398
|
+
if (localConfig && typeof localConfig === 'object') {
|
|
397
399
|
// Apply safe configuration overrides
|
|
398
400
|
if (localConfig.model)
|
|
399
401
|
effectiveConfig.model = localConfig.model;
|
|
@@ -482,7 +484,7 @@ function drawLogo() {
|
|
|
482
484
|
theme.colorFn(' █▀▀▄ █▀▀▀ █ █ █ █'),
|
|
483
485
|
theme.colorFn(' █ █ █▀▀▀ ▀▄▀ ▀▄▀ '),
|
|
484
486
|
theme.colorFn(' █▄▄▀ █▄▄▄ ▀ ▀ ▀ '),
|
|
485
|
-
' ' + theme.boldFn('v1.
|
|
487
|
+
' ' + theme.boldFn('v1.4.1'),
|
|
486
488
|
''
|
|
487
489
|
];
|
|
488
490
|
for (const line of logo) {
|
|
@@ -497,7 +499,7 @@ function drawLogo() {
|
|
|
497
499
|
indent + theme.colorFn('▀▀▀█▀▀▀ █▀▀▀ █▀▀█ █▄ ▄█ █ █ ▀▄ ▄▀ █▀▀▄ █▀▀▀ █ █'),
|
|
498
500
|
indent + theme.colorFn(' █ █▀▀▀ █▄▄▀ █ █ █ █ █ █ ▀▀ █ █ █▀▀▀ █ █'),
|
|
499
501
|
indent + theme.colorFn(' █ █▄▄▄ █ ▀▄ █ █ ▀▄▄▀ ▄▀ ▀▄ █▄▄▀ █▄▄▄ ▀▄▀ '),
|
|
500
|
-
indent + theme.boldFn('v1.
|
|
502
|
+
indent + theme.boldFn('v1.4.1'),
|
|
501
503
|
''
|
|
502
504
|
];
|
|
503
505
|
for (const line of logo) {
|
|
@@ -614,12 +616,162 @@ async function handleSessionDelete() {
|
|
|
614
616
|
}
|
|
615
617
|
}
|
|
616
618
|
}
|
|
619
|
+
async function handleThemeSelect(config) {
|
|
620
|
+
const currentTh = getCurrentTheme();
|
|
621
|
+
const themeChoices = listThemes().map(t => ({
|
|
622
|
+
name: `${t.emoji} ${t.boldFn(t.name.padEnd(18))} ${pc.dim(t.desc)} ${t.id === currentTh.id ? pc.green('(Active)') : ''}`,
|
|
623
|
+
value: t.id,
|
|
624
|
+
description: `Apply ${t.name} color palette (${t.hex}) to banners, prompts, and actions`
|
|
625
|
+
}));
|
|
626
|
+
try {
|
|
627
|
+
const selected = await select({
|
|
628
|
+
message: `${pc.bold('🎨 Select UI Theme / Выберите цветовую тему:')}`,
|
|
629
|
+
choices: themeChoices
|
|
630
|
+
});
|
|
631
|
+
if (selected) {
|
|
632
|
+
config.theme = selected;
|
|
633
|
+
await saveConfig(config);
|
|
634
|
+
const th = setActiveTheme(selected);
|
|
635
|
+
drawLogo();
|
|
636
|
+
p.log.success(th.boldFn(`🎨 Theme switched to ${th.emoji} ${th.name}!`));
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
catch { }
|
|
640
|
+
}
|
|
641
|
+
async function handleSettings(config) {
|
|
642
|
+
while (true) {
|
|
643
|
+
try {
|
|
644
|
+
const maxIter = config.maxIterations || 100;
|
|
645
|
+
const maxIterLabel = maxIter >= 9999 ? 'Unlimited' : `${maxIter} steps`;
|
|
646
|
+
const currentTh = getCurrentTheme();
|
|
647
|
+
const choice = await select({
|
|
648
|
+
message: `${pc.bold('⚙️ Settings')} ${pc.dim(`(devx v1.4.1 • theme: ${currentTh.name})`)}`,
|
|
649
|
+
choices: [
|
|
650
|
+
{
|
|
651
|
+
name: `🎨 Color Theme: ${currentTh.emoji} ${currentTh.name}`,
|
|
652
|
+
value: 'change_theme',
|
|
653
|
+
description: `Switch UI accent colors (${currentTh.desc})`
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
name: `${config.pureBlackTheme !== false ? pc.green('🖤 Pure Black Background: ON') : pc.yellow('🖤 Pure Black Background: OFF')}`,
|
|
657
|
+
value: 'toggle_black_theme',
|
|
658
|
+
description: config.pureBlackTheme !== false
|
|
659
|
+
? 'Apply deep OLED obsidian black background (#0a0a0c) like OpenCode'
|
|
660
|
+
: 'Use standard system terminal background color'
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
name: `${config.autoApprove ? pc.green('⚡ Auto-Approve (YOLO Mode): ON') : pc.yellow('🛡️ Auto-Approve (YOLO Mode): OFF')}`,
|
|
664
|
+
value: 'toggle_auto_approve',
|
|
665
|
+
description: config.autoApprove
|
|
666
|
+
? 'Permissions are automatically granted (no confirmation prompts for commands/files)'
|
|
667
|
+
: 'Agent asks for confirmation before executing bash commands or writing files'
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
name: `${config.enableMemory !== false ? pc.green('🧠 Project Memory Bank: ON') : pc.yellow('🧠 Project Memory Bank: OFF')}`,
|
|
671
|
+
value: 'toggle_memory',
|
|
672
|
+
description: config.enableMemory !== false
|
|
673
|
+
? 'Load persistent project rules and preferences from .devx/memory.md into AI context'
|
|
674
|
+
: 'Start sessions with a clean state without loading project memory'
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
name: `${config.checkUpdates !== false ? pc.green('🔔 Check for Updates on Startup: ON') : pc.yellow('🔔 Check for Updates on Startup: OFF')}`,
|
|
678
|
+
value: 'toggle_check_updates',
|
|
679
|
+
description: config.checkUpdates !== false
|
|
680
|
+
? 'Automatically check for updates from GitHub repository when launching devx'
|
|
681
|
+
: 'Disable update checking on startup (run /update manually instead)'
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
name: `🔄 Max Agent Iterations: ${currentTh.colorFn(maxIterLabel)}`,
|
|
685
|
+
value: 'change_max_iterations',
|
|
686
|
+
description: 'Limit how many tool steps (file edits, terminal commands) agent can do per request'
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
name: `${currentTh.colorFn('✨ About devx')} ${pc.dim('(v1.4.1 by ApvCode)')}`,
|
|
690
|
+
value: 'about',
|
|
691
|
+
description: 'Terminal-Native AI Coding Agent created by ApvCode (https://github.com/apvcode/Termux-Dev)'
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
name: '⬅️ Back / Save',
|
|
695
|
+
value: 'back',
|
|
696
|
+
description: 'Return to chat'
|
|
697
|
+
}
|
|
698
|
+
]
|
|
699
|
+
});
|
|
700
|
+
if (choice === 'change_theme') {
|
|
701
|
+
await handleThemeSelect(config);
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
if (choice === 'about') {
|
|
705
|
+
p.note(`⚡ devx v1.4.1 — Terminal-Native AI Coding Agent\n` +
|
|
706
|
+
`🎨 Theme: ${currentTh.emoji} ${currentTh.name}\n` +
|
|
707
|
+
`👤 Author: ApvCode (https://github.com/apvcode)\n` +
|
|
708
|
+
`🌟 Repository: https://github.com/apvcode/Termux-Dev\n` +
|
|
709
|
+
`📜 License: MIT License (2026)\n` +
|
|
710
|
+
`Built for Android Termux, Windows, macOS, and Linux.`, 'About devx');
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
if (choice === 'toggle_black_theme') {
|
|
714
|
+
config.pureBlackTheme = config.pureBlackTheme === false ? true : false;
|
|
715
|
+
await saveConfig(config);
|
|
716
|
+
if (config.pureBlackTheme) {
|
|
717
|
+
enableDarkTheme(true);
|
|
718
|
+
}
|
|
719
|
+
else {
|
|
720
|
+
resetTerminalTheme();
|
|
721
|
+
}
|
|
722
|
+
drawLogo();
|
|
723
|
+
p.log.success(`Pure Black background: ${config.pureBlackTheme ? pc.bold(pc.green('ON (Deep Black)')) : pc.bold(pc.yellow('OFF (System Default)'))}`);
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
if (choice === 'toggle_auto_approve') {
|
|
727
|
+
config.autoApprove = !config.autoApprove;
|
|
728
|
+
await saveConfig(config);
|
|
729
|
+
p.log.success(`Auto-approve permissions: ${config.autoApprove ? pc.bold(pc.green('ON (Automatic Yes)')) : pc.bold(pc.yellow('OFF (Ask every time)'))}`);
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
if (choice === 'toggle_memory') {
|
|
733
|
+
config.enableMemory = config.enableMemory === false ? true : false;
|
|
734
|
+
await saveConfig(config);
|
|
735
|
+
p.log.success(`Project memory bank: ${config.enableMemory !== false ? pc.bold(pc.green('ON (Persistent .devx/memory.md)')) : pc.bold(pc.yellow('OFF'))}`);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (choice === 'toggle_check_updates') {
|
|
739
|
+
config.checkUpdates = config.checkUpdates === false ? true : false;
|
|
740
|
+
await saveConfig(config);
|
|
741
|
+
p.log.success(`Check for updates: ${config.checkUpdates !== false ? pc.bold(pc.green('ON (Checked on startup)')) : pc.bold(pc.yellow('OFF (Manual only)'))}`);
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
if (choice === 'change_max_iterations') {
|
|
745
|
+
const val = await select({
|
|
746
|
+
message: 'Select maximum iterations limit per prompt:',
|
|
747
|
+
choices: [
|
|
748
|
+
{ name: '30 steps (Strict / Safe)', value: 30 },
|
|
749
|
+
{ name: '50 steps (Moderate)', value: 50 },
|
|
750
|
+
{ name: '100 steps (Recommended / Default)', value: 100 },
|
|
751
|
+
{ name: '200 steps (Very large refactors)', value: 200 },
|
|
752
|
+
{ name: 'Unlimited (No limit)', value: 9999 }
|
|
753
|
+
]
|
|
754
|
+
});
|
|
755
|
+
config.maxIterations = val;
|
|
756
|
+
await saveConfig(config);
|
|
757
|
+
p.log.success(`Max iterations updated to: ${pc.bold(val >= 9999 ? 'Unlimited' : `${val} steps`)}`);
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
catch {
|
|
763
|
+
break;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
process.stdin.resume();
|
|
767
|
+
return config;
|
|
768
|
+
}
|
|
617
769
|
export async function main() {
|
|
618
770
|
const program = new Command();
|
|
619
771
|
program
|
|
620
772
|
.name('devx')
|
|
621
773
|
.description('Terminal-native AI coding assistant and vibe-coding agent')
|
|
622
|
-
.version('1.
|
|
774
|
+
.version('1.4.1')
|
|
623
775
|
.option('-p, --prompt <task>', 'Run one-shot task non-interactively (headless mode)')
|
|
624
776
|
.option('-y, --yolo', 'Automatically approve all tool executions without confirmation')
|
|
625
777
|
.option('-m, --model <model>', 'Specify AI model to use for this execution')
|
|
@@ -689,6 +841,7 @@ export async function main() {
|
|
|
689
841
|
const sessionManager = new SessionManager(config.model, planMode);
|
|
690
842
|
drawLogo();
|
|
691
843
|
await runStartupUpdateCheck(config);
|
|
844
|
+
await MCPManager.getInstance().init();
|
|
692
845
|
let totalSessionCost = 0;
|
|
693
846
|
let currentDraft = '';
|
|
694
847
|
let autoTriggerPrompt = '';
|
|
@@ -772,156 +925,6 @@ export async function main() {
|
|
|
772
925
|
if (answer.startsWith('/')) {
|
|
773
926
|
const parts = answer.split(' ');
|
|
774
927
|
let cmd = parts[0];
|
|
775
|
-
async function handleThemeSelect(config) {
|
|
776
|
-
const currentTh = getCurrentTheme();
|
|
777
|
-
const themeChoices = listThemes().map(t => ({
|
|
778
|
-
name: `${t.emoji} ${t.boldFn(t.name.padEnd(18))} ${pc.dim(t.desc)} ${t.id === currentTh.id ? pc.green('(Active)') : ''}`,
|
|
779
|
-
value: t.id,
|
|
780
|
-
description: `Apply ${t.name} color palette (${t.hex}) to banners, prompts, and actions`
|
|
781
|
-
}));
|
|
782
|
-
try {
|
|
783
|
-
const selected = await select({
|
|
784
|
-
message: `${pc.bold('🎨 Select UI Theme / Выберите цветовую тему:')}`,
|
|
785
|
-
choices: themeChoices
|
|
786
|
-
});
|
|
787
|
-
if (selected) {
|
|
788
|
-
config.theme = selected;
|
|
789
|
-
await saveConfig(config);
|
|
790
|
-
const th = setActiveTheme(selected);
|
|
791
|
-
drawLogo();
|
|
792
|
-
p.log.success(th.boldFn(`🎨 Theme switched to ${th.emoji} ${th.name}!`));
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
catch { }
|
|
796
|
-
}
|
|
797
|
-
async function handleSettings(config) {
|
|
798
|
-
while (true) {
|
|
799
|
-
try {
|
|
800
|
-
const maxIter = config.maxIterations || 100;
|
|
801
|
-
const maxIterLabel = maxIter >= 9999 ? 'Unlimited' : `${maxIter} steps`;
|
|
802
|
-
const currentTh = getCurrentTheme();
|
|
803
|
-
const choice = await select({
|
|
804
|
-
message: `${pc.bold('⚙️ Settings')} ${pc.dim(`(devx v1.3.0 • theme: ${currentTh.name})`)}`,
|
|
805
|
-
choices: [
|
|
806
|
-
{
|
|
807
|
-
name: `🎨 Color Theme: ${currentTh.emoji} ${currentTh.name}`,
|
|
808
|
-
value: 'change_theme',
|
|
809
|
-
description: `Switch UI accent colors (${currentTh.desc})`
|
|
810
|
-
},
|
|
811
|
-
{
|
|
812
|
-
name: `${config.pureBlackTheme !== false ? pc.green('🖤 Pure Black Background: ON') : pc.yellow('🖤 Pure Black Background: OFF')}`,
|
|
813
|
-
value: 'toggle_black_theme',
|
|
814
|
-
description: config.pureBlackTheme !== false
|
|
815
|
-
? 'Apply deep OLED obsidian black background (#0a0a0c) like OpenCode'
|
|
816
|
-
: 'Use standard system terminal background color'
|
|
817
|
-
},
|
|
818
|
-
{
|
|
819
|
-
name: `${config.autoApprove ? pc.green('⚡ Auto-Approve (YOLO Mode): ON') : pc.yellow('🛡️ Auto-Approve (YOLO Mode): OFF')}`,
|
|
820
|
-
value: 'toggle_auto_approve',
|
|
821
|
-
description: config.autoApprove
|
|
822
|
-
? 'Permissions are automatically granted (no confirmation prompts for commands/files)'
|
|
823
|
-
: 'Agent asks for confirmation before executing bash commands or writing files'
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
name: `${config.enableMemory !== false ? pc.green('🧠 Project Memory Bank: ON') : pc.yellow('🧠 Project Memory Bank: OFF')}`,
|
|
827
|
-
value: 'toggle_memory',
|
|
828
|
-
description: config.enableMemory !== false
|
|
829
|
-
? 'Load persistent project rules and preferences from .devx/memory.md into AI context'
|
|
830
|
-
: 'Start sessions with a clean state without loading project memory'
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
name: `${config.checkUpdates !== false ? pc.green('🔔 Check for Updates on Startup: ON') : pc.yellow('🔔 Check for Updates on Startup: OFF')}`,
|
|
834
|
-
value: 'toggle_check_updates',
|
|
835
|
-
description: config.checkUpdates !== false
|
|
836
|
-
? 'Automatically check for updates from GitHub repository when launching devx'
|
|
837
|
-
: 'Disable update checking on startup (run /update manually instead)'
|
|
838
|
-
},
|
|
839
|
-
{
|
|
840
|
-
name: `🔄 Max Agent Iterations: ${currentTh.colorFn(maxIterLabel)}`,
|
|
841
|
-
value: 'change_max_iterations',
|
|
842
|
-
description: 'Limit how many tool steps (file edits, terminal commands) agent can do per request'
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
name: `${currentTh.colorFn('✨ About devx')} ${pc.dim('(v1.3.0 by ApvCode)')}`,
|
|
846
|
-
value: 'about',
|
|
847
|
-
description: 'Terminal-Native AI Coding Agent created by ApvCode (https://github.com/apvcode/Termux-Dev)'
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
name: '⬅️ Back / Save',
|
|
851
|
-
value: 'back',
|
|
852
|
-
description: 'Return to chat'
|
|
853
|
-
}
|
|
854
|
-
]
|
|
855
|
-
});
|
|
856
|
-
if (choice === 'change_theme') {
|
|
857
|
-
await handleThemeSelect(config);
|
|
858
|
-
continue;
|
|
859
|
-
}
|
|
860
|
-
if (choice === 'about') {
|
|
861
|
-
p.note(`⚡ devx v1.3.0 — Terminal-Native AI Coding Agent\n` +
|
|
862
|
-
`🎨 Theme: ${currentTh.emoji} ${currentTh.name}\n` +
|
|
863
|
-
`👤 Author: ApvCode (https://github.com/apvcode)\n` +
|
|
864
|
-
`🌟 Repository: https://github.com/apvcode/Termux-Dev\n` +
|
|
865
|
-
`📜 License: MIT License (2026)\n` +
|
|
866
|
-
`Built for Android Termux, Windows, macOS, and Linux.`, 'About devx');
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
869
|
-
if (choice === 'toggle_black_theme') {
|
|
870
|
-
config.pureBlackTheme = config.pureBlackTheme === false ? true : false;
|
|
871
|
-
await saveConfig(config);
|
|
872
|
-
if (config.pureBlackTheme) {
|
|
873
|
-
enableDarkTheme(true);
|
|
874
|
-
}
|
|
875
|
-
else {
|
|
876
|
-
resetTerminalTheme();
|
|
877
|
-
}
|
|
878
|
-
drawLogo();
|
|
879
|
-
p.log.success(`Pure Black background: ${config.pureBlackTheme ? pc.bold(pc.green('ON (Deep Black)')) : pc.bold(pc.yellow('OFF (System Default)'))}`);
|
|
880
|
-
continue;
|
|
881
|
-
}
|
|
882
|
-
if (choice === 'toggle_auto_approve') {
|
|
883
|
-
config.autoApprove = !config.autoApprove;
|
|
884
|
-
await saveConfig(config);
|
|
885
|
-
p.log.success(`Auto-approve permissions: ${config.autoApprove ? pc.bold(pc.green('ON (Automatic Yes)')) : pc.bold(pc.yellow('OFF (Ask every time)'))}`);
|
|
886
|
-
continue;
|
|
887
|
-
}
|
|
888
|
-
if (choice === 'toggle_memory') {
|
|
889
|
-
config.enableMemory = config.enableMemory === false ? true : false;
|
|
890
|
-
await saveConfig(config);
|
|
891
|
-
p.log.success(`Project memory bank: ${config.enableMemory !== false ? pc.bold(pc.green('ON (Persistent .devx/memory.md)')) : pc.bold(pc.yellow('OFF'))}`);
|
|
892
|
-
continue;
|
|
893
|
-
}
|
|
894
|
-
if (choice === 'toggle_check_updates') {
|
|
895
|
-
config.checkUpdates = config.checkUpdates === false ? true : false;
|
|
896
|
-
await saveConfig(config);
|
|
897
|
-
p.log.success(`Check for updates: ${config.checkUpdates !== false ? pc.bold(pc.green('ON (Checked on startup)')) : pc.bold(pc.yellow('OFF (Manual only)'))}`);
|
|
898
|
-
continue;
|
|
899
|
-
}
|
|
900
|
-
if (choice === 'change_max_iterations') {
|
|
901
|
-
const val = await select({
|
|
902
|
-
message: 'Select maximum iterations limit per prompt:',
|
|
903
|
-
choices: [
|
|
904
|
-
{ name: '30 steps (Strict / Safe)', value: 30 },
|
|
905
|
-
{ name: '50 steps (Moderate)', value: 50 },
|
|
906
|
-
{ name: '100 steps (Recommended / Default)', value: 100 },
|
|
907
|
-
{ name: '200 steps (Very large refactors)', value: 200 },
|
|
908
|
-
{ name: 'Unlimited (No limit)', value: 9999 }
|
|
909
|
-
]
|
|
910
|
-
});
|
|
911
|
-
config.maxIterations = val;
|
|
912
|
-
await saveConfig(config);
|
|
913
|
-
p.log.success(`Max iterations updated to: ${pc.bold(val >= 9999 ? 'Unlimited' : `${val} steps`)}`);
|
|
914
|
-
continue;
|
|
915
|
-
}
|
|
916
|
-
break;
|
|
917
|
-
}
|
|
918
|
-
catch {
|
|
919
|
-
break;
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
process.stdin.resume();
|
|
923
|
-
return config;
|
|
924
|
-
}
|
|
925
928
|
// 1. Check for custom slash commands (.devx/commands/*.md)
|
|
926
929
|
const customCmd = await CustomCommandManager.findCommand(cmd);
|
|
927
930
|
if (customCmd) {
|
|
@@ -933,7 +936,7 @@ export async function main() {
|
|
|
933
936
|
else {
|
|
934
937
|
const VALID_COMMANDS = [
|
|
935
938
|
'/new', '/reset', '/resume', '/session', '/sessions', '/history',
|
|
936
|
-
'/theme', '/themes', '/usage', '/export',
|
|
939
|
+
'/theme', '/themes', '/usage', '/export', '/mcp',
|
|
937
940
|
'/settings', '/update', '/model', '/provider', '/providers',
|
|
938
941
|
'/plan', '/agent', '/image', '/serve', '/memory', '/undo',
|
|
939
942
|
'/diff', '/commit', '/status', '/compact', '/init', '/doctor',
|
|
@@ -951,6 +954,7 @@ export async function main() {
|
|
|
951
954
|
{ name: '/session del - Select and delete saved sessions', value: '/session del' },
|
|
952
955
|
{ name: '/usage - Show network bandwidth, data saver & token cost', value: '/usage' },
|
|
953
956
|
{ name: '/export - Export session conversation to Markdown', value: '/export' },
|
|
957
|
+
{ name: '/mcp - Manage Model Context Protocol (MCP) servers & tools', value: '/mcp' },
|
|
954
958
|
{ name: '/theme - Switch UI color theme', value: '/theme' },
|
|
955
959
|
{ name: '/doctor - Run system & environment health diagnostics', value: '/doctor' },
|
|
956
960
|
{ name: '/settings - Configure permissions & auto-approval', value: '/settings' },
|
|
@@ -1189,13 +1193,7 @@ export async function main() {
|
|
|
1189
1193
|
p.log.warn('No changes to undo.');
|
|
1190
1194
|
}
|
|
1191
1195
|
else {
|
|
1192
|
-
|
|
1193
|
-
while (msgs.length > 1 && msgs[msgs.length - 1].role !== 'user') {
|
|
1194
|
-
msgs.pop();
|
|
1195
|
-
}
|
|
1196
|
-
if (msgs.length > 1 && msgs[msgs.length - 1].role === 'user') {
|
|
1197
|
-
msgs.pop();
|
|
1198
|
-
}
|
|
1196
|
+
history.popLastTurn();
|
|
1199
1197
|
p.log.success(pc.bold(pc.green(`⏪ Successfully reverted changes in ${count} file(s):`)));
|
|
1200
1198
|
for (const f of revertedFiles) {
|
|
1201
1199
|
console.log(pc.cyan(` • ${f}`));
|
|
@@ -1472,6 +1470,20 @@ export async function main() {
|
|
|
1472
1470
|
}
|
|
1473
1471
|
continue;
|
|
1474
1472
|
}
|
|
1473
|
+
if (cmd === '/mcp') {
|
|
1474
|
+
const sub = (parts[1] || '').toLowerCase();
|
|
1475
|
+
if (sub === 'reload' || sub === 'restart' || sub === 'r') {
|
|
1476
|
+
const s = p.spinner();
|
|
1477
|
+
s.start('Reloading MCP servers...');
|
|
1478
|
+
await MCPManager.getInstance().reload();
|
|
1479
|
+
s.stop();
|
|
1480
|
+
console.log('\n' + MCPManager.getInstance().renderStatusCard());
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
console.log('\n' + MCPManager.getInstance().renderStatusCard());
|
|
1484
|
+
}
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1475
1487
|
if (cmd === '/config') {
|
|
1476
1488
|
const masked = { ...config };
|
|
1477
1489
|
if (masked.apiKey)
|
|
@@ -1916,5 +1928,12 @@ export async function main() {
|
|
|
1916
1928
|
}
|
|
1917
1929
|
}
|
|
1918
1930
|
}
|
|
1931
|
+
MCPManager.getInstance().stopAll();
|
|
1919
1932
|
}
|
|
1933
|
+
process.on('exit', () => {
|
|
1934
|
+
try {
|
|
1935
|
+
MCPManager.getInstance().stopAll();
|
|
1936
|
+
}
|
|
1937
|
+
catch { }
|
|
1938
|
+
});
|
|
1920
1939
|
main().catch(console.error);
|