Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 署名行检查项,对齐贡献规范。
Expand Down
1 change: 1 addition & 0 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 "双休,五险一金"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ boss status

# 可选:查看本地平台注册与能力状态(不触网)
boss platforms
boss platforms --platform qiancheng # 仅查看单个平台;也支持 51job 别名

# 4. 搜索广州的 Golang 职位,要求双休+五险一金
boss search "Golang" --city 广州 --welfare "双休,五险一金"
Expand Down
2 changes: 1 addition & 1 deletion docs/capability-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` 为命令组入口。
25 changes: 22 additions & 3 deletions src/boss_agent_cli/commands/platforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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": [
Expand Down
8 changes: 7 additions & 1 deletion src/boss_agent_cli/commands/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 才执行一次只读在线验证",
Expand Down
35 changes: 34 additions & 1 deletion tests/test_platforms_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"])
Expand All @@ -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"]