skillfree 0.1.69 → 0.1.71

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/install.sh CHANGED
@@ -149,15 +149,27 @@ fi
149
149
  echo ""
150
150
  success "SkillFree CLI 安装完成"
151
151
 
152
- # 刷新 PATH
152
+ # 刷新 PATH(尝试多种方式)
153
153
  hash -r 2>/dev/null || true
154
- export PATH="$(npm root -g)/../bin:$PATH"
154
+ NPM_BIN="$(npm bin -g 2>/dev/null || npm root -g | sed 's|/node_modules||')/.bin"
155
+ export PATH="$(npm root -g)/../bin:$NPM_BIN:$PATH"
155
156
 
156
- if ! command -v skillfree &>/dev/null; then
157
- warn "CLI 已安装,但当前终端 PATH 未更新"
158
- warn "请新开一个终端窗口,然后运行:skillfree auth login"
159
- echo ""
160
- exit 0
157
+ # 找到 skillfree 可执行路径(用于后续调用)
158
+ SKILLFREE_BIN=""
159
+ if command -v skillfree &>/dev/null; then
160
+ SKILLFREE_BIN="skillfree"
161
+ else
162
+ # 尝试从 npm 全局 bin 目录找
163
+ _SF_PATH="$(npm root -g 2>/dev/null)/../bin/skillfree"
164
+ if [ -x "$_SF_PATH" ]; then
165
+ SKILLFREE_BIN="$_SF_PATH"
166
+ fi
167
+ fi
168
+
169
+ if [ -z "$SKILLFREE_BIN" ]; then
170
+ warn "CLI 已安装,但当前终端 PATH 未更新,继续完成配置..."
171
+ # 用 node 直接执行 CLI
172
+ SKILLFREE_BIN="node $(npm root -g 2>/dev/null)/skillfree/bin/skillfree.js"
161
173
  fi
162
174
 
163
175
  # ── Step 4: 登录(从 /dev/tty 读取,兼容 curl | bash)────────────────────────
@@ -189,7 +201,22 @@ while true; do
189
201
  done
190
202
 
191
203
  if [ -n "$API_KEY" ]; then
192
- SKILLFREE_API_KEY="$API_KEY" SKILLFREE_PLATFORMS="$SKILLFREE_PLATFORMS" skillfree auth save "$API_KEY"
204
+ SKILLFREE_API_KEY="$API_KEY" SKILLFREE_PLATFORMS="$SKILLFREE_PLATFORMS" $SKILLFREE_BIN auth save "$API_KEY"
205
+ fi
206
+
207
+ # ── 安装完成提示:PATH 问题 ────────────────────────────────────────────────────
208
+ if [ "$SKILLFREE_BIN" != "skillfree" ]; then
209
+ echo ""
210
+ warn "当前终端 PATH 未包含 npm 全局 bin,请运行以下命令之一让 skillfree 全局生效:"
211
+ echo ""
212
+ echo -e " ${CYAN} 方式一(推荐,重启终端永久生效):${NC}"
213
+ echo -e " ${DIM} 将以下内容加入 ~/.zshrc 或 ~/.bash_profile:${NC}"
214
+ NPM_PREFIX=$(npm config get prefix 2>/dev/null)
215
+ echo -e " ${DIM} export PATH=\"$NPM_PREFIX/bin:\$PATH\"${NC}"
216
+ echo ""
217
+ echo -e " ${CYAN} 方式二(仅当前终端临时生效):${NC}"
218
+ echo -e " ${DIM} export PATH=\"$NPM_PREFIX/bin:\$PATH\"${NC}"
219
+ echo ""
193
220
  fi
194
221
 
195
222
  # ── 完成 ──────────────────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillfree",
3
- "version": "0.1.69",
3
+ "version": "0.1.71",
4
4
  "description": "🦞 一个 API,满足所有龙虾技能需求",
5
5
  "main": "bin/skillfree.js",
