@simonyea/holysheep-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -0
- package/package.json +42 -0
- package/src/commands/balance.js +56 -0
- package/src/commands/doctor.js +109 -0
- package/src/commands/reset.js +53 -0
- package/src/commands/setup.js +155 -0
- package/src/index.js +103 -0
- package/src/tools/aider.js +79 -0
- package/src/tools/claude-code.js +75 -0
- package/src/tools/codex.js +117 -0
- package/src/tools/continue.js +79 -0
- package/src/tools/cursor.js +69 -0
- package/src/tools/gemini-cli.js +73 -0
- package/src/tools/index.js +13 -0
- package/src/tools/openclaw.js +79 -0
- package/src/tools/opencode.js +92 -0
- package/src/utils/config.js +52 -0
- package/src/utils/shell.js +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# ๐ HolySheep CLI
|
|
2
|
+
|
|
3
|
+
> ไธ้ฎ้
็ฝฎๆๆ AI ็ผ็จๅทฅๅ
ทๆฅๅ
ฅ HolySheep API โ ๅฝๅ
็ด่ฟ๏ผยฅ1=$1๏ผๆ ้้ญๆณ
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/holysheep-cli)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/holysheep-ai/cli)
|
|
8
|
+
|
|
9
|
+
**HolySheep CLI** ่ฎฉไฝ ็จไธๆกๅฝไปค๏ผๆ Claude CodeใCodexใGemini CLIใOpenCodeใOpenClawใAiderใCursorใContinue.dev ๅ
จ้จๆฅๅ
ฅ [HolySheep API](https://shop.holysheep.ai)ใ
|
|
10
|
+
|
|
11
|
+
ๆ ้้ไธชๅทฅๅ
ทๆๅจ้
็ฝฎ็ฏๅขๅ้ๅ้
็ฝฎๆไปถ๏ผไธ้ฎๆๅฎใ
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ๅฎ่ฃ
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g holysheep-cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
ๆ่
ๆ ้ๅฎ่ฃ
็ดๆฅ่ฟ่ก๏ผ
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx holysheep-cli setup
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## ๅฟซ้ๅผๅง
|
|
30
|
+
|
|
31
|
+
### ็ฌฌไธๆญฅ๏ผๆณจๅ่ดฆๅท๏ผ่ทๅ API Key
|
|
32
|
+
|
|
33
|
+
ๅๅพ **[shop.holysheep.ai](https://shop.holysheep.ai)** ๆณจๅ่ดฆๅท๏ผๅ
ๅผๅๅจใAPI ๅฏ้ฅใ้กต้ขๅๅปบ `cr_xxx` ๆ ผๅผ็ๅฏ้ฅใ
|
|
34
|
+
|
|
35
|
+
> ๐ก ยฅ1 = $1 ็พๅ
้ขๅบฆ๏ผไฝ้ขๆฐธไน
ๆๆ๏ผๆ้่ฎก่ดน
|
|
36
|
+
|
|
37
|
+
### ็ฌฌไบๆญฅ๏ผไธ้ฎ้
็ฝฎ
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
hs setup
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
ๆๆ็คบ้ๆฉ่ฆ้
็ฝฎ็ๅทฅๅ
ท๏ผ่พๅ
ฅ API Key๏ผๅฎๆ๏ผ
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
๐ HolySheep CLI โ ไธ้ฎ้
็ฝฎ AI ๅทฅๅ
ท
|
|
47
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
48
|
+
? API Key (cr_xxx): cr_xxxxxxxxxxxxxxxx
|
|
49
|
+
? ้ๆฉ่ฆ้
็ฝฎ็ๅทฅๅ
ท:
|
|
50
|
+
โ
Claude Code (ๅทฒๅฎ่ฃ
)
|
|
51
|
+
โ
Gemini CLI (ๅทฒๅฎ่ฃ
)
|
|
52
|
+
โ Codex CLI (ๆชๅฎ่ฃ
)
|
|
53
|
+
โ Aider (ๆชๅฎ่ฃ
)
|
|
54
|
+
|
|
55
|
+
โ Claude Code โ ~/.claude/settings.json (็ญๅๆข๏ผๆ ้้ๅฏ)
|
|
56
|
+
โ Gemini CLI โ ~/.gemini/settings.json
|
|
57
|
+
โ ็ฏๅขๅ้ๅทฒๅๅ
ฅ: ~/.zshrc
|
|
58
|
+
|
|
59
|
+
โ
้
็ฝฎๅฎๆ๏ผ
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## ๅฝไปค
|
|
65
|
+
|
|
66
|
+
| ๅฝไปค | ่ฏดๆ |
|
|
67
|
+
|------|------|
|
|
68
|
+
| `hs setup` | ไธ้ฎ้
็ฝฎๆๆ AI ๅทฅๅ
ท |
|
|
69
|
+
| `hs doctor` | ๆฃๆฅ้
็ฝฎ็ถๆๅ่ฟ้ๆง |
|
|
70
|
+
| `hs balance` | ๆฅ็่ดฆๆทไฝ้ขๅ็จ้ |
|
|
71
|
+
| `hs tools` | ๅๅบๆๆๆฏๆ็ๅทฅๅ
ท |
|
|
72
|
+
| `hs reset` | ๆธ
้คๆๆ้
็ฝฎ๏ผๆขๅค้ป่ฎค |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## ๆฏๆ็ๅทฅๅ
ท
|
|
77
|
+
|
|
78
|
+
| ๅทฅๅ
ท | ๅฎ่ฃ
ๆนๅผ | ้
็ฝฎๆนๅผ | ็ญๅๆข |
|
|
79
|
+
|------|---------|---------|-------|
|
|
80
|
+
| **[Claude Code](https://docs.anthropic.com/claude-code)** | `npm i -g @anthropic-ai/claude-code` | `~/.claude/settings.json` | โ
|
|
|
81
|
+
| **[Codex CLI](https://github.com/openai/codex)** | `npm i -g @openai/codex` | `~/.codex/config.yaml` + ็ฏๅขๅ้ | โ |
|
|
82
|
+
| **[Gemini CLI](https://github.com/google-gemini/gemini-cli)** | `npm i -g @google/gemini-cli` | `~/.gemini/settings.json` | โ |
|
|
83
|
+
| **[OpenCode](https://github.com/sst/opencode)** | `npm i -g opencode-ai` | `~/.config/opencode/config.json` | โ |
|
|
84
|
+
| **[OpenClaw](https://github.com/iOfficeAI/AionUi)** | ๅฎ็ฝไธ่ฝฝ | `~/.openclaw/settings.json` | โ
|
|
|
85
|
+
| **[Aider](https://aider.chat)** | `pip install aider-chat` | `~/.aider.conf.yml` + ็ฏๅขๅ้ | โ |
|
|
86
|
+
| **[Cursor](https://cursor.sh)** | ๅฎ็ฝไธ่ฝฝ | GUI ้
็ฝฎๅผๅฏผ | โ |
|
|
87
|
+
| **[Continue.dev](https://continue.dev)** | VS Code ๆไปถๅธๅบ | `~/.continue/config.json` | โ
|
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## ๆฅๅ
ฅไฟกๆฏ
|
|
92
|
+
|
|
93
|
+
| ็จ้ | ๅฐๅ |
|
|
94
|
+
|------|------|
|
|
95
|
+
| Anthropic SDK / Claude Code | `https://api.holysheep.ai` ๏ผไธๅธฆ /v1๏ผ |
|
|
96
|
+
| OpenAI ๅ
ผๅฎน / Codex / Aider | `https://api.holysheep.ai/v1` ๏ผๅธฆ /v1๏ผ |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## ๆๅจ้
็ฝฎๅ่
|
|
101
|
+
|
|
102
|
+
ๅฆๆไฝ ไธๆณ็จ CLI๏ผไนๅฏไปฅๆๅจ้
็ฝฎ๏ผ
|
|
103
|
+
|
|
104
|
+
### Claude Code
|
|
105
|
+
```bash
|
|
106
|
+
# ~/.claude/settings.json
|
|
107
|
+
{
|
|
108
|
+
"env": {
|
|
109
|
+
"ANTHROPIC_AUTH_TOKEN": "cr_xxx",
|
|
110
|
+
"ANTHROPIC_BASE_URL": "https://api.holysheep.ai"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### ็ฏๅขๅ้๏ผ้็จไบๆๆๅทฅๅ
ท๏ผ
|
|
116
|
+
```bash
|
|
117
|
+
export ANTHROPIC_API_KEY="cr_xxx"
|
|
118
|
+
export ANTHROPIC_BASE_URL="https://api.holysheep.ai"
|
|
119
|
+
export OPENAI_API_KEY="cr_xxx"
|
|
120
|
+
export OPENAI_BASE_URL="https://api.holysheep.ai/v1"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Codex CLI (`~/.codex/config.yaml`)
|
|
124
|
+
```yaml
|
|
125
|
+
providers:
|
|
126
|
+
- name: HolySheep
|
|
127
|
+
baseURL: https://api.holysheep.ai/v1
|
|
128
|
+
envKey: OPENAI_API_KEY
|
|
129
|
+
model: claude-sonnet-4-5
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Aider
|
|
133
|
+
```bash
|
|
134
|
+
aider --openai-api-base https://api.holysheep.ai/v1 \
|
|
135
|
+
--openai-api-key cr_xxx \
|
|
136
|
+
--model openai/claude-sonnet-4-5
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## ๅธธ่ง้ฎ้ข
|
|
142
|
+
|
|
143
|
+
**Q: ๆฏๆๅชไบๆจกๅ๏ผ**
|
|
144
|
+
A: ๆฏๆ Claude 3.5/3.7 ๅ
จ็ณปใGPT-4oใGemini 1.5 Pro ็ญไธปๆตๆจกๅ๏ผ่ฏฆ่ง [shop.holysheep.ai/app/apikeys](https://shop.holysheep.ai/app/apikeys)
|
|
145
|
+
|
|
146
|
+
**Q: ๅฝๅ
่ฝ็ดๆฅ็จๅ๏ผ**
|
|
147
|
+
A: ่ฝ๏ผ`api.holysheep.ai` ๅฝๅ
็ด่ฟ๏ผๆ ้ไปฃ็ใ
|
|
148
|
+
|
|
149
|
+
**Q: API Key ๆ ผๅผๆฏไปไน๏ผ**
|
|
150
|
+
A: `cr_` ๅผๅคด็ๅญ็ฌฆไธฒ๏ผๅจๆงๅถๅฐใAPI ๅฏ้ฅใ้กต้ขๅๅปบใ
|
|
151
|
+
|
|
152
|
+
**Q: ๅๅฎๆน API ๆไปไนๅบๅซ๏ผ**
|
|
153
|
+
A: ็ดๆฅๅฏนๆฅๅฎๆน API๏ผๆ ไปปไฝ้ๅฒ๏ผๆฑ็ ยฅ1=$1 ๅ
จ็ฝๆไผใ
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT ยฉ [HolySheep](https://shop.holysheep.ai)
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@simonyea/holysheep-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ไธ้ฎ้
็ฝฎๆๆ AI ็ผ็จๅทฅๅ
ทๆฅๅ
ฅ HolySheep API โ Claude Code / Codex / Gemini CLI / OpenCode / OpenClaw / Aider / Cursor",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude",
|
|
7
|
+
"codex",
|
|
8
|
+
"gemini",
|
|
9
|
+
"cursor",
|
|
10
|
+
"aider",
|
|
11
|
+
"opencode",
|
|
12
|
+
"openclaw",
|
|
13
|
+
"api",
|
|
14
|
+
"relay",
|
|
15
|
+
"china",
|
|
16
|
+
"holysheep",
|
|
17
|
+
"ai",
|
|
18
|
+
"coding"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://shop.holysheep.ai",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/holysheep123/holysheep-cli"
|
|
24
|
+
},
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"bin": {
|
|
27
|
+
"hs": "src/index.js",
|
|
28
|
+
"holysheep": "src/index.js"
|
|
29
|
+
},
|
|
30
|
+
"type": "commonjs",
|
|
31
|
+
"main": "src/index.js",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=16.0.0"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"chalk": "^4.1.2",
|
|
37
|
+
"commander": "^11.1.0",
|
|
38
|
+
"inquirer": "^8.2.6",
|
|
39
|
+
"node-fetch": "^2.7.0",
|
|
40
|
+
"ora": "^5.4.1"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hs balance โ ๆฅ็่ดฆๆทไฝ้ขๅไปๆฅ็จ้
|
|
3
|
+
*/
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const ora = require('ora')
|
|
6
|
+
const { getApiKey, SHOP_URL } = require('../utils/config')
|
|
7
|
+
|
|
8
|
+
async function balance() {
|
|
9
|
+
const apiKey = getApiKey()
|
|
10
|
+
if (!apiKey) {
|
|
11
|
+
console.log(chalk.red('\nๆชๆพๅฐ API Key๏ผ่ฏทๅ
่ฟ่ก: hs setup\n'))
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const spinner = ora('่ทๅ่ดฆๆทไฟกๆฏ...').start()
|
|
16
|
+
try {
|
|
17
|
+
const fetch = require('node-fetch')
|
|
18
|
+
// shop ็ /api/stats/overview ้่ฆ JWT๏ผ่ฟ้้่ฟ /internal ๆฅๅฃๆฅไฝ้ข
|
|
19
|
+
// ๆ่
้่ฟ shop API ๆฅ่ฏข
|
|
20
|
+
const res = await fetch(`${SHOP_URL}/api/stats/overview`, {
|
|
21
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
22
|
+
timeout: 8000,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
if (res.status === 401) {
|
|
26
|
+
spinner.fail('API Key ๆ ๆๆๅทฒ่ฟๆ๏ผ่ฏท้ๆฐ็ปๅฝ')
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
spinner.fail(`่ฏทๆฑๅคฑ่ดฅ (HTTP ${res.status})`)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const data = await res.json()
|
|
36
|
+
spinner.stop()
|
|
37
|
+
|
|
38
|
+
console.log()
|
|
39
|
+
console.log(chalk.bold('๐ฐ ่ดฆๆทไฝ้ข'))
|
|
40
|
+
console.log(chalk.gray('โ'.repeat(40)))
|
|
41
|
+
console.log()
|
|
42
|
+
console.log(` ${chalk.cyan('ไฝ้ข')} $${chalk.bold(Number(data.balance || 0).toFixed(4))}`)
|
|
43
|
+
console.log(` ${chalk.cyan('ไปๆฅๆถ่ดน')} $${Number(data.todayCost || 0).toFixed(4)}`)
|
|
44
|
+
console.log(` ${chalk.cyan('ๆฌๆๆถ่ดน')} $${Number(data.monthCost || 0).toFixed(4)}`)
|
|
45
|
+
console.log(` ${chalk.cyan('็ดฏ่ฎก่ฐ็จ')} ${(data.totalCalls || 0).toLocaleString()} ๆฌก`)
|
|
46
|
+
console.log()
|
|
47
|
+
console.log(chalk.gray(`ๅ
ๅผ: ${SHOP_URL}/app/recharge`))
|
|
48
|
+
console.log()
|
|
49
|
+
|
|
50
|
+
} catch (e) {
|
|
51
|
+
spinner.fail(`่ทๅๅคฑ่ดฅ: ${e.message}`)
|
|
52
|
+
console.log(chalk.gray(`\n่ฏทๅๅพ ${SHOP_URL} ๆฅ็่ดฆๆทไฟกๆฏ`))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = balance
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hs doctor โ ๆฃๆฅๆๆๅทฅๅ
ท็้
็ฝฎ็ถๆ
|
|
3
|
+
*/
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const { execSync } = require('child_process')
|
|
6
|
+
const { getApiKey, BASE_URL_ANTHROPIC, BASE_URL_OPENAI } = require('../utils/config')
|
|
7
|
+
const TOOLS = require('../tools')
|
|
8
|
+
|
|
9
|
+
async function doctor() {
|
|
10
|
+
console.log()
|
|
11
|
+
console.log(chalk.bold('๐ HolySheep Doctor โ ็ฏๅขๆฃๆฅ'))
|
|
12
|
+
console.log(chalk.gray('โ'.repeat(50)))
|
|
13
|
+
console.log()
|
|
14
|
+
|
|
15
|
+
// Node.js ็ๆฌ
|
|
16
|
+
const nodeVer = process.version
|
|
17
|
+
const nodeOk = parseInt(nodeVer.slice(1)) >= 16
|
|
18
|
+
printCheck(nodeOk, `Node.js ${nodeVer}`, nodeOk ? '' : '้่ฆ >= 16')
|
|
19
|
+
|
|
20
|
+
// API Key
|
|
21
|
+
const apiKey = getApiKey()
|
|
22
|
+
printCheck(!!apiKey, 'API Key', apiKey ? maskKey(apiKey) : `ๆช่ฎพ็ฝฎ โ ่ฟ่ก ${chalk.cyan('hs setup')} ้
็ฝฎ`)
|
|
23
|
+
|
|
24
|
+
// ็ฏๅขๅ้
|
|
25
|
+
const envAnthropicKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN
|
|
26
|
+
const envOpenAIKey = process.env.OPENAI_API_KEY
|
|
27
|
+
const envAnthropicUrl = process.env.ANTHROPIC_BASE_URL
|
|
28
|
+
const envOpenAIUrl = process.env.OPENAI_BASE_URL
|
|
29
|
+
|
|
30
|
+
console.log()
|
|
31
|
+
console.log(chalk.bold('็ฏๅขๅ้:'))
|
|
32
|
+
printCheck(!!envAnthropicKey, 'ANTHROPIC_API_KEY / AUTH_TOKEN', envAnthropicKey ? maskKey(envAnthropicKey) : 'ๆช่ฎพ็ฝฎ')
|
|
33
|
+
printCheck(!!envAnthropicUrl, 'ANTHROPIC_BASE_URL', envAnthropicUrl || 'ๆช่ฎพ็ฝฎ')
|
|
34
|
+
printCheck(!!envOpenAIKey, 'OPENAI_API_KEY', envOpenAIKey ? maskKey(envOpenAIKey) : 'ๆช่ฎพ็ฝฎ')
|
|
35
|
+
printCheck(!!envOpenAIUrl, 'OPENAI_BASE_URL', envOpenAIUrl || 'ๆช่ฎพ็ฝฎ')
|
|
36
|
+
|
|
37
|
+
// ๅๅทฅๅ
ทๆฃๆฅ
|
|
38
|
+
console.log()
|
|
39
|
+
console.log(chalk.bold('ๅทฅๅ
ท็ถๆ:'))
|
|
40
|
+
|
|
41
|
+
for (const tool of TOOLS) {
|
|
42
|
+
const installed = tool.checkInstalled()
|
|
43
|
+
const configured = installed ? tool.isConfigured() : null
|
|
44
|
+
const version = installed ? getVersion(tool.id) : null
|
|
45
|
+
|
|
46
|
+
if (!installed) {
|
|
47
|
+
console.log(` ${chalk.gray('โ')} ${chalk.gray(tool.name.padEnd(20))} ${chalk.gray('ๆชๅฎ่ฃ
')} ${chalk.gray(`โ ${tool.installCmd}`)}`)
|
|
48
|
+
} else if (configured) {
|
|
49
|
+
console.log(` ${chalk.green('โ')} ${chalk.green(tool.name.padEnd(20))} ${chalk.gray(version || 'ๅทฒๅฎ่ฃ
')} ${chalk.green('ๅทฒ้
็ฝฎ HolySheep')}`)
|
|
50
|
+
} else {
|
|
51
|
+
console.log(` ${chalk.yellow('!')} ${chalk.yellow(tool.name.padEnd(20))} ${chalk.gray(version || 'ๅทฒๅฎ่ฃ
')} ${chalk.yellow('ๆช้
็ฝฎ')} ${chalk.gray(`โ ่ฟ่ก hs setup`)}`)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log()
|
|
56
|
+
|
|
57
|
+
// ่ฟ้ๆงๆต่ฏ๏ผๅฏ้๏ผ
|
|
58
|
+
if (apiKey) {
|
|
59
|
+
process.stdout.write(chalk.gray('ๆต่ฏ API ่ฟ้ๆง... '))
|
|
60
|
+
try {
|
|
61
|
+
const fetch = require('node-fetch')
|
|
62
|
+
const res = await fetch(`${BASE_URL_ANTHROPIC}/v1/models`, {
|
|
63
|
+
headers: { 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
|
|
64
|
+
timeout: 8000,
|
|
65
|
+
})
|
|
66
|
+
if (res.ok) {
|
|
67
|
+
const data = await res.json()
|
|
68
|
+
const count = data.data?.length || '?'
|
|
69
|
+
console.log(chalk.green(`โ ่ฟ้ (${count} ไธชๆจกๅๅฏ็จ)`))
|
|
70
|
+
} else {
|
|
71
|
+
console.log(chalk.red(`โ ๅคฑ่ดฅ (HTTP ${res.status})`))
|
|
72
|
+
}
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.log(chalk.red(`โ ่ฟๆฅๅคฑ่ดฅ: ${e.message}`))
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function printCheck(ok, label, detail = '') {
|
|
82
|
+
const icon = ok ? chalk.green('โ') : chalk.red('โ')
|
|
83
|
+
const lbl = ok ? chalk.green(label.padEnd(35)) : chalk.red(label.padEnd(35))
|
|
84
|
+
const det = detail ? chalk.gray(detail) : ''
|
|
85
|
+
console.log(` ${icon} ${lbl} ${det}`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function maskKey(key) {
|
|
89
|
+
if (!key || key.length < 8) return '****'
|
|
90
|
+
return key.slice(0, 6) + '...' + key.slice(-4)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getVersion(toolId) {
|
|
94
|
+
const cmds = {
|
|
95
|
+
'claude-code': 'claude --version',
|
|
96
|
+
'codex': 'codex --version',
|
|
97
|
+
'gemini-cli': 'gemini --version',
|
|
98
|
+
'opencode': 'opencode --version',
|
|
99
|
+
'openclaw': 'openclaw --version',
|
|
100
|
+
'aider': 'aider --version',
|
|
101
|
+
}
|
|
102
|
+
const cmd = cmds[toolId]
|
|
103
|
+
if (!cmd) return null
|
|
104
|
+
try {
|
|
105
|
+
return execSync(cmd, { stdio: 'pipe' }).toString().trim().split('\n')[0].slice(0, 30)
|
|
106
|
+
} catch { return null }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = doctor
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hs reset โ ๆธ
้คๆๆๅทฅๅ
ท็ HolySheep ้
็ฝฎ๏ผๆขๅค้ป่ฎค
|
|
3
|
+
*/
|
|
4
|
+
const inquirer = require('inquirer')
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const ora = require('ora')
|
|
7
|
+
const { removeEnvFromShell } = require('../utils/shell')
|
|
8
|
+
const { saveConfig } = require('../utils/config')
|
|
9
|
+
const TOOLS = require('../tools')
|
|
10
|
+
|
|
11
|
+
async function reset(options) {
|
|
12
|
+
console.log()
|
|
13
|
+
if (!options.yes) {
|
|
14
|
+
const { confirm } = await inquirer.prompt([{
|
|
15
|
+
type: 'confirm',
|
|
16
|
+
name: 'confirm',
|
|
17
|
+
message: chalk.yellow('ๅฐๆธ
้คๆๆๅทฅๅ
ท็ HolySheep ้
็ฝฎๅ็ฏๅขๅ้๏ผ็ปง็ปญ๏ผ'),
|
|
18
|
+
default: false,
|
|
19
|
+
}])
|
|
20
|
+
if (!confirm) { console.log('ๅทฒๅๆถ\n'); return }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log()
|
|
24
|
+
for (const tool of TOOLS) {
|
|
25
|
+
if (!tool.checkInstalled() && !tool.isConfigured?.()) continue
|
|
26
|
+
const spinner = ora(`ๆธ
้ค ${tool.name}...`).start()
|
|
27
|
+
try {
|
|
28
|
+
tool.reset()
|
|
29
|
+
spinner.succeed(`${tool.name} ๅทฒๆธ
้ค`)
|
|
30
|
+
} catch (e) {
|
|
31
|
+
spinner.fail(`${tool.name}: ${e.message}`)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ๆธ
้ค shell ็ฏๅขๅ้
|
|
36
|
+
const spinner = ora('ๆธ
้ค shell ็ฏๅขๅ้...').start()
|
|
37
|
+
try {
|
|
38
|
+
const cleaned = removeEnvFromShell()
|
|
39
|
+
if (cleaned.length) spinner.succeed(`ๅทฒๆธ
้ค: ${cleaned.join(', ')}`)
|
|
40
|
+
else spinner.info('ๆ shell ็ฏๅขๅ้้่ฆๆธ
้ค')
|
|
41
|
+
} catch (e) {
|
|
42
|
+
spinner.fail(e.message)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ๆธ
้คๆฌๅฐไฟๅญ็ API Key
|
|
46
|
+
saveConfig({ apiKey: '' })
|
|
47
|
+
|
|
48
|
+
console.log()
|
|
49
|
+
console.log(chalk.green('โ
ๆธ
้คๅฎๆ๏ผๆๆๅทฅๅ
ทๅทฒๆขๅค้ป่ฎค้
็ฝฎ'))
|
|
50
|
+
console.log(chalk.gray('้ๆฐ้
็ฝฎ: hs setup\n'))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = reset
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hs setup โ ไธ้ฎ้
็ฝฎๆๆ AI ๅทฅๅ
ทๆฅๅ
ฅ HolySheep API
|
|
3
|
+
*/
|
|
4
|
+
const inquirer = require('inquirer')
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const ora = require('ora')
|
|
7
|
+
const { saveConfig, getApiKey, BASE_URL_ANTHROPIC, BASE_URL_OPENAI, SHOP_URL } = require('../utils/config')
|
|
8
|
+
const { writeEnvToShell } = require('../utils/shell')
|
|
9
|
+
const TOOLS = require('../tools')
|
|
10
|
+
|
|
11
|
+
const TOOL_CHOICES = TOOLS.map(t => ({
|
|
12
|
+
name: `${t.checkInstalled() ? chalk.green('โ') : chalk.gray('โ')} ${t.name.padEnd(18)} ${t.checkInstalled() ? chalk.gray('(ๅทฒๅฎ่ฃ
)') : chalk.gray('(ๆชๅฎ่ฃ
)')}`,
|
|
13
|
+
value: t.id,
|
|
14
|
+
short: t.name,
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
async function setup(options) {
|
|
18
|
+
console.log()
|
|
19
|
+
console.log(chalk.bold('๐ HolySheep CLI โ ไธ้ฎ้
็ฝฎ AI ๅทฅๅ
ท'))
|
|
20
|
+
console.log(chalk.gray('โ'.repeat(50)))
|
|
21
|
+
console.log()
|
|
22
|
+
|
|
23
|
+
// Step 1: ่ทๅ API Key
|
|
24
|
+
let apiKey = options.key || getApiKey()
|
|
25
|
+
|
|
26
|
+
if (!apiKey) {
|
|
27
|
+
console.log(chalk.yellow('้่ฆ API Key ๆ่ฝ้
็ฝฎๅทฅๅ
ทใ'))
|
|
28
|
+
console.log(chalk.cyan(`่ฟๆฒกๆ่ดฆๅท๏ผๅๅพๆณจๅ๏ผ${SHOP_URL}\n`))
|
|
29
|
+
|
|
30
|
+
const { key } = await inquirer.prompt([{
|
|
31
|
+
type: 'password',
|
|
32
|
+
name: 'key',
|
|
33
|
+
message: 'API Key (cr_xxx):',
|
|
34
|
+
validate: v => v.startsWith('cr_') ? true : '่ฏท่พๅ
ฅไปฅ cr_ ๅผๅคด็ API Key',
|
|
35
|
+
}])
|
|
36
|
+
apiKey = key
|
|
37
|
+
} else {
|
|
38
|
+
console.log(`${chalk.green('โ')} ไฝฟ็จๅทฒไฟๅญ็ API Key: ${chalk.cyan(maskKey(apiKey))}`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Step 2: ้ๆฉๅทฅๅ
ท
|
|
42
|
+
const { toolIds } = await inquirer.prompt([{
|
|
43
|
+
type: 'checkbox',
|
|
44
|
+
name: 'toolIds',
|
|
45
|
+
message: '้ๆฉ่ฆ้
็ฝฎ็ๅทฅๅ
ท๏ผ็ฉบๆ ผ้ไธญ๏ผๅ่ฝฆ็กฎ่ฎค๏ผ:',
|
|
46
|
+
choices: [
|
|
47
|
+
new inquirer.Separator('โโ ๅทฒๅฎ่ฃ
โโ'),
|
|
48
|
+
...TOOL_CHOICES.filter((_, i) => TOOLS[i].checkInstalled()),
|
|
49
|
+
new inquirer.Separator('โโ ๆชๅฎ่ฃ
โโ'),
|
|
50
|
+
...TOOL_CHOICES.filter((_, i) => !TOOLS[i].checkInstalled()),
|
|
51
|
+
],
|
|
52
|
+
pageSize: 12,
|
|
53
|
+
}])
|
|
54
|
+
|
|
55
|
+
if (toolIds.length === 0) {
|
|
56
|
+
console.log(chalk.yellow('\nๆช้ๆฉไปปไฝๅทฅๅ
ท๏ผ้ๅบใ'))
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log()
|
|
61
|
+
|
|
62
|
+
// Step 3: ้
็ฝฎๆฏไธชๅทฅๅ
ท
|
|
63
|
+
const selectedTools = TOOLS.filter(t => toolIds.includes(t.id))
|
|
64
|
+
const envVarsToWrite = {}
|
|
65
|
+
const results = []
|
|
66
|
+
|
|
67
|
+
for (const tool of selectedTools) {
|
|
68
|
+
const spinner = ora(`้
็ฝฎ ${tool.name}...`).start()
|
|
69
|
+
try {
|
|
70
|
+
const result = tool.configure(apiKey, BASE_URL_ANTHROPIC, BASE_URL_OPENAI)
|
|
71
|
+
|
|
72
|
+
if (result.manual) {
|
|
73
|
+
spinner.info(`${chalk.yellow(tool.name)} ้่ฆๆๅจ้
็ฝฎ:`)
|
|
74
|
+
result.steps.forEach((s, i) => console.log(` ${chalk.gray(i + 1 + '.')} ${s}`))
|
|
75
|
+
results.push({ tool, status: 'manual' })
|
|
76
|
+
} else {
|
|
77
|
+
// ๆถ้้่ฆๅๅ
ฅ shell ็็ฏๅขๅ้
|
|
78
|
+
if (result.envVars) Object.assign(envVarsToWrite, result.envVars)
|
|
79
|
+
spinner.succeed(`${chalk.green(tool.name)} ${chalk.gray(result.file ? `โ ${result.file}` : '')}`)
|
|
80
|
+
results.push({ tool, status: 'ok', result })
|
|
81
|
+
}
|
|
82
|
+
} catch (e) {
|
|
83
|
+
spinner.fail(`${chalk.red(tool.name)}: ${e.message}`)
|
|
84
|
+
results.push({ tool, status: 'error', error: e.message })
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Step 4: ๅๅ
ฅ้็จ็ฏๅขๅ้๏ผๅฆๆๆๅทฅๅ
ท้่ฆ๏ผ
|
|
89
|
+
const needsEnvVars = selectedTools.some(t => t.id === 'codex' || t.id === 'aider')
|
|
90
|
+
if (needsEnvVars || Object.keys(envVarsToWrite).length > 0) {
|
|
91
|
+
const defaultEnv = {
|
|
92
|
+
ANTHROPIC_API_KEY: apiKey,
|
|
93
|
+
ANTHROPIC_BASE_URL: BASE_URL_ANTHROPIC,
|
|
94
|
+
OPENAI_API_KEY: apiKey,
|
|
95
|
+
OPENAI_BASE_URL: BASE_URL_OPENAI,
|
|
96
|
+
}
|
|
97
|
+
Object.assign(envVarsToWrite, defaultEnv)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (Object.keys(envVarsToWrite).length > 0) {
|
|
101
|
+
const spinner = ora('ๅๅ
ฅ็ฏๅขๅ้ๅฐ shell ้
็ฝฎๆไปถ...').start()
|
|
102
|
+
try {
|
|
103
|
+
const written = writeEnvToShell(envVarsToWrite)
|
|
104
|
+
spinner.succeed(`็ฏๅขๅ้ๅทฒๅๅ
ฅ: ${written.map(f => chalk.cyan(f)).join(', ')}`)
|
|
105
|
+
} catch (e) {
|
|
106
|
+
spinner.fail(`ๅๅ
ฅ็ฏๅขๅ้ๅคฑ่ดฅ: ${e.message}`)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Step 5: ไฟๅญ API Key ๅฐๆฌๅฐ
|
|
111
|
+
saveConfig({ apiKey })
|
|
112
|
+
|
|
113
|
+
// ๆ่ฆ
|
|
114
|
+
console.log()
|
|
115
|
+
console.log(chalk.bold('โ'.repeat(50)))
|
|
116
|
+
console.log(chalk.green.bold('โ
้
็ฝฎๅฎๆ๏ผ'))
|
|
117
|
+
console.log()
|
|
118
|
+
|
|
119
|
+
const ok = results.filter(r => r.status === 'ok')
|
|
120
|
+
const manual = results.filter(r => r.status === 'manual')
|
|
121
|
+
const errors = results.filter(r => r.status === 'error')
|
|
122
|
+
|
|
123
|
+
if (ok.length) {
|
|
124
|
+
console.log(chalk.green(`ๅทฒ้
็ฝฎ ${ok.length} ไธชๅทฅๅ
ท:`))
|
|
125
|
+
ok.forEach(r => {
|
|
126
|
+
const hot = r.result?.hot ? chalk.cyan(' (็ญๅๆข๏ผๆ ้้ๅฏ)') : chalk.gray(' (้ๅฏ็ป็ซฏ็ๆ)')
|
|
127
|
+
console.log(` โ ${r.tool.name}${hot}`)
|
|
128
|
+
if (r.tool.hint) console.log(` ${chalk.gray('๐ก ' + r.tool.hint)}`)
|
|
129
|
+
})
|
|
130
|
+
console.log()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (manual.length) {
|
|
134
|
+
console.log(chalk.yellow(`${manual.length} ไธชๅทฅๅ
ท้่ฆๆๅจ้
็ฝฎ๏ผ่งไธๆนๆญฅ้ชค๏ผ`))
|
|
135
|
+
console.log()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (errors.length) {
|
|
139
|
+
console.log(chalk.red(`${errors.length} ไธชๅทฅๅ
ท้
็ฝฎๅคฑ่ดฅ:`))
|
|
140
|
+
errors.forEach(r => console.log(` โ ${r.tool.name}: ${r.error}`))
|
|
141
|
+
console.log()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
console.log(chalk.gray('ๅฆ้ๅๆขๅ
ถไปๅทฅๅ
ท๏ผ่ฟ่ก: hs setup'))
|
|
145
|
+
console.log(chalk.gray('ๆฅ็ไฝ้ข: hs balance'))
|
|
146
|
+
console.log(chalk.gray('ๆฃๆฅ้
็ฝฎ: hs doctor'))
|
|
147
|
+
console.log()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function maskKey(key) {
|
|
151
|
+
if (!key || key.length < 8) return '****'
|
|
152
|
+
return key.slice(0, 6) + '...' + key.slice(-4)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = setup
|
package/src/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const { program } = require('commander')
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const pkg = require('../package.json')
|
|
7
|
+
|
|
8
|
+
// Banner
|
|
9
|
+
function printBanner() {
|
|
10
|
+
console.log()
|
|
11
|
+
console.log(chalk.bold('๐ ' + chalk.hex('#e8a46a')('HolySheep CLI') + ' v' + pkg.version))
|
|
12
|
+
console.log(chalk.gray('ๅฎๆน Claude/GPT/Gemini API ยท ยฅ1=$1 ยท shop.holysheep.ai'))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('hs')
|
|
17
|
+
.description('ไธ้ฎ้
็ฝฎๆๆ AI ็ผ็จๅทฅๅ
ทๆฅๅ
ฅ HolySheep API')
|
|
18
|
+
.version(pkg.version, '-v, --version')
|
|
19
|
+
.addHelpText('before', `
|
|
20
|
+
๐ HolySheep CLI v${pkg.version}
|
|
21
|
+
ๅฎๆน Claude / GPT / Gemini API ยท ยฅ1=$1 ยท https://shop.holysheep.ai
|
|
22
|
+
|
|
23
|
+
ๆฏๆๅทฅๅ
ท: Claude Code ยท Codex ยท Gemini CLI ยท OpenCode ยท OpenClaw ยท Aider ยท Cursor ยท Continue
|
|
24
|
+
`)
|
|
25
|
+
|
|
26
|
+
// โโ setup โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
27
|
+
program
|
|
28
|
+
.command('setup')
|
|
29
|
+
.description('ไธ้ฎ้
็ฝฎ AI ๅทฅๅ
ทๆฅๅ
ฅ HolySheep API')
|
|
30
|
+
.option('-k, --key <apiKey>', '็ดๆฅๆๅฎ API Key๏ผ่ทณ่ฟไบคไบ๏ผ')
|
|
31
|
+
.option('-a, --all', '้
็ฝฎๆๆๅทฒๅฎ่ฃ
็ๅทฅๅ
ท๏ผ่ทณ่ฟ้ๆฉ๏ผ')
|
|
32
|
+
.action(async (opts) => {
|
|
33
|
+
printBanner()
|
|
34
|
+
await require('./commands/setup')(opts)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// โโ doctor โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
38
|
+
program
|
|
39
|
+
.command('doctor')
|
|
40
|
+
.alias('check')
|
|
41
|
+
.description('ๆฃๆฅ็ฏๅข้
็ฝฎๅๅๅทฅๅ
ท็ถๆ')
|
|
42
|
+
.action(async () => {
|
|
43
|
+
await require('./commands/doctor')()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// โโ balance โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
47
|
+
program
|
|
48
|
+
.command('balance')
|
|
49
|
+
.alias('bal')
|
|
50
|
+
.description('ๆฅ็่ดฆๆทไฝ้ขๅไปๆฅ็จ้')
|
|
51
|
+
.action(async () => {
|
|
52
|
+
await require('./commands/balance')()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// โโ reset โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
56
|
+
program
|
|
57
|
+
.command('reset')
|
|
58
|
+
.description('ๆธ
้คๆๆ HolySheep ้
็ฝฎ๏ผๆขๅค้ป่ฎค')
|
|
59
|
+
.option('-y, --yes', '่ทณ่ฟ็กฎ่ฎค็ดๆฅๆง่ก')
|
|
60
|
+
.action(async (opts) => {
|
|
61
|
+
await require('./commands/reset')(opts)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// โโ tools โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
65
|
+
program
|
|
66
|
+
.command('tools')
|
|
67
|
+
.description('ๅๅบๆๆๆฏๆ็ AI ๅทฅๅ
ท')
|
|
68
|
+
.action(() => {
|
|
69
|
+
const TOOLS = require('./tools')
|
|
70
|
+
console.log()
|
|
71
|
+
console.log(chalk.bold('ๆฏๆ็ AI ๅทฅๅ
ท:'))
|
|
72
|
+
console.log()
|
|
73
|
+
TOOLS.forEach(t => {
|
|
74
|
+
const installed = t.checkInstalled()
|
|
75
|
+
const icon = installed ? chalk.green('โ') : chalk.gray('โ')
|
|
76
|
+
const status = installed ? chalk.green('ๅทฒๅฎ่ฃ
') : chalk.gray('ๆชๅฎ่ฃ
')
|
|
77
|
+
console.log(` ${icon} ${t.name.padEnd(20)} ${status}`)
|
|
78
|
+
console.log(` ${chalk.gray('ๅฎ่ฃ
: ' + t.installCmd)}`)
|
|
79
|
+
console.log()
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// ้ป่ฎค๏ผๆ ๅฝไปคๆถๆพ็คบๅธฎๅฉ + ๆ็คบ setup
|
|
84
|
+
program
|
|
85
|
+
.action(() => {
|
|
86
|
+
printBanner()
|
|
87
|
+
console.log()
|
|
88
|
+
console.log(chalk.cyan('ๅฟซ้ๅผๅง:'))
|
|
89
|
+
console.log(` ${chalk.bold('hs setup')} ไธ้ฎ้
็ฝฎๆๆ AI ๅทฅๅ
ท`)
|
|
90
|
+
console.log(` ${chalk.bold('hs doctor')} ๆฃๆฅ้
็ฝฎ็ถๆ`)
|
|
91
|
+
console.log(` ${chalk.bold('hs balance')} ๆฅ็่ดฆๆทไฝ้ข`)
|
|
92
|
+
console.log(` ${chalk.bold('hs tools')} ๆฅ็ๆฏๆ็ๅทฅๅ
ทๅ่กจ`)
|
|
93
|
+
console.log()
|
|
94
|
+
console.log(chalk.gray(`ๆณจๅ่ดฆๅท: https://shop.holysheep.ai`))
|
|
95
|
+
console.log()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
program.parse(process.argv)
|
|
99
|
+
|
|
100
|
+
// ๆ ๅๆฐๆถๆพ็คบ้ป่ฎคไฟกๆฏ
|
|
101
|
+
if (process.argv.length === 2) {
|
|
102
|
+
program.help()
|
|
103
|
+
}
|