@datename/fastcode-termux 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +400 -2
- package/bin/fastcode.mjs +59 -0
- package/dist/agent/guards.d.ts +35 -0
- package/dist/agent/guards.js +74 -0
- package/dist/agent/limits.d.ts +24 -0
- package/dist/agent/limits.js +71 -0
- package/dist/agent/protocol.d.ts +4 -0
- package/dist/agent/protocol.js +126 -0
- package/dist/agent/tools.d.ts +1 -0
- package/dist/agent/tools.js +377 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.js +476 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +518 -0
- package/dist/commands/about.d.ts +8 -0
- package/dist/commands/about.js +16 -0
- package/dist/commands/agent.d.ts +11 -0
- package/dist/commands/agent.js +18 -0
- package/dist/commands/clear.d.ts +11 -0
- package/dist/commands/clear.js +9 -0
- package/dist/commands/config.d.ts +7 -0
- package/dist/commands/config.js +24 -0
- package/dist/commands/cost.d.ts +9 -0
- package/dist/commands/cost.js +13 -0
- package/dist/commands/cwd.d.ts +7 -0
- package/dist/commands/cwd.js +7 -0
- package/dist/commands/exit.d.ts +9 -0
- package/dist/commands/exit.js +8 -0
- package/dist/commands/help.d.ts +6 -0
- package/dist/commands/help.js +18 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.js +58 -0
- package/dist/commands/login.d.ts +16 -0
- package/dist/commands/login.js +61 -0
- package/dist/commands/logout.d.ts +9 -0
- package/dist/commands/logout.js +53 -0
- package/dist/commands/model.d.ts +11 -0
- package/dist/commands/model.js +30 -0
- package/dist/commands/plugin.d.ts +11 -0
- package/dist/commands/plugin.js +74 -0
- package/dist/commands/provider.d.ts +11 -0
- package/dist/commands/provider.js +28 -0
- package/dist/commands/reset.d.ts +9 -0
- package/dist/commands/reset.js +13 -0
- package/dist/commands/skills.d.ts +11 -0
- package/dist/commands/skills.js +106 -0
- package/dist/commands/system.d.ts +11 -0
- package/dist/commands/system.js +20 -0
- package/dist/commands/theme.d.ts +11 -0
- package/dist/commands/theme.js +22 -0
- package/dist/commands/tools.d.ts +7 -0
- package/dist/commands/tools.js +29 -0
- package/dist/commands/whoami.d.ts +9 -0
- package/dist/commands/whoami.js +51 -0
- package/dist/config/paths.d.ts +4 -0
- package/dist/config/paths.js +59 -0
- package/dist/config/store.d.ts +69 -0
- package/dist/config/store.js +208 -0
- package/dist/config/themes.d.ts +73 -0
- package/dist/config/themes.js +77 -0
- package/dist/config/trust.d.ts +9 -0
- package/dist/config/trust.js +67 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +31 -0
- package/dist/lib/diagnostics.d.ts +41 -0
- package/dist/lib/diagnostics.js +139 -0
- package/dist/lib/http.d.ts +13 -0
- package/dist/lib/http.js +70 -0
- package/dist/lib/markdown.d.ts +1 -0
- package/dist/lib/markdown.js +32 -0
- package/dist/lib/pkg.d.ts +5 -0
- package/dist/lib/pkg.js +27 -0
- package/dist/lib/platform.d.ts +7 -0
- package/dist/lib/platform.js +57 -0
- package/dist/lib/startup.d.ts +6 -0
- package/dist/lib/startup.js +25 -0
- package/dist/lib/uiMode.d.ts +2 -0
- package/dist/lib/uiMode.js +7 -0
- package/dist/plugins/manager.d.ts +23 -0
- package/dist/plugins/manager.js +101 -0
- package/dist/providers/anthropic.d.ts +21 -0
- package/dist/providers/anthropic.js +107 -0
- package/dist/providers/custom.d.ts +24 -0
- package/dist/providers/custom.js +25 -0
- package/dist/providers/deepseek.d.ts +24 -0
- package/dist/providers/deepseek.js +15 -0
- package/dist/providers/google.d.ts +24 -0
- package/dist/providers/google.js +19 -0
- package/dist/providers/groq.d.ts +24 -0
- package/dist/providers/groq.js +20 -0
- package/dist/providers/index.d.ts +201 -0
- package/dist/providers/index.js +37 -0
- package/dist/providers/mistral.d.ts +24 -0
- package/dist/providers/mistral.js +19 -0
- package/dist/providers/moonshot.d.ts +24 -0
- package/dist/providers/moonshot.js +22 -0
- package/dist/providers/ollama.d.ts +24 -0
- package/dist/providers/ollama.js +22 -0
- package/dist/providers/openai.d.ts +24 -0
- package/dist/providers/openai.js +25 -0
- package/dist/providers/openaiCompatible.d.ts +17 -0
- package/dist/providers/openaiCompatible.js +110 -0
- package/dist/providers/openrouter.d.ts +24 -0
- package/dist/providers/openrouter.js +26 -0
- package/dist/providers/qwen.d.ts +24 -0
- package/dist/providers/qwen.js +23 -0
- package/dist/providers/xai.d.ts +24 -0
- package/dist/providers/xai.js +18 -0
- package/dist/providers/zhipu.d.ts +24 -0
- package/dist/providers/zhipu.js +23 -0
- package/dist/session/log.d.ts +29 -0
- package/dist/session/log.js +135 -0
- package/dist/skills/manager.d.ts +18 -0
- package/dist/skills/manager.js +201 -0
- package/dist/skills/parser.d.ts +18 -0
- package/dist/skills/parser.js +65 -0
- package/dist/types.d.ts +146 -0
- package/dist/types.js +1 -0
- package/dist/ui/Banner.d.ts +5 -0
- package/dist/ui/Banner.js +65 -0
- package/dist/ui/Message.d.ts +7 -0
- package/dist/ui/Message.js +13 -0
- package/dist/ui/Prompt.d.ts +10 -0
- package/dist/ui/Prompt.js +38 -0
- package/dist/ui/Spinner.d.ts +5 -0
- package/dist/ui/Spinner.js +33 -0
- package/dist/ui/StatusBar.d.ts +10 -0
- package/dist/ui/StatusBar.js +19 -0
- package/dist/ui/TrustGate.d.ts +5 -0
- package/dist/ui/TrustGate.js +26 -0
- package/package.json +96 -4
- package/src/agent/guards.ts +74 -0
- package/src/agent/limits.ts +71 -0
- package/src/agent/protocol.ts +126 -0
- package/src/agent/tools.ts +377 -0
- package/src/app.ts +476 -0
- package/src/cli.ts +308 -0
- package/src/commands/about.ts +16 -0
- package/src/commands/agent.ts +18 -0
- package/src/commands/clear.ts +9 -0
- package/src/commands/config.ts +24 -0
- package/src/commands/cost.ts +13 -0
- package/src/commands/cwd.ts +7 -0
- package/src/commands/exit.ts +8 -0
- package/src/commands/help.ts +18 -0
- package/src/commands/index.ts +58 -0
- package/src/commands/login.ts +61 -0
- package/src/commands/logout.ts +53 -0
- package/src/commands/model.ts +30 -0
- package/src/commands/plugin.ts +74 -0
- package/src/commands/provider.ts +28 -0
- package/src/commands/reset.ts +13 -0
- package/src/commands/skills.ts +106 -0
- package/src/commands/system.ts +20 -0
- package/src/commands/theme.ts +22 -0
- package/src/commands/tools.ts +29 -0
- package/src/commands/whoami.ts +51 -0
- package/src/config/paths.ts +59 -0
- package/src/config/store.ts +240 -0
- package/src/config/themes.ts +77 -0
- package/src/config/trust.ts +67 -0
- package/src/index.ts +31 -0
- package/src/lib/diagnostics.ts +139 -0
- package/src/lib/http.ts +70 -0
- package/src/lib/markdown.ts +32 -0
- package/src/lib/pkg.ts +35 -0
- package/src/lib/platform.ts +57 -0
- package/src/lib/startup.ts +25 -0
- package/src/lib/uiMode.ts +7 -0
- package/src/plugins/manager.ts +101 -0
- package/src/providers/anthropic.ts +107 -0
- package/src/providers/custom.ts +25 -0
- package/src/providers/deepseek.ts +15 -0
- package/src/providers/google.ts +19 -0
- package/src/providers/groq.ts +20 -0
- package/src/providers/index.ts +37 -0
- package/src/providers/mistral.ts +19 -0
- package/src/providers/moonshot.ts +22 -0
- package/src/providers/ollama.ts +22 -0
- package/src/providers/openai.ts +25 -0
- package/src/providers/openaiCompatible.ts +110 -0
- package/src/providers/openrouter.ts +26 -0
- package/src/providers/qwen.ts +23 -0
- package/src/providers/xai.ts +18 -0
- package/src/providers/zhipu.ts +23 -0
- package/src/session/log.ts +135 -0
- package/src/skills/manager.ts +201 -0
- package/src/skills/parser.ts +65 -0
- package/src/types.ts +143 -0
- package/src/ui/Banner.ts +68 -0
- package/src/ui/Message.ts +13 -0
- package/src/ui/Prompt.ts +38 -0
- package/src/ui/Spinner.ts +33 -0
- package/src/ui/StatusBar.ts +19 -0
- package/src/ui/TrustGate.ts +26 -0
- package/tsconfig.json +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SimpleLittleDev
|
|
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
CHANGED
|
@@ -1,3 +1,401 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ⚡ FastCode
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>A colorful, fast, terminal-first AI coding assistant.</strong>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Multi-LLM chat • Agent Skills • Slash commands • Themes • Termux-ready
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img alt="Node" src="https://img.shields.io/badge/node-%3E%3D18.17-3c873a?style=for-the-badge&logo=node.js&logoColor=white">
|
|
13
|
+
<img alt="npm" src="https://img.shields.io/badge/npm-@datename%2Ffastcode--termux-cb3837?style=for-the-badge&logo=npm&logoColor=white">
|
|
14
|
+
<img alt="License" src="https://img.shields.io/badge/license-MIT-f59e0b?style=for-the-badge">
|
|
15
|
+
<img alt="Termux" src="https://img.shields.io/badge/Termux-ready-7c3aed?style=for-the-badge&logo=android&logoColor=white">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @datename/fastcode-termux
|
|
20
|
+
fastcode
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Short alias included:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
fc
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🌈 What Is FastCode?
|
|
32
|
+
|
|
33
|
+
FastCode is a beautiful TUI coding assistant that runs inside your terminal.
|
|
34
|
+
It connects to your favorite AI provider, keeps the workflow command-driven,
|
|
35
|
+
and supports Anthropic-style **Agent Skills** for specialized abilities.
|
|
36
|
+
|
|
37
|
+
It is built for developers who want an AI assistant that feels quick, direct,
|
|
38
|
+
and usable from anywhere: Linux, macOS, Windows, and Android through Termux.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## ✨ Highlights
|
|
43
|
+
|
|
44
|
+
| Feature | What You Get |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| 🎨 Colorful TUI | Big FastCode banner, themes, transcript bubbles, status bar |
|
|
47
|
+
| 🤖 Multi-provider | Anthropic, OpenAI, Gemini, OpenRouter, Groq, DeepSeek, Mistral, Ollama |
|
|
48
|
+
| 🧠 Agent Skills | Install and enable `SKILL.md` powered workflows |
|
|
49
|
+
| 🧩 Plugins | Import always-active plugin packs with bundled skills |
|
|
50
|
+
| 🛠️ Coding Agent | Shell, file editing, grep, patching, and sandboxed local tools |
|
|
51
|
+
| ⚡ Slash commands | Switch models, manage keys, enable skills, inspect config |
|
|
52
|
+
| 📱 Termux-ready | Stable UI mode helps avoid flicker on Android terminals |
|
|
53
|
+
| 🔐 Local config | Keys and preferences stay under `~/.fastcode` |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 🚀 Install
|
|
58
|
+
|
|
59
|
+
### Install from the source repo (recommended)
|
|
60
|
+
|
|
61
|
+
The repo ships a self-contained bundle at `package/dist/cli.js`, so a plain
|
|
62
|
+
`git clone` runs without `npm install`:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/dateName/fastcode-termux.git
|
|
66
|
+
cd fastcode-termux
|
|
67
|
+
bash scripts/install.sh
|
|
68
|
+
fastcode
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Manual equivalent:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git clone https://github.com/dateName/fastcode-termux.git
|
|
75
|
+
cd fastcode-termux/package
|
|
76
|
+
npm install # ⚠️ do not skip
|
|
77
|
+
npm link
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Global install
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install -g @datename/fastcode-termux
|
|
84
|
+
fastcode
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Run without installing globally
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
npx @datename/fastcode-termux
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Start with a prompt
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
fastcode "explain this repository"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 🔑 Add Your API Key
|
|
102
|
+
|
|
103
|
+
Use environment variables:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
107
|
+
export OPENAI_API_KEY="sk-..."
|
|
108
|
+
export OPENROUTER_API_KEY="sk-or-..."
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Or bind a key from inside FastCode — scoped to a specific provider + model (input is masked):
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
/login # guided: provider → model → key
|
|
115
|
+
/login openai gpt-4o-mini sk-...
|
|
116
|
+
/login anthropic claude-3-5-sonnet-latest sk-ant-...
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Then start chatting:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
fastcode
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 🧩 Providers
|
|
128
|
+
|
|
129
|
+
| Provider | Default Model | Auth |
|
|
130
|
+
| --- | --- | --- |
|
|
131
|
+
| `anthropic` | `claude-3-5-sonnet-latest` | `ANTHROPIC_API_KEY` or `CLAUDE_API_KEY` |
|
|
132
|
+
| `openai` | `gpt-4o-mini` | `OPENAI_API_KEY` |
|
|
133
|
+
| `google` | `gemini-1.5-flash` | `GEMINI_API_KEY` or `GOOGLE_API_KEY` |
|
|
134
|
+
| `openrouter` | `anthropic/claude-3.5-sonnet` | `OPENROUTER_API_KEY` |
|
|
135
|
+
| `groq` | `llama-3.3-70b-versatile` | `GROQ_API_KEY` |
|
|
136
|
+
| `deepseek` | `deepseek-chat` | `DEEPSEEK_API_KEY` |
|
|
137
|
+
| `mistral` | `mistral-small-latest` | `MISTRAL_API_KEY` |
|
|
138
|
+
| `ollama` | `llama3.2` | Local, no API key required |
|
|
139
|
+
|
|
140
|
+
Switch anytime:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
/provider openai
|
|
144
|
+
/model gpt-4o-mini
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 🪄 Agent Skills
|
|
150
|
+
|
|
151
|
+
FastCode can install and inject Anthropic-style skills into the system prompt.
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
/skills search pdf
|
|
155
|
+
/skills install pdf
|
|
156
|
+
/skills install anthropics/skills/pdf
|
|
157
|
+
/skills install https://example.com/my-skill/SKILL.md
|
|
158
|
+
/skills enable pdf
|
|
159
|
+
/skills list
|
|
160
|
+
/skills info pdf
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Installed skills live here:
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
~/.fastcode/skills/<name>/SKILL.md
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 🛠️ Coding Agent
|
|
172
|
+
|
|
173
|
+
FastCode can act as a local coding agent. Agent mode is enabled by default and
|
|
174
|
+
works with any provider, including local Ollama models.
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
/agent status
|
|
178
|
+
/agent on
|
|
179
|
+
/agent off
|
|
180
|
+
/tools
|
|
181
|
+
/cwd
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Available tools include:
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
shell, pwd, read_file, read_many, write_file, append_file, apply_patch,
|
|
188
|
+
replace_in_file, list_files, grep, stat_path, make_dir, copy_file,
|
|
189
|
+
move_path, delete_file
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Tools run inside a sandbox rooted at the directory where you start FastCode.
|
|
193
|
+
File tools cannot access paths outside that root. Shell commands run with:
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
FASTCODE_SANDBOX=1
|
|
197
|
+
FASTCODE_SANDBOX_ROOT=<current-working-directory>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Example:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
cd ~/my-project
|
|
204
|
+
fastcode "run the tests, find the failing file, patch it, and verify the fix"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 🧩 Plugins
|
|
210
|
+
|
|
211
|
+
Plugins are always-active behavior packs. A plugin folder can contain:
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
my-plugin/
|
|
215
|
+
├── PLUGIN.md
|
|
216
|
+
└── skills/
|
|
217
|
+
└── reviewer/
|
|
218
|
+
└── SKILL.md
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Import and enable a plugin:
|
|
222
|
+
|
|
223
|
+
```text
|
|
224
|
+
/plugin import ./my-plugin reviewer
|
|
225
|
+
/plugin list
|
|
226
|
+
/plugin info reviewer
|
|
227
|
+
/plugin disable reviewer
|
|
228
|
+
/plugin enable reviewer
|
|
229
|
+
/plugin remove reviewer
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Installed plugins live under:
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
~/.fastcode/plugins/
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 🎮 Slash Commands
|
|
241
|
+
|
|
242
|
+
| Command | Action |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| `/help` | Show command list |
|
|
245
|
+
| `/agent [on/off/status]` | Toggle local coding-agent tools |
|
|
246
|
+
| `/tools` | Show available coding tools |
|
|
247
|
+
| `/cwd` | Show agent sandbox root |
|
|
248
|
+
| `/plugin ...` | Import and manage always-active plugin packs |
|
|
249
|
+
| `/provider [id]` | List or switch provider |
|
|
250
|
+
| `/model [id]` | List or switch model |
|
|
251
|
+
| `/login [provider] [model] [key]` | Bind an API key to a provider + model (guided when omitted) |
|
|
252
|
+
| `/logout <provider> [model]` | Remove a scoped key (`--all` for the whole provider) |
|
|
253
|
+
| `/skills ...` | Search, install, enable, disable, list skills |
|
|
254
|
+
| `/theme [id]` | Switch theme |
|
|
255
|
+
| `/cost` | Show token and cost usage |
|
|
256
|
+
| `/system [text]` | Show or update system prompt |
|
|
257
|
+
| `/whoami` | Show configured provider keys |
|
|
258
|
+
| `/config` | Print config and paths |
|
|
259
|
+
| `/clear` | Clear conversation |
|
|
260
|
+
| `/reset` | Reset config |
|
|
261
|
+
| `/about` | Show version and platform |
|
|
262
|
+
| `/exit` | Quit |
|
|
263
|
+
|
|
264
|
+
Keyboard controls:
|
|
265
|
+
|
|
266
|
+
```text
|
|
267
|
+
Esc cancel streaming
|
|
268
|
+
Ctrl+C press twice to quit
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 🎨 Themes
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
/theme fastcode
|
|
277
|
+
/theme neon
|
|
278
|
+
/theme sunset
|
|
279
|
+
/theme matrix
|
|
280
|
+
/theme mono
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Want the calmest terminal experience?
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
FASTCODE_STABLE_UI=1 fastcode
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Termux enables stable UI automatically.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 📱 Termux
|
|
294
|
+
|
|
295
|
+
Install Node.js first:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
pkg install nodejs
|
|
299
|
+
npm install -g @datename/fastcode-termux
|
|
300
|
+
fastcode
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
If the command is not found, check your npm global binary path:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
npm bin -g
|
|
307
|
+
echo "$PATH"
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
FastCode stores config inside your home directory:
|
|
311
|
+
|
|
312
|
+
```text
|
|
313
|
+
~/.fastcode/
|
|
314
|
+
├── config.json
|
|
315
|
+
├── auth.json
|
|
316
|
+
├── skills/
|
|
317
|
+
├── plugins/
|
|
318
|
+
├── cache/
|
|
319
|
+
├── sessions/
|
|
320
|
+
└── logs/
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
You can move that root with:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
FASTCODE_HOME=/path/to/fastcode fastcode
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## 🛠️ Development
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
git clone https://github.com/dateName/fastcode-termux
|
|
335
|
+
cd FastCode
|
|
336
|
+
npm install
|
|
337
|
+
npm run dev
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Quality checks:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
npm run check
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Or run each step:
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
npm test
|
|
350
|
+
npm run typecheck
|
|
351
|
+
npm run lint
|
|
352
|
+
npm run build
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Run the built CLI:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
node ./bin/fastcode.mjs
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 📦 Publish Notes
|
|
364
|
+
|
|
365
|
+
The package exposes two global commands:
|
|
366
|
+
|
|
367
|
+
```json
|
|
368
|
+
{
|
|
369
|
+
"bin": {
|
|
370
|
+
"fastcode": "./bin/fastcode.mjs",
|
|
371
|
+
"fc": "./bin/fastcode.mjs"
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Publish public scoped releases with:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
npm publish --access public
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Safety, sessions and limits (0.1.6)
|
|
385
|
+
|
|
386
|
+
| Feature | Behaviour | Override |
|
|
387
|
+
| --- | --- | --- |
|
|
388
|
+
| Project trust | First run in a folder asks before agent tools load; the list lives in ~/.fastcode/trusted.json | fastcode trust / untrust / trusted, FASTCODE_TRUST_ALL=1 |
|
|
389
|
+
| Dangerous-command guard | rm -rf, del /f, rmdir /s, format / mkfs / diskpart, dd if=, writes to /dev/sd, shutdown / reboot / poweroff and fork bombs are refused before execution | FASTCODE_ALLOW_DANGEROUS=1, FASTCODE_SHELL_ALLOWLIST, FASTCODE_SHELL_DENY_EXTRA |
|
|
390
|
+
| Unified tool-output cap | Output is truncated while it is produced, not sliced afterwards (default 30000 characters) | FASTCODE_TOOL_OUTPUT_LIMIT |
|
|
391
|
+
| Session log | Append-only JSONL in ~/.fastcode/sessions, resumable after a crash (cache cap 256MB by default) | fastcode sessions, fastcode resume, FASTCODE_SESSION_LOG=0, FASTCODE_SESSION_CACHE_MB |
|
|
392
|
+
|
|
393
|
+
## 🙏 Credits
|
|
394
|
+
|
|
395
|
+
- **SimpleLittleDev** — author of the original FastCode TUI; the npm package
|
|
396
|
+
`@simplelittledev/fastcode` and its credit belong to them.
|
|
397
|
+
- All upstream dependency authors (Ink, React, meow, cfonts, marked, chalk, ...).
|
|
398
|
+
|
|
399
|
+
## 📜 License
|
|
400
|
+
|
|
401
|
+
MIT © SimpleLittleDev
|
package/bin/fastcode.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// FastCode CLI shim.
|
|
3
|
+
//
|
|
4
|
+
// Resolution order:
|
|
5
|
+
// 1. dist/cli.js — self-contained esbuild bundle (committed to git: works
|
|
6
|
+
// after a plain `git clone`, no `npm install` required)
|
|
7
|
+
// 2. dist/index.js — tsc output (needs node_modules)
|
|
8
|
+
// 3. src/index.ts — dev fallback via tsx
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
|
|
13
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const bundleEntry = join(here, "..", "dist", "cli.js");
|
|
15
|
+
const distEntry = join(here, "..", "dist", "index.js");
|
|
16
|
+
const srcEntry = [join(here, "..", "src", "index.ts"), join(here, "..", "src", "index.tsx")].find((p) => existsSync(p));
|
|
17
|
+
|
|
18
|
+
const MISSING_DEPS_HELP = `
|
|
19
|
+
╭─────────────────────────────────────────────╮
|
|
20
|
+
│ ⚠️ FastCode 缺少依赖包 │
|
|
21
|
+
╰─────────────────────────────────────────────╯
|
|
22
|
+
|
|
23
|
+
请选择以下任一方式修复:
|
|
24
|
+
|
|
25
|
+
【方式一】一键安装(推荐)
|
|
26
|
+
bash scripts/install.sh
|
|
27
|
+
|
|
28
|
+
【方式二】手动安装依赖
|
|
29
|
+
cd package && npm install
|
|
30
|
+
|
|
31
|
+
【方式三】下载便携版
|
|
32
|
+
https://github.com/dateName/fastcode-termux/releases
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
async function run() {
|
|
36
|
+
try {
|
|
37
|
+
if (existsSync(bundleEntry)) {
|
|
38
|
+
await import(pathToFileURL(bundleEntry).href);
|
|
39
|
+
} else if (existsSync(distEntry)) {
|
|
40
|
+
await import(pathToFileURL(distEntry).href);
|
|
41
|
+
} else if (srcEntry) {
|
|
42
|
+
// Local dev fallback — let users `node ./bin/fastcode.mjs` from the repo
|
|
43
|
+
const { register } = await import("node:module");
|
|
44
|
+
register("tsx/esm", import.meta.url);
|
|
45
|
+
await import(pathToFileURL(srcEntry).href);
|
|
46
|
+
} else {
|
|
47
|
+
console.error("FastCode build artifacts not found. Did you run `npm run build`?");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (err && err.code === "ERR_MODULE_NOT_FOUND") {
|
|
52
|
+
console.error(MISSING_DEPS_HELP);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
run();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dangerous-command guard.
|
|
3
|
+
*
|
|
4
|
+
* Blocks destructive shell patterns before execution. Word-boundary escapes
|
|
5
|
+
* are written as character classes so the intent is identical without
|
|
6
|
+
* boundary syntax.
|
|
7
|
+
*
|
|
8
|
+
* Overrides:
|
|
9
|
+
* FASTCODE_ALLOW_DANGEROUS=1 bypass the deny list (reported in output)
|
|
10
|
+
* FASTCODE_SHELL_ALLOWLIST=a;b only commands matching these regexes run
|
|
11
|
+
* FASTCODE_SHELL_DENY_EXTRA=x;y extra regexes to deny
|
|
12
|
+
* FASTCODE_RESTRICT_TO_WORKSPACE=1 also reject ../ and .. escapes
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_DENY_PATTERNS: string[];
|
|
15
|
+
export declare const FORK_BOMB_MARKERS: string[];
|
|
16
|
+
/**
|
|
17
|
+
* Decide whether a shell command may run.
|
|
18
|
+
* Returns { allow: true } or { allow: false, output: explanation }.
|
|
19
|
+
*/
|
|
20
|
+
export declare function evaluateShellCommand(command: any): {
|
|
21
|
+
allow: boolean;
|
|
22
|
+
output: any;
|
|
23
|
+
bypassed: boolean;
|
|
24
|
+
pattern?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
allow: boolean;
|
|
27
|
+
pattern: string;
|
|
28
|
+
output: string;
|
|
29
|
+
bypassed?: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
allow: boolean;
|
|
32
|
+
output: string;
|
|
33
|
+
bypassed?: undefined;
|
|
34
|
+
pattern?: undefined;
|
|
35
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dangerous-command guard.
|
|
3
|
+
*
|
|
4
|
+
* Blocks destructive shell patterns before execution. Word-boundary escapes
|
|
5
|
+
* are written as character classes so the intent is identical without
|
|
6
|
+
* boundary syntax.
|
|
7
|
+
*
|
|
8
|
+
* Overrides:
|
|
9
|
+
* FASTCODE_ALLOW_DANGEROUS=1 bypass the deny list (reported in output)
|
|
10
|
+
* FASTCODE_SHELL_ALLOWLIST=a;b only commands matching these regexes run
|
|
11
|
+
* FASTCODE_SHELL_DENY_EXTRA=x;y extra regexes to deny
|
|
12
|
+
* FASTCODE_RESTRICT_TO_WORKSPACE=1 also reject ../ and .. escapes
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_DENY_PATTERNS = [
|
|
15
|
+
"(^|[^a-z])rm +-[rf]{1,2}([^a-z]|$)",
|
|
16
|
+
"(^|[^a-z])del +/[fq]([^a-z]|$)",
|
|
17
|
+
"(^|[^a-z])rmdir +/s([^a-z]|$)",
|
|
18
|
+
"(^|[^a-z-])(format|mkfs|diskpart)([^a-z]|$)",
|
|
19
|
+
"(^|[^a-z])dd +if=",
|
|
20
|
+
"> */dev/sd",
|
|
21
|
+
"(^|[^a-z])(shutdown|reboot|poweroff)([^a-z]|$)",
|
|
22
|
+
];
|
|
23
|
+
export const FORK_BOMB_MARKERS = [":(){", ":|:&"];
|
|
24
|
+
function enabled(name) {
|
|
25
|
+
const value = process.env[name];
|
|
26
|
+
if (value === undefined)
|
|
27
|
+
return false;
|
|
28
|
+
return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
|
|
29
|
+
}
|
|
30
|
+
function splitList(value) {
|
|
31
|
+
return (value ?? "").split(/[;,]/).map((entry) => entry.trim()).filter(Boolean);
|
|
32
|
+
}
|
|
33
|
+
function matches(lower, pattern) {
|
|
34
|
+
try {
|
|
35
|
+
return new RegExp(pattern).test(lower);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Decide whether a shell command may run.
|
|
43
|
+
* Returns { allow: true } or { allow: false, output: explanation }.
|
|
44
|
+
*/
|
|
45
|
+
export function evaluateShellCommand(command) {
|
|
46
|
+
const cmd = String(command ?? "").trim();
|
|
47
|
+
const lower = cmd.toLowerCase();
|
|
48
|
+
if (enabled("FASTCODE_ALLOW_DANGEROUS"))
|
|
49
|
+
return { allow: true, output: undefined, bypassed: true };
|
|
50
|
+
const deny = DEFAULT_DENY_PATTERNS.concat(splitList(process.env["FASTCODE_SHELL_DENY_EXTRA"]));
|
|
51
|
+
for (const pattern of deny) {
|
|
52
|
+
if (matches(lower, pattern)) {
|
|
53
|
+
return {
|
|
54
|
+
allow: false,
|
|
55
|
+
pattern,
|
|
56
|
+
output: "Error: blocked by the safety guard (dangerous pattern: " + pattern + "). " +
|
|
57
|
+
"Set FASTCODE_ALLOW_DANGEROUS=1 to override.",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const marker of FORK_BOMB_MARKERS) {
|
|
62
|
+
if (lower.includes(marker))
|
|
63
|
+
return { allow: false, output: "Error: blocked by the safety guard (fork bomb pattern)." };
|
|
64
|
+
}
|
|
65
|
+
const allowlist = splitList(process.env["FASTCODE_SHELL_ALLOWLIST"]);
|
|
66
|
+
if (allowlist.length > 0 && !allowlist.some((pattern) => matches(lower, pattern)))
|
|
67
|
+
return { allow: false, output: "Error: blocked by the safety guard (not in FASTCODE_SHELL_ALLOWLIST)." };
|
|
68
|
+
if (enabled("FASTCODE_RESTRICT_TO_WORKSPACE")) {
|
|
69
|
+
const backslash = String.fromCharCode(92);
|
|
70
|
+
if (cmd.includes("../") || cmd.includes(".." + backslash))
|
|
71
|
+
return { allow: false, output: "Error: blocked by the safety guard (path traversal)." };
|
|
72
|
+
}
|
|
73
|
+
return { allow: true, output: undefined };
|
|
74
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for how much tool output reaches the model.
|
|
3
|
+
*
|
|
4
|
+
* Output is bounded while it is produced, not by slicing a finished string
|
|
5
|
+
* afterwards, so a runaway command or a huge directory listing cannot grow
|
|
6
|
+
* without limit. Override the cap with FASTCODE_TOOL_OUTPUT_LIMIT (characters).
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_TOOL_OUTPUT_LIMIT = 30000;
|
|
9
|
+
export declare function toolOutputLimit(): number;
|
|
10
|
+
/**
|
|
11
|
+
* Bounded text accumulator.
|
|
12
|
+
*
|
|
13
|
+
* mode "head" keeps the first N characters (listings, search hits);
|
|
14
|
+
* mode "tail" keeps the last N (command logs, where the error is last).
|
|
15
|
+
* trimEnd()/toString() mimic a plain string so callers stay simple.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createOutputBuffer(limit?: number, mode?: string): {
|
|
18
|
+
readonly full: boolean;
|
|
19
|
+
push(chunk: any): void;
|
|
20
|
+
line(value: any): void;
|
|
21
|
+
value(): string;
|
|
22
|
+
trimEnd(): string;
|
|
23
|
+
toString(): string;
|
|
24
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for how much tool output reaches the model.
|
|
3
|
+
*
|
|
4
|
+
* Output is bounded while it is produced, not by slicing a finished string
|
|
5
|
+
* afterwards, so a runaway command or a huge directory listing cannot grow
|
|
6
|
+
* without limit. Override the cap with FASTCODE_TOOL_OUTPUT_LIMIT (characters).
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_TOOL_OUTPUT_LIMIT = 30000;
|
|
9
|
+
export function toolOutputLimit() {
|
|
10
|
+
const raw = Number(process.env["FASTCODE_TOOL_OUTPUT_LIMIT"]);
|
|
11
|
+
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : DEFAULT_TOOL_OUTPUT_LIMIT;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Bounded text accumulator.
|
|
15
|
+
*
|
|
16
|
+
* mode "head" keeps the first N characters (listings, search hits);
|
|
17
|
+
* mode "tail" keeps the last N (command logs, where the error is last).
|
|
18
|
+
* trimEnd()/toString() mimic a plain string so callers stay simple.
|
|
19
|
+
*/
|
|
20
|
+
export function createOutputBuffer(limit = toolOutputLimit(), mode = "head") {
|
|
21
|
+
const NL = String.fromCharCode(10);
|
|
22
|
+
let text = "";
|
|
23
|
+
let dropped = 0;
|
|
24
|
+
const buffer = {
|
|
25
|
+
get full() {
|
|
26
|
+
return text.length >= limit;
|
|
27
|
+
},
|
|
28
|
+
push(chunk) {
|
|
29
|
+
const value = String(chunk);
|
|
30
|
+
if (mode === "tail") {
|
|
31
|
+
text += value;
|
|
32
|
+
if (text.length > limit) {
|
|
33
|
+
const over = text.length - limit;
|
|
34
|
+
dropped += over;
|
|
35
|
+
text = text.slice(over);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (text.length >= limit) {
|
|
40
|
+
dropped += value.length;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const room = limit - text.length;
|
|
44
|
+
if (value.length <= room) {
|
|
45
|
+
text += value;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
text += value.slice(0, room);
|
|
49
|
+
dropped += value.length - room;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
line(value) {
|
|
53
|
+
if (text.length > 0)
|
|
54
|
+
buffer.push(NL);
|
|
55
|
+
buffer.push(value);
|
|
56
|
+
},
|
|
57
|
+
value() {
|
|
58
|
+
if (dropped <= 0)
|
|
59
|
+
return text;
|
|
60
|
+
const note = "[" + dropped + " more characters omitted]";
|
|
61
|
+
return mode === "tail" ? note + NL + text : text + NL + note;
|
|
62
|
+
},
|
|
63
|
+
trimEnd() {
|
|
64
|
+
return buffer.value().trimEnd();
|
|
65
|
+
},
|
|
66
|
+
toString() {
|
|
67
|
+
return buffer.value();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
return buffer;
|
|
71
|
+
}
|