6
6
  "bin": {
@@ -4,36 +4,24 @@ const path = require('path')
4
4
  const os = require('os')
5
5
  const { saveConfig, BASE_URL } = require('../lib/client')
6
6
 
7
- // ── 平台 → 技能安装路径映射(与 postinstall.js 保持一致)─────────────────
8
- const PLATFORM_PATHS = {
9
- openclaw: [
10
- path.join(os.homedir(), '.openclaw', 'skills', 'skillfree'),
11
- path.join(os.homedir(), '.agents', 'skills', 'skillfree'),
12
- ],
13
- claude: [
14
- path.join(os.homedir(), '.claude', 'skills', 'skillfree'),
15
- ],
16
- codex: [
17
- path.join(os.homedir(), '.codex', 'skills', 'skillfree'),
18
- ],
19
- continue: [
20
- path.join(os.homedir(), '.continue', 'skills', 'skillfree'),
21
- ],
22
- cursor: [
23
- path.join(os.homedir(), '.cursor', 'skills', 'skillfree'),
24
- ],
25
- }
26
-
27
7
  /**
28
- * 将 apiKey 写入各平台配置 + shell 环境变量
8
+ * 将 apiKey 注入到各平台配置 + shell 环境变量
9
+ *
10
+ * 各平台注入方式:
11
+ * openclaw → ~/.openclaw/openclaw.json (skills.entries.skillfree.apiKey)
12
+ * hermes → ~/.hermes/.env (SKILLFREE_API_KEY=xxx)
13
+ * claude → ~/.claude/settings.json (env.SKILLFREE_API_KEY)
14
+ * codex → 无专用配置,走 shell 环境变量即可
15
+ * 通用 → ~/.zshrc / ~/.bash_profile (export SKILLFREE_API_KEY=xxx)
29
16
  */
30
17
  function injectToOpenclaw(apiKey) {
31
- // 1. OpenClaw: 写入 openclaw.json
32
- const openclawDir = path.join(os.homedir(), '.openclaw')
33
- const cfgPath = path.join(openclawDir, 'openclaw.json')
34
- if (fs.existsSync(openclawDir) && fs.existsSync(cfgPath)) {
18
+ const HOME = os.homedir()
19
+
20
+ // ── 1. OpenClaw: 写入 openclaw.json ────────────────────────────────────────
21
+ const openclawCfgPath = path.join(HOME, '.openclaw', 'openclaw.json')
22
+ if (fs.existsSync(path.join(HOME, '.openclaw')) && fs.existsSync(openclawCfgPath)) {
35
23
  let cfg = {}
36
- try { cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8')) } catch {}
24
+ try { cfg = JSON.parse(fs.readFileSync(openclawCfgPath, 'utf8')) } catch {}
37
25
  cfg.skills = cfg.skills || {}
38
26
  cfg.skills.entries = cfg.skills.entries || {}
39
27
  cfg.skills.entries['skillfree'] = {
@@ -42,38 +30,102 @@ function injectToOpenclaw(apiKey) {
42
30
  apiKey,
43
31
  }
44
32
  try {
45
- fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + '\n')
46
- console.log('✅ openclaw.json 已更新,OpenClaw 下次启动自动识别 skillfree skill')
33
+ fs.writeFileSync(openclawCfgPath, JSON.stringify(cfg, null, 2) + '\n')
34
+ console.log('✅ [OpenClaw] openclaw.json 已更新')
35
+ } catch (e) {
36
+ console.warn('⚠️ [OpenClaw] 无法写入 openclaw.json:', e.message)
37
+ }
38
+ }
39
+
40
+ // ── 2. Hermes: 写入 ~/.hermes/.env ─────────────────────────────────────────
41
+ const hermesDir = path.join(HOME, '.hermes')
42
+ if (fs.existsSync(hermesDir)) {
43
+ const hermesEnvPath = path.join(hermesDir, '.env')
44
+ _injectEnvFile(hermesEnvPath, 'SKILLFREE_API_KEY', apiKey)
45
+ console.log('✅ [Hermes] ~/.hermes/.env 已写入 SKILLFREE_API_KEY')
46
+ }
47
+
48
+ // ── 3. Claude Code: 写入 ~/.claude/settings.json ───────────────────────────
49
+ const claudeDir = path.join(HOME, '.claude')
50
+ if (fs.existsSync(claudeDir)) {
51
+ const claudeSettingsPath = path.join(claudeDir, 'settings.json')
52
+ let settings = {}
53
+ if (fs.existsSync(claudeSettingsPath)) {
54
+ try { settings = JSON.parse(fs.readFileSync(claudeSettingsPath, 'utf8')) } catch {}
55
+ }
56
+ settings.env = settings.env || {}
57
+ settings.env['SKILLFREE_API_KEY'] = apiKey
58
+ try {
59
+ fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + '\n')
60
+ console.log('✅ [Claude Code] ~/.claude/settings.json 已写入 SKILLFREE_API_KEY')
61
+ } catch (e) {
62
+ console.warn('⚠️ [Claude Code] 无法写入 settings.json:', e.message)
63
+ }
64
+ }
65
+
66
+ // ── 4. Codex: 写入 ~/.codex/config.json ────────────────────────────────────
67
+ const codexDir = path.join(HOME, '.codex')
68
+ if (fs.existsSync(codexDir)) {
69
+ const codexCfgPath = path.join(codexDir, 'config.json')
70
+ let cfg = {}
71
+ if (fs.existsSync(codexCfgPath)) {
72
+ try { cfg = JSON.parse(fs.readFileSync(codexCfgPath, 'utf8')) } catch {}
73
+ }
74
+ cfg.env = cfg.env || {}
75
+ cfg.env['SKILLFREE_API_KEY'] = apiKey
76
+ try {
77
+ fs.writeFileSync(codexCfgPath, JSON.stringify(cfg, null, 2) + '\n')
78
+ console.log('✅ [Codex] ~/.codex/config.json 已写入 SKILLFREE_API_KEY')
47
79
  } catch (e) {
48
- console.warn('⚠️ 无法写入 openclaw.json(权限问题?):', e.message)
80
+ console.warn('⚠️ [Codex] 无法写入 config.json', e.message)
49
81
  }
50
82
  }
51
83
 
52
- // 2. 写入 shell 配置文件(~/.zshrc 或 ~/.bash_profile)
84
+ // ── 5. 通用:写入 shell 配置文件 ───────────────────────────────────────────
53
85
  const exportLine = `\nexport SKILLFREE_API_KEY="${apiKey}"\n`
54
86
  const shellFiles = [
55
- path.join(os.homedir(), '.zshrc'),
56
- path.join(os.homedir(), '.bash_profile'),
87
+ path.join(HOME, '.zshrc'),
88
+ path.join(HOME, '.bash_profile'),
57
89
  ]
58
90
  let wrote = false
59
91
  for (const f of shellFiles) {
60
92
  if (fs.existsSync(f)) {
61
93
  const content = fs.readFileSync(f, 'utf8')
62
94
  if (content.includes('SKILLFREE_API_KEY')) {
63
- const updated = content.replace(/\nexport SKILLFREE_API_KEY=.*\n?/g, exportLine)
64
- fs.writeFileSync(f, updated)
95
+ fs.writeFileSync(f, content.replace(/\nexport SKILLFREE_API_KEY=.*\n?/g, exportLine))
65
96
  } else {
66
97
  fs.appendFileSync(f, exportLine)
67
98
  }
68
- console.log(`✅ ${path.basename(f)} 已写入 SKILLFREE_API_KEY`)
99
+ console.log(`✅ [Shell] ${path.basename(f)} 已写入 SKILLFREE_API_KEY`)
69
100
  wrote = true
70
101
  break
71
102
  }
72
103
  }
73
104
  if (!wrote) {
74
105
  fs.writeFileSync(shellFiles[0], `# SkillFree API Key${exportLine}`)
75
- console.log('✅ ~/.zshrc 已创建并写入 SKILLFREE_API_KEY')
106
+ console.log('✅ [Shell] ~/.zshrc 已创建并写入 SKILLFREE_API_KEY')
107
+ }
108
+ }
109
+
110
+ /**
111
+ * 向 .env 文件注入或更新一个 KEY=value 行
112
+ */
113
+ function _injectEnvFile(envPath, key, value) {
114
+ const line = `${key}="${value}"`
115
+ let content = ''
116
+ if (fs.existsSync(envPath)) {
117
+ content = fs.readFileSync(envPath, 'utf8')
118
+ if (content.includes(key + '=')) {
119
+ // 替换已有行
120
+ content = content.replace(new RegExp(`^${key}=.*$`, 'm'), line)
121
+ } else {
122
+ content = content.trimEnd() + '\n' + line + '\n'
123
+ }
124
+ } else {
125
+ content = line + '\n'
76
126
  }
127
+ fs.mkdirSync(path.dirname(envPath), { recursive: true })
128
+ fs.writeFileSync(envPath, content)
77
129
  }
78
130
 
79
131
  function printQuickExamples() {