@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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本地配置管理 — 存储 API Key 和用户偏好
|
|
3
|
+
* 配置文件: ~/.holysheep/config.json
|
|
4
|
+
*/
|
|
5
|
+
const fs = require('fs')
|
|
6
|
+
const path = require('path')
|
|
7
|
+
const os = require('os')
|
|
8
|
+
|
|
9
|
+
const CONFIG_DIR = path.join(os.homedir(), '.holysheep')
|
|
10
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json')
|
|
11
|
+
|
|
12
|
+
const BASE_URL_ANTHROPIC = 'https://api.holysheep.ai' // 不带 /v1 (Anthropic SDK)
|
|
13
|
+
const BASE_URL_OPENAI = 'https://api.holysheep.ai/v1' // 带 /v1 (OpenAI 兼容)
|
|
14
|
+
const SHOP_URL = 'https://shop.holysheep.ai'
|
|
15
|
+
|
|
16
|
+
function ensureDir() {
|
|
17
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
18
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true })
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function loadConfig() {
|
|
23
|
+
try {
|
|
24
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
25
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'))
|
|
26
|
+
}
|
|
27
|
+
} catch {}
|
|
28
|
+
return {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function saveConfig(data) {
|
|
32
|
+
ensureDir()
|
|
33
|
+
const current = loadConfig()
|
|
34
|
+
const merged = { ...current, ...data }
|
|
35
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2))
|
|
36
|
+
return merged
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getApiKey() {
|
|
40
|
+
return loadConfig().apiKey || process.env.HOLYSHEEP_API_KEY || ''
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
CONFIG_DIR,
|
|
45
|
+
CONFIG_FILE,
|
|
46
|
+
BASE_URL_ANTHROPIC,
|
|
47
|
+
BASE_URL_OPENAI,
|
|
48
|
+
SHOP_URL,
|
|
49
|
+
loadConfig,
|
|
50
|
+
saveConfig,
|
|
51
|
+
getApiKey,
|
|
52
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell RC 文件管理 — 写入/清理环境变量
|
|
3
|
+
*/
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const os = require('os')
|
|
7
|
+
|
|
8
|
+
const MARKER_START = '# >>> holysheep-cli managed >>>'
|
|
9
|
+
const MARKER_END = '# <<< holysheep-cli managed <<<'
|
|
10
|
+
|
|
11
|
+
function getShellRcFiles() {
|
|
12
|
+
const home = os.homedir()
|
|
13
|
+
const shell = process.env.SHELL || ''
|
|
14
|
+
const candidates = []
|
|
15
|
+
|
|
16
|
+
if (shell.includes('zsh')) candidates.push(path.join(home, '.zshrc'))
|
|
17
|
+
if (shell.includes('bash')) candidates.push(path.join(home, '.bashrc'), path.join(home, '.bash_profile'))
|
|
18
|
+
if (shell.includes('fish')) candidates.push(path.join(home, '.config', 'fish', 'config.fish'))
|
|
19
|
+
|
|
20
|
+
// 默认兜底
|
|
21
|
+
if (candidates.length === 0) {
|
|
22
|
+
const zshrc = path.join(home, '.zshrc')
|
|
23
|
+
const bashrc = path.join(home, '.bashrc')
|
|
24
|
+
if (fs.existsSync(zshrc)) candidates.push(zshrc)
|
|
25
|
+
if (fs.existsSync(bashrc)) candidates.push(bashrc)
|
|
26
|
+
if (candidates.length === 0) candidates.push(zshrc)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return candidates
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function removeHsBlock(content) {
|
|
33
|
+
const re = new RegExp(
|
|
34
|
+
`\\n?${escapeRegex(MARKER_START)}[\\s\\S]*?${escapeRegex(MARKER_END)}\\n?`,
|
|
35
|
+
'g'
|
|
36
|
+
)
|
|
37
|
+
return content.replace(re, '')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildEnvBlock(envVars) {
|
|
41
|
+
const lines = [MARKER_START]
|
|
42
|
+
for (const [k, v] of Object.entries(envVars)) {
|
|
43
|
+
lines.push(`export ${k}="${v}"`)
|
|
44
|
+
}
|
|
45
|
+
lines.push(MARKER_END)
|
|
46
|
+
return '\n' + lines.join('\n') + '\n'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function writeEnvToShell(envVars) {
|
|
50
|
+
const files = getShellRcFiles()
|
|
51
|
+
const written = []
|
|
52
|
+
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
let content = ''
|
|
55
|
+
try { content = fs.readFileSync(file, 'utf8') } catch {}
|
|
56
|
+
content = removeHsBlock(content)
|
|
57
|
+
content += buildEnvBlock(envVars)
|
|
58
|
+
fs.writeFileSync(file, content, 'utf8')
|
|
59
|
+
written.push(file)
|
|
60
|
+
}
|
|
61
|
+
return written
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function removeEnvFromShell() {
|
|
65
|
+
const files = getShellRcFiles()
|
|
66
|
+
const cleaned = []
|
|
67
|
+
for (const file of files) {
|
|
68
|
+
if (!fs.existsSync(file)) continue
|
|
69
|
+
let content = fs.readFileSync(file, 'utf8')
|
|
70
|
+
const cleaned_content = removeHsBlock(content)
|
|
71
|
+
if (cleaned_content !== content) {
|
|
72
|
+
fs.writeFileSync(file, cleaned_content, 'utf8')
|
|
73
|
+
cleaned.push(file)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return cleaned
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function escapeRegex(s) {
|
|
80
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { getShellRcFiles, writeEnvToShell, removeEnvFromShell }
|