From 2ef32a9dcc5a5069990df8b5f1675e7f8e93eef3 Mon Sep 17 00:00:00 2001 From: Myfro9 <36755290+Myfro9@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:14:49 +0800 Subject: [PATCH] sync: WIN10-I9-64G 2026-07-20 --- .gitignore | 3 + .../.langgraph_api/.langgraph_ops.pckl | Bin 42212 -> 0 bytes langgraph-plan-review/SKILL.md | 58 ++++--- langgraph-plan-review/scripts/clean_run.py | 120 +++++++++++++ tools-sync/SKILL.md | 162 ++++++++++++++++++ tools-sync/references/skills_env_template.md | 68 ++++++++ tools-sync/scripts/sync_repos.ps1 | 113 ++++++++++++ 7 files changed, 502 insertions(+), 22 deletions(-) delete mode 100644 langgraph-plan-review/.langgraph_api/.langgraph_ops.pckl create mode 100644 langgraph-plan-review/scripts/clean_run.py create mode 100644 tools-sync/SKILL.md create mode 100644 tools-sync/references/skills_env_template.md create mode 100644 tools-sync/scripts/sync_repos.ps1 diff --git a/.gitignore b/.gitignore index 0a1dc58..f3c5465 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,6 @@ web-design-guidelines/SKILL.md *.mjs *.pckl *.pyc + +*.sqlite +**/.langgraph_api/ diff --git a/langgraph-plan-review/.langgraph_api/.langgraph_ops.pckl b/langgraph-plan-review/.langgraph_api/.langgraph_ops.pckl deleted file mode 100644 index c3b8e8ec7a5835abb22d4f21afe27fd8455d8aa4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42212 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" --notes-dir Notes --prompt "<原始请求>" + # resume(写完/改完 Task10.md 后;resume 值 base64(JSON)): + $resume = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('true')) + & $PY $RUN --task-id 10 --work-dir "" --notes-dir Notes --resume-b64 $resume --codex-review-command-b64 $CMD --timeout 900 + ``` + 每次调用推进到下一个 `interrupt` 或结束,打印一行 JSON:`{"status":"waiting","action_required":{...}}` + 或 `{"status":"done","has_serious_issue":...}`。`action_required` 的处理同下(write_plan / decide / + revise / write_rejection),resume 值:`write_plan`/`revise`/`write_rejection` 用 `true`;`decide` 用 + `{"accepts":true}` 或 `{"accepts":false,"reason":"..."}`。 -- 🚫 **绝对禁止**:直接 `import` / 在进程内运行本 skill 的图定义模块 - (`scripts\graph.py`、`scripts\workflow.py`、`scripts\agents.py`)来跑工作流。包括但不限于: - - `python -c "from graph import ...; graph.invoke(...)"` 或 `.stream(...)` - - 写临时脚本 build 编译图后在进程内调用 - - 任何绕过 `http://127.0.0.1:2024` 的「就地执行」方式 +- **codex 评审的两个必备条件**(本次踩坑记录): + 1. **codex CLI 要足够新**。config.toml 若配了较新模型(如 `gpt-5.6-sol`),旧 codex 会返回 400 + `requires a newer version of Codex`。升级:`npm i -g @openai/codex@latest`(≥0.144.5 实测可用)。 + 2. **codex 子进程要能到 chatgpt.com**。`clean_run.py` 会自动读 Windows 系统代理(HKCU Internet + Settings 的 `ProxyServer`)设进 `HTTP(S)_PROXY`,让 codex 走代理;也可用 `PLAN_REVIEW_PROXY` 覆盖。 + 3. **codex 超时**:`review_task.py` 的内层 codex 超时取 argv[5](默认 300s,评审常不够)。用 + `--codex-review-command-b64` 传一条**末尾带超时秒数**的命令(见 Workflow),并把 `--timeout` 设一致。 - 这类调用在 dev server 进程**之外**运行,Studio 追踪不到状态,**一律不允许**—— - 即使只是想「快速验证一个节点」也不行。 - -- ℹ️ **例外说明**:`review_task.py`(Codex 评审 shim)会直接调 `codex`,这是**合规的**—— - 它是由运行在 dev server 内的图通过 `codex_review_command` 调起的评审步骤,不是绕过 - dev server 去驱动工作流本身。区别在于:驱动图 = 必须走 dev server;图内部调用的工具 = 正常。 - -- 🛠 **改了 `graph.py`/`workflow.py`/`agents.py` 后**:dev server 内存里仍是旧代码。先 - `manage_dev_server.ps1 stop` 再 `start`(或让 `--reload` 生效),再经 `run_langgraph.ps1` - 重跑,使改动在被追踪的运行中生效。 +- **改了 `workflow.py`/`agents.py`/`clean_run.py` 后**:无 dev server 缓存,下次 `clean_run.py` 直接生效。 + 若图结构改到与旧 checkpoint 不兼容,删 `scripts\.plan_review_state.sqlite` 重新开始该 thread。 ## Pre-flight: Environment Setup @@ -75,7 +82,10 @@ conda run -n langgraph langgraph --version - The workflow uses LangGraph `interrupt()` and persists state via the langgraph dev server. - Each `run_langgraph.ps1` invocation advances the graph to the next interrupt or completion. Use `-Resume` to continue the same thread after completing the requested Claude Code action. -## Dev Server Lifecycle +## Dev Server Lifecycle ⛔ DEPRECATED + +> **已弃用(2026-07 起)。** 本 skill 现用 `clean_run.py` 进程内驱动,**不再需要 dev server**。 +> 下面这套 `manage_dev_server.ps1` / `langgraph dev` / Studio 仅作历史参考,正常流程不要用。 The `langgraph dev` server must be running for the entire duration of a workflow session. Use `manage_dev_server.ps1` to start it before the first `run_langgraph.ps1` call and stop it after the workflow completes. @@ -99,6 +109,10 @@ C:\Users\bowei\.claude\skills\langgraph-plan-review\scripts\manage_dev_server.ps ## Workflow +> **注意**:下列步骤是**旧的 dev-server 流程**(`manage_dev_server.ps1` + `run_langgraph.ps1`)。 +> 正常请用上方"**运行方式:进程内驱动**"节的 `clean_run.py`。以下 action 语义(write_plan / decide / +> revise / write_rejection 及其 resume 值)两种流程通用,可参考。 + 1. Determine `TaskId` from the user. If missing, ask for it. 2. Start the dev server (idempotent): ```powershell diff --git a/langgraph-plan-review/scripts/clean_run.py b/langgraph-plan-review/scripts/clean_run.py new file mode 100644 index 0000000..12e6730 --- /dev/null +++ b/langgraph-plan-review/scripts/clean_run.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +"""In-process driver for the plan-review graph — NO langgraph dev server. + +Builds the compiled graph in-process (workflow.build_workflow) with a SqliteSaver so +state survives between invocations, and drives interrupts directly. Sets HTTP(S)_PROXY +from the Windows system proxy (or PLAN_REVIEW_PROXY) so the codex subprocess spawned by +the review node can reach its backend through the proxy. + +CLI (mirrors the old run_workflow.py): + --task-id 10 [--work-dir DIR] [--notes-dir Notes] [--prompt "..."] + [--resume-b64 ] [--codex-review-command-b64 ] [--timeout 600] +Prints one JSON line: {"status":"waiting","action_required":{...}} or {"status":"done",...}. +""" +from __future__ import annotations +import os, sys, json, base64, argparse, sqlite3 +from pathlib import Path + +SCRIPTS = Path(__file__).resolve().parent +sys.path.insert(0, str(SCRIPTS)) + + +def resolve_proxy() -> str: + px = os.environ.get("PLAN_REVIEW_PROXY", "").strip() + if not px: + try: + import winreg + k = winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", + ) + enable, _ = winreg.QueryValueEx(k, "ProxyEnable") + server, _ = winreg.QueryValueEx(k, "ProxyServer") + if enable and server and "=" not in str(server): # simple host:port, not per-scheme + px = "http://" + str(server) + except Exception: + px = "" + if px: + for v in ("HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", + "http_proxy", "https_proxy", "all_proxy"): + os.environ[v] = px + return px + + +def open_saver(db_path: str): + from langgraph.checkpoint.sqlite import SqliteSaver + conn = sqlite3.connect(db_path, check_same_thread=False) + saver = SqliteSaver(conn) + try: + saver.setup() + except Exception: + pass + return saver + + +def extract_interrupt(result): + if not isinstance(result, dict): + return None + ints = result.get("__interrupt__") + if not ints: + return None + first = ints[0] if isinstance(ints, (list, tuple)) else ints + return getattr(first, "value", first) + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--task-id", required=True) + ap.add_argument("--work-dir", default=".") + ap.add_argument("--notes-dir", default="Notes") + ap.add_argument("--prompt", default="") + ap.add_argument("--resume-b64", default="") + ap.add_argument("--codex-review-command-b64", default="") + ap.add_argument("--timeout", type=int, default=600) + ap.add_argument("--db", default=str(SCRIPTS / ".plan_review_state.sqlite")) + args = ap.parse_args() + + proxy = resolve_proxy() + + from workflow import build_workflow + from langgraph.types import Command + + codex_cmd = None + if args.codex_review_command_b64: + codex_cmd = json.loads(base64.b64decode(args.codex_review_command_b64).decode("utf-8")) + + saver = open_saver(args.db) + graph = build_workflow(checkpointer=saver) + + config = {"configurable": {"thread_id": str(args.task_id), "codex_timeout": args.timeout}} + if codex_cmd: + config["configurable"]["codex_review_command"] = codex_cmd + + if args.resume_b64: + resume_val = json.loads(base64.b64decode(args.resume_b64).decode("utf-8")) + result = graph.invoke(Command(resume=resume_val), config) + else: + init = { + "task_id": str(args.task_id), + "user_prompt": args.prompt, + "work_dir": args.work_dir, + "notes_dir": args.notes_dir, + "codex_session_id": "", + } + result = graph.invoke(init, config) + + payload = extract_interrupt(result) + if payload is not None: + out = {"status": "waiting", "thread_id": str(args.task_id), + "action_required": payload, "proxy": proxy} + else: + out = {"status": "done", "thread_id": str(args.task_id), + "has_serious_issue": bool(result.get("has_serious_issue")), + "review_comment": result.get("review_comment", ""), + "proxy": proxy} + print(json.dumps(out, ensure_ascii=False)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools-sync/SKILL.md b/tools-sync/SKILL.md new file mode 100644 index 0000000..6659d88 --- /dev/null +++ b/tools-sync/SKILL.md @@ -0,0 +1,162 @@ +--- +name: tools-sync +description: 在本机统一同步并配置 Claude Code 与 Codex 的 skills、MCP server 和开发环境:将 ~\.claude\skills 和 ~\.codex\skills 与 git.rpchannel.com 上的 bowei/skills-win 仓库保持同步,审计 skills 中的硬编码参数并迁移到本机 ~\skills_env.md,校验 langgraph conda 环境,并确保 E:\MCP_design 下所有 MCP 都已在 Claude Code 和 Codex 中注册。当用户提到"同步skills"、"skills同步"、"tools sync"、"tools-sync"、"同步codex"、"同步MCP"、"环境同步"、"skills-win"、"把skills推上去/拉下来"、"新电脑配置claude/codex环境"、"检查MCP注册"、"skills_env"时,必须使用此技能,即使用户没有明确说"skill"二字。 +--- + +# tools-sync:Claude Code / Codex 工具链同步 + +## 目标与总体思路 + +一台开发机上有两个 AI 编码工具(Claude Code 和 Codex),它们各自有 skills 目录和 MCP +注册表。这个 skill 的职责是让它们保持一致,并且可以在一台新电脑上从零复原整套配置: + +- **skills 的唯一真源**是 `http://git.rpchannel.com/bowei/skills-win.git`(remote 名 `origin`)。 + `~\.claude\skills` 是主工作副本,`~\.codex\skills` 是同一仓库的第二个检出(镜像)。 + Codex 没有注册命令——它在会话启动时自动扫描 `~\.codex\skills` 下所有含 `SKILL.md` + 的目录,所以"注册到 Codex" = "目录出现在那里且含 SKILL.md"。 +- **机器相关的参数不进 git**。每台电脑的软件安装路径、IP、账号等都记录在 + `~\skills_env.md`(用户主目录下,天然在两个仓库检出之外,不会被 git 同步)。 + skills 里引用参数时写"见 ~\skills_env.md 的 XXX 条目",不写死路径。 +- **凭据不写进任何会被同步的文件**。git.rpchannel.com 的凭据优先用 Windows + 凭据管理器(`cmdkey /list` 里应有 `git:http://git.rpchannel.com` 条目); + 只有在新机器首次配置时,才从 `~\skills_env.md` 读取用户名/密码完成首次 + clone(之后 credential helper 会缓存)。 + +完整跑一遍下面 6 个阶段就是一次"同步"。用户只要求其中一部分(比如"把 skills 推上去") +时,跑对应阶段即可,但阶段 0 永远先做。 + +## 阶段 0 — 读取本机环境档案 ~\skills_env.md + +先读 `~\skills_env.md`。后续所有阶段的路径、URL、账号都以它为准。 + +- 如果文件不存在(通常是新电脑):从本 skill 的 + `references/skills_env_template.md` 复制一份到 `~\skills_env.md`, + 然后逐项核对模板里的路径在本机是否真实存在(`Test-Path`),把不符的改成实际值, + 缺失的软件记为"未安装"。凭据字段让用户填写或从用户处确认,不要猜。 +- 如果存在:快速通读,注意 `status` 类标记和上次同步遗留的 TODO。 + +## 阶段 1 — 同步 ~\.claude\skills(主副本) + +用 `scripts/sync_repos.ps1` 做机械部分;它失败或报冲突时再人工介入。 + +```powershell +# 从 skill 目录运行;RepoUrl 取自 skills_env.md +powershell -File \scripts\sync_repos.ps1 -RepoUrl +``` + +脚本对主副本做的事:`git add -A` → 有变更则 commit(消息格式 +`sync: <机器名> <日期> <一句话摘要>`)→ `git pull --rebase` → `git push`。 + +人工介入的情形: + +- **rebase 冲突**:逐个文件看冲突双方,skills 文本冲突通常保留两边语义合并; + 解不了就 `git rebase --abort` 并向用户报告冲突文件清单,让用户裁决。 +- **push 被拒(认证)**:检查凭据管理器条目;新机器上用 + `git config --global credential.helper manager` 后重试一次,让 credential + helper 弹窗或从 skills_env.md 读凭据拼一次性 URL 完成首次认证。 + 认证成功后确认凭据已被缓存(再 fetch 一次不应再要密码)。 +- **不该入库的文件**:commit 前扫一眼 `git status`,运行时产物(.sqlite、.pckl、 + 日志、缓存目录)应加进 `.gitignore` 而不是提交。看到就顺手补 `.gitignore`。 + +## 阶段 2 — 同步 ~\.codex\skills(镜像检出) + +同一个脚本会接着处理 codex 侧。逻辑和原因: + +- 已是 git 仓库 → `git pull --rebase` 即可。 +- 还不是 git 仓库(首次转换)→ 脚本执行 `git init` + `remote add origin` + + `fetch` + `git reset origin/main`,然后**停下来**列出"本地与仓库不一致"的文件。 + 这一步停是有原因的:codex 目录里可能有比仓库新的本地修改或 codex 独有的 + skill。处理原则——codex 独有且有价值的 skill,先复制到 `~\.claude\skills` + 走阶段 1 入库,再回来;确认没有需要保留的差异后,用 `-Force` 重跑让脚本 + `git checkout -f` 对齐到仓库版本。codex 自带的系统 skills(`.system/`、 + vercel 系列等)已在 `.gitignore` 里,不会被动。 +- 同步完成后校验注册:仓库里每个顶层 skill 目录都应在 `~\.codex\skills` + 出现且含 `SKILL.md`。列出两侧目录做差集,差集应为空(忽略 .gitignore + 中的 codex 专属条目)。提醒用户:Codex 需要开新会话才会扫到新 skills。 + +## 阶段 3 — 硬编码审计与 skills_env.md 回填 + +目的:让仓库里的 skills 在任何一台按 `~\skills_env.md` 配置好的电脑上都能用。 + +在 `~\.claude\skills`(排除 `.system`)里搜这几类硬编码: + +- 盘符绝对路径:正则 `[A-Za-z]:[\\/]`(如 `D:\Xilinx\Vivado`、`E:\MCP_design`) +- IP 地址:`\d+\.\d+\.\d+\.\d+` +- 明文凭据:`password`、`密码`、常见口令字样 + +对每个命中做判断,不要机械替换: + +- **机器相关的值**(安装路径、板卡 IP、conda 路径)→ 确认已记录在 + `~\skills_env.md` 对应条目(没有就补上),然后把 skill 原文改成引用式写法, + 例如"Vivado 路径见 `~\skills_env.md` 的 `VIVADO_PATH`"。skill 的执行逻辑 + 改为:运行时先读 skills_env.md 取值。 +- **明文密码出现在会被 git 同步的文件里** → 这是必须当场修复的问题: + 从文件里删掉,移入 `~\skills_env.md`,并向用户报告(密码已进过 git + 历史的话,建议用户改密码)。 +- **协议性/普适的值**(如标准端口号、公开 URL)→ 保留,不算硬编码。 + +一次审计不必把所有历史 skills 全部重构完;至少保证:新增/本次改动的 skill 零硬编码, +存量 skill 的命中清单写进最终报告,让用户决定分批改。改动之后回到阶段 1 再 +commit + push 一次,并在 codex 侧 pull,保证两边一致。 + +## 阶段 4 — langgraph 开发环境校验 + +很多 skills(vivado-mcp、fpga 系列、langgraph 系列)依赖 conda 的 `langgraph` 环境。 +校验方式(路径以 skills_env.md 的 `CONDA_LANGGRAPH_PYTHON` 为准): + +```powershell +& -c "import langgraph, langchain; print('langgraph env OK')" +``` + +失败(环境不存在或包缺失)→ 调用 `langgraph-vivado-install` skill 完成安装, +装好后把实际的 python 路径回填到 `~\skills_env.md`。 + +## 阶段 5 — MCP server 注册校验(Claude Code + Codex 两边) + +MCP 的清单真源是 `E:\MCP_design\mcp_list.md`(路径见 skills_env.md 的 +`MCP_DESIGN_ROOT`),每行一个 MCP 工程目录。对清单里的每一项: + +1. **Claude Code 侧**:`claude mcp list` 或读 `~\.claude.json` 的 `mcpServers`, + 确认存在对应条目。缺失的用 `claude mcp add ...` 注册,命令、解释器 + 路径和 env 变量都取自 `~\skills_env.md` 的 MCP 配置节。 +2. **Codex 侧**:读 `~\.codex\config.toml` 的 `[mcp_servers.]` 节。 + 缺失的按 skills_env.md 里的同一份配置补写 TOML 节(stdio 类型, + 记得带 `PYTHONIOENCODING=utf-8`、`PYTHONUTF8=1`,Codex 在 Windows 上 + 没有这两个变量时中文输出会乱码)。 +3. **可启动性抽查**:对新注册的 MCP,直接运行其 command + args 数秒, + 确认进程能起来、没有立刻报 import/路径错误(stdio MCP 起来后会静默等 + 输入,这就算通过,Ctrl-C 掉即可)。 + +注意两侧配置语义相同但格式不同(JSON vs TOML),同一个 MCP 在两边的 +command/args/env 应当一致;发现两边漂移(比如只有一边改了 VIVADO_PATH)时, +以 skills_env.md 记录的值为准改齐两边。 + +## 阶段 6 — 输出同步报告 + +最后用这个结构向用户汇报(有问题的条目放前面): + +``` +# tools-sync 同步报告 <日期> +## skills 同步 +- ~\.claude\skills: +- ~\.codex\skills: +## 硬编码审计 +- 本次修复: <清单> +- 遗留待改: <清单> +## 环境 +- langgraph env: OK / 已重装 / 失败原因 +- MCP 注册: <两侧各缺了什么、补了什么、抽查结果> +## 需要用户决定的事项 +- <冲突、密码泄露、codex 独有 skill 去留……没有则写"无"> +``` + +## 边界与安全 + +- 本 skill 会 push 到远端仓库——commit 前把将要提交的文件列表给用户过目 + (自动化场景下至少写进报告)。绝不 `push --force`。 +- `~\skills_env.md` 含凭据,任何情况下不将其内容或凭据字段写入仓库内文件、 + commit message 或对外输出。 +- 不动 `~\.codex\skills\.system\`(Codex 自带系统 skills)和 + `~\.claude\skills\.system\`。 +- 修改 `~\.codex\config.toml` 前先备份为 `config.toml.bak-<日期>`,TOML 写坏 + 会导致 Codex 起不来。 diff --git a/tools-sync/references/skills_env_template.md b/tools-sync/references/skills_env_template.md new file mode 100644 index 0000000..ba19620 --- /dev/null +++ b/tools-sync/references/skills_env_template.md @@ -0,0 +1,68 @@ +# skills_env — 本机环境档案(模板) + +> 复制本文件到 `~\skills_env.md` 后逐项核对。此文件**只留在本机,不进 git**: +> 每台电脑的路径/IP/凭据不同。skills 中凡是机器相关的参数都从这里取值。 +> 值为 `KEY = value` 形式,方便脚本和模型直接检索。 + +## 同步仓库 + +``` +SKILLS_REPO_URL = http://git.rpchannel.com/bowei/skills-win.git +SKILLS_REPO_USER = bowei +SKILLS_REPO_PASS = <填写,或留空表示已存入 Windows 凭据管理器> +CLAUDE_SKILLS_DIR = C:\Users\\.claude\skills +CODEX_SKILLS_DIR = C:\Users\\.codex\skills +``` + +凭据说明:首次 clone 成功后运行 `git config --global credential.helper manager`, +让 Windows 凭据管理器接管,此后 `SKILLS_REPO_PASS` 可以清空。 + +## Python / Conda + +``` +CONDA_ROOT = C:\ProgramData\miniconda3 +CONDA_LANGGRAPH_PYTHON = C:\Users\\.conda\envs\langgraph\python.exe +``` + +## EDA / 硬件工具 + +``` +VIVADO_PATH = D:\Xilinx\Vivado\2018.1\bin\vivado.bat +KICAD_PYTHONPATH = C:\Program Files\KiCad\10.0\bin\Lib\site-packages +MATLAB_MCP_EXE = C:\Users\\.matlab\agentic-toolkits\bin\matlab-mcp-server.exe +``` + +## 板卡 / 仪器 IP + +``` +N9320B_HOST = 192.168.1.147 # Keysight N9320B 频谱仪 +SMOD_BOARD_IP = 192.168.1.143 # SMOD 板(ATSC 激励器远程升级) +``` + +## MCP 注册配置(真源:MCP_DESIGN_ROOT\mcp_list.md) + +``` +MCP_DESIGN_ROOT = E:\MCP_design +``` + +每个 MCP 在 Claude Code(`~\.claude.json` 的 `mcpServers`)和 Codex +(`~\.codex\config.toml` 的 `[mcp_servers.*]`)中应使用**同一份** command/args/env。 +标准配置如下(路径变量引用上文条目): + +| name | command | args | env | +|------------|----------------------------------|---------------------------------------------------|-----| +| vivado-mcp | {CONDA_LANGGRAPH_PYTHON} | E:\MCP_design\vivado-mcp-main\run_server.py(Codex)/ -m vivado_mcp(Claude) | VIVADO_PATH={VIVADO_PATH} | +| mcp_n9320b | {CONDA_LANGGRAPH_PYTHON} | E:\MCP_design\mcp_n9320b\n9320b_mcp.py | N9320B_HOST={N9320B_HOST} | +| cubemx | E:\MCP_design\MCP_cubemx\cubemx-mcp\.venv\Scripts\python.exe | E:\MCP_design\MCP_cubemx\cubemx-mcp\server\main.py | PYTHONPATH=E:\MCP_design\MCP_cubemx\cubemx-mcp\server | +| kicad | node | E:\MCP_design\KiCAD-MCP-Server\dist\index.js | NODE_ENV=production; PYTHONPATH={KICAD_PYTHONPATH}; KICAD_AUTO_LAUNCH=false | +| simetrix | \Scripts\mcp-simetrix.exe | | SIMETRIX_PROJECT_ROOT=E:\ | +| matlab | {MATLAB_MCP_EXE} | --matlab-session-mode=existing --extension-file=...\simulink\tools\tools.json | | + +Codex 侧所有 stdio MCP 额外加 `PYTHONIOENCODING=utf-8`、`PYTHONUTF8=1`。 + +## 本机状态备注(同步时更新) + +``` +LAST_SYNC = <日期> +TODO = <遗留事项> +``` diff --git a/tools-sync/scripts/sync_repos.ps1 b/tools-sync/scripts/sync_repos.ps1 new file mode 100644 index 0000000..acca70d --- /dev/null +++ b/tools-sync/scripts/sync_repos.ps1 @@ -0,0 +1,113 @@ +# tools-sync: mechanical git sync of the two skills checkouts. +# Claude side (~\.claude\skills) is the primary working copy: commit -> pull --rebase -> push. +# Codex side (~\.codex\skills) is a mirror checkout of the same repo: bootstrap if needed, then pull. +# Judgment calls (conflicts, codex-only skills worth keeping) are left to the caller. + +param( + [Parameter(Mandatory = $true)][string]$RepoUrl, + [string]$ClaudeSkills = "$env:USERPROFILE\.claude\skills", + [string]$CodexSkills = "$env:USERPROFILE\.codex\skills", + [string]$Branch = "main", + # Bootstrap of the codex checkout stops when local files differ from the repo; + # -Force lets it overwrite them (caller must have rescued codex-only edits first). + [switch]$Force, + # Report what would happen without committing/pushing/checking out. + [switch]$DryRun +) + +$ErrorActionPreference = "Stop" + +function Invoke-Git { + param([string]$Dir, [string[]]$GitArgs) + # PS 5.1: git writes progress/warnings to stderr; 2>&1 wraps them in ErrorRecords + # which terminate under EAP=Stop. Relax EAP locally and stringify every line. + $prev = $ErrorActionPreference + $ErrorActionPreference = "Continue" + $out = & git -C $Dir @GitArgs 2>&1 | ForEach-Object { "$_" } + $code = $LASTEXITCODE + $ErrorActionPreference = $prev + return @{ Code = $code; Out = (($out -join "`n")).Trim() } +} + +function Fail([string]$Msg) { Write-Host "FAIL: $Msg"; exit 1 } + +# ---------- Phase 1: primary checkout (~\.claude\skills) ---------- +Write-Host "=== [1/2] primary: $ClaudeSkills ===" +if (-not (Test-Path (Join-Path $ClaudeSkills ".git"))) { + Fail "$ClaudeSkills is not a git repo. Clone $RepoUrl there first (new machine: git clone $RepoUrl `"$ClaudeSkills`")." +} + +$st = Invoke-Git $ClaudeSkills @("status", "--porcelain") +if ($st.Out) { + Write-Host "local changes:"; Write-Host $st.Out + if ($DryRun) { + Write-Host "(dry-run) would commit these changes" + } else { + Invoke-Git $ClaudeSkills @("add", "-A") | Out-Null + $msg = "sync: $env:COMPUTERNAME $(Get-Date -Format yyyy-MM-dd)" + $r = Invoke-Git $ClaudeSkills @("commit", "-m", $msg) + if ($r.Code -ne 0) { Fail "commit failed:`n$($r.Out)" } + Write-Host "committed: $msg" + } +} else { + Write-Host "working tree clean" +} + +if (-not $DryRun) { + $r = Invoke-Git $ClaudeSkills @("pull", "--rebase", "origin", $Branch) + if ($r.Code -ne 0) { + Write-Host $r.Out + Fail "pull --rebase failed on primary. Resolve conflicts (or 'git rebase --abort') then re-run." + } + Write-Host $r.Out + $r = Invoke-Git $ClaudeSkills @("push", "origin", $Branch) + if ($r.Code -ne 0) { Write-Host $r.Out; Fail "push failed (auth? see skill Phase 1)." } + Write-Host "primary in sync with origin/$Branch" +} + +# ---------- Phase 2: mirror checkout (~\.codex\skills) ---------- +Write-Host "=== [2/2] mirror: $CodexSkills ===" +if (-not (Test-Path $CodexSkills)) { New-Item -ItemType Directory -Force $CodexSkills | Out-Null } + +if (-not (Test-Path (Join-Path $CodexSkills ".git"))) { + Write-Host "bootstrapping mirror as a checkout of $RepoUrl" + if ($DryRun) { Write-Host "(dry-run) would git init + fetch + align to origin/$Branch"; exit 0 } + Invoke-Git $CodexSkills @("init") | Out-Null + Invoke-Git $CodexSkills @("remote", "add", "origin", $RepoUrl) | Out-Null + $r = Invoke-Git $CodexSkills @("fetch", "origin", $Branch) + if ($r.Code -ne 0) { Write-Host $r.Out; Fail "fetch failed during bootstrap." } + # Point index at origin/main without touching files, so status shows local-vs-repo drift. + Invoke-Git $CodexSkills @("reset", "origin/$Branch") | Out-Null + Invoke-Git $CodexSkills @("branch", "-f", $Branch, "origin/$Branch") | Out-Null + Invoke-Git $CodexSkills @("checkout", $Branch) 2>$null | Out-Null + $drift = Invoke-Git $CodexSkills @("status", "--porcelain") + $modified = ($drift.Out -split "`n" | Where-Object { $_ -match '^\s*(M|D)' }) + if ($modified -and -not $Force) { + Write-Host "these tracked files differ locally from the repo:" + $modified | ForEach-Object { Write-Host " $_" } + Fail "codex dir has local drift. Rescue anything worth keeping into the primary checkout, then re-run with -Force." + } + $r = Invoke-Git $CodexSkills @("checkout", "-f", $Branch) + if ($r.Code -ne 0) { Write-Host $r.Out; Fail "checkout failed during bootstrap." } + Invoke-Git $CodexSkills @("branch", "--set-upstream-to=origin/$Branch", $Branch) | Out-Null + Write-Host "mirror bootstrapped at origin/$Branch (untracked codex-local files left untouched)" +} else { + if ($DryRun) { + Invoke-Git $CodexSkills @("fetch", "origin", $Branch) | Out-Null + $r = Invoke-Git $CodexSkills @("log", "--oneline", "HEAD..origin/$Branch") + Write-Host "(dry-run) mirror is behind by:" + if ($r.Out) { Write-Host $r.Out } else { Write-Host " (nothing, or not yet a checkout)" } + } else { + $st2 = Invoke-Git $CodexSkills @("status", "--porcelain") + if ($st2.Out) { + Write-Host "WARNING: mirror has local changes (should be edited on the primary side instead):" + Write-Host $st2.Out + } + $r = Invoke-Git $CodexSkills @("pull", "--rebase", "origin", $Branch) + if ($r.Code -ne 0) { Write-Host $r.Out; Fail "pull failed on mirror." } + Write-Host $r.Out + Write-Host "mirror in sync with origin/$Branch" + } +} + +Write-Host "=== sync_repos done ==="