dark 14e297a488 feat: 落地 PAM 智能部署 Agent 骨架
- 新增 pam_deploy_graph 包,包含 Agent runtime、ActionRouter、脚本/MCP/fake runner
- 支持 hybrid_node_mcp 策略:PAM_HOME 走脚本 action,PAM_NODE 走 MCP
- 支持 script_only 离线策略,全部 action 走现有脚本 action
- 新增 LLM structured output 骨架和规则 fallback,支持意图识别、参数抽取、计划生成
- 新增 LangGraph StateGraph 工厂和 MCP client adapter
- 新增 CLI:preview、analyze、run-global、run-deploy
- 增加 fake 完整部署流程、单 IP 失败待回滚确认状态和报告输出
- 增加单元测试覆盖路由、parser、runner、Skill 加载、LLM 输出、MCP adapter 和 LangGraph 图
- 更新 README,记录当前代码骨架、进度、使用方式和下一步计划
2026-05-29 15:53:47 +08:00

70 lines
2.4 KiB
Python

"""Command line interface for the PAM deploy agent."""
from __future__ import annotations
import argparse
import json
from dataclasses import asdict
from .agent import PamDeployAgent
from .checkpoint_store import redact_mapping
from .params_loader import load_params_file
def main() -> None:
parser = argparse.ArgumentParser(prog="pam-deploy-agent")
sub = parser.add_subparsers(dest="command", required=True)
preview = sub.add_parser("preview")
preview.add_argument("--config", required=True)
preview.add_argument("--strategy", default="hybrid_node_mcp", choices=["hybrid_node_mcp", "script_only", "fake"])
analyze = sub.add_parser("analyze")
analyze.add_argument("--text", required=True)
analyze.add_argument("--config")
run = sub.add_parser("run-global")
run.add_argument("--config", required=True)
run.add_argument("--strategy", default="fake", choices=["hybrid_node_mcp", "script_only", "fake"])
run.add_argument("--confirm", action="store_true")
deploy = sub.add_parser("run-deploy")
deploy.add_argument("--config", required=True)
deploy.add_argument("--strategy", default="fake", choices=["hybrid_node_mcp", "script_only", "fake"])
deploy.add_argument("--target-ip", action="append", default=[])
deploy.add_argument("--confirm", action="store_true")
args = parser.parse_args()
params = load_params_file(args.config) if getattr(args, "config", None) else {}
agent = PamDeployAgent()
if args.command == "analyze":
result = agent.analyze_request(args.text, params)
payload = redact_mapping({key: asdict(value) for key, value in result.items()})
print(json.dumps(payload, ensure_ascii=False, indent=2))
return
if args.command == "preview":
print(agent.preview(params, args.strategy))
return
if not args.confirm:
raise SystemExit("Refusing to execute actions without --confirm.")
if args.command == "run-global":
state = agent.create_state(params=params, execution_strategy=args.strategy)
state = agent.run_global_flow(state)
print(json.dumps({"events": state.events}, ensure_ascii=False, indent=2))
return
state = agent.create_state(
params=params,
execution_strategy=args.strategy,
target_ips=args.target_ip,
)
state = agent.run_deploy_flow(state)
print(agent.render_report(state))
if __name__ == "__main__":
main()