skillfree 0.1.66 → 0.1.68

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
@@ -39,7 +39,7 @@ echo -e " ${DIM}─────────────────────
39
39
  echo ""
40
40
 
41
41
  # ── Step 1: 检查环境 ──────────────────────────────────────────────────────────
42
- step "[ 1 / 3 ] 检查环境"
42
+ step "[ 1 / 4 ] 检查环境"
43
43
 
44
44
  if ! command -v node &>/dev/null; then
45
45
  err "未检测到 Node.js,请先安装:https://nodejs.org(需要 18+)"
@@ -55,8 +55,69 @@ if ! command -v npm &>/dev/null; then
55
55
  fi
56
56
  success "npm $(npm -v)"
57
57
 
58
- # ── Step 2: 安装 CLI ──────────────────────────────────────────────────────────
59
- step "[ 2 / 3 ] 安装 SkillFree CLI"
58
+ # ── Step 2: 选择 AI 平台 ──────────────────────────────────────────────────────
59
+ step "[ 2 / 4 ] 选择你使用的 AI 平台"
60
+ echo ""
61
+ echo -e " SkillFree 将作为 Skill 安装到对应平台,${DIM}可多选,用逗号或空格分隔${NC}"
62
+ echo ""
63
+
64
+ # 自动检测已安装的平台
65
+ DETECTED=()
66
+ [ -d "$HOME/.openclaw" ] && DETECTED+=("openclaw")
67
+ [ -d "$HOME/.claude" ] && DETECTED+=("claude")
68
+ [ -d "$HOME/.codex" ] && DETECTED+=("codex")
69
+ [ -d "$HOME/.continue" ] && DETECTED+=("continue")
70
+ [ -d "$HOME/.cursor/extensions" ] && DETECTED+=("cursor")
71
+
72
+ echo -e " ${BOLD}可选平台:${NC}"
73
+ echo -e " ${CYAN} 1)${NC} OpenClaw ${DIM}→ ~/.openclaw/skills/skillfree/${NC}"
74
+ echo -e " ${CYAN} 2)${NC} Claude Code ${DIM}→ ~/.claude/skills/skillfree/${NC}"
75
+ echo -e " ${CYAN} 3)${NC} Codex CLI ${DIM}→ ~/.codex/skills/skillfree/${NC}"
76
+ echo ""
77
+
78
+ if [ ${#DETECTED[@]} -gt 0 ]; then
79
+ echo -e " ${GREEN}已检测到:${DETECTED[*]}${NC}"
80
+ echo ""
81
+ fi
82
+
83
+ printf " 请输入编号(如 1 或 1,2,3),直接回车选全部检测到的平台: "
84
+ read -r PLATFORM_INPUT </dev/tty
85
+
86
+ # 解析选择
87
+ SELECTED_PLATFORMS=()
88
+
89
+ if [ -z "$PLATFORM_INPUT" ]; then
90
+ # 回车 → 使用检测到的平台,没检测到则三个都选
91
+ if [ ${#DETECTED[@]} -gt 0 ]; then
92
+ SELECTED_PLATFORMS=("${DETECTED[@]}")
93
+ else
94
+ SELECTED_PLATFORMS=("openclaw" "claude" "codex")
95
+ fi
96
+ else
97
+ # 解析数字(支持逗号/空格分隔)
98
+ INPUT_CLEAN="${PLATFORM_INPUT//,/ }"
99
+ for num in $INPUT_CLEAN; do
100
+ case "$num" in
101
+ 1) SELECTED_PLATFORMS+=("openclaw") ;;
102
+ 2) SELECTED_PLATFORMS+=("claude") ;;
103
+ 3) SELECTED_PLATFORMS+=("codex") ;;
104
+ esac
105
+ done
106
+ fi
107
+
108
+ if [ ${#SELECTED_PLATFORMS[@]} -gt 0 ]; then
109
+ echo ""
110
+ echo -e " ${GREEN}将安装到:${SELECTED_PLATFORMS[*]}${NC}"
111
+ else
112
+ echo ""
113
+ warn "未选择平台,仅安装 CLI 命令行工具"
114
+ fi
115
+
116
+ # 导出给 postinstall.js 使用
117
+ export SKILLFREE_PLATFORMS="${SELECTED_PLATFORMS[*]}"
118
+
119
+ # ── Step 3: 安装 CLI ──────────────────────────────────────────────────────────
120
+ step "[ 3 / 4 ] 安装 SkillFree CLI"
60
121
  echo ""
61
122
  echo -e " ${DIM}正在从 npm 安装 skillfree...${NC}"
62
123
  echo ""
@@ -91,8 +152,8 @@ if ! command -v skillfree &>/dev/null; then
91
152
  exit 0
92
153
  fi
93
154
 
94
- # ── Step 3: 登录(从 /dev/tty 读取,兼容 curl | bash)────────────────────────
95
- step "[ 3 / 3 ] 登录账号"
155
+ # ── Step 4: 登录(从 /dev/tty 读取,兼容 curl | bash)────────────────────────
156
+ step "[ 4 / 4 ] 登录账号"
96
157
  echo ""
97
158
  echo -e " 还没有账号?${CYAN}https://skillfree.tech/app${NC} 免费注册,注册即送 ¥5"
98
159
  echo -e " 注册后进入控制台 → ${BOLD}API Keys${NC} → 创建一个 Key,粘贴到下方"
@@ -120,7 +181,7 @@ while true; do
120
181
  done
121
182
 
122
183
  if [ -n "$API_KEY" ]; then
123
- SKILLFREE_API_KEY="$API_KEY" skillfree auth save "$API_KEY"
184
+ SKILLFREE_API_KEY="$API_KEY" SKILLFREE_PLATFORMS="$SKILLFREE_PLATFORMS" skillfree auth save "$API_KEY"
124
185
  fi
125
186
 
126
187
  # ── 完成 ──────────────────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillfree",
3
- "version": "0.1.66",
3
+ "version": "0.1.68",
4
4
  "description": "🦞 一个 API,满足所有龙虾技能需求",
5
5
  "main": "bin/skillfree.js",
6
6
  "bin": {
package/postinstall.js CHANGED
@@ -2,24 +2,54 @@
2
2
  /**
3
3
  * postinstall.js
4
4
  * npm install -g skillfree 后自动:
5
- * 1. 将技能文件部署到 ~/.agents/skills/skillfree/ ~/.openclaw/skills/skillfree/
6
- * 2. 将 API Key 写入 ~/.openclaw/openclaw.json(让 OpenClaw 自动识别 skill)
5
+ * 1. 将技能文件部署到各 AI 平台的 skills/skillfree/ 目录
6
+ * 2. 将 API Key 写入 OpenClaw 配置(如果已安装)
7
+ *
8
+ * 支持的平台(通过 SKILLFREE_PLATFORMS 环境变量控制):
9
+ * openclaw → ~/.openclaw/skills/skillfree/ + ~/.agents/skills/skillfree/
10
+ * claude → ~/.claude/skills/skillfree/
11
+ * codex → ~/.codex/skills/skillfree/
12
+ * continue → ~/.continue/skills/skillfree/
13
+ * cursor → ~/.cursor/skills/skillfree/
7
14
  */
8
15
 
9
16
  const fs = require('fs')
10
17
  const path = require('path')
11
18
  const os = require('os')
12
19
 
13
- const PKG_DIR = __dirname
14
- const HOME = os.homedir()
15
- const API_KEY = process.env.SKILLFREE_API_KEY || ''
20
+ const PKG_DIR = __dirname
21
+ const HOME = os.homedir()
22
+ const API_KEY = process.env.SKILLFREE_API_KEY || ''
23
+
24
+ // ── 平台 → 技能安装路径映射 ─────────────────────────────────────────────────
25
+ const PLATFORM_PATHS = {
26
+ openclaw: [
27
+ path.join(HOME, '.openclaw', 'skills', 'skillfree'),
28
+ path.join(HOME, '.agents', 'skills', 'skillfree'),
29
+ ],
30
+ claude: [
31
+ path.join(HOME, '.claude', 'skills', 'skillfree'),
32
+ ],
33
+ codex: [
34
+ path.join(HOME, '.codex', 'skills', 'skillfree'),
35
+ ],
36
+ }
16
37
 
17
- // skill 部署目标目录(多个路径全部写入)
18
- const SKILL_TARGETS = [
19
- path.join(HOME, '.agents', 'skills', 'skillfree'),
20
- path.join(HOME, '.openclaw', 'skills', 'skillfree'),
21
- ]
38
+ // 解析目标平台
39
+ function getTargetPlatforms() {
40
+ const envVal = process.env.SKILLFREE_PLATFORMS || ''
41
+ if (!envVal.trim()) {
42
+ // 未指定时:自动检测已安装的平台
43
+ return Object.keys(PLATFORM_PATHS).filter(p => {
44
+ const baseDir = path.join(HOME, '.' + p)
45
+ return fs.existsSync(baseDir)
46
+ })
47
+ }
48
+ // 支持空格/逗号分隔
49
+ return envVal.split(/[\s,]+/).filter(p => p && PLATFORM_PATHS[p])
50
+ }
22
51
 
52
+ // ── 文件部署 ─────────────────────────────────────────────────────────────────
23
53
  const FILES = ['SKILL.md', 'package.json']
24
54
  const DIRS = ['bin', 'scripts']
25
55
 
@@ -48,33 +78,32 @@ function deploySkill(skillDir) {
48
78
  }
49
79
  fs.writeFileSync(
50
80
  path.join(skillDir, '.skillfree-installed'),
51
- JSON.stringify({ installedAt: new Date().toISOString(), version: require('./package.json').version }, null, 2) + '\n'
81
+ JSON.stringify({
82
+ installedAt: new Date().toISOString(),
83
+ version: require('./package.json').version,
84
+ }, null, 2) + '\n'
52
85
  )
53
86
  }
54
87
 
88
+ // ── OpenClaw 特有:写入 openclaw.json ────────────────────────────────────────
55
89
  function injectOpenclawConfig(apiKey) {
56
- // 只在有 openclaw 目录时注入
57
90
  const openclawDir = path.join(HOME, '.openclaw')
58
91
  if (!fs.existsSync(openclawDir)) return
59
92
 
60
93
  const cfgPath = path.join(openclawDir, 'openclaw.json')
61
-
62
- // ⚠️ 关键:文件不存在时直接 return,绝不用空对象覆盖
63
94
  if (!fs.existsSync(cfgPath)) return
64
95
 
65
96
  let cfg = {}
66
97
  try {
67
98
  cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'))
68
99
  } catch (e) {
69
- // JSON 解析失败(文件损坏等)→ 同样放弃写入,不覆盖
70
- console.warn('⚠️ openclaw.json 解析失败,跳过自动配置(文件可能损坏)')
100
+ console.warn('⚠️ openclaw.json 解析失败,跳过自动配置')
71
101
  return
72
102
  }
73
103
 
74
104
  cfg.skills = cfg.skills || {}
75
105
  cfg.skills.entries = cfg.skills.entries || {}
76
106
 
77
- // 只写 enabled,不覆盖用户已有的 apiKey
78
107
  const existing = cfg.skills.entries['skillfree'] || {}
79
108
  cfg.skills.entries['skillfree'] = {
80
109
  ...existing,
@@ -84,23 +113,46 @@ function injectOpenclawConfig(apiKey) {
84
113
 
85
114
  try {
86
115
  fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + '\n')
87
- console.log('✅ openclaw.json 已更新,skill 下次启动自动生效')
116
+ console.log(' ✅ openclaw.json 已更新,skill 下次启动自动生效')
88
117
  } catch (e) {
89
118
  // 权限问题静默跳过
90
119
  }
91
120
  }
92
121
 
122
+ // ── 主流程 ───────────────────────────────────────────────────────────────────
93
123
  try {
94
- // 1. 部署 skill 到所有目标目录
95
- for (const target of SKILL_TARGETS) {
96
- deploySkill(target)
124
+ const platforms = getTargetPlatforms()
125
+
126
+ if (platforms.length === 0) {
127
+ // 没有检测到任何平台,保底装到 ~/.agents/skills/
128
+ const fallback = path.join(HOME, '.agents', 'skills', 'skillfree')
129
+ deploySkill(fallback)
130
+ console.log(`✅ SkillFree skill 已安装到 ${fallback}`)
131
+ return
132
+ }
133
+
134
+ const installed = []
135
+
136
+ for (const platform of platforms) {
137
+ const targets = PLATFORM_PATHS[platform] || []
138
+ for (const skillDir of targets) {
139
+ deploySkill(skillDir)
140
+ installed.push({ platform, skillDir })
141
+ }
142
+
143
+ // OpenClaw 额外注入 openclaw.json
144
+ if (platform === 'openclaw') {
145
+ injectOpenclawConfig(API_KEY)
146
+ }
97
147
  }
98
- console.log('✅ SkillFree skill 已安装到:')
99
- SKILL_TARGETS.forEach(t => console.log(` ${t}`))
100
148
 
101
- // 2. 注入 openclaw.json(让 skill 自动被 OpenClaw 识别)
102
- injectOpenclawConfig(API_KEY)
149
+ if (installed.length > 0) {
150
+ console.log('✅ SkillFree skill 已安装到:')
151
+ for (const { platform, skillDir } of installed) {
152
+ console.log(` [${platform}] ${skillDir}`)
153
+ }
154
+ }
103
155
 
104
156
  } catch (e) {
105
- // 静默失败,不影响正常安装
157
+ // 静默失败,不影响正常 npm 安装
106
158
  }
@@ -4,15 +4,34 @@ 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
+
7
27
  /**
8
- * 将 apiKey 写入 ~/.openclaw/openclaw.json skills.entries.skillfree
9
- * 同时设置当前进程的 SKILLFREE_API_KEY 环境变量
28
+ * 将 apiKey 写入各平台配置 + shell 环境变量
10
29
  */
11
30
  function injectToOpenclaw(apiKey) {
12
- // 1. 写入 openclaw.json
31
+ // 1. OpenClaw: 写入 openclaw.json
13
32
  const openclawDir = path.join(os.homedir(), '.openclaw')
14
33
  const cfgPath = path.join(openclawDir, 'openclaw.json')
15
- if (fs.existsSync(openclawDir)) {
34
+ if (fs.existsSync(openclawDir) && fs.existsSync(cfgPath)) {
16
35
  let cfg = {}
17
36
  try { cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8')) } catch {}
18
37
  cfg.skills = cfg.skills || {}
@@ -41,7 +60,6 @@ function injectToOpenclaw(apiKey) {
41
60
  if (fs.existsSync(f)) {
42
61
  const content = fs.readFileSync(f, 'utf8')
43
62
  if (content.includes('SKILLFREE_API_KEY')) {
44
- // 替换已有行
45
63
  const updated = content.replace(/\nexport SKILLFREE_API_KEY=.*\n?/g, exportLine)
46
64
  fs.writeFileSync(f, updated)
47
65
  } else {
@@ -53,7 +71,6 @@ function injectToOpenclaw(apiKey) {
53
71
  }
54
72
  }
55
73
  if (!wrote) {
56
- // 创建 .zshrc
57
74
  fs.writeFileSync(shellFiles[0], `# SkillFree API Key${exportLine}`)
58
75
  console.log('✅ ~/.zshrc 已创建并写入 SKILLFREE_API_KEY')
59
76
  }