termux-dev 1.0.2
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/LICENSE +21 -0
- package/README.md +290 -0
- package/assets/banner.svg +33 -0
- package/assets/preview.png +0 -0
- package/bin/devx.js +2 -0
- package/dist/cli/clipboard.js +136 -0
- package/dist/cli/files.js +93 -0
- package/dist/cli/index.js +1506 -0
- package/dist/cli/markdown.js +147 -0
- package/dist/cli/prompt.js +553 -0
- package/dist/cli/providers.js +892 -0
- package/dist/cli/server.js +137 -0
- package/dist/cli/updater.js +245 -0
- package/dist/core/history.js +121 -0
- package/dist/core/loop.js +164 -0
- package/dist/core/memory.js +68 -0
- package/dist/core/models.js +72 -0
- package/dist/core/pricing.js +65 -0
- package/dist/core/session.js +129 -0
- package/dist/core/snapshot.js +88 -0
- package/dist/core/types.js +1 -0
- package/dist/permissions/guard.js +104 -0
- package/dist/prompts/builder.js +69 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers/openai.js +318 -0
- package/dist/tools/bash.js +51 -0
- package/dist/tools/diagnostics.js +63 -0
- package/dist/tools/fs.js +185 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/packages.js +80 -0
- package/dist/tools/plan.js +52 -0
- package/dist/tools/questions.js +101 -0
- package/dist/tools/search.js +90 -0
- package/dist/tools/web.js +155 -0
- package/package.json +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ApvCode
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="assets/banner.svg" alt="DEVX" width="800" />
|
|
4
|
+
|
|
5
|
+
<br/><br/>
|
|
6
|
+
|
|
7
|
+
**Ultra-fast, autonomous AI pair-programmer & vibe-coding terminal agent.**
|
|
8
|
+
Built specifically for **Android Termux**, **Windows**, **macOS**, and **Linux**.
|
|
9
|
+
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://github.com/apvcode/Termux-Dev/actions/workflows/ci.yml)
|
|
12
|
+
[](https://nodejs.org)
|
|
13
|
+
[](https://www.typescriptlang.org)
|
|
14
|
+
[](#)
|
|
15
|
+
|
|
16
|
+
<br/>
|
|
17
|
+
|
|
18
|
+
[๐ฌ๐ง **English**](#-highlights) โข [๐ท๐บ **ะ ัััะบะธะน**](#-ััััะบะธะน)
|
|
19
|
+
|
|
20
|
+
<br/><br/>
|
|
21
|
+
|
|
22
|
+
<img src="assets/preview.png" alt="devx Terminal Interface" width="750" style="border-radius: 8px;" />
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ๐ Highlights
|
|
29
|
+
|
|
30
|
+
- **๐ง Dual-Brain Architecture (PLAN & AGENT Modes):**
|
|
31
|
+
Instantly toggle between **PLAN** (safe architect, interactive requirements questionnaire, no code dumps) and **AGENT** (autonomous file edits, terminal commands, auto-installer).
|
|
32
|
+
- **๐ One-Click Plan Approval (`[๐ Go / โ๏ธ Other]`):**
|
|
33
|
+
When an architectural plan is finalized, review and confirm with `Go` to immediately unleash the coder agent.
|
|
34
|
+
- **๐ผ๏ธ Multimodal Vision Attachments:**
|
|
35
|
+
Paste screenshots directly from clipboard (`/image` or `Ctrl+P`) with smart duplicate badges `[1.png 203kb]`, `[1(copy).png 421kb]`.
|
|
36
|
+
- **๐ Built-in Live Web Server (`/serve`):**
|
|
37
|
+
Instantly preview web apps and HTML5 games on port 3000. Seamlessly opens on Android via `termux-open-url`.
|
|
38
|
+
- **โช Instant Snapshot Rollback (`/undo`):**
|
|
39
|
+
Every change made by the AI is recorded. Roll back unwanted edits cleanly with a single command.
|
|
40
|
+
- **๐ฉบ Self-Healing Diagnostics & Auto-Installer:**
|
|
41
|
+
Built-in support for TypeScript (`tsc`), JavaScript (`node --check`), Python (`py_compile`), and Rust (`cargo check`). The AI automatically finds and fixes errors before finishing turns.
|
|
42
|
+
- **๐ง Project Memory Bank (`.devx/memory.md`):**
|
|
43
|
+
Persistent project context across sessions with `/memory add <rule>`.
|
|
44
|
+
- **๐จ Pure Black Obsidian Theme (`#0a0a0c`):**
|
|
45
|
+
Deep OLED black background designed for distraction-free CLI vibe-coding.
|
|
46
|
+
- **๐ Smart Session History (`/resume` & `/session`):**
|
|
47
|
+
Resume sessions with last 20 messages neatly rendered in full Markdown and track unique session IDs (`#a8f9z`).
|
|
48
|
+
- **โก Universal AI Provider Support:**
|
|
49
|
+
**OpenRouter**, **Google Gemini**, **DeepSeek**, **Groq**, **Mistral**, **OpenAI**, **Anthropic**, **Alibaba**, and local models (**Ollama**, **LM Studio**).
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## ๐ฆ Installation & Setup
|
|
54
|
+
|
|
55
|
+
### Prerequisites
|
|
56
|
+
- **Node.js**: `v20.0.0` or higher
|
|
57
|
+
- **npm**, **pnpm**, or **yarn**
|
|
58
|
+
|
|
59
|
+
### โก Fast Global Install (Recommended)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install -g termux-dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### ๐ฑ Android (Termux) Setup
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# 1. Update packages & install NodeJS
|
|
69
|
+
pkg update && pkg install -y nodejs-lts
|
|
70
|
+
|
|
71
|
+
# 2. Install devx globally via npm
|
|
72
|
+
npm install -g termux-dev
|
|
73
|
+
|
|
74
|
+
# 3. Launch devx anywhere!
|
|
75
|
+
devx
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### ๐ ๏ธ Build from Source (Developers)
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
git clone https://github.com/apvcode/Termux-Dev.git
|
|
82
|
+
cd Termux-Dev
|
|
83
|
+
npm install
|
|
84
|
+
npm link
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## ๐ Getting Started
|
|
91
|
+
|
|
92
|
+
Launch `devx` in any project folder:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
devx
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
* On first run, `devx` launches an interactive setup wizard to configure your preferred AI provider and API key.
|
|
99
|
+
* Start directly in **PLAN mode**:
|
|
100
|
+
```bash
|
|
101
|
+
devx --plan
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## โจ๏ธ Slash Commands
|
|
107
|
+
|
|
108
|
+
Type `/` in the prompt to open the autocomplete command palette:
|
|
109
|
+
|
|
110
|
+
| Command | Description |
|
|
111
|
+
| :--- | :--- |
|
|
112
|
+
| **`/plan`** | Switch to **PLAN** mode (architect & requirements planner) |
|
|
113
|
+
| **`/agent`** | Switch to **AGENT** mode (coder & autonomous executor) |
|
|
114
|
+
| **`/image`** | Paste image from clipboard as `[1.png 203kb]` |
|
|
115
|
+
| **`/serve [port]`** | Start local HTTP server for web/game preview (`/serve stop` to halt) |
|
|
116
|
+
| **`/memory`** | View, add (`/memory add <fact>`), or clear project memory bank |
|
|
117
|
+
| **`/undo`** | Revert all file changes from the last AI turn |
|
|
118
|
+
| **`/diff`** | View colored git diff of modified project files |
|
|
119
|
+
| **`/commit`** | AI-generated semantic commit message & git commit |
|
|
120
|
+
| **`/status`** | View git repository status |
|
|
121
|
+
| **`/session`** | View active session ID, stats, and metadata |
|
|
122
|
+
| **`/resume`** | Browse and resume saved chat sessions |
|
|
123
|
+
| **`/session del`** | Selectively or bulk delete saved sessions |
|
|
124
|
+
| **`/settings`** | Configure YOLO auto-approve, project memory, theme, and update checks |
|
|
125
|
+
| **`/update`** | Check and install latest updates from GitHub |
|
|
126
|
+
| **`/model`** | Switch model for the active provider with live search |
|
|
127
|
+
| **`/provider`** | Switch provider (OpenRouter, Gemini, Groq, DeepSeek, Local) |
|
|
128
|
+
| **`/compact`** | Compact and summarize chat context tokens |
|
|
129
|
+
| **`/clear`** | Clear screen and redraw banner |
|
|
130
|
+
| **`/init`** | Generate `AGENTS.md` developer guide in project root |
|
|
131
|
+
| **`/help`** | Display all available commands |
|
|
132
|
+
| **`/exit`** | Exit devx cleanly |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## โจ๏ธ Keybindings
|
|
137
|
+
|
|
138
|
+
- **`Tab`** โ Instantly toggle between **PLAN** and **AGENT** modes without losing your draft text.
|
|
139
|
+
- **`Ctrl+P`** / **`Ctrl+V`** โ Paste image from clipboard directly into prompt.
|
|
140
|
+
- **`@filename`** โ Fast fuzzy file autocomplete and full file embedding.
|
|
141
|
+
- **`Backspace`** โ Atomically deletes entire badges `[Pasted text #1]` and `[1.png 203kb]` in one press.
|
|
142
|
+
- **`Ctrl+C`** โ Stop current generation immediately or exit.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## โญ๏ธ Support the Project
|
|
147
|
+
|
|
148
|
+
If you find **devx** useful, please consider giving it a โญ๏ธ star on [GitHub](https://github.com/apvcode/Termux-Dev) โ it helps the project grow and motivates further development!
|
|
149
|
+
|
|
150
|
+
<br/>
|
|
151
|
+
<hr/>
|
|
152
|
+
<br/>
|
|
153
|
+
|
|
154
|
+
# ๐ท๐บ ะ ัััะบะธะน
|
|
155
|
+
|
|
156
|
+
## ๐ ะะปะฐะฒะฝัะต ะฒะพะทะผะพะถะฝะพััะธ
|
|
157
|
+
|
|
158
|
+
- **๐ง ะะฒัั
ัะตะถะธะผะฝะฐั ะฐัั
ะธัะตะบัััะฐ (PLAN ะธ AGENT):**
|
|
159
|
+
ะะณะฝะพะฒะตะฝะฝะพะต ะฟะตัะตะบะปััะตะฝะธะต ะผะตะถะดั **PLAN** (ะฑะตะทะพะฟะฐัะฝัะน ะฐัั
ะธัะตะบัะพั, ะธะฝัะตัะฐะบัะธะฒะฝัะต ะพะฟัะพัะฝะธะบะธ, ะทะฐะฟัะตั ะฝะฐ ะฝะตัะฐะฝะบัะธะพะฝะธัะพะฒะฐะฝะฝัะต ะฟัะฐะฒะบะธ) ะธ **AGENT** (ะฐะฒัะพะฝะพะผะฝะพะต ัะพะทะดะฐะฝะธะต/ัะตะดะฐะบัะธัะพะฒะฐะฝะธะต ัะฐะนะปะพะฒ, ะฒัะฟะพะปะฝะตะฝะธะต bash-ะบะพะผะฐะฝะด, ะฐะฒัะพ-ัััะฐะฝะพะฒะบะฐ ะฟะฐะบะตัะพะฒ).
|
|
160
|
+
- **๐ ะฃัะฒะตัะถะดะตะฝะธะต ะฟะปะฐะฝะฐ ะฒ 1 ะบะปะธะบ (`[๐ Go / โ๏ธ Other]`):**
|
|
161
|
+
ะะพะณะดะฐ ะฐัั
ะธัะตะบัััะฝัะน ะฟะปะฐะฝ ะณะพัะพะฒ, ะฟะพะดัะฒะตัะดะธัะต ะตะณะพ ะบะฝะพะฟะบะพะน `Go` โ ะฐะณะตะฝั ะผะณะฝะพะฒะตะฝะฝะพ ะฟะตัะตะบะปััะธััั ะฒ ัะตะถะธะผ ะบะพะดะตัะฐ ะธ ะฟัะธัััะฟะธั ะบ ัะตะฐะปะธะทะฐัะธะธ.
|
|
162
|
+
- **๐ผ๏ธ ะัะปััะธะผะพะดะฐะปัะฝะพะต ะทัะตะฝะธะต ะธ ะฒััะฐะฒะบะฐ ัะบัะธะฝัะพัะพะฒ:**
|
|
163
|
+
ะััะฐะฒะปัะนัะต ะธะทะพะฑัะฐะถะตะฝะธั ะฟััะผะพ ะธะท ะฑััะตัะฐ ะพะฑะผะตะฝะฐ (`/image` ะธะปะธ `Ctrl+P`) ั ะฐะฒัะพ-ะฑะตะนะดะถะฐะผะธ `[1.png 203kb]`, `[1(copy).png 421kb]`.
|
|
164
|
+
- **๐ ะัััะพะตะฝะฝัะน ะปะพะบะฐะปัะฝัะน ะฒะตะฑ-ัะตัะฒะตั (`/serve`):**
|
|
165
|
+
ะะณะฝะพะฒะตะฝะฝัะน ะฟัะตะดะฟัะพัะผะพัั ะฒะตะฑ-ะฟัะธะปะพะถะตะฝะธะน ะธ HTML5-ะธะณั ะฝะฐ ะฟะพััั 3000. ะะฐ Android ะฐะฒัะพะผะฐัะธัะตัะบะธ ะพัะบััะฒะฐะตััั ัะตัะตะท `termux-open-url`.
|
|
166
|
+
- **โช ะะณะฝะพะฒะตะฝะฝัะน ะพัะบะฐั ะธะทะผะตะฝะตะฝะธะน (`/undo`):**
|
|
167
|
+
ะะฐะถะดะพะต ะดะตะนััะฒะธะต AI ะปะพะณะธััะตััั ะฒ ัะฝะธะผะบะธ ัะพััะพัะฝะธั. ะัะฑัะต ะฝะตะถะตะปะฐัะตะปัะฝัะต ะฟัะฐะฒะบะธ ะพัะผะตะฝััััั ะพะดะฝะพะน ะบะพะผะฐะฝะดะพะน.
|
|
168
|
+
- **๐ฉบ ะกะฐะผะพะดะธะฐะณะฝะพััะธะบะฐ ะธ ะฐะฒัะพ-ะธัะฟัะฐะฒะปะตะฝะธะต ะพัะธะฑะพะบ:**
|
|
169
|
+
ะัััะพะตะฝะฝะฐั ะฟัะพะฒะตัะบะฐ ะบะพะดะฐ ะดะปั TypeScript (`tsc`), JavaScript (`node --check`), Python (`py_compile`) ะธ Rust (`cargo check`). AI ัะฐะผ ะฝะฐั
ะพะดะธั ะธ ะธัะฟัะฐะฒะปัะตั ัะธะฝัะฐะบัะธัะตัะบะธะต ะพัะธะฑะบะธ ะฟะตัะตะด ะทะฐะฒะตััะตะฝะธะตะผ ะพัะฒะตัะฐ.
|
|
170
|
+
- **๐ง ะะฐะฝะบ ะฟะฐะผััะธ ะฟัะพะตะบัะฐ (`.devx/memory.md`):**
|
|
171
|
+
ะะพะปะณะพััะพัะฝะฐั ะฟะฐะผััั ะฟัะฐะฒะธะป ะธ ะฐัั
ะธัะตะบัััะฝัั
ัะตัะตะฝะธะน ะผะตะถะดั ัะตััะธัะผะธ (`/memory add <ะฟัะฐะฒะธะปะพ>`).
|
|
172
|
+
- **๐จ ะงะธััะพ ัััะฝะฐั ัะตะผะฐ Obsidian Black (`#0a0a0c`):**
|
|
173
|
+
ะะปัะฑะพะบะธะน OLED-ัััะฝัะน ัะพะฝ ะฒ ััะธะปะต OpenCode ะดะปั ะบะพะผัะพััะฝะพะน ะฝะพัะฝะพะน ัะฐะทัะฐะฑะพัะบะธ.
|
|
174
|
+
- **๐ ะััะพัะธั ัะตััะธะน ั ัะฝะธะบะฐะปัะฝัะผะธ ID (`/resume` ะธ `/session`):**
|
|
175
|
+
ะะพัััะฐะฝะพะฒะปะตะฝะธะต ัะตััะธะน ั ะฟัะตะดะฟัะพัะผะพััะพะผ ะฟะพัะปะตะดะฝะธั
20 ัะพะพะฑัะตะฝะธะน ะฒ Markdown ะธ ะบะพัะพัะบะธะผะธ ั
ัั-ID (`#a8f9z`).
|
|
176
|
+
- **โก ะะพะดะดะตัะถะบะฐ ะปัะฑัั
ะฟัะพะฒะฐะนะดะตัะพะฒ:**
|
|
177
|
+
**OpenRouter**, **Google Gemini**, **DeepSeek**, **Groq**, **Mistral**, **OpenAI**, **Anthropic**, **Alibaba**, ะฐ ัะฐะบะถะต ะปะพะบะฐะปัะฝัะต **Ollama** ะธ **LM Studio**.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## ๐ฆ ะฃััะฐะฝะพะฒะบะฐ ะธ ะทะฐะฟััะบ
|
|
182
|
+
|
|
183
|
+
### ะขัะตะฑะพะฒะฐะฝะธั
|
|
184
|
+
- **Node.js**: `v20.0.0` ะธะปะธ ะฒััะต
|
|
185
|
+
- **npm**, **pnpm** ะธะปะธ **yarn**
|
|
186
|
+
|
|
187
|
+
### โก ะััััะฐั ะณะปะพะฑะฐะปัะฝะฐั ัััะฐะฝะพะฒะบะฐ (ะ ะตะบะพะผะตะฝะดัะตััั)
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm install -g termux-dev
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### ๐ฑ ะฃััะฐะฝะพะฒะบะฐ ะฝะฐ Android (Termux)
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# 1. ะะฑะฝะพะฒะปัะตะผ ะฟะฐะบะตัั ะธ ััะฐะฒะธะผ NodeJS
|
|
197
|
+
pkg update && pkg install -y nodejs-lts
|
|
198
|
+
|
|
199
|
+
# 2. ะฃััะฐะฝะฐะฒะปะธะฒะฐะตะผ devx ะณะปะพะฑะฐะปัะฝะพ ัะตัะตะท npm
|
|
200
|
+
npm install -g termux-dev
|
|
201
|
+
|
|
202
|
+
# 3. ะะฐะฟััะบะฐะตะผ devx ะฒ ะปัะฑะพะน ะฟะฐะฟะบะต!
|
|
203
|
+
devx
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### ๐ ๏ธ ะกะฑะพัะบะฐ ะธะท ะธัั
ะพะดะฝะธะบะพะฒ (ะะปั ัะฐะทัะฐะฑะพััะธะบะพะฒ)
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
git clone https://github.com/apvcode/Termux-Dev.git
|
|
210
|
+
cd Termux-Dev
|
|
211
|
+
npm install
|
|
212
|
+
npm link
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## ๐ ะะฐัะฐะปะพ ัะฐะฑะพัั
|
|
219
|
+
|
|
220
|
+
ะะฐะฟัััะธัะต ะบะพะผะฐะฝะดั ะฒ ะฟะฐะฟะบะต ะปัะฑะพะณะพ ะฒะฐัะตะณะพ ะฟัะพะตะบัะฐ:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
devx
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
* ะัะธ ะฟะตัะฒะพะผ ะทะฐะฟััะบะต ะพัะบัะพะตััั ะผะฐััะตั ะฝะฐัััะพะนะบะธ: ะฒัะฑะตัะธัะต ะปัะฑะธะผะพะณะพ AI-ะฟัะพะฒะฐะนะดะตัะฐ ะธ ะฒะฒะตะดะธัะต API-ะบะปัั.
|
|
227
|
+
* ะะฐะฟััะบ ััะฐะทั ะฒ ัะตะถะธะผะต ะฐัั
ะธัะตะบัะพัะฐ:
|
|
228
|
+
```bash
|
|
229
|
+
devx --plan
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## โจ๏ธ ะกะปัั-ะบะพะผะฐะฝะดั
|
|
235
|
+
|
|
236
|
+
ะะฐะฟะธัะธัะต `/` ะฒ ัััะพะบะต ะฒะฒะพะดะฐ, ััะพะฑั ะพัะบัััั ะธะฝัะตัะฐะบัะธะฒะฝะพะต ะผะตะฝั ะบะพะผะฐะฝะด:
|
|
237
|
+
|
|
238
|
+
| ะะพะผะฐะฝะดะฐ | ะะฟะธัะฐะฝะธะต |
|
|
239
|
+
| :--- | :--- |
|
|
240
|
+
| **`/plan`** | ะะตัะตะบะปััะธัััั ะฒ ัะตะถะธะผ ะฐัั
ะธัะตะบัะพัะฐ (**PLAN**) |
|
|
241
|
+
| **`/agent`** | ะะตัะตะบะปััะธัััั ะฒ ัะตะถะธะผ ะธัะฟะพะปะฝะธัะตะปั (**AGENT**) |
|
|
242
|
+
| **`/image`** | ะััะฐะฒะธัั ะบะฐััะธะฝะบั ะธะท ะฑััะตัะฐ ะพะฑะผะตะฝะฐ ะบะฐะบ `[1.png 203kb]` |
|
|
243
|
+
| **`/serve [ะฟะพัั]`** | ะะฐะฟัััะธัั ะปะพะบะฐะปัะฝัะน ะฒะตะฑ-ัะตัะฒะตั (`/serve stop` ะดะปั ะพััะฐะฝะพะฒะบะธ) |
|
|
244
|
+
| **`/memory`** | ะะพัะผะพััะตัั, ะดะพะฑะฐะฒะธัั (`/memory add <ัะฐะบั>`) ะธะปะธ ะพัะธััะธัั ะฑะฐะฝะบ ะฟะฐะผััะธ |
|
|
245
|
+
| **`/undo`** | ะัะบะฐัะธัั ะฒัะต ะธะทะผะตะฝะตะฝะธั ัะฐะนะปะพะฒ ะทะฐ ะฟะพัะปะตะดะฝะธะน ัะฐะณ AI |
|
|
246
|
+
| **`/diff`** | ะะพะบะฐะทะฐัั ัะฒะตัะฝะพะน git diff ะธะทะผะตะฝัะฝะฝัั
ัะฐะนะปะพะฒ |
|
|
247
|
+
| **`/commit`** | ะกะณะตะฝะตัะธัะพะฒะฐัั ัะพะพะฑัะตะฝะธะต ะบะพะผะผะธัะฐ ั ะฟะพะผะพััั AI ะธ ะทะฐะบะพะผะผะธัะธัั ะฒ git |
|
|
248
|
+
| **`/status`** | ะะพะบะฐะทะฐัั ัะตะบััะธะน ััะฐััั Git ัะตะฟะพะทะธัะพัะธั |
|
|
249
|
+
| **`/session`** | ะะพะบะฐะทะฐัั ID, ััะฐัะธััะธะบั ะธ ัะฐะนะป ะฐะบัะธะฒะฝะพะน ัะตััะธะธ |
|
|
250
|
+
| **`/resume`** | ะัะฑัะฐัั ะธ ะฒะพัััะฐะฝะพะฒะธัั ัะพั
ัะฐะฝัะฝะฝัั ัะตััะธั ั ะธััะพัะธะตะน |
|
|
251
|
+
| **`/session del`** | ะัะฑะพัะพัะฝะพ ะธะปะธ ะฟะพะปะฝะพัััั ัะดะฐะปะธัั ัะตััะธะธ |
|
|
252
|
+
| **`/settings`** | ะะฐัััะพะนะบะธ ะฐะฒัะพ-ะฟะพะดัะฒะตัะถะดะตะฝะธั, ะฟะฐะผััะธ, ัะตะผั ะธ ะฟัะพะฒะตัะบะธ ะพะฑะฝะพะฒะปะตะฝะธะน |
|
|
253
|
+
| **`/update`** | ะัะพะฒะตัะธัั ะธ ัััะฐะฝะพะฒะธัั ะฟะพัะปะตะดะฝะธะต ะพะฑะฝะพะฒะปะตะฝะธั ั GitHub |
|
|
254
|
+
| **`/model`** | ะกะผะตะฝะธัั ะผะพะดะตะปั ัะตะบััะตะณะพ ะฟัะพะฒะฐะนะดะตัะฐ ั ะถะธะฒัะผ ะฟะพะธัะบะพะผ |
|
|
255
|
+
| **`/provider`** | ะกะผะตะฝะธัั AI-ะฟัะพะฒะฐะนะดะตัะฐ (OpenRouter, Gemini, Groq, DeepSeek, Local) |
|
|
256
|
+
| **`/compact`** | ะกะถะฐัั ะบะพะฝัะตะบัั ะดะธะฐะปะพะณะฐ ะดะปั ัะบะพะฝะพะผะธะธ ัะพะบะตะฝะพะฒ |
|
|
257
|
+
| **`/clear`** | ะัะธััะธัั ัะบัะฐะฝ ัะตัะผะธะฝะฐะปะฐ ะธ ะฟะตัะตัะธัะพะฒะฐัั ะฑะฐะฝะฝะตั |
|
|
258
|
+
| **`/init`** | ะกะพะทะดะฐัั ัะฐะนะป ะธะฝััััะบัะธะน `AGENTS.md` ะฒ ะบะพัะฝะต ะฟัะพะตะบัะฐ |
|
|
259
|
+
| **`/help`** | ะะพะบะฐะทะฐัั ัะฟะธัะพะบ ะฒัะตั
ะดะพัััะฟะฝัั
ะบะพะผะฐะฝะด |
|
|
260
|
+
| **`/exit`** | ะะฐะฒะตััะธัั ัะฐะฑะพัั devx |
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## โจ๏ธ ะะพัััะธะต ะบะปะฐะฒะธัะธ
|
|
265
|
+
|
|
266
|
+
- **`Tab`** โ ะะณะฝะพะฒะตะฝะฝะพะต ะฟะตัะตะบะปััะตะฝะธะต ะผะตะถะดั ัะตะถะธะผะฐะผะธ **PLAN** ะธ **AGENT** ะฑะตะท ะฟะพัะตัะธ ะฝะฐะฑัะฐะฝะฝะพะณะพ ัะตะบััะฐ.
|
|
267
|
+
- **`Ctrl+P`** / **`Ctrl+V`** โ ะััะฐะฒะบะฐ ัะบัะธะฝัะพัะฐ/ะบะฐััะธะฝะบะธ ะธะท ะฑััะตัะฐ ะพะฑะผะตะฝะฐ.
|
|
268
|
+
- **`@ัะฐะนะป`** โ ะฃะผะฝะพะต ะฐะฒัะพะดะพะฟะพะปะฝะตะฝะธะต ัะฐะนะปะพะฒ ะธ ะฟัะธะบัะตะฟะปะตะฝะธะต ะธั
ัะพะดะตัะถะธะผะพะณะพ ะบ ะทะฐะฟัะพัั.
|
|
269
|
+
- **`Backspace`** โ ะัะพะผะฐัะฝะพะต ัะดะฐะปะตะฝะธะต ะฑะตะนะดะถะตะน `[Pasted text #1]` ะธ `[1.png 203kb]` ะทะฐ ะพะดะฝะพ ะฝะฐะถะฐัะธะต.
|
|
270
|
+
- **`Ctrl+C`** โ ะะณะฝะพะฒะตะฝะฝะฐั ะพััะฐะฝะพะฒะบะฐ ะณะตะฝะตัะฐัะธะธ ะพัะฒะตัะฐ ะธะปะธ ะฒัั
ะพะด.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## โญ๏ธ ะะพะดะดะตัะถะธัะต ะฟัะพะตะบั
|
|
275
|
+
|
|
276
|
+
ะัะปะธ ะฒะฐะผ ะฟะพะฝัะฐะฒะธะปัั **devx**, ะฟะพะถะฐะปัะนััะฐ, ะฟะพััะฐะฒััะต โญ๏ธ ะทะฒัะทะดะพัะบั ะฝะฐ [GitHub](https://github.com/apvcode/Termux-Dev) โ ััะพ ะฟะพะผะพะณะฐะตั ะฟัะพะตะบัั ัะฐััะธ ะธ ะผะพัะธะฒะธััะตั ะดะพะฑะฐะฒะปััั ะฝะพะฒัะต ะบััััะต ะฒะพะทะผะพะถะฝะพััะธ!
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## ๐ License
|
|
281
|
+
|
|
282
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
<div align="center">
|
|
287
|
+
|
|
288
|
+
Made with โค๏ธ by [ApvCode](https://github.com/ApvCode) for developers, vibe-coders, and Termux hackers.
|
|
289
|
+
|
|
290
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 850 180" width="100%" height="180">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#0a0a0c"/>
|
|
5
|
+
<stop offset="100%" stop-color="#111116"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="cyanGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
8
|
+
<stop offset="0%" stop-color="#00f2fe"/>
|
|
9
|
+
<stop offset="50%" stop-color="#4facfe"/>
|
|
10
|
+
<stop offset="100%" stop-color="#00f2fe"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
|
13
|
+
<feGaussianBlur stdDeviation="5" result="blur" />
|
|
14
|
+
<feComposite in="SourceGraphic" in2="blur" operator="over" />
|
|
15
|
+
</filter>
|
|
16
|
+
</defs>
|
|
17
|
+
|
|
18
|
+
<!-- Container Box -->
|
|
19
|
+
<rect x="2" y="2" width="846" height="176" rx="12" fill="url(#bgGrad)" stroke="#22222c" stroke-width="1.5"/>
|
|
20
|
+
|
|
21
|
+
<!-- Logo Text DEVX -->
|
|
22
|
+
<g filter="url(#glow)">
|
|
23
|
+
<text x="425" y="105" font-family="'Courier New', 'Consolas', 'Fira Code', monospace" font-size="78" font-weight="900" fill="url(#cyanGrad)" text-anchor="middle" letter-spacing="12">DEVX</text>
|
|
24
|
+
</g>
|
|
25
|
+
|
|
26
|
+
<!-- Tagline & Badge -->
|
|
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.0.2</tspan>
|
|
29
|
+
</text>
|
|
30
|
+
|
|
31
|
+
<!-- Top Accent Line -->
|
|
32
|
+
<rect x="325" y="12" width="200" height="2" rx="1" fill="url(#cyanGrad)" opacity="0.8"/>
|
|
33
|
+
</svg>
|
|
Binary file
|
package/bin/devx.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import fsSync from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { exec } from 'child_process';
|
|
6
|
+
const MEDIA_DIR = path.join(process.cwd(), '.devx', 'media');
|
|
7
|
+
export function formatFileSize(bytes) {
|
|
8
|
+
if (bytes < 1024)
|
|
9
|
+
return `${bytes}b`;
|
|
10
|
+
const kb = Math.round(bytes / 1024);
|
|
11
|
+
if (kb < 1024)
|
|
12
|
+
return `${kb}kb`;
|
|
13
|
+
const mb = (bytes / (1024 * 1024)).toFixed(1);
|
|
14
|
+
return `${mb}mb`;
|
|
15
|
+
}
|
|
16
|
+
export function getUniqueImageName(baseName, existingNames) {
|
|
17
|
+
if (!existingNames.has(baseName)) {
|
|
18
|
+
return baseName;
|
|
19
|
+
}
|
|
20
|
+
const ext = path.extname(baseName);
|
|
21
|
+
const nameWithoutExt = path.basename(baseName, ext);
|
|
22
|
+
let copyIndex = 1;
|
|
23
|
+
while (true) {
|
|
24
|
+
const candidate = copyIndex === 1
|
|
25
|
+
? `${nameWithoutExt}(copy)${ext}`
|
|
26
|
+
: `${nameWithoutExt}(copy ${copyIndex})${ext}`;
|
|
27
|
+
if (!existingNames.has(candidate)) {
|
|
28
|
+
return candidate;
|
|
29
|
+
}
|
|
30
|
+
copyIndex++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function saveClipboardImage(preferredName = 'image.png', existingNames) {
|
|
34
|
+
if (!fsSync.existsSync(MEDIA_DIR)) {
|
|
35
|
+
await fs.mkdir(MEDIA_DIR, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
const uniqueName = getUniqueImageName(preferredName, existingNames);
|
|
38
|
+
const targetPath = path.join(MEDIA_DIR, uniqueName);
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
const isWindows = os.platform() === 'win32';
|
|
41
|
+
const isMac = os.platform() === 'darwin';
|
|
42
|
+
if (isWindows) {
|
|
43
|
+
const psScript = `
|
|
44
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
45
|
+
Add-Type -AssemblyName System.Drawing
|
|
46
|
+
$img = [System.Windows.Forms.Clipboard]::GetImage()
|
|
47
|
+
if ($img -ne $null) {
|
|
48
|
+
$img.Save('${targetPath.replace(/\\/g, '\\\\')}', [System.Drawing.Imaging.ImageFormat]::Png)
|
|
49
|
+
Write-Output "SAVED"
|
|
50
|
+
} else {
|
|
51
|
+
Write-Output "NO_IMAGE"
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
const b64 = Buffer.from(psScript, 'utf16le').toString('base64');
|
|
55
|
+
exec(`powershell.exe -NoProfile -NonInteractive -EncodedCommand ${b64}`, (err, stdout) => {
|
|
56
|
+
if (!err && stdout.includes('SAVED') && fsSync.existsSync(targetPath)) {
|
|
57
|
+
const stat = fsSync.statSync(targetPath);
|
|
58
|
+
resolve({
|
|
59
|
+
fileName: uniqueName,
|
|
60
|
+
filePath: targetPath,
|
|
61
|
+
size: stat.size,
|
|
62
|
+
sizeStr: formatFileSize(stat.size)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
resolve(null);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else if (isMac) {
|
|
71
|
+
exec(`pngpaste "${targetPath}"`, (err) => {
|
|
72
|
+
if (!err && fsSync.existsSync(targetPath)) {
|
|
73
|
+
const stat = fsSync.statSync(targetPath);
|
|
74
|
+
resolve({
|
|
75
|
+
fileName: uniqueName,
|
|
76
|
+
filePath: targetPath,
|
|
77
|
+
size: stat.size,
|
|
78
|
+
sizeStr: formatFileSize(stat.size)
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
resolve(null);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Linux / Termux: try xclip / wl-paste
|
|
88
|
+
exec(`xclip -selection clipboard -t image/png -o > "${targetPath}" 2>/dev/null || wl-paste -t image/png > "${targetPath}" 2>/dev/null`, () => {
|
|
89
|
+
if (fsSync.existsSync(targetPath)) {
|
|
90
|
+
const stat = fsSync.statSync(targetPath);
|
|
91
|
+
if (stat.size > 100) {
|
|
92
|
+
return resolve({
|
|
93
|
+
fileName: uniqueName,
|
|
94
|
+
filePath: targetPath,
|
|
95
|
+
size: stat.size,
|
|
96
|
+
sizeStr: formatFileSize(stat.size)
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
fsSync.unlinkSync(targetPath);
|
|
101
|
+
}
|
|
102
|
+
catch { }
|
|
103
|
+
}
|
|
104
|
+
resolve(null);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
export async function processPastedFilePath(rawPath, existingNames) {
|
|
110
|
+
const cleanPath = rawPath.trim().replace(/^['"&]+|['"]+$/g, '').trim();
|
|
111
|
+
const resolved = path.resolve(process.cwd(), cleanPath);
|
|
112
|
+
const imageExts = new Set(['.png', '.jpg', '.jpeg', '.webp', '.gif', '.svg', '.bmp']);
|
|
113
|
+
const ext = path.extname(resolved).toLowerCase();
|
|
114
|
+
if (imageExts.has(ext) && fsSync.existsSync(resolved)) {
|
|
115
|
+
try {
|
|
116
|
+
const stat = fsSync.statSync(resolved);
|
|
117
|
+
if (stat.isFile()) {
|
|
118
|
+
const baseName = path.basename(resolved);
|
|
119
|
+
const uniqueName = getUniqueImageName(baseName, existingNames);
|
|
120
|
+
if (!fsSync.existsSync(MEDIA_DIR)) {
|
|
121
|
+
await fs.mkdir(MEDIA_DIR, { recursive: true });
|
|
122
|
+
}
|
|
123
|
+
const targetPath = path.join(MEDIA_DIR, uniqueName);
|
|
124
|
+
await fs.copyFile(resolved, targetPath);
|
|
125
|
+
return {
|
|
126
|
+
fileName: uniqueName,
|
|
127
|
+
filePath: targetPath,
|
|
128
|
+
size: stat.size,
|
|
129
|
+
sizeStr: formatFileSize(stat.size)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch { }
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import fsSync from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
const IGNORED_NAMES = new Set([
|
|
5
|
+
'node_modules',
|
|
6
|
+
'.git',
|
|
7
|
+
'.next',
|
|
8
|
+
'dist',
|
|
9
|
+
'build',
|
|
10
|
+
'coverage',
|
|
11
|
+
'.turbo',
|
|
12
|
+
'.cache',
|
|
13
|
+
'vendor',
|
|
14
|
+
'.tempmediaStorage'
|
|
15
|
+
]);
|
|
16
|
+
let cachedFiles = [];
|
|
17
|
+
let lastScanTime = 0;
|
|
18
|
+
export async function scanProjectFiles(force = false) {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
if (!force && cachedFiles.length > 0 && (now - lastScanTime < 5000)) {
|
|
21
|
+
return cachedFiles;
|
|
22
|
+
}
|
|
23
|
+
const results = [];
|
|
24
|
+
async function walk(dir, depth = 0) {
|
|
25
|
+
if (depth > 6 || results.length > 300)
|
|
26
|
+
return;
|
|
27
|
+
try {
|
|
28
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (entry.name.startsWith('.') && entry.name !== '.env')
|
|
31
|
+
continue;
|
|
32
|
+
if (IGNORED_NAMES.has(entry.name))
|
|
33
|
+
continue;
|
|
34
|
+
const fullPath = path.join(dir, entry.name);
|
|
35
|
+
const rel = path.relative(process.cwd(), fullPath).replace(/\\/g, '/');
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
results.push(`${rel}/`);
|
|
38
|
+
await walk(fullPath, depth + 1);
|
|
39
|
+
}
|
|
40
|
+
else if (entry.isFile()) {
|
|
41
|
+
results.push(rel);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch { }
|
|
46
|
+
}
|
|
47
|
+
await walk(process.cwd());
|
|
48
|
+
cachedFiles = results;
|
|
49
|
+
lastScanTime = now;
|
|
50
|
+
return results;
|
|
51
|
+
}
|
|
52
|
+
const IMAGE_EXTS = {
|
|
53
|
+
'.png': 'image/png',
|
|
54
|
+
'.jpg': 'image/jpeg',
|
|
55
|
+
'.jpeg': 'image/jpeg',
|
|
56
|
+
'.webp': 'image/webp',
|
|
57
|
+
'.gif': 'image/gif',
|
|
58
|
+
'.svg': 'image/svg+xml'
|
|
59
|
+
};
|
|
60
|
+
export async function resolveAtMentions(text) {
|
|
61
|
+
const mentionRegex = /@([a-zA-Z0-9_\-./]+)/g;
|
|
62
|
+
const attachments = [];
|
|
63
|
+
const images = [];
|
|
64
|
+
const seenPaths = new Set();
|
|
65
|
+
let match;
|
|
66
|
+
while ((match = mentionRegex.exec(text)) !== null) {
|
|
67
|
+
const rawPath = match[1];
|
|
68
|
+
const resolved = path.resolve(process.cwd(), rawPath);
|
|
69
|
+
if (seenPaths.has(resolved))
|
|
70
|
+
continue;
|
|
71
|
+
seenPaths.add(resolved);
|
|
72
|
+
if (fsSync.existsSync(resolved)) {
|
|
73
|
+
try {
|
|
74
|
+
const stat = fsSync.statSync(resolved);
|
|
75
|
+
const ext = path.extname(resolved).toLowerCase();
|
|
76
|
+
if (stat.isFile()) {
|
|
77
|
+
if (IMAGE_EXTS[ext]) {
|
|
78
|
+
const buf = await fs.readFile(resolved);
|
|
79
|
+
const b64 = buf.toString('base64');
|
|
80
|
+
const dataUrl = `data:${IMAGE_EXTS[ext]};base64,${b64}`;
|
|
81
|
+
images.push({ path: rawPath, dataUrl });
|
|
82
|
+
}
|
|
83
|
+
else if (stat.size < 50000) {
|
|
84
|
+
const content = await fs.readFile(resolved, 'utf8');
|
|
85
|
+
attachments.push({ path: rawPath, content });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch { }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { text, attachments, images };
|
|
93
|
+
}
|