From 09f87d490819db644152659282f1189098a740fd Mon Sep 17 00:00:00 2001 From: can4hou6joeng4 Date: Wed, 10 Jun 2026 18:38:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=E5=8D=95=E5=B9=B3=E5=8F=B0=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 ++ README.en.md | 1 + README.md | 1 + docs/capability-matrix.md | 2 +- src/boss_agent_cli/commands/platforms.py | 25 +++++++++++++++-- src/boss_agent_cli/commands/schema.py | 8 +++++- tests/test_platforms_cmd.py | 35 +++++++++++++++++++++++- 7 files changed, 69 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05dfa8f..190f56a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ## [Unreleased] +### Added +- `boss platforms` 新增 `--platform` 单平台过滤,支持 `qiancheng` 与 `51job` 别名,仅读取本地能力元数据并保持未知平台的 `INVALID_PARAM` JSON 包络。 + ### Changed - 补强 `boss config` 未知配置项错误路径的 stdout 单行 JSON 包络契约测试,确保 Agent 可稳定解析 `INVALID_PARAM`。 - PR 模板补充无 `Co-authored-by` 尾注或 AI 署名行检查项,对齐贡献规范。 diff --git a/README.en.md b/README.en.md index 9a3d0c6..e00ca45 100644 --- a/README.en.md +++ b/README.en.md @@ -127,6 +127,7 @@ boss status # Optional: inspect local platform capability status (no network) boss platforms +boss platforms --platform qiancheng # Inspect one platform; 51job alias is supported # 4. Search Golang jobs in Guangzhou with 双休 + 五险一金 boss search "Golang" --city 广州 --welfare "双休,五险一金" diff --git a/README.md b/README.md index 484b374..f249166 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ boss status # 可选:查看本地平台注册与能力状态(不触网) boss platforms +boss platforms --platform qiancheng # 仅查看单个平台;也支持 51job 别名 # 4. 搜索广州的 Golang 职位,要求双休+五险一金 boss search "Golang" --city 广州 --welfare "双休,五险一金" diff --git a/docs/capability-matrix.md b/docs/capability-matrix.md index 1d68020..5665251 100644 --- a/docs/capability-matrix.md +++ b/docs/capability-matrix.md @@ -107,6 +107,6 @@ 说明: - **通道**:httpx 为直接 API 请求,浏览器通道仅作兼容保留;命中风控时不应切换自动化通道继续重试。AI 服务为第三方大模型 API,不应输入平台聊天记录、候选人简历或联系方式等未获授权的个人信息。 - 若以 CLI 直连为主,优先通过 `boss schema` 进行能力发现与参数校验;当前 schema 会同时暴露 `supported_platforms` 与 `supported_recruiter_platforms`。 -- 当前多平台状态:`zhipin` 已覆盖求职者与招聘者实现,但敏感链路默认受低风险模式阻断;`zhilian` 已接通候选者侧登录和只读链路,招聘者侧暂未接入;`qiancheng` / 51job 仅为已注册占位适配器,真实工作流统一返回 `NOT_SUPPORTED`。 +- 当前多平台状态:`boss platforms` 返回本地平台注册与能力状态,也可通过 `boss platforms --platform qiancheng` / `--platform 51job` 只查看单个平台或别名;`zhipin` 已覆盖求职者与招聘者实现,但敏感链路默认受低风险模式阻断;`zhilian` 已接通候选者侧登录和只读链路,招聘者侧暂未接入;`qiancheng` / 51job 仅为已注册占位适配器,真实工作流统一返回 `NOT_SUPPORTED`。 - 当前登录状态:`zhipin` / `zhilian` 保留用户主动登录兼容链路,但不得用于规避平台风控。 - 以 `boss schema` 为准:当前暴露 34 个顶层命令;其中 `hr` 下还有 9 个一级招聘者子命令,`ai` / `resume` 为命令组入口。 diff --git a/src/boss_agent_cli/commands/platforms.py b/src/boss_agent_cli/commands/platforms.py index 1d1ea71..5d07086 100644 --- a/src/boss_agent_cli/commands/platforms.py +++ b/src/boss_agent_cli/commands/platforms.py @@ -52,9 +52,27 @@ } -def platform_capability_data() -> dict[str, Any]: +def _resolve_platform_filter(platform_name: str | None) -> str | None: + if platform_name is None: + return None + aliases = {"51job": "qiancheng"} + resolved = aliases.get(platform_name, platform_name) + candidate_platforms = [name for name in list_platforms() if name not in _ALIAS_NAMES] + if resolved not in candidate_platforms: + supported = ", ".join([*candidate_platforms, *sorted(aliases)]) + raise click.BadParameter( + f"unknown platform {platform_name!r}, supported: {supported}", + param_hint="--platform", + ) + return resolved + + +def platform_capability_data(platform_name: str | None = None) -> dict[str, Any]: """Return local-only platform capability metadata without creating clients.""" + resolved_platform = _resolve_platform_filter(platform_name) candidate_platforms = [name for name in list_platforms() if name not in _ALIAS_NAMES] + if resolved_platform is not None: + candidate_platforms = [resolved_platform] recruiter_platforms = list_recruiter_platforms() platforms = [] for name in candidate_platforms: @@ -92,13 +110,14 @@ def _render_platforms(data: dict[str, Any]) -> None: @click.command("platforms") +@click.option("--platform", "platform_name", default=None, help="仅查看指定平台(支持 qiancheng / 51job 等已注册平台或别名)") @click.pass_context -def platforms_cmd(ctx: click.Context) -> None: +def platforms_cmd(ctx: click.Context, platform_name: str | None) -> None: """列出本地已注册平台与能力状态。""" handle_output( ctx, "platforms", - platform_capability_data(), + platform_capability_data(platform_name), render=_render_platforms, hints={ "next_actions": [ diff --git a/src/boss_agent_cli/commands/schema.py b/src/boss_agent_cli/commands/schema.py index 5092b35..43035a6 100644 --- a/src/boss_agent_cli/commands/schema.py +++ b/src/boss_agent_cli/commands/schema.py @@ -274,7 +274,13 @@ def _format_mcp_tools(data: dict[str, Any]) -> list[dict[str, Any]]: "platforms": { "description": "列出本地已注册平台与能力状态;只读本地元数据,不触发登录、浏览器、CDP 或网络请求", "args": [], - "options": {}, + "options": { + "--platform": { + "type": "string", + "default": None, + "description": "仅查看指定平台(支持 qiancheng / 51job 等已注册平台或别名)", + }, + }, }, "status": { "description": "轻量检查当前登录态分层健康状态;默认不请求平台,--live 才执行一次只读在线验证", diff --git a/tests/test_platforms_cmd.py b/tests/test_platforms_cmd.py index 9457449..bab619d 100644 --- a/tests/test_platforms_cmd.py +++ b/tests/test_platforms_cmd.py @@ -30,6 +30,38 @@ def test_platforms_outputs_local_capability_matrix() -> None: assert platforms["zhilian"]["capabilities"]["readonly"]["search"] == "available" +def test_platforms_can_filter_single_platform_by_registered_name() -> None: + runner = CliRunner() + result = runner.invoke(cli, ["platforms", "--platform", "qiancheng"]) + + assert result.exit_code == 0, result.output + payload = json.loads(result.output) + assert payload["data"]["count"] == 1 + assert payload["data"]["platforms"][0]["name"] == "qiancheng" + assert payload["data"]["platforms"][0]["status"] == "placeholder" + + +def test_platforms_can_filter_single_platform_by_alias() -> None: + runner = CliRunner() + result = runner.invoke(cli, ["platforms", "--platform", "51job"]) + + assert result.exit_code == 0, result.output + payload = json.loads(result.output) + assert payload["data"]["count"] == 1 + assert payload["data"]["platforms"][0]["name"] == "qiancheng" + + +def test_platforms_unknown_platform_uses_json_error_envelope() -> None: + runner = CliRunner() + result = runner.invoke(cli, ["platforms", "--platform", "unknown"]) + + assert result.exit_code == 1, result.output + payload = json.loads(result.output) + assert payload["ok"] is False + assert payload["error"]["code"] == "INVALID_PARAM" + assert "unknown platform" in payload["error"]["message"] + + def test_platforms_is_listed_in_schema() -> None: runner = CliRunner() result = runner.invoke(cli, ["schema"]) @@ -38,5 +70,6 @@ def test_platforms_is_listed_in_schema() -> None: payload = json.loads(result.output) platforms_schema = payload["data"]["commands"]["platforms"] assert platforms_schema["args"] == [] - assert platforms_schema["options"] == {} + assert "--platform" in platforms_schema["options"] + assert platforms_schema["options"]["--platform"]["default"] is None assert "不触发登录" in platforms_schema["description"]