@reconcrap/boss-recommend-mcp 2.1.1 → 2.1.3
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 +96 -2
- package/package.json +3 -1
- package/scripts/install-macos.sh +280 -0
- package/skills/boss-recommend-pipeline/SKILL.md +29 -8
- package/src/cli.js +221 -46
- package/src/index.js +65 -0
- package/src/recommend-scheduler.js +482 -0
package/src/cli.js
CHANGED
|
@@ -28,6 +28,10 @@ import {
|
|
|
28
28
|
prepareRecommendPipelineRunTool,
|
|
29
29
|
startRecommendPipelineRunTool
|
|
30
30
|
} from "./recommend-mcp.js";
|
|
31
|
+
import {
|
|
32
|
+
getRecommendScheduledRunTool,
|
|
33
|
+
scheduleRecommendPipelineRunTool
|
|
34
|
+
} from "./recommend-scheduler.js";
|
|
31
35
|
import {
|
|
32
36
|
getBossScreenConfigResolution,
|
|
33
37
|
resolveBossChatRuntimeLayout as resolveCdpBossChatRuntimeLayout,
|
|
@@ -50,10 +54,12 @@ const chromeOnboardingUrlPattern = /^chrome:\/\/(welcome|intro|newtab|signin|his
|
|
|
50
54
|
const bossLoginUrlPattern = /(?:zhipin\.com\/web\/user(?:\/|\?|$)|passport\.zhipin\.com)/i;
|
|
51
55
|
const bossLoginTitlePattern = /登录|signin|扫码登录|BOSS直聘登录/i;
|
|
52
56
|
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";
|
|
57
|
+
const defaultMcpServerName = "boss-recommend";
|
|
58
|
+
const defaultMcpCommand = "npx";
|
|
59
|
+
const recommendMcpPackageName = "@reconcrap/boss-recommend-mcp";
|
|
60
|
+
const recommendMcpBinaryName = "boss-recommend-mcp";
|
|
61
|
+
const globalMcpWrapperFileName = "boss-recommend-mcp-mcp-server";
|
|
62
|
+
const supportedMcpLaunchModes = ["npx", "global-wrapper"];
|
|
57
63
|
const autoSyncSkipCommands = new Set(["install", "install-skill", "where", "help", "--help", "-h", "list-jobs", "jobs", "recommend-jobs"]);
|
|
58
64
|
const externalMcpTargetsEnv = "BOSS_RECOMMEND_MCP_CONFIG_TARGETS";
|
|
59
65
|
const externalSkillDirsEnv = "BOSS_RECOMMEND_EXTERNAL_SKILL_DIRS";
|
|
@@ -124,15 +130,22 @@ function getCodexHome() {
|
|
|
124
130
|
: path.join(os.homedir(), ".codex");
|
|
125
131
|
}
|
|
126
132
|
|
|
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
|
-
|
|
133
|
+
function getStateHome() {
|
|
134
|
+
return process.env.BOSS_RECOMMEND_HOME
|
|
135
|
+
? path.resolve(process.env.BOSS_RECOMMEND_HOME)
|
|
136
|
+
: path.join(os.homedir(), ".boss-recommend-mcp");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getGlobalMcpWrapperPath(options = {}) {
|
|
140
|
+
if (typeof options["mcp-wrapper-path"] === "string" && options["mcp-wrapper-path"].trim()) {
|
|
141
|
+
return path.resolve(options["mcp-wrapper-path"].trim());
|
|
142
|
+
}
|
|
143
|
+
return path.join(getStateHome(), "bin", globalMcpWrapperFileName);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function ensureDir(targetPath) {
|
|
147
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
148
|
+
}
|
|
136
149
|
|
|
137
150
|
function pathExists(targetPath) {
|
|
138
151
|
try {
|
|
@@ -738,13 +751,55 @@ function parseMcpClientTargets(rawValue) {
|
|
|
738
751
|
return unique;
|
|
739
752
|
}
|
|
740
753
|
|
|
741
|
-
function isPlainObject(value) {
|
|
742
|
-
return value && typeof value === "object" && !Array.isArray(value);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
function
|
|
746
|
-
const
|
|
747
|
-
|
|
754
|
+
function isPlainObject(value) {
|
|
755
|
+
return value && typeof value === "object" && !Array.isArray(value);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function normalizeMcpLaunchMode(options = {}) {
|
|
759
|
+
const raw = String(options["mcp-launch"] || options.mcpLaunch || "").trim().toLowerCase().replace(/_/g, "-");
|
|
760
|
+
if (!raw) return "npx";
|
|
761
|
+
if (raw === "default") return "npx";
|
|
762
|
+
if (raw === "global" || raw === "wrapper") return "global-wrapper";
|
|
763
|
+
if (supportedMcpLaunchModes.includes(raw)) return raw;
|
|
764
|
+
throw new Error(`Unsupported --mcp-launch value: ${raw}. Supported: ${supportedMcpLaunchModes.join(", ")}`);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function buildGlobalMcpWrapperScript() {
|
|
768
|
+
return `#!/usr/bin/env bash
|
|
769
|
+
set -euo pipefail
|
|
770
|
+
|
|
771
|
+
export NVM_DIR="\${NVM_DIR:-$HOME/.nvm}"
|
|
772
|
+
if [ -s "$NVM_DIR/nvm.sh" ]; then
|
|
773
|
+
. "$NVM_DIR/nvm.sh"
|
|
774
|
+
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
|
|
775
|
+
export NVM_DIR="$HOME/.nvm"
|
|
776
|
+
. "$NVM_DIR/nvm.sh"
|
|
777
|
+
fi
|
|
778
|
+
|
|
779
|
+
if ! command -v ${recommendMcpBinaryName} >/dev/null 2>&1; then
|
|
780
|
+
echo "${recommendMcpBinaryName} not found on PATH. Install or reload nvm, then run: npm -g i ${recommendMcpPackageName}@latest" >&2
|
|
781
|
+
exit 127
|
|
782
|
+
fi
|
|
783
|
+
|
|
784
|
+
exec ${recommendMcpBinaryName} start "$@"
|
|
785
|
+
`;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
function ensureGlobalMcpWrapper(options = {}) {
|
|
789
|
+
const wrapperPath = getGlobalMcpWrapperPath(options);
|
|
790
|
+
ensureDir(path.dirname(wrapperPath));
|
|
791
|
+
fs.writeFileSync(wrapperPath, buildGlobalMcpWrapperScript(), "utf8");
|
|
792
|
+
try {
|
|
793
|
+
fs.chmodSync(wrapperPath, 0o755);
|
|
794
|
+
} catch {
|
|
795
|
+
// Some filesystems ignore POSIX executable bits; the path is still valid for POSIX hosts.
|
|
796
|
+
}
|
|
797
|
+
return wrapperPath;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function shouldDefaultRecommendDetachedMcpEnv(options = {}) {
|
|
801
|
+
const client = normalizeMcpClientName(options.client);
|
|
802
|
+
const agent = normalizeAgentName(options.agent);
|
|
748
803
|
return client === "openclaw"
|
|
749
804
|
|| client === "qclaw"
|
|
750
805
|
|| agent === "openclaw"
|
|
@@ -764,10 +819,28 @@ function getAgentConfigOutputDir(options = {}) {
|
|
|
764
819
|
return path.join(getStateHome(), "agent-mcp-configs");
|
|
765
820
|
}
|
|
766
821
|
|
|
767
|
-
function buildMcpLaunchConfig(options = {}) {
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
822
|
+
function buildMcpLaunchConfig(options = {}) {
|
|
823
|
+
const mcpLaunchMode = normalizeMcpLaunchMode(options);
|
|
824
|
+
if (mcpLaunchMode === "global-wrapper") {
|
|
825
|
+
const args = parseJsonOption(options["args-json"], "args-json");
|
|
826
|
+
const env = parseJsonOption(options["env-json"], "env-json");
|
|
827
|
+
const launchConfig = {
|
|
828
|
+
command: ensureGlobalMcpWrapper(options),
|
|
829
|
+
args: Array.isArray(args) ? args : []
|
|
830
|
+
};
|
|
831
|
+
const mergedEnv = {
|
|
832
|
+
...getDefaultMcpEnv(options),
|
|
833
|
+
...(isPlainObject(env) ? env : {})
|
|
834
|
+
};
|
|
835
|
+
if (Object.keys(mergedEnv).length > 0) {
|
|
836
|
+
launchConfig.env = mergedEnv;
|
|
837
|
+
}
|
|
838
|
+
return launchConfig;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
const command = typeof options.command === "string" && options.command.trim()
|
|
842
|
+
? options.command.trim()
|
|
843
|
+
: defaultMcpCommand;
|
|
771
844
|
const args = parseJsonOption(options["args-json"], "args-json");
|
|
772
845
|
const env = parseJsonOption(options["env-json"], "env-json");
|
|
773
846
|
const launchArgs = Array.isArray(args) && args.length > 0
|
|
@@ -2625,6 +2698,8 @@ function printHelp() {
|
|
|
2625
2698
|
console.log(" boss-recommend-mcp Start the MCP server");
|
|
2626
2699
|
console.log(" boss-recommend-mcp start Start the MCP server");
|
|
2627
2700
|
console.log(" boss-recommend-mcp prepare-run Validate a cron-ready recommend run payload without starting screening");
|
|
2701
|
+
console.log(" boss-recommend-mcp schedule-run Create a package-owned delayed recommend run");
|
|
2702
|
+
console.log(" boss-recommend-mcp schedule-status Check a package-owned delayed recommend run");
|
|
2628
2703
|
console.log(" boss-recommend-mcp run Start a CDP-only recommend run through the shared run service");
|
|
2629
2704
|
console.log(" boss-recommend-mcp list-jobs CDP-only list of exact recommend job names for cron/one-shot inputs");
|
|
2630
2705
|
console.log(" boss-recommend-mcp chat <subcommand> Run CDP-only boss-chat health/prepare/status commands");
|
|
@@ -2633,14 +2708,17 @@ function printHelp() {
|
|
|
2633
2708
|
console.log(" boss-recommend-mcp init-config Create screening-config.json if missing (prefer workspace config/, fallback ~/.boss-recommend-mcp)");
|
|
2634
2709
|
console.log(" boss-recommend-mcp config set Write baseUrl/apiKey/model (prefer workspace config/, fallback ~/.boss-recommend-mcp)");
|
|
2635
2710
|
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");
|
|
2711
|
+
console.log(" boss-recommend-mcp mcp-config Generate MCP config JSON for Cursor/Trae(含 trae-cn)/Claude Code/OpenClaw/QClaw");
|
|
2712
|
+
console.log(" boss-recommend-mcp doctor Check config/runtime/calibration prerequisites (supports --agent trae-cn/qclaw/cursor/...)");
|
|
2713
|
+
console.log(" boss-recommend-mcp calibrate Disabled until CDP-only featured calibration is live-verified");
|
|
2714
|
+
console.log(" boss-recommend-mcp launch-chrome Launch or reuse Chrome debug instance and open Boss recommend page");
|
|
2715
|
+
console.log(" boss-recommend-mcp where Print installed package, skill, and config paths");
|
|
2716
|
+
console.log(" boss-recommend-mcp install --mcp-launch global-wrapper Use ~/.boss-recommend-mcp/bin wrapper so npm global upgrades affect MCP hosts");
|
|
2641
2717
|
console.log("");
|
|
2642
2718
|
console.log("Run command:");
|
|
2643
2719
|
console.log(" boss-recommend-mcp prepare-run --instruction \"...\" --overrides-file overrides.json --confirmation-file confirmation.json");
|
|
2720
|
+
console.log(" boss-recommend-mcp schedule-run --schedule-delay-minutes 10 --instruction-file boss-recommend-instruction.txt --overrides-file overrides.json --confirmation-file confirmation.json");
|
|
2721
|
+
console.log(" boss-recommend-mcp schedule-status --schedule-id <id>");
|
|
2644
2722
|
console.log(" boss-recommend-mcp run --instruction \"推荐页上筛选211男生,近14天没有,有大模型平台经验\" --overrides-file overrides.json --confirmation-file confirmation.json");
|
|
2645
2723
|
console.log(" boss-recommend-mcp run --detached --instruction \"...\" --overrides-file overrides.json --confirmation-file confirmation.json");
|
|
2646
2724
|
console.log(" boss-recommend-mcp list-jobs --slow-live --port 9222");
|
|
@@ -2665,14 +2743,15 @@ function printMcpConfig(options = {}) {
|
|
|
2665
2743
|
}
|
|
2666
2744
|
}
|
|
2667
2745
|
|
|
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
|
-
|
|
2746
|
+
async function installAll(options = {}) {
|
|
2747
|
+
const runtimeDirsResult = await ensureRuntimeDirectories(options);
|
|
2748
|
+
const skillResults = installSkill();
|
|
2749
|
+
const configResult = await ensureUserConfig(options);
|
|
2750
|
+
const mcpLaunchMode = normalizeMcpLaunchMode(options);
|
|
2751
|
+
const mcpTemplateResult = writeMcpConfigFiles({ ...options, agent: undefined, client: "all" });
|
|
2752
|
+
const externalMcpResult = installExternalMcpConfigs(options);
|
|
2753
|
+
const externalSkillResult = mirrorSkillToExternalDirs(options);
|
|
2754
|
+
console.log(
|
|
2676
2755
|
`Runtime directories prepared: created=${runtimeDirsResult.created.length}, existing=${runtimeDirsResult.existed.length}, failed=${runtimeDirsResult.failed.length}`
|
|
2677
2756
|
);
|
|
2678
2757
|
console.log(`- recommend runtime: ${runtimeDirsResult.stateHome}`);
|
|
@@ -2700,10 +2779,13 @@ async function installAll(options = {}) {
|
|
|
2700
2779
|
console.warn(`screening-config.json skip default patch: ${configResult.patch_error}`);
|
|
2701
2780
|
}
|
|
2702
2781
|
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
|
-
}
|
|
2782
|
+
console.log(`MCP config templates exported to: ${mcpTemplateResult.outputDir}`);
|
|
2783
|
+
for (const item of mcpTemplateResult.files) {
|
|
2784
|
+
console.log(`- ${item.client}: ${item.file}`);
|
|
2785
|
+
}
|
|
2786
|
+
if (mcpLaunchMode === "global-wrapper") {
|
|
2787
|
+
console.log(`Upgrade-stable MCP wrapper: ${getGlobalMcpWrapperPath(options)}`);
|
|
2788
|
+
}
|
|
2707
2789
|
if (externalMcpResult.targets.length > 0) {
|
|
2708
2790
|
console.log(`Auto-configured external MCP files: ${externalMcpResult.applied.length}`);
|
|
2709
2791
|
for (const item of externalMcpResult.applied) {
|
|
@@ -2833,6 +2915,62 @@ async function preparePipelineOnce(options = {}) {
|
|
|
2833
2915
|
}
|
|
2834
2916
|
}
|
|
2835
2917
|
|
|
2918
|
+
function addScheduleOptions(args, options = {}) {
|
|
2919
|
+
const scheduleId = String(options["schedule-id"] || options.schedule_id || options.scheduleId || "").trim();
|
|
2920
|
+
if (scheduleId) args.schedule_id = scheduleId;
|
|
2921
|
+
const runAt = String(options["schedule-run-at"] || options.schedule_run_at || options.scheduleRunAt || options["run-at"] || options.run_at || "").trim();
|
|
2922
|
+
if (runAt) args.schedule_run_at = runAt;
|
|
2923
|
+
const delayMinutes = parseNonNegativeInteger(options["schedule-delay-minutes"] ?? options.schedule_delay_minutes ?? options.scheduleDelayMinutes);
|
|
2924
|
+
if (delayMinutes !== undefined) args.schedule_delay_minutes = delayMinutes;
|
|
2925
|
+
const delaySeconds = parseNonNegativeInteger(options["schedule-delay-seconds"] ?? options.schedule_delay_seconds ?? options.scheduleDelaySeconds);
|
|
2926
|
+
if (delaySeconds !== undefined) args.schedule_delay_seconds = delaySeconds;
|
|
2927
|
+
return args;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
async function schedulePipelineOnce(options = {}) {
|
|
2931
|
+
const workspaceRoot = getWorkspaceRoot(options);
|
|
2932
|
+
const { args, port } = buildRecommendRunCliInput(options);
|
|
2933
|
+
addScheduleOptions(args, options);
|
|
2934
|
+
const result = await scheduleRecommendPipelineRunTool({
|
|
2935
|
+
workspaceRoot,
|
|
2936
|
+
args
|
|
2937
|
+
});
|
|
2938
|
+
printJson({
|
|
2939
|
+
...result,
|
|
2940
|
+
cli: {
|
|
2941
|
+
...(result.cli || {}),
|
|
2942
|
+
command: "schedule-run",
|
|
2943
|
+
cdp_only: true,
|
|
2944
|
+
package_owned_scheduler: true,
|
|
2945
|
+
workspace_root: workspaceRoot,
|
|
2946
|
+
port
|
|
2947
|
+
}
|
|
2948
|
+
});
|
|
2949
|
+
if (result.status !== "SCHEDULED") {
|
|
2950
|
+
process.exitCode = 1;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
function scheduleStatusCli(options = {}) {
|
|
2955
|
+
const scheduleId = String(options["schedule-id"] || options.schedule_id || options.scheduleId || "").trim();
|
|
2956
|
+
const result = getRecommendScheduledRunTool({
|
|
2957
|
+
args: {
|
|
2958
|
+
schedule_id: scheduleId
|
|
2959
|
+
}
|
|
2960
|
+
});
|
|
2961
|
+
printJson({
|
|
2962
|
+
...result,
|
|
2963
|
+
cli: {
|
|
2964
|
+
command: "schedule-status",
|
|
2965
|
+
cdp_only: true,
|
|
2966
|
+
package_owned_scheduler: true
|
|
2967
|
+
}
|
|
2968
|
+
});
|
|
2969
|
+
if (result.status !== "OK") {
|
|
2970
|
+
process.exitCode = 1;
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2836
2974
|
async function runPipelineOnce(options = {}) {
|
|
2837
2975
|
const workspaceRoot = getWorkspaceRoot(options);
|
|
2838
2976
|
const { args, port } = buildRecommendRunCliInput(options);
|
|
@@ -3046,6 +3184,39 @@ export async function runCli(argv = process.argv) {
|
|
|
3046
3184
|
process.exitCode = 1;
|
|
3047
3185
|
}
|
|
3048
3186
|
break;
|
|
3187
|
+
case "schedule-run":
|
|
3188
|
+
case "schedule":
|
|
3189
|
+
try {
|
|
3190
|
+
await schedulePipelineOnce(options);
|
|
3191
|
+
} catch (error) {
|
|
3192
|
+
printJson({
|
|
3193
|
+
status: "FAILED",
|
|
3194
|
+
schedule_created: false,
|
|
3195
|
+
error: {
|
|
3196
|
+
code: "INVALID_CLI_INPUT",
|
|
3197
|
+
message: error.message || "Invalid CLI input",
|
|
3198
|
+
retryable: false
|
|
3199
|
+
}
|
|
3200
|
+
});
|
|
3201
|
+
process.exitCode = 1;
|
|
3202
|
+
}
|
|
3203
|
+
break;
|
|
3204
|
+
case "schedule-status":
|
|
3205
|
+
case "scheduled-run":
|
|
3206
|
+
try {
|
|
3207
|
+
scheduleStatusCli(options);
|
|
3208
|
+
} catch (error) {
|
|
3209
|
+
printJson({
|
|
3210
|
+
status: "FAILED",
|
|
3211
|
+
error: {
|
|
3212
|
+
code: "INVALID_CLI_INPUT",
|
|
3213
|
+
message: error.message || "Invalid CLI input",
|
|
3214
|
+
retryable: false
|
|
3215
|
+
}
|
|
3216
|
+
});
|
|
3217
|
+
process.exitCode = 1;
|
|
3218
|
+
}
|
|
3219
|
+
break;
|
|
3049
3220
|
case "list-jobs":
|
|
3050
3221
|
case "jobs":
|
|
3051
3222
|
case "recommend-jobs":
|
|
@@ -3189,11 +3360,13 @@ export async function runCli(argv = process.argv) {
|
|
|
3189
3360
|
}
|
|
3190
3361
|
|
|
3191
3362
|
export const __testables = {
|
|
3192
|
-
buildRecommendJobListCliInput,
|
|
3193
|
-
buildBossChatCliInput,
|
|
3194
|
-
buildDefaultMcpArgs,
|
|
3195
|
-
buildMcpLaunchConfig,
|
|
3196
|
-
|
|
3363
|
+
buildRecommendJobListCliInput,
|
|
3364
|
+
buildBossChatCliInput,
|
|
3365
|
+
buildDefaultMcpArgs,
|
|
3366
|
+
buildMcpLaunchConfig,
|
|
3367
|
+
ensureGlobalMcpWrapper,
|
|
3368
|
+
getGlobalMcpWrapperPath,
|
|
3369
|
+
collectRuntimeDirectories,
|
|
3197
3370
|
ensureBossChatRuntimeReady: ensureBossChatRuntimeReadyLocal,
|
|
3198
3371
|
ensureRuntimeDirectories,
|
|
3199
3372
|
getBossChatCliRunTarget,
|
|
@@ -3206,6 +3379,8 @@ export const __testables = {
|
|
|
3206
3379
|
resolveBossChatRuntimeLayout: resolveCdpBossChatRuntimeLayout,
|
|
3207
3380
|
runBossChatCliCommand,
|
|
3208
3381
|
preparePipelineOnce,
|
|
3382
|
+
schedulePipelineOnce,
|
|
3383
|
+
scheduleStatusCli,
|
|
3209
3384
|
runPipelineOnce
|
|
3210
3385
|
};
|
|
3211
3386
|
|
package/src/index.js
CHANGED
|
@@ -39,6 +39,12 @@ import {
|
|
|
39
39
|
startRecruitPipelineRunTool,
|
|
40
40
|
validateRecruitPipelineArgs
|
|
41
41
|
} from "./recruit-mcp.js";
|
|
42
|
+
import {
|
|
43
|
+
__setRecommendSchedulerSpawnForTests,
|
|
44
|
+
getRecommendScheduledRunTool,
|
|
45
|
+
runScheduledRecommendWorker,
|
|
46
|
+
scheduleRecommendPipelineRunTool
|
|
47
|
+
} from "./recommend-scheduler.js";
|
|
42
48
|
import {
|
|
43
49
|
__resetRecommendMcpStateForTests,
|
|
44
50
|
__setRecommendMcpConnectorForTests,
|
|
@@ -90,6 +96,8 @@ const require = createRequire(import.meta.url);
|
|
|
90
96
|
const { version: SERVER_VERSION } = require("../package.json");
|
|
91
97
|
|
|
92
98
|
const TOOL_PREPARE_RUN = "prepare_recommend_pipeline_run";
|
|
99
|
+
const TOOL_SCHEDULE_RUN = "schedule_recommend_pipeline_run";
|
|
100
|
+
const TOOL_GET_SCHEDULED_RUN = "get_recommend_scheduled_run";
|
|
93
101
|
const TOOL_START_RUN = "start_recommend_pipeline_run";
|
|
94
102
|
const TOOL_GET_RUN = "get_recommend_pipeline_run";
|
|
95
103
|
const TOOL_CANCEL_RUN = "cancel_recommend_pipeline_run";
|
|
@@ -1083,6 +1091,36 @@ function createListRecommendJobsInputSchema() {
|
|
|
1083
1091
|
};
|
|
1084
1092
|
}
|
|
1085
1093
|
|
|
1094
|
+
function createScheduleRunInputSchema() {
|
|
1095
|
+
const base = createRunInputSchema();
|
|
1096
|
+
return {
|
|
1097
|
+
...base,
|
|
1098
|
+
properties: {
|
|
1099
|
+
...base.properties,
|
|
1100
|
+
schedule_id: {
|
|
1101
|
+
type: "string",
|
|
1102
|
+
description: "可选,自定义定时任务 id;默认自动生成"
|
|
1103
|
+
},
|
|
1104
|
+
schedule_run_at: {
|
|
1105
|
+
type: "string",
|
|
1106
|
+
description: "ISO 时间字符串;到点后由 package-owned detached scheduler 启动已准备好的 payload"
|
|
1107
|
+
},
|
|
1108
|
+
schedule_delay_minutes: {
|
|
1109
|
+
type: "number",
|
|
1110
|
+
minimum: 0,
|
|
1111
|
+
description: "从现在开始延迟多少分钟后启动;适合 OpenClaw cron/定时任务设置"
|
|
1112
|
+
},
|
|
1113
|
+
schedule_delay_seconds: {
|
|
1114
|
+
type: "number",
|
|
1115
|
+
minimum: 0,
|
|
1116
|
+
description: "从现在开始延迟多少秒后启动;主要用于短延迟或测试"
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
required: ["instruction"],
|
|
1120
|
+
additionalProperties: false
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1086
1124
|
function createToolsSchema() {
|
|
1087
1125
|
return [
|
|
1088
1126
|
{
|
|
@@ -1095,6 +1133,23 @@ function createToolsSchema() {
|
|
|
1095
1133
|
description: "只校验 Boss 推荐页流水线参数是否已可用于 cron/一次性任务;不会启动筛选任务。只有返回 READY/cron_ready=true 后才应创建定时任务。",
|
|
1096
1134
|
inputSchema: createRunInputSchema()
|
|
1097
1135
|
},
|
|
1136
|
+
{
|
|
1137
|
+
name: TOOL_SCHEDULE_RUN,
|
|
1138
|
+
description: "创建 package-owned Boss 推荐页定时任务:先校验 READY/cron_ready,再保存完整 payload,并由 detached scheduler 到点直接启动,不再依赖 AI harness 自己拼 shell cron。",
|
|
1139
|
+
inputSchema: createScheduleRunInputSchema()
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
name: TOOL_GET_SCHEDULED_RUN,
|
|
1143
|
+
description: "查询 package-owned 推荐页定时任务状态;返回 schedule_id、worker 状态、到点后启动的 run_id 与运行快照。",
|
|
1144
|
+
inputSchema: {
|
|
1145
|
+
type: "object",
|
|
1146
|
+
properties: {
|
|
1147
|
+
schedule_id: { type: "string" }
|
|
1148
|
+
},
|
|
1149
|
+
required: ["schedule_id"],
|
|
1150
|
+
additionalProperties: false
|
|
1151
|
+
}
|
|
1152
|
+
},
|
|
1098
1153
|
{
|
|
1099
1154
|
name: TOOL_START_RUN,
|
|
1100
1155
|
description: "异步启动 Boss 推荐页流水线(含同步门禁预检);只有在前置确认与页面就绪通过后才返回 run_id。",
|
|
@@ -2626,6 +2681,10 @@ async function handleRequest(message, workspaceRoot) {
|
|
|
2626
2681
|
payload = await listRecommendJobsTool({ workspaceRoot, args });
|
|
2627
2682
|
} else if (toolName === TOOL_PREPARE_RUN) {
|
|
2628
2683
|
payload = prepareRecommendPipelineRunTool({ workspaceRoot, args });
|
|
2684
|
+
} else if (toolName === TOOL_SCHEDULE_RUN) {
|
|
2685
|
+
payload = await scheduleRecommendPipelineRunTool({ workspaceRoot, args });
|
|
2686
|
+
} else if (toolName === TOOL_GET_SCHEDULED_RUN) {
|
|
2687
|
+
payload = getRecommendScheduledRunTool({ args });
|
|
2629
2688
|
} else if (toolName === TOOL_START_RUN) {
|
|
2630
2689
|
payload = await handleStartRunTool({ workspaceRoot, args });
|
|
2631
2690
|
} else if (toolName === TOOL_GET_RUN) {
|
|
@@ -2825,6 +2884,12 @@ export const __testables = {
|
|
|
2825
2884
|
resetRecommendMcpStateForTests() {
|
|
2826
2885
|
__resetRecommendMcpStateForTests();
|
|
2827
2886
|
},
|
|
2887
|
+
setRecommendSchedulerSpawnForTests(nextImpl) {
|
|
2888
|
+
__setRecommendSchedulerSpawnForTests(nextImpl);
|
|
2889
|
+
},
|
|
2890
|
+
runScheduledRecommendWorkerForTests(options = {}) {
|
|
2891
|
+
return runScheduledRecommendWorker(options);
|
|
2892
|
+
},
|
|
2828
2893
|
setChatMcpConnectorForTests(nextImpl) {
|
|
2829
2894
|
forceChatInProcForTests = typeof nextImpl === "function";
|
|
2830
2895
|
__setChatMcpConnectorForTests(nextImpl);
|