@reconcrap/boss-recommend-mcp 2.1.1 → 2.1.2
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 +79 -1
- package/package.json +6 -5
- package/scripts/install-macos.sh +280 -0
- package/src/cli.js +122 -46
package/README.md
CHANGED
|
@@ -7,6 +7,68 @@ Boss 推荐 / 搜索 / 聊天筛选 MCP(stdio)服务。
|
|
|
7
7
|
- npm: `@reconcrap/boss-recommend-mcp`(https://www.npmjs.com/package/@reconcrap/boss-recommend-mcp)
|
|
8
8
|
- GitHub: `reconcrap-cpu/boss-recommend-mcp`(https://github.com/reconcrap-cpu/boss-recommend-mcp)
|
|
9
9
|
|
|
10
|
+
## AI harness install entrypoint
|
|
11
|
+
|
|
12
|
+
如果用户只把这个 GitHub 链接交给 Codex、Claude Code、Cursor、OpenClaw、QClaw、Trae 等 AI harness,并要求“安装这个工具”,请优先执行本节,而不是直接在 macOS 上裸跑 `npm install -g`。
|
|
13
|
+
|
|
14
|
+
AI harness 不能只完成 npm 安装就结束。安装流程还必须帮助用户完成必填 LLM 配置;如果用户没有提前提供,请向用户索取:
|
|
15
|
+
|
|
16
|
+
- LLM base URL(默认可用 `https://api.openai.com/v1`)
|
|
17
|
+
- LLM API key
|
|
18
|
+
- LLM model(默认可用 `gpt-4.1-mini`)
|
|
19
|
+
|
|
20
|
+
然后写入配置:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
boss-recommend-mcp config set --base-url <baseUrl> --api-key <apiKey> --model <model> --thinking-level low
|
|
24
|
+
boss-recommend-mcp doctor
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
如果用户用 macOS bootstrap,它会自动尝试交互式询问并写入这些字段。非交互式 AI harness 如果拿不到用户输入,应暂停并询问用户上述三项,不要把安装标记为完成。
|
|
28
|
+
|
|
29
|
+
macOS 首次安装推荐使用仓库里的 nvm bootstrap。它会把 Node/npm/global packages 放到用户目录,避免首次安装或后续升级时出现:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
EACCES: permission denied, mkdir '/usr/local/lib/node_modules/@reconcrap'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
这是 npm global prefix 权限问题,不是 `boss-recommend-mcp` 包内部创建目录失败。
|
|
36
|
+
|
|
37
|
+
macOS 一键安装:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
curl -fsSL https://raw.githubusercontent.com/reconcrap-cpu/boss-recommend-mcp/main/scripts/install-macos.sh | bash
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
如果要直接配置某个宿主:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
curl -fsSL https://raw.githubusercontent.com/reconcrap-cpu/boss-recommend-mcp/main/scripts/install-macos.sh | bash -s -- --agent openclaw
|
|
47
|
+
curl -fsSL https://raw.githubusercontent.com/reconcrap-cpu/boss-recommend-mcp/main/scripts/install-macos.sh | bash -s -- --agent qclaw
|
|
48
|
+
curl -fsSL https://raw.githubusercontent.com/reconcrap-cpu/boss-recommend-mcp/main/scripts/install-macos.sh | bash -s -- --agent trae-cn
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
安装后,未来升级只需要在同一个 nvm shell 里运行:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm -g i @reconcrap/boss-recommend-mcp@latest
|
|
55
|
+
boss-recommend-mcp where
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
如果升级前 `npm config get prefix` 返回 `/usr/local`,说明当前 shell 没有使用 nvm Node;请先重新加载 nvm,不要使用 `sudo npm install -g`。
|
|
59
|
+
|
|
60
|
+
macOS bootstrap 会执行 `boss-recommend-mcp install --mcp-launch global-wrapper`。该模式会把 MCP 宿主配置为启动稳定 wrapper:`~/.boss-recommend-mcp/bin/boss-recommend-mcp-mcp-server`。这个 wrapper 每次启动时都会调用当前全局 `boss-recommend-mcp start`,因此后续 `npm -g i @reconcrap/boss-recommend-mcp@latest` 会更新 MCP 宿主实际运行的版本,不需要每次升级后重写 MCP 配置。
|
|
61
|
+
|
|
62
|
+
如果 AI harness 已经从用户处拿到 LLM 信息,可以非交互式传给 bootstrap:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
curl -fsSL https://raw.githubusercontent.com/reconcrap-cpu/boss-recommend-mcp/main/scripts/install-macos.sh \
|
|
66
|
+
| BOSS_RECOMMEND_BASE_URL="https://api.openai.com/v1" \
|
|
67
|
+
BOSS_RECOMMEND_API_KEY="<apiKey>" \
|
|
68
|
+
BOSS_RECOMMEND_MODEL="gpt-4.1-mini" \
|
|
69
|
+
bash -s -- --agent openclaw
|
|
70
|
+
```
|
|
71
|
+
|
|
10
72
|
2.0.0 是 CDP-only 重写版本:活跃浏览器路径只允许 Chrome DevTools Protocol 的 `DOM` / `Input` / `Page` / `Network` / `Accessibility` 等域,不使用 `Runtime.evaluate` 或页面 JS。包内保留 recommend、search/recruit、chat 三条域服务,并共享浏览器、生命周期、筛选、CV 获取、无限滚动、自愈与 CSV 报告层。
|
|
11
73
|
|
|
12
74
|
安装 `boss-recommend-mcp` 后可以直接:
|
|
@@ -125,6 +187,13 @@ npm install -g @reconcrap/boss-recommend-mcp@latest
|
|
|
125
187
|
boss-recommend-mcp start
|
|
126
188
|
```
|
|
127
189
|
|
|
190
|
+
macOS 首次安装如果没有确认 npm prefix 在用户目录,优先使用本文开头的 `scripts/install-macos.sh`。完成 bootstrap 后,后续升级仍然使用同一个 npm 命令:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npm -g i @reconcrap/boss-recommend-mcp@latest
|
|
194
|
+
boss-recommend-mcp where
|
|
195
|
+
```
|
|
196
|
+
|
|
128
197
|
无需安装(npx 直接运行):
|
|
129
198
|
|
|
130
199
|
```bash
|
|
@@ -150,7 +219,8 @@ node src/cli.js start
|
|
|
150
219
|
如果检测到 legacy Boss server entries,installer 会:
|
|
151
220
|
|
|
152
221
|
- 保留非 Boss MCP server。
|
|
153
|
-
-
|
|
222
|
+
- 默认写入统一 server:`boss-recommend -> npx -y @reconcrap/boss-recommend-mcp@<installed-version> start`
|
|
223
|
+
- 如果传入 `--mcp-launch global-wrapper`,写入升级稳定入口:`boss-recommend -> ~/.boss-recommend-mcp/bin/boss-recommend-mcp-mcp-server`。该 wrapper 会加载 `~/.nvm/nvm.sh` 并执行当前全局 `boss-recommend-mcp start`,适合 macOS 上通过 `npm -g i @reconcrap/boss-recommend-mcp@latest` 持续升级。
|
|
154
224
|
- 从同一个 `mcp.json` 删除旧 `boss-recruit-mcp`、standalone `boss-chat`、旧本地 Boss repo 路径,避免 agent 继续调用 legacy 包。
|
|
155
225
|
- 在原文件旁生成 `mcp.json.boss-mcp-migration-*.bak`。
|
|
156
226
|
- 同步外部 skills 目录里的 `boss-recommend-pipeline`、`boss-recruit-pipeline`、`boss-chat`。
|
|
@@ -166,6 +236,14 @@ boss-recommend-mcp doctor --agent openclaw
|
|
|
166
236
|
boss-recommend-mcp doctor --agent qclaw
|
|
167
237
|
```
|
|
168
238
|
|
|
239
|
+
macOS 上如果希望 MCP 宿主总是使用全局 npm 最新安装版本:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
boss-recommend-mcp install --mcp-launch global-wrapper --agent openclaw
|
|
243
|
+
boss-recommend-mcp install --mcp-launch global-wrapper --agent qclaw
|
|
244
|
+
boss-recommend-mcp install --mcp-launch global-wrapper --agent trae-cn
|
|
245
|
+
```
|
|
246
|
+
|
|
169
247
|
自定义路径:
|
|
170
248
|
|
|
171
249
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reconcrap/boss-recommend-mcp",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Unified MCP pipeline for recommend-page filtering and screening on Boss Zhipin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"boss",
|
|
@@ -79,10 +79,11 @@
|
|
|
79
79
|
"live:chat-image-screening": "node scripts/live-chat-image-screening-smoke.js"
|
|
80
80
|
},
|
|
81
81
|
"files": [
|
|
82
|
-
"bin",
|
|
83
|
-
"config/screening-config.example.json",
|
|
84
|
-
"skills",
|
|
85
|
-
"scripts/
|
|
82
|
+
"bin",
|
|
83
|
+
"config/screening-config.example.json",
|
|
84
|
+
"skills",
|
|
85
|
+
"scripts/install-macos.sh",
|
|
86
|
+
"scripts/postinstall.cjs",
|
|
86
87
|
"src/core",
|
|
87
88
|
"src/domains",
|
|
88
89
|
"src/chat-mcp.js",
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
PACKAGE_NAME="@reconcrap/boss-recommend-mcp"
|
|
5
|
+
DEFAULT_NODE_VERSION="${BOSS_RECOMMEND_NODE_VERSION:-22}"
|
|
6
|
+
DEFAULT_NVM_VERSION="${BOSS_RECOMMEND_NVM_VERSION:-v0.40.4}"
|
|
7
|
+
|
|
8
|
+
NODE_VERSION="$DEFAULT_NODE_VERSION"
|
|
9
|
+
NVM_VERSION="$DEFAULT_NVM_VERSION"
|
|
10
|
+
AGENT="${BOSS_RECOMMEND_AGENT:-}"
|
|
11
|
+
DRY_RUN=0
|
|
12
|
+
SKIP_DOCTOR=0
|
|
13
|
+
SKIP_LLM_CONFIG=0
|
|
14
|
+
BASE_URL="${BOSS_RECOMMEND_BASE_URL:-https://api.openai.com/v1}"
|
|
15
|
+
API_KEY="${BOSS_RECOMMEND_API_KEY:-}"
|
|
16
|
+
MODEL="${BOSS_RECOMMEND_MODEL:-gpt-4.1-mini}"
|
|
17
|
+
THINKING_LEVEL="${BOSS_RECOMMEND_THINKING_LEVEL:-low}"
|
|
18
|
+
GREETING_MESSAGE="${BOSS_RECOMMEND_GREETING_MESSAGE:-Hi同学,能麻烦发下简历吗?}"
|
|
19
|
+
|
|
20
|
+
usage() {
|
|
21
|
+
cat <<'EOF'
|
|
22
|
+
Install boss-recommend-mcp on macOS with nvm-backed npm globals.
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
install-macos.sh [--agent <agent|all>] [--node-version <version>] [--nvm-version <tag>] [--dry-run] [--skip-doctor] [--skip-llm-config]
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
curl -fsSL https://raw.githubusercontent.com/reconcrap-cpu/boss-recommend-mcp/main/scripts/install-macos.sh | bash
|
|
29
|
+
curl -fsSL https://raw.githubusercontent.com/reconcrap-cpu/boss-recommend-mcp/main/scripts/install-macos.sh | bash -s -- --agent openclaw
|
|
30
|
+
|
|
31
|
+
Supported agents: cursor, trae, trae-cn, claude, openclaw, qclaw, all
|
|
32
|
+
|
|
33
|
+
LLM config can be supplied non-interactively with:
|
|
34
|
+
BOSS_RECOMMEND_BASE_URL, BOSS_RECOMMEND_API_KEY, BOSS_RECOMMEND_MODEL,
|
|
35
|
+
BOSS_RECOMMEND_THINKING_LEVEL, BOSS_RECOMMEND_GREETING_MESSAGE
|
|
36
|
+
EOF
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
log() {
|
|
40
|
+
printf '%s\n' "[boss-recommend-mcp] $*"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
die() {
|
|
44
|
+
printf '%s\n' "[boss-recommend-mcp] ERROR: $*" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
run() {
|
|
49
|
+
log "+ $*"
|
|
50
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
51
|
+
"$@"
|
|
52
|
+
fi
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
while [ "$#" -gt 0 ]; do
|
|
56
|
+
case "$1" in
|
|
57
|
+
--agent)
|
|
58
|
+
[ "$#" -ge 2 ] || die "--agent requires a value"
|
|
59
|
+
AGENT="$2"
|
|
60
|
+
shift 2
|
|
61
|
+
;;
|
|
62
|
+
--node-version)
|
|
63
|
+
[ "$#" -ge 2 ] || die "--node-version requires a value"
|
|
64
|
+
NODE_VERSION="$2"
|
|
65
|
+
shift 2
|
|
66
|
+
;;
|
|
67
|
+
--nvm-version)
|
|
68
|
+
[ "$#" -ge 2 ] || die "--nvm-version requires a value"
|
|
69
|
+
NVM_VERSION="$2"
|
|
70
|
+
shift 2
|
|
71
|
+
;;
|
|
72
|
+
--dry-run)
|
|
73
|
+
DRY_RUN=1
|
|
74
|
+
shift
|
|
75
|
+
;;
|
|
76
|
+
--skip-doctor)
|
|
77
|
+
SKIP_DOCTOR=1
|
|
78
|
+
shift
|
|
79
|
+
;;
|
|
80
|
+
--skip-llm-config)
|
|
81
|
+
SKIP_LLM_CONFIG=1
|
|
82
|
+
shift
|
|
83
|
+
;;
|
|
84
|
+
--base-url)
|
|
85
|
+
[ "$#" -ge 2 ] || die "--base-url requires a value"
|
|
86
|
+
BASE_URL="$2"
|
|
87
|
+
shift 2
|
|
88
|
+
;;
|
|
89
|
+
--api-key)
|
|
90
|
+
[ "$#" -ge 2 ] || die "--api-key requires a value"
|
|
91
|
+
API_KEY="$2"
|
|
92
|
+
shift 2
|
|
93
|
+
;;
|
|
94
|
+
--model)
|
|
95
|
+
[ "$#" -ge 2 ] || die "--model requires a value"
|
|
96
|
+
MODEL="$2"
|
|
97
|
+
shift 2
|
|
98
|
+
;;
|
|
99
|
+
--thinking-level)
|
|
100
|
+
[ "$#" -ge 2 ] || die "--thinking-level requires a value"
|
|
101
|
+
THINKING_LEVEL="$2"
|
|
102
|
+
shift 2
|
|
103
|
+
;;
|
|
104
|
+
--greeting-message)
|
|
105
|
+
[ "$#" -ge 2 ] || die "--greeting-message requires a value"
|
|
106
|
+
GREETING_MESSAGE="$2"
|
|
107
|
+
shift 2
|
|
108
|
+
;;
|
|
109
|
+
-h|--help)
|
|
110
|
+
usage
|
|
111
|
+
exit 0
|
|
112
|
+
;;
|
|
113
|
+
*)
|
|
114
|
+
die "Unknown option: $1"
|
|
115
|
+
;;
|
|
116
|
+
esac
|
|
117
|
+
done
|
|
118
|
+
|
|
119
|
+
prompt_text() {
|
|
120
|
+
local label="$1"
|
|
121
|
+
local default_value="$2"
|
|
122
|
+
local secret="${3:-0}"
|
|
123
|
+
local value
|
|
124
|
+
if [ ! -r /dev/tty ]; then
|
|
125
|
+
return 1
|
|
126
|
+
fi
|
|
127
|
+
if [ "$secret" -eq 1 ]; then
|
|
128
|
+
printf '%s' "${label}: " > /dev/tty
|
|
129
|
+
IFS= read -r -s value < /dev/tty || return 1
|
|
130
|
+
printf '\n' > /dev/tty
|
|
131
|
+
elif [ -n "$default_value" ]; then
|
|
132
|
+
printf '%s' "${label} [${default_value}]: " > /dev/tty
|
|
133
|
+
IFS= read -r value < /dev/tty || return 1
|
|
134
|
+
if [ -z "$value" ]; then
|
|
135
|
+
value="$default_value"
|
|
136
|
+
fi
|
|
137
|
+
else
|
|
138
|
+
printf '%s' "${label}: " > /dev/tty
|
|
139
|
+
IFS= read -r value < /dev/tty || return 1
|
|
140
|
+
fi
|
|
141
|
+
printf '%s' "$value"
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if [ "$(uname -s)" != "Darwin" ]; then
|
|
145
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
146
|
+
log "dry-run on non-macOS host; skipping platform enforcement"
|
|
147
|
+
else
|
|
148
|
+
die "This bootstrap script is for macOS. Use npm install -g ${PACKAGE_NAME}@latest on other platforms."
|
|
149
|
+
fi
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
|
|
153
|
+
|
|
154
|
+
load_nvm() {
|
|
155
|
+
if [ -s "$NVM_DIR/nvm.sh" ]; then
|
|
156
|
+
# shellcheck disable=SC1090
|
|
157
|
+
. "$NVM_DIR/nvm.sh"
|
|
158
|
+
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
|
|
159
|
+
export NVM_DIR="$HOME/.nvm"
|
|
160
|
+
# shellcheck disable=SC1091
|
|
161
|
+
. "$HOME/.nvm/nvm.sh"
|
|
162
|
+
fi
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
install_nvm() {
|
|
166
|
+
if command -v nvm >/dev/null 2>&1; then
|
|
167
|
+
return
|
|
168
|
+
fi
|
|
169
|
+
log "nvm was not found; installing ${NVM_VERSION} into ${NVM_DIR}"
|
|
170
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
171
|
+
log "+ curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash"
|
|
172
|
+
return
|
|
173
|
+
fi
|
|
174
|
+
curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh" | bash
|
|
175
|
+
load_nvm
|
|
176
|
+
command -v nvm >/dev/null 2>&1 || die "nvm installed but is not available in this shell. Open a new terminal and rerun this script."
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
load_nvm
|
|
180
|
+
install_nvm
|
|
181
|
+
|
|
182
|
+
run nvm install "$NODE_VERSION"
|
|
183
|
+
run nvm alias default "$NODE_VERSION"
|
|
184
|
+
run nvm use "$NODE_VERSION"
|
|
185
|
+
|
|
186
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
187
|
+
NODE_PATH="$(command -v node || true)"
|
|
188
|
+
NPM_PATH="$(command -v npm || true)"
|
|
189
|
+
NPM_PREFIX="$(npm config get prefix || true)"
|
|
190
|
+
log "node: ${NODE_PATH}"
|
|
191
|
+
log "npm: ${NPM_PATH}"
|
|
192
|
+
log "npm prefix: ${NPM_PREFIX}"
|
|
193
|
+
|
|
194
|
+
case "$NPM_PREFIX" in
|
|
195
|
+
/usr/local|/usr/local/*)
|
|
196
|
+
die "npm is still using /usr/local. Reload nvm and rerun this script; do not use sudo npm install -g."
|
|
197
|
+
;;
|
|
198
|
+
esac
|
|
199
|
+
case "$NPM_PREFIX" in
|
|
200
|
+
"$NVM_DIR"/*)
|
|
201
|
+
;;
|
|
202
|
+
*)
|
|
203
|
+
die "npm prefix is not under ${NVM_DIR}. Current prefix: ${NPM_PREFIX}"
|
|
204
|
+
;;
|
|
205
|
+
esac
|
|
206
|
+
else
|
|
207
|
+
log "+ verify: npm config get prefix must be under ${NVM_DIR}, not /usr/local"
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
run npm -g i "${PACKAGE_NAME}@latest"
|
|
211
|
+
run boss-recommend-mcp where
|
|
212
|
+
|
|
213
|
+
INSTALL_ARGS=(install --mcp-launch global-wrapper)
|
|
214
|
+
DOCTOR_ARGS=(doctor)
|
|
215
|
+
if [ -n "$AGENT" ]; then
|
|
216
|
+
INSTALL_ARGS+=(--agent "$AGENT")
|
|
217
|
+
DOCTOR_ARGS+=(--agent "$AGENT")
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
run boss-recommend-mcp "${INSTALL_ARGS[@]}"
|
|
221
|
+
|
|
222
|
+
if [ "$SKIP_LLM_CONFIG" -eq 0 ]; then
|
|
223
|
+
log "LLM screening config is required before running candidate screening."
|
|
224
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
225
|
+
if [ -r /dev/tty ]; then
|
|
226
|
+
BASE_URL="$(prompt_text "LLM base URL" "$BASE_URL")"
|
|
227
|
+
MODEL="$(prompt_text "LLM model" "$MODEL")"
|
|
228
|
+
THINKING_LEVEL="$(prompt_text "LLM thinking level" "$THINKING_LEVEL")"
|
|
229
|
+
GREETING_MESSAGE="$(prompt_text "Greeting message for candidates" "$GREETING_MESSAGE")"
|
|
230
|
+
if [ -z "$API_KEY" ]; then
|
|
231
|
+
API_KEY="$(prompt_text "LLM API key (input hidden)" "" 1)"
|
|
232
|
+
fi
|
|
233
|
+
fi
|
|
234
|
+
if [ -z "$BASE_URL" ] || [ -z "$API_KEY" ] || [ -z "$MODEL" ]; then
|
|
235
|
+
cat >&2 <<EOF
|
|
236
|
+
[boss-recommend-mcp] LLM config is still required.
|
|
237
|
+
[boss-recommend-mcp] Ask the user for:
|
|
238
|
+
1. LLM base URL
|
|
239
|
+
2. LLM API key
|
|
240
|
+
3. LLM model name
|
|
241
|
+
[boss-recommend-mcp] Then run:
|
|
242
|
+
boss-recommend-mcp config set --base-url <baseUrl> --api-key <apiKey> --model <model> --thinking-level ${THINKING_LEVEL}
|
|
243
|
+
EOF
|
|
244
|
+
exit 2
|
|
245
|
+
fi
|
|
246
|
+
fi
|
|
247
|
+
|
|
248
|
+
CONFIG_ARGS=(config set --base-url "$BASE_URL" --api-key "$API_KEY" --model "$MODEL")
|
|
249
|
+
if [ -n "$THINKING_LEVEL" ]; then
|
|
250
|
+
CONFIG_ARGS+=(--thinking-level "$THINKING_LEVEL")
|
|
251
|
+
fi
|
|
252
|
+
if [ -n "$GREETING_MESSAGE" ]; then
|
|
253
|
+
CONFIG_ARGS+=(--greeting-message "$GREETING_MESSAGE")
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
257
|
+
log "+ boss-recommend-mcp config set --base-url ${BASE_URL:-<baseUrl>} --api-key <hidden> --model ${MODEL:-<model>} --thinking-level ${THINKING_LEVEL:-<level>}"
|
|
258
|
+
else
|
|
259
|
+
log "+ boss-recommend-mcp config set --base-url ${BASE_URL} --api-key <hidden> --model ${MODEL}"
|
|
260
|
+
boss-recommend-mcp "${CONFIG_ARGS[@]}"
|
|
261
|
+
fi
|
|
262
|
+
else
|
|
263
|
+
log "Skipping LLM config because --skip-llm-config was provided."
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
if [ "$SKIP_DOCTOR" -eq 0 ]; then
|
|
267
|
+
log "+ boss-recommend-mcp ${DOCTOR_ARGS[*]}"
|
|
268
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
269
|
+
if ! boss-recommend-mcp "${DOCTOR_ARGS[@]}"; then
|
|
270
|
+
log "doctor reported follow-up work. The npm package install still completed."
|
|
271
|
+
fi
|
|
272
|
+
fi
|
|
273
|
+
fi
|
|
274
|
+
|
|
275
|
+
cat <<EOF
|
|
276
|
+
[boss-recommend-mcp] install complete.
|
|
277
|
+
[boss-recommend-mcp] Future upgrades:
|
|
278
|
+
npm -g i ${PACKAGE_NAME}@latest
|
|
279
|
+
boss-recommend-mcp where
|
|
280
|
+
EOF
|
package/src/cli.js
CHANGED
|
@@ -50,10 +50,12 @@ const chromeOnboardingUrlPattern = /^chrome:\/\/(welcome|intro|newtab|signin|his
|
|
|
50
50
|
const bossLoginUrlPattern = /(?:zhipin\.com\/web\/user(?:\/|\?|$)|passport\.zhipin\.com)/i;
|
|
51
51
|
const bossLoginTitlePattern = /登录|signin|扫码登录|BOSS直聘登录/i;
|
|
52
52
|
const supportedMcpClients = ["generic", "cursor", "trae", "claudecode", "openclaw", "qclaw"];
|
|
53
|
-
const defaultMcpServerName = "boss-recommend";
|
|
54
|
-
const defaultMcpCommand = "npx";
|
|
55
|
-
const recommendMcpPackageName = "@reconcrap/boss-recommend-mcp";
|
|
56
|
-
const recommendMcpBinaryName = "boss-recommend-mcp";
|
|
53
|
+
const defaultMcpServerName = "boss-recommend";
|
|
54
|
+
const defaultMcpCommand = "npx";
|
|
55
|
+
const recommendMcpPackageName = "@reconcrap/boss-recommend-mcp";
|
|
56
|
+
const recommendMcpBinaryName = "boss-recommend-mcp";
|
|
57
|
+
const globalMcpWrapperFileName = "boss-recommend-mcp-mcp-server";
|
|
58
|
+
const supportedMcpLaunchModes = ["npx", "global-wrapper"];
|
|
57
59
|
const autoSyncSkipCommands = new Set(["install", "install-skill", "where", "help", "--help", "-h", "list-jobs", "jobs", "recommend-jobs"]);
|
|
58
60
|
const externalMcpTargetsEnv = "BOSS_RECOMMEND_MCP_CONFIG_TARGETS";
|
|
59
61
|
const externalSkillDirsEnv = "BOSS_RECOMMEND_EXTERNAL_SKILL_DIRS";
|
|
@@ -124,15 +126,22 @@ function getCodexHome() {
|
|
|
124
126
|
: path.join(os.homedir(), ".codex");
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
function getStateHome() {
|
|
128
|
-
return process.env.BOSS_RECOMMEND_HOME
|
|
129
|
-
? path.resolve(process.env.BOSS_RECOMMEND_HOME)
|
|
130
|
-
: path.join(os.homedir(), ".boss-recommend-mcp");
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
function getStateHome() {
|
|
130
|
+
return process.env.BOSS_RECOMMEND_HOME
|
|
131
|
+
? path.resolve(process.env.BOSS_RECOMMEND_HOME)
|
|
132
|
+
: path.join(os.homedir(), ".boss-recommend-mcp");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getGlobalMcpWrapperPath(options = {}) {
|
|
136
|
+
if (typeof options["mcp-wrapper-path"] === "string" && options["mcp-wrapper-path"].trim()) {
|
|
137
|
+
return path.resolve(options["mcp-wrapper-path"].trim());
|
|
138
|
+
}
|
|
139
|
+
return path.join(getStateHome(), "bin", globalMcpWrapperFileName);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function ensureDir(targetPath) {
|
|
143
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
144
|
+
}
|
|
136
145
|
|
|
137
146
|
function pathExists(targetPath) {
|
|
138
147
|
try {
|
|
@@ -738,13 +747,55 @@ function parseMcpClientTargets(rawValue) {
|
|
|
738
747
|
return unique;
|
|
739
748
|
}
|
|
740
749
|
|
|
741
|
-
function isPlainObject(value) {
|
|
742
|
-
return value && typeof value === "object" && !Array.isArray(value);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
function
|
|
746
|
-
const
|
|
747
|
-
|
|
750
|
+
function isPlainObject(value) {
|
|
751
|
+
return value && typeof value === "object" && !Array.isArray(value);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function normalizeMcpLaunchMode(options = {}) {
|
|
755
|
+
const raw = String(options["mcp-launch"] || options.mcpLaunch || "").trim().toLowerCase().replace(/_/g, "-");
|
|
756
|
+
if (!raw) return "npx";
|
|
757
|
+
if (raw === "default") return "npx";
|
|
758
|
+
if (raw === "global" || raw === "wrapper") return "global-wrapper";
|
|
759
|
+
if (supportedMcpLaunchModes.includes(raw)) return raw;
|
|
760
|
+
throw new Error(`Unsupported --mcp-launch value: ${raw}. Supported: ${supportedMcpLaunchModes.join(", ")}`);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function buildGlobalMcpWrapperScript() {
|
|
764
|
+
return `#!/usr/bin/env bash
|
|
765
|
+
set -euo pipefail
|
|
766
|
+
|
|
767
|
+
export NVM_DIR="\${NVM_DIR:-$HOME/.nvm}"
|
|
768
|
+
if [ -s "$NVM_DIR/nvm.sh" ]; then
|
|
769
|
+
. "$NVM_DIR/nvm.sh"
|
|
770
|
+
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
|
|
771
|
+
export NVM_DIR="$HOME/.nvm"
|
|
772
|
+
. "$NVM_DIR/nvm.sh"
|
|
773
|
+
fi
|
|
774
|
+
|
|
775
|
+
if ! command -v ${recommendMcpBinaryName} >/dev/null 2>&1; then
|
|
776
|
+
echo "${recommendMcpBinaryName} not found on PATH. Install or reload nvm, then run: npm -g i ${recommendMcpPackageName}@latest" >&2
|
|
777
|
+
exit 127
|
|
778
|
+
fi
|
|
779
|
+
|
|
780
|
+
exec ${recommendMcpBinaryName} start "$@"
|
|
781
|
+
`;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function ensureGlobalMcpWrapper(options = {}) {
|
|
785
|
+
const wrapperPath = getGlobalMcpWrapperPath(options);
|
|
786
|
+
ensureDir(path.dirname(wrapperPath));
|
|
787
|
+
fs.writeFileSync(wrapperPath, buildGlobalMcpWrapperScript(), "utf8");
|
|
788
|
+
try {
|
|
789
|
+
fs.chmodSync(wrapperPath, 0o755);
|
|
790
|
+
} catch {
|
|
791
|
+
// Some filesystems ignore POSIX executable bits; the path is still valid for POSIX hosts.
|
|
792
|
+
}
|
|
793
|
+
return wrapperPath;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function shouldDefaultRecommendDetachedMcpEnv(options = {}) {
|
|
797
|
+
const client = normalizeMcpClientName(options.client);
|
|
798
|
+
const agent = normalizeAgentName(options.agent);
|
|
748
799
|
return client === "openclaw"
|
|
749
800
|
|| client === "qclaw"
|
|
750
801
|
|| agent === "openclaw"
|
|
@@ -764,10 +815,28 @@ function getAgentConfigOutputDir(options = {}) {
|
|
|
764
815
|
return path.join(getStateHome(), "agent-mcp-configs");
|
|
765
816
|
}
|
|
766
817
|
|
|
767
|
-
function buildMcpLaunchConfig(options = {}) {
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
818
|
+
function buildMcpLaunchConfig(options = {}) {
|
|
819
|
+
const mcpLaunchMode = normalizeMcpLaunchMode(options);
|
|
820
|
+
if (mcpLaunchMode === "global-wrapper") {
|
|
821
|
+
const args = parseJsonOption(options["args-json"], "args-json");
|
|
822
|
+
const env = parseJsonOption(options["env-json"], "env-json");
|
|
823
|
+
const launchConfig = {
|
|
824
|
+
command: ensureGlobalMcpWrapper(options),
|
|
825
|
+
args: Array.isArray(args) ? args : []
|
|
826
|
+
};
|
|
827
|
+
const mergedEnv = {
|
|
828
|
+
...getDefaultMcpEnv(options),
|
|
829
|
+
...(isPlainObject(env) ? env : {})
|
|
830
|
+
};
|
|
831
|
+
if (Object.keys(mergedEnv).length > 0) {
|
|
832
|
+
launchConfig.env = mergedEnv;
|
|
833
|
+
}
|
|
834
|
+
return launchConfig;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const command = typeof options.command === "string" && options.command.trim()
|
|
838
|
+
? options.command.trim()
|
|
839
|
+
: defaultMcpCommand;
|
|
771
840
|
const args = parseJsonOption(options["args-json"], "args-json");
|
|
772
841
|
const env = parseJsonOption(options["env-json"], "env-json");
|
|
773
842
|
const launchArgs = Array.isArray(args) && args.length > 0
|
|
@@ -2633,11 +2702,12 @@ function printHelp() {
|
|
|
2633
2702
|
console.log(" boss-recommend-mcp init-config Create screening-config.json if missing (prefer workspace config/, fallback ~/.boss-recommend-mcp)");
|
|
2634
2703
|
console.log(" boss-recommend-mcp config set Write baseUrl/apiKey/model (prefer workspace config/, fallback ~/.boss-recommend-mcp)");
|
|
2635
2704
|
console.log(" boss-recommend-mcp set-port Persist preferred Chrome debug port to screening-config.json");
|
|
2636
|
-
console.log(" boss-recommend-mcp mcp-config Generate MCP config JSON for Cursor/Trae(含 trae-cn)/Claude Code/OpenClaw/QClaw");
|
|
2637
|
-
console.log(" boss-recommend-mcp doctor Check config/runtime/calibration prerequisites (supports --agent trae-cn/qclaw/cursor/...)");
|
|
2638
|
-
console.log(" boss-recommend-mcp calibrate Disabled until CDP-only featured calibration is live-verified");
|
|
2639
|
-
console.log(" boss-recommend-mcp launch-chrome Launch or reuse Chrome debug instance and open Boss recommend page");
|
|
2640
|
-
console.log(" boss-recommend-mcp where Print installed package, skill, and config paths");
|
|
2705
|
+
console.log(" boss-recommend-mcp mcp-config Generate MCP config JSON for Cursor/Trae(含 trae-cn)/Claude Code/OpenClaw/QClaw");
|
|
2706
|
+
console.log(" boss-recommend-mcp doctor Check config/runtime/calibration prerequisites (supports --agent trae-cn/qclaw/cursor/...)");
|
|
2707
|
+
console.log(" boss-recommend-mcp calibrate Disabled until CDP-only featured calibration is live-verified");
|
|
2708
|
+
console.log(" boss-recommend-mcp launch-chrome Launch or reuse Chrome debug instance and open Boss recommend page");
|
|
2709
|
+
console.log(" boss-recommend-mcp where Print installed package, skill, and config paths");
|
|
2710
|
+
console.log(" boss-recommend-mcp install --mcp-launch global-wrapper Use ~/.boss-recommend-mcp/bin wrapper so npm global upgrades affect MCP hosts");
|
|
2641
2711
|
console.log("");
|
|
2642
2712
|
console.log("Run command:");
|
|
2643
2713
|
console.log(" boss-recommend-mcp prepare-run --instruction \"...\" --overrides-file overrides.json --confirmation-file confirmation.json");
|
|
@@ -2665,14 +2735,15 @@ function printMcpConfig(options = {}) {
|
|
|
2665
2735
|
}
|
|
2666
2736
|
}
|
|
2667
2737
|
|
|
2668
|
-
async function installAll(options = {}) {
|
|
2669
|
-
const runtimeDirsResult = await ensureRuntimeDirectories(options);
|
|
2670
|
-
const skillResults = installSkill();
|
|
2671
|
-
const configResult = await ensureUserConfig(options);
|
|
2672
|
-
const
|
|
2673
|
-
const
|
|
2674
|
-
const
|
|
2675
|
-
|
|
2738
|
+
async function installAll(options = {}) {
|
|
2739
|
+
const runtimeDirsResult = await ensureRuntimeDirectories(options);
|
|
2740
|
+
const skillResults = installSkill();
|
|
2741
|
+
const configResult = await ensureUserConfig(options);
|
|
2742
|
+
const mcpLaunchMode = normalizeMcpLaunchMode(options);
|
|
2743
|
+
const mcpTemplateResult = writeMcpConfigFiles({ ...options, agent: undefined, client: "all" });
|
|
2744
|
+
const externalMcpResult = installExternalMcpConfigs(options);
|
|
2745
|
+
const externalSkillResult = mirrorSkillToExternalDirs(options);
|
|
2746
|
+
console.log(
|
|
2676
2747
|
`Runtime directories prepared: created=${runtimeDirsResult.created.length}, existing=${runtimeDirsResult.existed.length}, failed=${runtimeDirsResult.failed.length}`
|
|
2677
2748
|
);
|
|
2678
2749
|
console.log(`- recommend runtime: ${runtimeDirsResult.stateHome}`);
|
|
@@ -2700,10 +2771,13 @@ async function installAll(options = {}) {
|
|
|
2700
2771
|
console.warn(`screening-config.json skip default patch: ${configResult.patch_error}`);
|
|
2701
2772
|
}
|
|
2702
2773
|
console.log(`请在该目录修改 baseUrl/apiKey/model 并替换占位词后再运行:${path.dirname(configResult.path)}`);
|
|
2703
|
-
console.log(`MCP config templates exported to: ${mcpTemplateResult.outputDir}`);
|
|
2704
|
-
for (const item of mcpTemplateResult.files) {
|
|
2705
|
-
console.log(`- ${item.client}: ${item.file}`);
|
|
2706
|
-
}
|
|
2774
|
+
console.log(`MCP config templates exported to: ${mcpTemplateResult.outputDir}`);
|
|
2775
|
+
for (const item of mcpTemplateResult.files) {
|
|
2776
|
+
console.log(`- ${item.client}: ${item.file}`);
|
|
2777
|
+
}
|
|
2778
|
+
if (mcpLaunchMode === "global-wrapper") {
|
|
2779
|
+
console.log(`Upgrade-stable MCP wrapper: ${getGlobalMcpWrapperPath(options)}`);
|
|
2780
|
+
}
|
|
2707
2781
|
if (externalMcpResult.targets.length > 0) {
|
|
2708
2782
|
console.log(`Auto-configured external MCP files: ${externalMcpResult.applied.length}`);
|
|
2709
2783
|
for (const item of externalMcpResult.applied) {
|
|
@@ -3189,11 +3263,13 @@ export async function runCli(argv = process.argv) {
|
|
|
3189
3263
|
}
|
|
3190
3264
|
|
|
3191
3265
|
export const __testables = {
|
|
3192
|
-
buildRecommendJobListCliInput,
|
|
3193
|
-
buildBossChatCliInput,
|
|
3194
|
-
buildDefaultMcpArgs,
|
|
3195
|
-
buildMcpLaunchConfig,
|
|
3196
|
-
|
|
3266
|
+
buildRecommendJobListCliInput,
|
|
3267
|
+
buildBossChatCliInput,
|
|
3268
|
+
buildDefaultMcpArgs,
|
|
3269
|
+
buildMcpLaunchConfig,
|
|
3270
|
+
ensureGlobalMcpWrapper,
|
|
3271
|
+
getGlobalMcpWrapperPath,
|
|
3272
|
+
collectRuntimeDirectories,
|
|
3197
3273
|
ensureBossChatRuntimeReady: ensureBossChatRuntimeReadyLocal,
|
|
3198
3274
|
ensureRuntimeDirectories,
|
|
3199
3275
|
getBossChatCliRunTarget,
|