termux-dev 1.2.2 → 1.4.0
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 +48 -0
- package/assets/banner.svg +1 -1
- package/assets/preview.png +0 -0
- package/dist/cli/doctor.js +8 -2
- package/dist/cli/export.js +62 -0
- package/dist/cli/headless.js +110 -0
- package/dist/cli/index.js +411 -224
- package/dist/cli/prompt.js +16 -2
- package/dist/cli/server.js +1 -1
- package/dist/cli/updater.js +0 -6
- package/dist/core/commands.js +100 -0
- 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/repomap.js +135 -0
- package/dist/core/usage.js +119 -0
- 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 +69 -15
- package/dist/prompts/builder.js +9 -0
- package/dist/providers/openai.js +37 -8
- 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
|
@@ -85,6 +85,20 @@ npm install
|
|
|
85
85
|
npm link
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
### 🗑️ Complete Uninstallation
|
|
89
|
+
|
|
90
|
+
To completely remove `devx` along with all configuration, saved sessions, and data:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# 1. Uninstall the global npm package
|
|
94
|
+
npm uninstall -g termux-dev
|
|
95
|
+
|
|
96
|
+
# 2. Remove configuration and session history (Linux / macOS / Termux)
|
|
97
|
+
rm -rf ~/.devx ~/.devxrc.json
|
|
98
|
+
|
|
99
|
+
# (Windows PowerShell)
|
|
100
|
+
Remove-Item -Recurse -Force "$HOME\.devx", "$HOME\.devxrc.json" -ErrorAction SilentlyContinue
|
|
101
|
+
```
|
|
88
102
|
|
|
89
103
|
---
|
|
90
104
|
|
|
@@ -101,6 +115,11 @@ devx
|
|
|
101
115
|
```bash
|
|
102
116
|
devx --plan
|
|
103
117
|
```
|
|
118
|
+
* Run in **Headless One-Shot Mode** (scripts, CI/CD, Termux:Widget):
|
|
119
|
+
```bash
|
|
120
|
+
devx -p "review latest git diff and find security bugs"
|
|
121
|
+
devx -p "fix build errors" --yolo
|
|
122
|
+
```
|
|
104
123
|
|
|
105
124
|
---
|
|
106
125
|
|
|
@@ -112,6 +131,11 @@ Type `/` in the prompt to open the autocomplete command palette:
|
|
|
112
131
|
| :--- | :--- |
|
|
113
132
|
| **`/plan`** | Switch to **PLAN** mode (architect & requirements planner) |
|
|
114
133
|
| **`/agent`** | Switch to **AGENT** mode (coder & autonomous executor) |
|
|
134
|
+
| **`/mcp`** | Manage Model Context Protocol (MCP) servers & external tools (`/mcp reload`) |
|
|
135
|
+
| **`/usage`** | View live network bandwidth (KB/MB), token costs, and API request counts |
|
|
136
|
+
| **`/export`** | Export session conversation to a clean GitHub-Flavored Markdown transcript |
|
|
137
|
+
| **`/theme`** | Switch UI color theme (Cyan, Purple, Matrix, Amber, Crimson, Monochrome) |
|
|
138
|
+
| **`/doctor`** | Run environment health diagnostics (Node, Termux, Compilers, API keys) |
|
|
115
139
|
| **`/image`** | Paste image from clipboard as `[1.png 203kb]` |
|
|
116
140
|
| **`/serve [port]`** | Start local HTTP server for web/game preview (`/serve stop` to halt) |
|
|
117
141
|
| **`/memory`** | View, add (`/memory add <fact>`), or clear project memory bank |
|
|
@@ -213,6 +237,20 @@ npm install
|
|
|
213
237
|
npm link
|
|
214
238
|
```
|
|
215
239
|
|
|
240
|
+
### 🗑️ Полное удаление
|
|
241
|
+
|
|
242
|
+
Чтобы полностью удалить `devx` вместе с конфигурацией, историей сессий и сохранёнными данными:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# 1. Удаляем глобальный npm-пакет
|
|
246
|
+
npm uninstall -g termux-dev
|
|
247
|
+
|
|
248
|
+
# 2. Удаляем конфиг и историю сессий (Linux / macOS / Termux)
|
|
249
|
+
rm -rf ~/.devx ~/.devxrc.json
|
|
250
|
+
|
|
251
|
+
# (Windows PowerShell)
|
|
252
|
+
Remove-Item -Recurse -Force "$HOME\.devx", "$HOME\.devxrc.json" -ErrorAction SilentlyContinue
|
|
253
|
+
```
|
|
216
254
|
|
|
217
255
|
---
|
|
218
256
|
|
|
@@ -229,6 +267,11 @@ devx
|
|
|
229
267
|
```bash
|
|
230
268
|
devx --plan
|
|
231
269
|
```
|
|
270
|
+
* Запуск в **Headless One-Shot режиме** (скрипты, CI/CD, Termux:Widget):
|
|
271
|
+
```bash
|
|
272
|
+
devx -p "проверь последний git diff и найди баги"
|
|
273
|
+
devx -p "исправь ошибки сборки" --yolo
|
|
274
|
+
```
|
|
232
275
|
|
|
233
276
|
---
|
|
234
277
|
|
|
@@ -240,6 +283,11 @@ devx
|
|
|
240
283
|
| :--- | :--- |
|
|
241
284
|
| **`/plan`** | Переключиться в режим архитектора (**PLAN**) |
|
|
242
285
|
| **`/agent`** | Переключиться в режим исполнителя (**AGENT**) |
|
|
286
|
+
| **`/mcp`** | Управление MCP-серверами и внешними инструментами (`/mcp reload`) |
|
|
287
|
+
| **`/usage`** | Показать сетевой трафик (КБ/МБ), токены, число запросов и расходы ($) |
|
|
288
|
+
| **`/export`** | Экспортировать сессию диалога в чистый GitHub Markdown файл |
|
|
289
|
+
| **`/theme`** | Сменить цветовую тему (Cyan, Purple, Matrix, Amber, Crimson, Monochrome) |
|
|
290
|
+
| **`/doctor`** | Запустить системную диагностику (Node, Termux, Компиляторы, Ключи) |
|
|
243
291
|
| **`/image`** | Вставить картинку из буфера обмена как `[1.png 203kb]` |
|
|
244
292
|
| **`/serve [порт]`** | Запустить локальный веб-сервер (`/serve stop` для остановки) |
|
|
245
293
|
| **`/memory`** | Посмотреть, добавить (`/memory add <факт>`) или очистить банк памяти |
|
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.0</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.0'
|
|
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', () => {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export class SessionExporter {
|
|
4
|
+
static async exportToMarkdown(messages, model, targetFilename) {
|
|
5
|
+
try {
|
|
6
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
7
|
+
let fileName = targetFilename?.trim() || `devx-session-${timestamp.slice(0, 19)}.md`;
|
|
8
|
+
if (!fileName.endsWith('.md'))
|
|
9
|
+
fileName += '.md';
|
|
10
|
+
const filePath = path.resolve(process.cwd(), fileName);
|
|
11
|
+
const lines = [
|
|
12
|
+
`# 📝 devx Session Transcript`,
|
|
13
|
+
``,
|
|
14
|
+
`- **Date:** ${new Date().toLocaleString()}`,
|
|
15
|
+
`- **Model:** \`${model}\``,
|
|
16
|
+
`- **Total Messages:** ${messages.length}`,
|
|
17
|
+
`- **Working Directory:** \`${process.cwd()}\``,
|
|
18
|
+
``,
|
|
19
|
+
`---`,
|
|
20
|
+
``
|
|
21
|
+
];
|
|
22
|
+
for (const msg of messages) {
|
|
23
|
+
if (msg.role === 'system')
|
|
24
|
+
continue; // Skip raw system prompt
|
|
25
|
+
if (msg.role === 'user') {
|
|
26
|
+
lines.push(`## 👤 User\n`);
|
|
27
|
+
lines.push(msg.content || '');
|
|
28
|
+
if (msg.images && msg.images.length > 0) {
|
|
29
|
+
lines.push(`\n*Attached Images: ${msg.images.map(i => i.path).join(', ')}*`);
|
|
30
|
+
}
|
|
31
|
+
lines.push(`\n---\n`);
|
|
32
|
+
}
|
|
33
|
+
else if (msg.role === 'assistant') {
|
|
34
|
+
lines.push(`## 🤖 Assistant\n`);
|
|
35
|
+
if (msg.content) {
|
|
36
|
+
lines.push(msg.content);
|
|
37
|
+
}
|
|
38
|
+
if (msg.tool_calls && msg.tool_calls.length > 0) {
|
|
39
|
+
lines.push(`\n**Executed Tools:**`);
|
|
40
|
+
for (const tc of msg.tool_calls) {
|
|
41
|
+
lines.push(`- \`${tc.name}\`: \`\`\`json\n${JSON.stringify(tc.arguments, null, 2)}\n\`\`\``);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
lines.push(`\n---\n`);
|
|
45
|
+
}
|
|
46
|
+
else if (msg.role === 'tool') {
|
|
47
|
+
lines.push(`> **Tool Result (${msg.name || 'tool'}):**\n`);
|
|
48
|
+
let displayContent = msg.content || '';
|
|
49
|
+
if (displayContent.length > 2000) {
|
|
50
|
+
displayContent = displayContent.slice(0, 2000) + '\n... [truncated]';
|
|
51
|
+
}
|
|
52
|
+
lines.push('```\n' + displayContent + '\n```\n');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
await fs.writeFile(filePath, lines.join('\n'), 'utf8');
|
|
56
|
+
return { success: true, filePath };
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
return { success: false, filePath: '', error: err.message };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
import { History } from '../core/history.js';
|
|
3
|
+
import { Agent } from '../core/loop.js';
|
|
4
|
+
import { buildSystemPrompt } from '../prompts/builder.js';
|
|
5
|
+
import { createProvider } from '../providers/index.js';
|
|
6
|
+
import { getTools } from '../tools/index.js';
|
|
7
|
+
import { CLIConsoleGuard } from '../permissions/guard.js';
|
|
8
|
+
import { globalSnapshotManager } from '../core/snapshot.js';
|
|
9
|
+
import { UsageTracker } from '../core/usage.js';
|
|
10
|
+
export async function runHeadlessMode(userPrompt, config, options = {}) {
|
|
11
|
+
const planMode = !!options.planMode;
|
|
12
|
+
const isYolo = !!options.yolo || !!config.autoApprove;
|
|
13
|
+
const isQuiet = !!options.quiet;
|
|
14
|
+
const isJson = !!options.json;
|
|
15
|
+
let history = new History();
|
|
16
|
+
const sysPrompt = await buildSystemPrompt(planMode);
|
|
17
|
+
history.addMessage({ role: 'system', content: sysPrompt });
|
|
18
|
+
history.addMessage({ role: 'user', content: userPrompt });
|
|
19
|
+
const provider = createProvider(config);
|
|
20
|
+
const tools = getTools(planMode);
|
|
21
|
+
const guard = new CLIConsoleGuard(isYolo, config.bashAllowlist || []);
|
|
22
|
+
const agent = new Agent(config, provider, tools, history, guard);
|
|
23
|
+
const executedTools = [];
|
|
24
|
+
let accumulatedText = '';
|
|
25
|
+
let accumulatedReasoning = '';
|
|
26
|
+
let isFatalError = false;
|
|
27
|
+
let errorMessage = '';
|
|
28
|
+
const abortController = new AbortController();
|
|
29
|
+
process.on('SIGINT', () => {
|
|
30
|
+
abortController.abort();
|
|
31
|
+
if (!isJson) {
|
|
32
|
+
console.error(pc.yellow('\n[devx headless] Aborted by user (SIGINT)'));
|
|
33
|
+
}
|
|
34
|
+
process.exit(130);
|
|
35
|
+
});
|
|
36
|
+
try {
|
|
37
|
+
if (!isQuiet && !isJson) {
|
|
38
|
+
console.log(pc.bold(pc.cyan(`⚡ devx v1.4.0 (headless) | ${planMode ? 'PLAN' : 'AGENT'} | ${config.model}`)));
|
|
39
|
+
console.log(pc.dim(`Task: ${userPrompt}\n`));
|
|
40
|
+
}
|
|
41
|
+
for await (const event of agent.run(abortController.signal)) {
|
|
42
|
+
if (event.type === 'reasoning_delta') {
|
|
43
|
+
accumulatedReasoning += event.delta;
|
|
44
|
+
if (!isQuiet && !isJson) {
|
|
45
|
+
process.stdout.write(pc.dim(event.delta));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (event.type === 'text_delta') {
|
|
49
|
+
accumulatedText += event.delta;
|
|
50
|
+
if (!isJson) {
|
|
51
|
+
process.stdout.write(event.delta);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else if (event.type === 'tool_start') {
|
|
55
|
+
if (!isQuiet && !isJson) {
|
|
56
|
+
console.log('\n' + pc.bold(pc.white(`› ${event.actionDesc}`)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (event.type === 'tool_end') {
|
|
60
|
+
executedTools.push({ id: event.id, name: event.name, result: event.result });
|
|
61
|
+
}
|
|
62
|
+
else if (event.type === 'error') {
|
|
63
|
+
errorMessage = event.message;
|
|
64
|
+
if (event.isFatal) {
|
|
65
|
+
isFatalError = true;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
globalSnapshotManager.finishTurn();
|
|
71
|
+
if (isJson) {
|
|
72
|
+
const summary = UsageTracker.getInstance().getSummary();
|
|
73
|
+
const output = {
|
|
74
|
+
success: !isFatalError,
|
|
75
|
+
model: config.model,
|
|
76
|
+
prompt: userPrompt,
|
|
77
|
+
result: accumulatedText,
|
|
78
|
+
reasoning: accumulatedReasoning || undefined,
|
|
79
|
+
executedTools,
|
|
80
|
+
usage: {
|
|
81
|
+
requests: summary.requestsCount,
|
|
82
|
+
totalTokens: summary.totalTokens,
|
|
83
|
+
cost: summary.totalCost,
|
|
84
|
+
totalBytes: summary.totalBytes
|
|
85
|
+
},
|
|
86
|
+
error: isFatalError ? errorMessage : undefined
|
|
87
|
+
};
|
|
88
|
+
console.log(JSON.stringify(output, null, 2));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
if (accumulatedText && !accumulatedText.endsWith('\n')) {
|
|
92
|
+
process.stdout.write('\n');
|
|
93
|
+
}
|
|
94
|
+
if (isFatalError) {
|
|
95
|
+
console.error(pc.red(`\n❌ Error: ${errorMessage}`));
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return isFatalError ? 1 : 0;
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (isJson) {
|
|
103
|
+
console.log(JSON.stringify({ success: false, error: err.message }, null, 2));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.error(pc.red(`\n❌ Fatal Headless Execution Error: ${err.message}`));
|
|
107
|
+
}
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
}
|