autoclaw 1.0.38 → 1.1.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/LICENSE +21 -21
- package/README.md +201 -188
- package/README.zh-CN.md +192 -0
- package/dist/agent.js +155 -38
- package/dist/index.js +37 -4
- package/dist/tools/browser.js +5 -5
- package/dist/tools/prompt-optimizer.js +10 -10
- package/dist/tools/screenshot.js +4 -4
- package/dist/tools/search.js +8 -8
- package/package.json +70 -70
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 AutoClaw Contributor
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 AutoClaw Contributor
|
|
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,188 +1,201 @@
|
|
|
1
|
-
# AutoClaw 🦞
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/autoclaw)
|
|
4
|
-
[](https://www.npmjs.com/package/autoclaw)
|
|
5
|
-
[](https://github.com/tsingliuwin/autoclaw)
|
|
6
|
-
[](https://github.com/tsingliuwin/autoclaw/blob/main/LICENSE)
|
|
7
|
-
[](http://makeapullrequest.com)
|
|
8
|
-
|
|
9
|
-
**The
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
🔗 **GitHub Repository**: [https://github.com/tsingliuwin/autoclaw](https://github.com/tsingliuwin/autoclaw)
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- **
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
- `
|
|
124
|
-
- `
|
|
125
|
-
- `
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
1
|
+
# AutoClaw 🦞
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/autoclaw)
|
|
4
|
+
[](https://www.npmjs.com/package/autoclaw)
|
|
5
|
+
[](https://github.com/tsingliuwin/autoclaw)
|
|
6
|
+
[](https://github.com/tsingliuwin/autoclaw/blob/main/LICENSE)
|
|
7
|
+
[](http://makeapullrequest.com)
|
|
8
|
+
|
|
9
|
+
**The Engineering-First Headless Agent Framework: Stable, Scalable Automation for the Post-Vision Era.**
|
|
10
|
+
|
|
11
|
+
English | [简体中文](./README.zh-CN.md)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
🔗 **GitHub Repository**: [https://github.com/tsingliuwin/autoclaw](https://github.com/tsingliuwin/autoclaw)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
AutoClaw is a high-stability, open-source automation framework specifically engineered for **headless systems**.
|
|
20
|
+
|
|
21
|
+
Unlike "screen-seeing" agents (such as OpenClaw) that rely on visual interpretation, AutoClaw is built on a foundation of precise command-driven execution. This makes it significantly more **stable**, **robust from an engineering perspective**, and **easier to scale** across complex environments—whether it's a local server, a CI/CD pipeline, or thousands of containerized nodes.
|
|
22
|
+
|
|
23
|
+
## Why AutoClaw?
|
|
24
|
+
- 🐳 **Docker Native**: Built to run safely inside containers. Minimal footprint (Node.js/Alpine friendly).
|
|
25
|
+
- 🚀 **Better Engineering**: Operates via precise system APIs and shell commands rather than unstable visual recognition, ensuring deterministic outcomes.
|
|
26
|
+
- 🛡️ **Superior Stability**: Immune to issues like UI rendering, screen resolution, or network lag that plague vision-based agents.
|
|
27
|
+
- 📈 **Massive Scalability**: Low resource consumption allows orchestrating thousands of instances (e.g., in K8s) for true automation swarms.
|
|
28
|
+
- 🔌 **Swarm Ready**: Stateless design allows for easy orchestration via K8s, Docker Swarm, or simple shell loops.
|
|
29
|
+
- 🧩 **Extensible Integrations**: Built-in support for Web Search (Tavily), Email (SMTP), and Notification Webhooks (Feishu, DingTalk, WeCom).
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- 📜 **Headless Execution**: No browsers, no GUIs. Pure terminal efficiency.
|
|
34
|
+
- 🤖 **Non-Interactive Mode**: Intelligent flag handling (`-y`, `--no-interactive`) for zero-touch automation.
|
|
35
|
+
- 📂 **Universal Control**: From simple file I/O to complex system administration.
|
|
36
|
+
- 🧠 **Context Aware**: Detects container environments and provides accurate system time for relative date queries.
|
|
37
|
+
- 🌐 **Web Search**: Integrated with Tavily for real-time information retrieval.
|
|
38
|
+
- 🕒 **Time Accuracy**: Built-in tool to get precise system date and time for correct temporal context.
|
|
39
|
+
- 📧 **Communication**: Send emails and push notifications to chat groups automatically.
|
|
40
|
+
|
|
41
|
+
## Tech Stack
|
|
42
|
+
- **Runtime**: Node.js
|
|
43
|
+
- **Language**: TypeScript
|
|
44
|
+
- **Framework**: Commander.js
|
|
45
|
+
- **UI**: Inquirer (interactivity), Chalk (styling), Ora (spinners)
|
|
46
|
+
- **AI**: OpenAI SDK (Compatible with DeepSeek, LocalLLM, etc.)
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
### User Installation
|
|
51
|
+
Install globally via npm:
|
|
52
|
+
```bash
|
|
53
|
+
npm install -g autoclaw
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Development Installation
|
|
57
|
+
1. Clone the repository:
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/tsingliuwin/autoclaw.git
|
|
60
|
+
cd autoclaw
|
|
61
|
+
```
|
|
62
|
+
2. Install dependencies:
|
|
63
|
+
```bash
|
|
64
|
+
npm install
|
|
65
|
+
```
|
|
66
|
+
3. Build the project:
|
|
67
|
+
```bash
|
|
68
|
+
npm run build
|
|
69
|
+
```
|
|
70
|
+
4. Link globally (optional):
|
|
71
|
+
```bash
|
|
72
|
+
npm link
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
1. **Setup**: Run the interactive setup wizard to configure your API keys and integrations.
|
|
78
|
+
```bash
|
|
79
|
+
autoclaw setup
|
|
80
|
+
```
|
|
81
|
+
2. **Run**: Start the agent in interactive mode.
|
|
82
|
+
```bash
|
|
83
|
+
autoclaw
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
### Interactive Mode
|
|
89
|
+
Simply run `autoclaw` to enter the chat loop.
|
|
90
|
+
```bash
|
|
91
|
+
autoclaw
|
|
92
|
+
> List all TypeScript files in the src folder.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Headless Mode (One-Shot)
|
|
96
|
+
Run a single command and exit.
|
|
97
|
+
```bash
|
|
98
|
+
autoclaw "Check disk usage and save the report to usage.txt" --no-interactive
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Auto-Confirm (CI/CD)
|
|
102
|
+
Automatically approve all tool executions (dangerous, use with caution or in sandboxes).
|
|
103
|
+
```bash
|
|
104
|
+
autoclaw "Refactor src/index.ts to use ES modules" -y
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### CLI Options
|
|
108
|
+
- `-m, --model <model>`: Specify the LLM model (default: `gpt-4o`).
|
|
109
|
+
- `-n, --no-interactive`: Exit after processing the initial query (Headless mode).
|
|
110
|
+
- `-y, --yes`: Auto-confirm all tool executions (e.g., shell commands).
|
|
111
|
+
|
|
112
|
+
## Configuration
|
|
113
|
+
|
|
114
|
+
AutoClaw uses a hierarchical configuration system.
|
|
115
|
+
|
|
116
|
+
**Priority Order (Highest to Lowest):**
|
|
117
|
+
1. **CLI Arguments**: (e.g., `-m gpt-4o`)
|
|
118
|
+
2. **Environment Variables**: (`OPENAI_API_KEY`, `.env` file)
|
|
119
|
+
3. **Project Config**: (`./.autoclaw/setting.json` in current directory)
|
|
120
|
+
4. **Global Config**: (`~/.autoclaw/setting.json`)
|
|
121
|
+
|
|
122
|
+
### Supported Configuration Keys (JSON)
|
|
123
|
+
- `apiKey`: Your OpenAI API Key.
|
|
124
|
+
- `baseUrl`: Custom Base URL (e.g., for DeepSeek or LocalLLM).
|
|
125
|
+
- `model`: Default model to use.
|
|
126
|
+
- `tavilyApiKey`: API Key for Tavily Web Search.
|
|
127
|
+
- `smtpHost`, `smtpPort`, `smtpUser`, `smtpPass`, `smtpFrom`: SMTP Email settings.
|
|
128
|
+
- `feishuWebhook`, `dingtalkWebhook`, `wecomWebhook`: Notification webhooks.
|
|
129
|
+
|
|
130
|
+
### Project-Level Config Example
|
|
131
|
+
Create a file at `.autoclaw/setting.json`:
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"model": "gpt-3.5-turbo",
|
|
135
|
+
"baseUrl": "https://api.deepseek.com/v1"
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> **⚠️ Security Warning**: If you store your `apiKey` or secrets in `.autoclaw/setting.json`, make sure to add `.autoclaw/` to your `.gitignore` file to prevent leaking secrets!
|
|
140
|
+
|
|
141
|
+
## Integrations
|
|
142
|
+
|
|
143
|
+
### Web Search (Tavily)
|
|
144
|
+
AutoClaw can search the web if you provide a Tavily API Key during setup or in config.
|
|
145
|
+
- **Usage**: "Search for the latest Node.js release notes."
|
|
146
|
+
|
|
147
|
+
### Email (SMTP)
|
|
148
|
+
Configure SMTP settings to let the agent send emails.
|
|
149
|
+
- **Usage**: "Send an email to user@example.com with the summary of the log file."
|
|
150
|
+
|
|
151
|
+
### Notifications (Feishu/DingTalk/WeCom)
|
|
152
|
+
Configure webhooks to receive alerts or reports in your team chat apps.
|
|
153
|
+
- **Usage**: "Notify the team on Feishu that the build has finished."
|
|
154
|
+
|
|
155
|
+
### Date & Time
|
|
156
|
+
Built-in utility to provide the agent with the current system time, ensuring accurate handling of relative time requests.
|
|
157
|
+
- **Usage**: "What's the date today?" or "Remind me to check the logs next Monday."
|
|
158
|
+
|
|
159
|
+
## Docker Support
|
|
160
|
+
|
|
161
|
+
### Chinese Font Issues in Screenshots
|
|
162
|
+
When running AutoClaw inside a Docker container (especially Alpine or Debian Slim), screenshots of Chinese websites may display text as square boxes ("tofu") due to missing fonts. Emojis (e.g., 🔥) may also appear as squares.
|
|
163
|
+
|
|
164
|
+
**Solution:** Install CJK (Chinese/Japanese/Korean) and Emoji fonts in your container.
|
|
165
|
+
|
|
166
|
+
**For Debian/Ubuntu:**
|
|
167
|
+
```bash
|
|
168
|
+
apt-get update && apt-get install -y fonts-noto-cjk fonts-wqy-zenhei fonts-noto-color-emoji
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**For Alpine Linux:**
|
|
172
|
+
```bash
|
|
173
|
+
apk add font-noto-cjk font-noto-emoji
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT
|
|
179
|
+
|
|
180
|
+
## Contributing
|
|
181
|
+
|
|
182
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
183
|
+
|
|
184
|
+
1. Fork the Project
|
|
185
|
+
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
|
|
186
|
+
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
|
|
187
|
+
4. Push to the Branch (`git push origin feature/AmazingFeature`)
|
|
188
|
+
5. Open a Pull Request
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
GitHub: [https://github.com/tsingliuwin/autoclaw](https://github.com/tsingliuwin/autoclaw)
|
|
192
|
+
|
|
193
|
+
## Star History
|
|
194
|
+
|
|
195
|
+
<a href="https://www.star-history.com/?repos=tsingliuwin%2Fautoclaw&type=date&legend=top-left">
|
|
196
|
+
<picture>
|
|
197
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=tsingliuwin/autoclaw&type=date&theme=dark&legend=top-left" />
|
|
198
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=tsingliuwin/autoclaw&type=date&legend=top-left" />
|
|
199
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=tsingliuwin/autoclaw&type=date&legend=top-left" />
|
|
200
|
+
</picture>
|
|
201
|
+
</a>
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# AutoClaw 🦞
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/autoclaw)
|
|
4
|
+
[](https://www.npmjs.com/package/autoclaw)
|
|
5
|
+
[](https://github.com/tsingliuwin/autoclaw)
|
|
6
|
+
[](https://github.com/tsingliuwin/autoclaw/blob/main/LICENSE)
|
|
7
|
+
[](http://makeapullrequest.com)
|
|
8
|
+
|
|
9
|
+
**稳定、高工程化、易规模化:专为无界面系统设计的高效自动化 Agent 框架。**
|
|
10
|
+
|
|
11
|
+
[English](./README.md) | 简体中文
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
🔗 **GitHub 仓库**: [https://github.com/tsingliuwin/autoclaw](https://github.com/tsingliuwin/autoclaw)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
AutoClaw 是一款针对 **“无界面系统” (Headless Systems)** 的高稳定性自动化 Agent 开源框架。
|
|
20
|
+
|
|
21
|
+
相比于 OpenClaw 等需要“看屏幕”的 Agent(如视觉解析),AutoClaw 采用纯指令驱动,具有更强的**工程化**属性、更高的**稳定性**,以及极易**规模化**的特点。它专为在各种复杂环境中执行确定性的自动化任务而设计——无论是本地服务器、CI/CD 流水线,还是成千上万个容器节点。
|
|
22
|
+
|
|
23
|
+
## 为什么选择 AutoClaw?
|
|
24
|
+
|
|
25
|
+
- 🐳 **Docker 友好**: 专为容器化环境设计,无 GUI 依赖,极致轻量(Node.js/Alpine 友好)。
|
|
26
|
+
- 🚀 **更强工程化 (Better Engineering)**: 并非依赖不稳定的视觉识别,而是通过系统 API 和 Shell 指令精准操作,确保任务执行的确定性。
|
|
27
|
+
- 🛡️ **高稳定性 (Superior Stability)**: 摆脱了图形界面渲染、屏幕分辨率、网络延迟对视觉识别的影响,即便在极端的 Headless 环境下也能稳定运行。
|
|
28
|
+
- 📈 **易于规模化 (Massive Scalability)**: 低资源占用使得你可以同时编排成千上万个 Agent 实例(如在 Kubernetes 集群中),实现真正的自动化蜂群。
|
|
29
|
+
- 🔌 **集群就绪 (Swarm Ready)**: 无状态设计,支持通过 K8s、Docker Swarm 或简单的 Shell 脚本进行大规模调度。
|
|
30
|
+
- 🧩 **可扩展集成**: 内置支持网页搜索 (Tavily)、邮件发送 (SMTP) 以及通知钩子 (飞书、钉钉、企业微信)。
|
|
31
|
+
|
|
32
|
+
## 特性
|
|
33
|
+
|
|
34
|
+
- 📜 **无头执行 (Headless Execution)**: 真正的无头模式,无需浏览器或图形化界面。
|
|
35
|
+
- 🤖 **非交互模式**: 支持自动化标志(`-y`, `--no-interactive`),完美适配零干预的自动化流程。
|
|
36
|
+
- 📂 **全方位控制 (Universal Control)**: 从基础的文件 I/O 到复杂的系统管理与代码重构。
|
|
37
|
+
- 🧠 **上下文感知 (Context Aware)**: 自动识别操作系统与容器环境,并提供精确的系统时间以处理相对时间查询。
|
|
38
|
+
- 🌐 **网页搜索**: 集成 Tavily,支持实时信息检索。
|
|
39
|
+
- 🕒 **时间精准**: 内置工具获取精确系统日期和时间,确保正确的时间上下文。
|
|
40
|
+
- 📧 **通讯能力**: 自动发送电子邮件并将通知推送至聊天群组。
|
|
41
|
+
|
|
42
|
+
## 技术栈
|
|
43
|
+
- **运行时**: Node.js
|
|
44
|
+
- **语言**: TypeScript
|
|
45
|
+
- **框架**: Commander.js
|
|
46
|
+
- **UI**: Inquirer (交互), Chalk (样式), Ora (加载动画)
|
|
47
|
+
- **AI**: OpenAI SDK (兼容 DeepSeek, LocalLLM 等)
|
|
48
|
+
|
|
49
|
+
## 安装
|
|
50
|
+
|
|
51
|
+
### 用户安装
|
|
52
|
+
通过 npm 全局安装:
|
|
53
|
+
```bash
|
|
54
|
+
npm install -g autoclaw
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 开发安装
|
|
58
|
+
1. 克隆仓库:
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/tsingliuwin/autoclaw.git
|
|
61
|
+
cd autoclaw
|
|
62
|
+
```
|
|
63
|
+
2. 安装依赖:
|
|
64
|
+
```bash
|
|
65
|
+
npm install
|
|
66
|
+
```
|
|
67
|
+
3. 构建项目:
|
|
68
|
+
```bash
|
|
69
|
+
npm run build
|
|
70
|
+
```
|
|
71
|
+
4. 全局链接 (可选):
|
|
72
|
+
```bash
|
|
73
|
+
npm link
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 快速上手
|
|
77
|
+
|
|
78
|
+
1. **配置**: 运行交互式设置向导以配置您的 API 密钥和集成插件。
|
|
79
|
+
```bash
|
|
80
|
+
autoclaw setup
|
|
81
|
+
```
|
|
82
|
+
2. **运行**: 在交互模式下启动 Agent。
|
|
83
|
+
```bash
|
|
84
|
+
autoclaw
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 使用方法
|
|
88
|
+
|
|
89
|
+
### 交互模式
|
|
90
|
+
直接运行 `autoclaw` 进入对话循环。
|
|
91
|
+
```bash
|
|
92
|
+
autoclaw
|
|
93
|
+
> 列出 src 文件夹中所有的 TypeScript 文件。
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 无头模式 (一次性任务)
|
|
97
|
+
执行单个指令后立即退出。
|
|
98
|
+
```bash
|
|
99
|
+
autoclaw "检查磁盘使用情况并将报告保存到 usage.txt" --no-interactive
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 自动确认 (CI/CD)
|
|
103
|
+
自动批准所有工具执行(危险操作,请谨慎使用或在沙箱环境下运行)。
|
|
104
|
+
```bash
|
|
105
|
+
autoclaw "将 src/index.ts 重构为使用 ES 模块" -y
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### CLI 选项
|
|
109
|
+
- `-m, --model <model>`: 指定 LLM 模型 (默认: `gpt-4o`)。
|
|
110
|
+
- `-n, --no-interactive`: 处理完初始查询后退出 (无头模式)。
|
|
111
|
+
- `-y, --yes`: 自动确认所有工具执行 (例如 Shell 命令)。
|
|
112
|
+
|
|
113
|
+
## 配置
|
|
114
|
+
|
|
115
|
+
AutoClaw 使用层级配置系统。
|
|
116
|
+
|
|
117
|
+
**优先级排序 (从高到低):**
|
|
118
|
+
1. **CLI 参数**: (例如 `-m gpt-4o`)
|
|
119
|
+
2. **环境变量**: (`OPENAI_API_KEY`, `.env` 文件)
|
|
120
|
+
3. **项目配置**: (当前目录下的 `./.autoclaw/setting.json`)
|
|
121
|
+
4. **全局配置**: (`~/.autoclaw/setting.json`)
|
|
122
|
+
|
|
123
|
+
### 支持的配置键 (JSON)
|
|
124
|
+
- `apiKey`: 您的 OpenAI API 密钥。
|
|
125
|
+
- `baseUrl`: 自定义 API 基础地址 (例如 DeepSeek 或本地 LLM)。
|
|
126
|
+
- `model`: 默认使用的模型。
|
|
127
|
+
- `tavilyApiKey`: Tavily 网页搜索的 API 密钥。
|
|
128
|
+
- `smtpHost`, `smtpPort`, `smtpUser`, `smtpPass`, `smtpFrom`: SMTP 邮件设置。
|
|
129
|
+
- `feishuWebhook`, `dingtalkWebhook`, `wecomWebhook`: 通知钩子地址。
|
|
130
|
+
|
|
131
|
+
### 项目级配置示例
|
|
132
|
+
在 `.autoclaw/setting.json` 创建文件:
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"model": "gpt-3.5-turbo",
|
|
136
|
+
"baseUrl": "https://api.deepseek.com/v1"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
> **⚠️ 安全警告**: 如果您在 `.autoclaw/setting.json` 中存储了 `apiKey` 或机密信息,请务必将 `.autoclaw/` 添加到您的 `.gitignore` 文件中,以防泄露!
|
|
141
|
+
|
|
142
|
+
## 集成功能
|
|
143
|
+
|
|
144
|
+
### 网页搜索 (Tavily)
|
|
145
|
+
如果您在设置中提供了 Tavily API 密钥,AutoClaw 可以搜索网页。
|
|
146
|
+
- **示例**: "搜索最新的 Node.js 发布说明。"
|
|
147
|
+
|
|
148
|
+
### 邮件 (SMTP)
|
|
149
|
+
配置 SMTP 设置以允许 Agent 发送邮件。
|
|
150
|
+
- **示例**: "向 user@example.com 发送一封包含日志文件摘要的邮件。"
|
|
151
|
+
|
|
152
|
+
### 通知 (飞书/钉钉/企业微信)
|
|
153
|
+
配置 Webhook 以在团队聊天应用中接收警报或报告。
|
|
154
|
+
- **示例**: "在飞书上通知团队构建已完成。"
|
|
155
|
+
|
|
156
|
+
### 日期与时间
|
|
157
|
+
内置工具为 Agent 提供当前系统时间,确保准确处理相对时间请求。
|
|
158
|
+
- **示例**: "今天是几号?" 或 "提醒我下周一检查日志。"
|
|
159
|
+
|
|
160
|
+
## Docker 支持
|
|
161
|
+
|
|
162
|
+
### 截图中的中文显示问题
|
|
163
|
+
在 Docker 容器(尤其是 Alpine 或 Debian Slim)中运行时,网页截图中的中文可能会显示为方块("豆腐块")。表情符号(如 🔥)也可能显示为方块。
|
|
164
|
+
|
|
165
|
+
**解决方案:** 在容器中安装 CJK(中日韩)和 Emoji 字体。
|
|
166
|
+
|
|
167
|
+
**Debian/Ubuntu:**
|
|
168
|
+
```bash
|
|
169
|
+
apt-get update && apt-get install -y fonts-noto-cjk fonts-wqy-zenhei fonts-noto-color-emoji
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Alpine Linux:**
|
|
173
|
+
```bash
|
|
174
|
+
apk add font-noto-cjk font-noto-emoji
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 开源协议
|
|
178
|
+
|
|
179
|
+
MIT
|
|
180
|
+
|
|
181
|
+
## 贡献指南
|
|
182
|
+
|
|
183
|
+
欢迎贡献!请随时提交 Pull Request。
|
|
184
|
+
|
|
185
|
+
1. Fork 本项目
|
|
186
|
+
2. 创建您的特性分支 (`git checkout -b feature/AmazingFeature`)
|
|
187
|
+
3. 提交您的更改 (`git commit -m 'Add some AmazingFeature'`)
|
|
188
|
+
4. 推送至分支 (`git push origin feature/AmazingFeature`)
|
|
189
|
+
5. 开启一个 Pull Request
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
GitHub: [https://github.com/tsingliuwin/autoclaw](https://github.com/tsingliuwin/autoclaw)
|
package/dist/agent.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
+
import * as fs from 'fs';
|
|
4
5
|
import * as os from 'os';
|
|
6
|
+
import * as path from 'path';
|
|
5
7
|
import { getToolDefinitions, executeToolHandler } from './tools/index.js';
|
|
6
8
|
export class Agent {
|
|
7
9
|
client;
|
|
8
10
|
messages;
|
|
9
11
|
model;
|
|
10
12
|
config;
|
|
13
|
+
lastOutputFile = null;
|
|
11
14
|
constructor(apiKey, baseURL, model = 'gpt-4-turbo-preview', config = {}) {
|
|
12
15
|
this.client = new OpenAI({
|
|
13
16
|
apiKey: apiKey,
|
|
@@ -15,36 +18,37 @@ export class Agent {
|
|
|
15
18
|
});
|
|
16
19
|
this.model = model;
|
|
17
20
|
this.config = config;
|
|
18
|
-
const systemInfo = `
|
|
19
|
-
System Information:
|
|
20
|
-
- OS: ${os.type()} ${os.release()} (${os.platform()})
|
|
21
|
-
- Architecture: ${os.arch()}
|
|
22
|
-
- Node.js Version: ${process.version}
|
|
23
|
-
- Current Working Directory: ${process.cwd()}
|
|
24
|
-
- User: ${os.userInfo().username}
|
|
25
|
-
- Home Directory: ${os.homedir()}
|
|
26
|
-
- Current Date: ${new Date().toLocaleString()}
|
|
21
|
+
const systemInfo = `
|
|
22
|
+
System Information:
|
|
23
|
+
- OS: ${os.type()} ${os.release()} (${os.platform()})
|
|
24
|
+
- Architecture: ${os.arch()}
|
|
25
|
+
- Node.js Version: ${process.version}
|
|
26
|
+
- Current Working Directory: ${process.cwd()}
|
|
27
|
+
- User: ${os.userInfo().username}
|
|
28
|
+
- Home Directory: ${os.homedir()}
|
|
29
|
+
- Current Date: ${new Date().toLocaleString()}
|
|
27
30
|
`;
|
|
28
31
|
this.messages = [
|
|
29
32
|
{
|
|
30
33
|
role: "system",
|
|
31
|
-
content: `You are AutoClaw,
|
|
32
|
-
You
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
content: `You are AutoClaw, an engineering-first headless agent framework designed for stable, scalable automation.
|
|
35
|
+
You operate through precise command-driven execution rather than visual interpretation, ensuring deterministic and reproducible outcomes.
|
|
36
|
+
You may run on a local workstation, a headless server, inside a Docker container, or as part of a larger automated pipeline.
|
|
37
|
+
|
|
38
|
+
CONTEXT:
|
|
39
|
+
${systemInfo}
|
|
40
|
+
|
|
41
|
+
ENVIRONMENT CONSTRAINTS:
|
|
42
|
+
1. HEADLESS: No GUI available. Do not try to open browsers or apps.
|
|
43
|
+
2. CONTAINER-OPTIMIZED: Assume you are in a sandbox. You can be aggressive with file creation but robust with errors.
|
|
44
|
+
3. NON-INTERACTIVE: Always use flags to suppress prompts (e.g., 'apt-get -y', 'rm -rf').
|
|
45
|
+
|
|
46
|
+
GUIDELINES:
|
|
47
|
+
1. EFFICIENCY: Your goal is speed and success. Write scripts that just work.
|
|
48
|
+
2. ROBUSTNESS: Use standard Linux/Unix tools found in minimal images (Alpine/Debian).
|
|
49
|
+
3. TOOLS: Use 'execute_shell_command' for actions, 'write_file' for code generation.
|
|
50
|
+
4. CLARITY: Output concise logs. You are a worker unit, not a chat bot.
|
|
51
|
+
5. OPTIMIZATION: When asked to generate creative content (images, stories, complex code), use 'optimize_prompt' first to ensure the best possible output quality.
|
|
48
52
|
`
|
|
49
53
|
}
|
|
50
54
|
];
|
|
@@ -55,27 +59,140 @@ GUIDELINES:
|
|
|
55
59
|
while (active) {
|
|
56
60
|
const spinner = ora('Thinking...').start();
|
|
57
61
|
try {
|
|
58
|
-
const
|
|
62
|
+
const stream = await this.client.chat.completions.create({
|
|
59
63
|
model: this.model,
|
|
60
64
|
messages: this.messages,
|
|
61
65
|
tools: getToolDefinitions(),
|
|
62
|
-
tool_choice: "auto"
|
|
66
|
+
tool_choice: "auto",
|
|
67
|
+
stream: true
|
|
63
68
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
let content = '';
|
|
70
|
+
let reasoningContent = '';
|
|
71
|
+
let toolCalls = [];
|
|
72
|
+
let contentStarted = false;
|
|
73
|
+
let reasoningStarted = false;
|
|
74
|
+
const toolNamesSeen = new Set();
|
|
75
|
+
for await (const chunk of stream) {
|
|
76
|
+
const delta = chunk.choices[0]?.delta;
|
|
77
|
+
// Handle reasoning/thinking content (e.g., DeepSeek)
|
|
78
|
+
if (delta?.reasoning_content) {
|
|
79
|
+
if (!reasoningStarted) {
|
|
80
|
+
spinner.stop();
|
|
81
|
+
process.stdout.write(chalk.dim('\n[Thinking] '));
|
|
82
|
+
reasoningStarted = true;
|
|
83
|
+
}
|
|
84
|
+
process.stdout.write(chalk.dim(delta.reasoning_content));
|
|
85
|
+
reasoningContent += delta.reasoning_content;
|
|
86
|
+
}
|
|
87
|
+
// Handle regular content
|
|
88
|
+
if (delta?.content) {
|
|
89
|
+
if (!contentStarted) {
|
|
90
|
+
spinner.stop();
|
|
91
|
+
if (reasoningStarted)
|
|
92
|
+
process.stdout.write('\n');
|
|
93
|
+
process.stdout.write(chalk.blue("AutoClaw: "));
|
|
94
|
+
contentStarted = true;
|
|
95
|
+
}
|
|
96
|
+
process.stdout.write(delta.content);
|
|
97
|
+
content += delta.content;
|
|
98
|
+
}
|
|
99
|
+
// Handle tool calls - show name as soon as available
|
|
100
|
+
if (delta?.tool_calls) {
|
|
101
|
+
for (const tc of delta.tool_calls) {
|
|
102
|
+
const idx = tc.index;
|
|
103
|
+
if (!toolCalls[idx]) {
|
|
104
|
+
toolCalls[idx] = { id: tc.id || '', type: 'function', function: { name: '', arguments: '' } };
|
|
105
|
+
}
|
|
106
|
+
if (tc.id)
|
|
107
|
+
toolCalls[idx].id = tc.id;
|
|
108
|
+
if (tc.function?.name)
|
|
109
|
+
toolCalls[idx].function.name += tc.function.name;
|
|
110
|
+
if (tc.function?.arguments)
|
|
111
|
+
toolCalls[idx].function.arguments += tc.function.arguments;
|
|
112
|
+
// Show tool name as soon as it's complete
|
|
113
|
+
if (tc.function?.name && !toolNamesSeen.has(idx)) {
|
|
114
|
+
toolNamesSeen.add(idx);
|
|
115
|
+
spinner.stop();
|
|
116
|
+
if (contentStarted)
|
|
117
|
+
process.stdout.write('\n');
|
|
118
|
+
if (reasoningStarted && !contentStarted)
|
|
119
|
+
process.stdout.write('\n');
|
|
120
|
+
process.stdout.write(chalk.cyan(`[Calling] ${tc.function.name}\n`));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (reasoningStarted) {
|
|
126
|
+
console.log(); // newline after reasoning
|
|
69
127
|
}
|
|
70
|
-
if (
|
|
71
|
-
|
|
128
|
+
if (contentStarted) {
|
|
129
|
+
console.log(); // newline after streamed content
|
|
130
|
+
}
|
|
131
|
+
if (!reasoningStarted && !contentStarted) {
|
|
132
|
+
spinner.stop();
|
|
133
|
+
}
|
|
134
|
+
// Build the full message for history
|
|
135
|
+
const message = { role: "assistant" };
|
|
136
|
+
if (content)
|
|
137
|
+
message.content = content;
|
|
138
|
+
if (reasoningContent)
|
|
139
|
+
message.reasoning_content = reasoningContent;
|
|
140
|
+
if (toolCalls.length > 0) {
|
|
141
|
+
message.tool_calls = toolCalls;
|
|
142
|
+
message.content = message.content || null;
|
|
143
|
+
}
|
|
144
|
+
this.messages.push(message);
|
|
145
|
+
if (toolCalls.length > 0) {
|
|
146
|
+
for (const toolCall of toolCalls) {
|
|
72
147
|
if (toolCall.type !== 'function')
|
|
73
148
|
continue;
|
|
74
149
|
const functionName = toolCall.function.name;
|
|
75
150
|
const functionArgs = JSON.parse(toolCall.function.arguments);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
151
|
+
// Display tool call info
|
|
152
|
+
console.log(chalk.cyan(`\n[Tool] ${functionName}`));
|
|
153
|
+
const argsStr = JSON.stringify(functionArgs, null, 2);
|
|
154
|
+
const argsLines = argsStr.split('\n');
|
|
155
|
+
if (argsLines.length > 8) {
|
|
156
|
+
console.log(chalk.dim(argsLines.slice(0, 8).join('\n')));
|
|
157
|
+
console.log(chalk.dim(` ... (${argsLines.length - 8} more lines)`));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
console.log(chalk.dim(argsStr));
|
|
161
|
+
}
|
|
162
|
+
const execSpinner = ora('Executing...').start();
|
|
163
|
+
let toolResult;
|
|
164
|
+
try {
|
|
165
|
+
toolResult = await executeToolHandler(functionName, functionArgs, this.config);
|
|
166
|
+
execSpinner.stop();
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
execSpinner.fail('Tool execution failed');
|
|
170
|
+
toolResult = `Error: ${err.message}`;
|
|
171
|
+
}
|
|
172
|
+
// Display result with folding for long output
|
|
173
|
+
const MAX_PREVIEW_LINES = 20;
|
|
174
|
+
const resultLines = toolResult.split('\n');
|
|
175
|
+
console.log(chalk.green(`[Result]`));
|
|
176
|
+
if (resultLines.length > MAX_PREVIEW_LINES) {
|
|
177
|
+
// Show preview
|
|
178
|
+
console.log(resultLines.slice(0, MAX_PREVIEW_LINES).join('\n'));
|
|
179
|
+
const remaining = resultLines.length - MAX_PREVIEW_LINES;
|
|
180
|
+
console.log(chalk.dim(`\n ... ${remaining} more lines (${resultLines.length} lines total)`));
|
|
181
|
+
// Save full output to file
|
|
182
|
+
const outputDir = path.join(os.homedir(), '.autoclaw', 'output');
|
|
183
|
+
if (!fs.existsSync(outputDir)) {
|
|
184
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
185
|
+
}
|
|
186
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
187
|
+
const outputFile = path.join(outputDir, `${functionName}_${ts}.txt`);
|
|
188
|
+
fs.writeFileSync(outputFile, toolResult, 'utf-8');
|
|
189
|
+
this.lastOutputFile = outputFile;
|
|
190
|
+
console.log(chalk.dim(` Type '/view' to see full output`));
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
console.log(toolResult);
|
|
194
|
+
this.lastOutputFile = null;
|
|
195
|
+
}
|
|
79
196
|
this.messages.push({
|
|
80
197
|
role: "tool",
|
|
81
198
|
tool_call_id: toolCall.id,
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import * as path from 'path';
|
|
|
9
9
|
import * as os from 'os';
|
|
10
10
|
import * as readline from 'node:readline/promises';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
|
+
import { spawn } from 'child_process';
|
|
12
13
|
// Handle Ctrl+C gracefully
|
|
13
14
|
function handleExit() {
|
|
14
15
|
console.log(chalk.cyan("\n\nGoodbye! (Interrupted)"));
|
|
@@ -23,6 +24,7 @@ process.on('SIGTERM', handleExit);
|
|
|
23
24
|
const GLOBAL_CONFIG_DIR = path.join(os.homedir(), '.autoclaw');
|
|
24
25
|
const GLOBAL_CONFIG_FILE = path.join(GLOBAL_CONFIG_DIR, 'setting.json');
|
|
25
26
|
const LOCAL_CONFIG_FILE = path.join(process.cwd(), '.autoclaw', 'setting.json');
|
|
27
|
+
const GLOBAL_ENV_FILE = path.join(GLOBAL_CONFIG_DIR, '.env');
|
|
26
28
|
function loadJsonConfig(filePath) {
|
|
27
29
|
if (fs.existsSync(filePath)) {
|
|
28
30
|
try {
|
|
@@ -34,8 +36,9 @@ function loadJsonConfig(filePath) {
|
|
|
34
36
|
}
|
|
35
37
|
return {};
|
|
36
38
|
}
|
|
37
|
-
// Load
|
|
38
|
-
|
|
39
|
+
// Load env vars only from AutoClaw's own config directory to avoid
|
|
40
|
+
// unrelated project/home .env files overriding API settings.
|
|
41
|
+
dotenv.config({ path: GLOBAL_ENV_FILE });
|
|
39
42
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
40
43
|
// In dist/index.js, package.json is usually up one level in the root
|
|
41
44
|
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
@@ -406,6 +409,32 @@ async function runChat(queryParts, options) {
|
|
|
406
409
|
console.log(chalk.cyan("Goodbye!"));
|
|
407
410
|
break;
|
|
408
411
|
}
|
|
412
|
+
if (userInput.toLowerCase() === '/view') {
|
|
413
|
+
if (agent.lastOutputFile && fs.existsSync(agent.lastOutputFile)) {
|
|
414
|
+
rl.pause();
|
|
415
|
+
try {
|
|
416
|
+
await new Promise((resolve, reject) => {
|
|
417
|
+
const isWin = process.platform === 'win32';
|
|
418
|
+
const cmd = isWin ? 'more' : (process.env.PAGER || 'less');
|
|
419
|
+
const args = isWin ? [agent.lastOutputFile] : ['-R', agent.lastOutputFile];
|
|
420
|
+
const child = spawn(cmd, args, { stdio: 'inherit' });
|
|
421
|
+
child.on('close', () => resolve());
|
|
422
|
+
child.on('error', (err) => {
|
|
423
|
+
console.error(chalk.red(`Failed to open pager: ${err.message}`));
|
|
424
|
+
console.log(chalk.dim(`You can manually view: ${agent.lastOutputFile}`));
|
|
425
|
+
resolve();
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
finally {
|
|
430
|
+
rl.resume();
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
console.log(chalk.yellow("No tool output to view."));
|
|
435
|
+
}
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
409
438
|
if (userInput.trim() === '')
|
|
410
439
|
continue;
|
|
411
440
|
rl.pause();
|
|
@@ -418,7 +447,7 @@ async function runChat(queryParts, options) {
|
|
|
418
447
|
}
|
|
419
448
|
}
|
|
420
449
|
catch (err) {
|
|
421
|
-
if (
|
|
450
|
+
if (isUserAbort(err)) {
|
|
422
451
|
console.log(chalk.cyan("\nGoodbye!"));
|
|
423
452
|
}
|
|
424
453
|
else {
|
|
@@ -429,9 +458,13 @@ async function runChat(queryParts, options) {
|
|
|
429
458
|
rl.close();
|
|
430
459
|
}
|
|
431
460
|
}
|
|
461
|
+
function isUserAbort(err) {
|
|
462
|
+
return err.code === 'ABORT_ERR'
|
|
463
|
+
|| (err.message && (err.message.includes('User force closed') || err.message.includes('Prompt was canceled')));
|
|
464
|
+
}
|
|
432
465
|
// Global error handler
|
|
433
466
|
main().catch(err => {
|
|
434
|
-
if (
|
|
467
|
+
if (isUserAbort(err)) {
|
|
435
468
|
console.log(chalk.cyan("\nGoodbye!"));
|
|
436
469
|
process.exit(0);
|
|
437
470
|
}
|
package/dist/tools/browser.js
CHANGED
|
@@ -48,13 +48,13 @@ export const BrowserTool = {
|
|
|
48
48
|
if (!article) {
|
|
49
49
|
// Fallback: just return body text if Readability fails
|
|
50
50
|
const bodyText = await page.innerText('body');
|
|
51
|
-
return `Could not parse article content with Readability. Raw text content:
|
|
52
|
-
|
|
51
|
+
return `Could not parse article content with Readability. Raw text content:
|
|
52
|
+
|
|
53
53
|
${bodyText.slice(0, 5000)}... (truncated)`;
|
|
54
54
|
}
|
|
55
|
-
return `Title: ${article.title}
|
|
56
|
-
|
|
57
|
-
Content:
|
|
55
|
+
return `Title: ${article.title}
|
|
56
|
+
|
|
57
|
+
Content:
|
|
58
58
|
${(article.textContent || "").trim()}`;
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
|
@@ -37,20 +37,20 @@ export const PromptOptimizerTool = {
|
|
|
37
37
|
messages: [
|
|
38
38
|
{
|
|
39
39
|
role: "system",
|
|
40
|
-
content: `You are an expert Prompt Engineer. Your goal is to rewrite the user's raw prompt to be clear, precise, and highly effective for LLMs or professional communication.
|
|
41
|
-
|
|
42
|
-
RULES:
|
|
43
|
-
1. Preserve the original intent.
|
|
44
|
-
2. Structure the prompt logically (e.g., Role, Context, Task, Constraints, Output Format).
|
|
45
|
-
3. Use professional and concise language.
|
|
40
|
+
content: `You are an expert Prompt Engineer. Your goal is to rewrite the user's raw prompt to be clear, precise, and highly effective for LLMs or professional communication.
|
|
41
|
+
|
|
42
|
+
RULES:
|
|
43
|
+
1. Preserve the original intent.
|
|
44
|
+
2. Structure the prompt logically (e.g., Role, Context, Task, Constraints, Output Format).
|
|
45
|
+
3. Use professional and concise language.
|
|
46
46
|
4. Return ONLY the optimized prompt. Do not add conversational filler.`
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
role: "user",
|
|
50
|
-
content: `Raw Prompt: "${args.raw_prompt}"
|
|
51
|
-
|
|
52
|
-
${contextMsg}
|
|
53
|
-
|
|
50
|
+
content: `Raw Prompt: "${args.raw_prompt}"
|
|
51
|
+
|
|
52
|
+
${contextMsg}
|
|
53
|
+
|
|
54
54
|
Please optimize this prompt.`
|
|
55
55
|
}
|
|
56
56
|
]
|
package/dist/tools/screenshot.js
CHANGED
|
@@ -151,10 +151,10 @@ export const ScreenshotTool = {
|
|
|
151
151
|
// Alpine: apk add font-noto-cjk font-noto-emoji
|
|
152
152
|
// Debian/Ubuntu: apt-get install fonts-noto-cjk fonts-wqy-zenhei fonts-noto-color-emoji
|
|
153
153
|
await page.addStyleTag({
|
|
154
|
-
content: `
|
|
155
|
-
body, h1, h2, h3, h4, h5, h6, p, span, div, li, a, button, input, textarea {
|
|
156
|
-
font-family: "PingFang SC", "Heiti SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "Noto Sans CJK SC", "Noto Sans SC", "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif !important;
|
|
157
|
-
}
|
|
154
|
+
content: `
|
|
155
|
+
body, h1, h2, h3, h4, h5, h6, p, span, div, li, a, button, input, textarea {
|
|
156
|
+
font-family: "PingFang SC", "Heiti SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "Noto Sans CJK SC", "Noto Sans SC", "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif !important;
|
|
157
|
+
}
|
|
158
158
|
`
|
|
159
159
|
});
|
|
160
160
|
// Wait for fonts to be ready
|
package/dist/tools/search.js
CHANGED
|
@@ -49,22 +49,22 @@ export const SearchTool = {
|
|
|
49
49
|
}
|
|
50
50
|
const data = await response.json();
|
|
51
51
|
// Format the results beautifully for the LLM
|
|
52
|
-
let output = `Search Results for "${args.query}":
|
|
53
|
-
|
|
52
|
+
let output = `Search Results for "${args.query}":
|
|
53
|
+
|
|
54
54
|
`;
|
|
55
55
|
if (data.answer) {
|
|
56
|
-
output += `💡 **Direct Answer**: ${data.answer}
|
|
57
|
-
|
|
56
|
+
output += `💡 **Direct Answer**: ${data.answer}
|
|
57
|
+
|
|
58
58
|
`;
|
|
59
59
|
}
|
|
60
60
|
if (data.results && Array.isArray(data.results)) {
|
|
61
61
|
data.results.forEach((result, index) => {
|
|
62
|
-
output += `### ${index + 1}. ${result.title}
|
|
62
|
+
output += `### ${index + 1}. ${result.title}
|
|
63
63
|
`;
|
|
64
|
-
output += `🔗 ${result.url}
|
|
64
|
+
output += `🔗 ${result.url}
|
|
65
65
|
`;
|
|
66
|
-
output += `📝 ${result.content}
|
|
67
|
-
|
|
66
|
+
output += `📝 ${result.content}
|
|
67
|
+
|
|
68
68
|
`;
|
|
69
69
|
});
|
|
70
70
|
}
|
package/package.json
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "autoclaw",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"type": "module",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"autoclaw": "dist/index.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "tsc",
|
|
11
|
-
"start": "node dist/index.js",
|
|
12
|
-
"dev": "node --loader ts-node/esm src/index.ts",
|
|
13
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
14
|
-
"prepublishOnly": "npm run build"
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist",
|
|
18
|
-
"README.md",
|
|
19
|
-
"package.json",
|
|
20
|
-
"LICENSE"
|
|
21
|
-
],
|
|
22
|
-
"keywords": [
|
|
23
|
-
"ai",
|
|
24
|
-
"cli",
|
|
25
|
-
"agent",
|
|
26
|
-
"automation",
|
|
27
|
-
"openai",
|
|
28
|
-
"tool",
|
|
29
|
-
"docker",
|
|
30
|
-
"headless",
|
|
31
|
-
"devops",
|
|
32
|
-
"llm",
|
|
33
|
-
"gpt-4",
|
|
34
|
-
"typescript",
|
|
35
|
-
"orchestration",
|
|
36
|
-
"infrastructure",
|
|
37
|
-
"terminal"
|
|
38
|
-
],
|
|
39
|
-
"author": "AutoClaw Contributor",
|
|
40
|
-
"license": "MIT",
|
|
41
|
-
"repository": {
|
|
42
|
-
"type": "git",
|
|
43
|
-
"url": "git+https://github.com/tsingliuwin/autoclaw.git"
|
|
44
|
-
},
|
|
45
|
-
"bugs": {
|
|
46
|
-
"url": "https://github.com/tsingliuwin/autoclaw/issues"
|
|
47
|
-
},
|
|
48
|
-
"homepage": "https://github.com/tsingliuwin/autoclaw#readme",
|
|
49
|
-
"description": "A lightweight AI agent CLI tool that brings the power of LLMs to your terminal.",
|
|
50
|
-
"dependencies": {
|
|
51
|
-
"@mozilla/readability": "^0.6.0",
|
|
52
|
-
"chalk": "^5.6.2",
|
|
53
|
-
"commander": "^14.0.3",
|
|
54
|
-
"dotenv": "^16.4.7",
|
|
55
|
-
"inquirer": "^13.2.2",
|
|
56
|
-
"jsdom": "^28.0.0",
|
|
57
|
-
"nodemailer": "^8.0.0",
|
|
58
|
-
"openai": "^6.18.0",
|
|
59
|
-
"ora": "^9.3.0",
|
|
60
|
-
"playwright": "^1.58.2"
|
|
61
|
-
},
|
|
62
|
-
"devDependencies": {
|
|
63
|
-
"@types/inquirer": "^9.0.9",
|
|
64
|
-
"@types/jsdom": "^27.0.0",
|
|
65
|
-
"@types/node": "^25.2.1",
|
|
66
|
-
"@types/nodemailer": "^7.0.9",
|
|
67
|
-
"ts-node": "^10.9.2",
|
|
68
|
-
"typescript": "^5.9.3"
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "autoclaw",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"autoclaw": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"dev": "node --loader ts-node/esm src/index.ts",
|
|
13
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"package.json",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"ai",
|
|
24
|
+
"cli",
|
|
25
|
+
"agent",
|
|
26
|
+
"automation",
|
|
27
|
+
"openai",
|
|
28
|
+
"tool",
|
|
29
|
+
"docker",
|
|
30
|
+
"headless",
|
|
31
|
+
"devops",
|
|
32
|
+
"llm",
|
|
33
|
+
"gpt-4",
|
|
34
|
+
"typescript",
|
|
35
|
+
"orchestration",
|
|
36
|
+
"infrastructure",
|
|
37
|
+
"terminal"
|
|
38
|
+
],
|
|
39
|
+
"author": "AutoClaw Contributor",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/tsingliuwin/autoclaw.git"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/tsingliuwin/autoclaw/issues"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/tsingliuwin/autoclaw#readme",
|
|
49
|
+
"description": "A lightweight AI agent CLI tool that brings the power of LLMs to your terminal.",
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@mozilla/readability": "^0.6.0",
|
|
52
|
+
"chalk": "^5.6.2",
|
|
53
|
+
"commander": "^14.0.3",
|
|
54
|
+
"dotenv": "^16.4.7",
|
|
55
|
+
"inquirer": "^13.2.2",
|
|
56
|
+
"jsdom": "^28.0.0",
|
|
57
|
+
"nodemailer": "^8.0.0",
|
|
58
|
+
"openai": "^6.18.0",
|
|
59
|
+
"ora": "^9.3.0",
|
|
60
|
+
"playwright": "^1.58.2"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/inquirer": "^9.0.9",
|
|
64
|
+
"@types/jsdom": "^27.0.0",
|
|
65
|
+
"@types/node": "^25.2.1",
|
|
66
|
+
"@types/nodemailer": "^7.0.9",
|
|
67
|
+
"ts-node": "^10.9.2",
|
|
68
|
+
"typescript": "^5.9.3"
|
|
69
|
+
}
|
|
70
|
+
}
|