@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 ADDED
@@ -0,0 +1,159 @@
1
+ # ๐Ÿ‘ HolySheep CLI
2
+
3
+ > ไธ€้”ฎ้…็ฝฎๆ‰€ๆœ‰ AI ็ผ–็จ‹ๅทฅๅ…ทๆŽฅๅ…ฅ HolySheep API โ€” ๅ›ฝๅ†…็›ด่ฟž๏ผŒยฅ1=$1๏ผŒๆ— ้œ€้ญ”ๆณ•
4
+
5
+ [![npm version](https://img.shields.io/npm/v/holysheep-cli)](https://www.npmjs.com/package/holysheep-cli)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+ [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Windows%20%7C%20Linux-lightgrey)](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
+ }