feat: add forge-hub sync — lightweight runtime sync#25
Conversation
|
Thanks for this — the motivation is solid and the implementation is clean. One change needed before we can merge: Missing
|
Per review feedback on PR LinekForge#25: syncCmd missed the cleanDirContents step before cpDir for channels. If a channel file is deleted or renamed in source, the old .ts file would otherwise remain in ~/.forge-hub/channels/ and channel-loader would keep loading it (harmless warning at best, broken channel registration at worst). Mirrors installCmd behavior at L79-82. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@AmberCXX 感谢耐心等待!上周 麻烦 rebase 到最新 main 后 force-push,我再 review。主要关注 之前 review 提的 — Forge |
Per review feedback on PR LinekForge#25: syncCmd missed the cleanDirContents step before cpDir for channels. If a channel file is deleted or renamed in source, the old .ts file would otherwise remain in ~/.forge-hub/channels/ and channel-loader would keep loading it (harmless warning at best, broken channel registration at worst). Mirrors installCmd behavior at L79-82. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1fbf827 to
5038153
Compare
|
@LinekForge 已 rebase 到最新 main(538ce38),冲突处理记录: Rebase 结果:
Helper 兼容性确认(按你提示的几个点):
自检:
新 HEAD: — Forge |
|
@AmberCXX 看到你 rebase 了,但 merge state 显示 DIRTY(仍有冲突)。你 rebase 到的 当前 main HEAD 是 git fetch origin
git rebase origin/main
# 解决冲突后
git push --force-with-lease主要冲突点应该在 cli.ts 的 — Forge |
git pull 后源码更新,但 ~/.forge-hub/ 运行时文件不会自动同步, 导致通道插件调用新 HubAPI 方法(如 isAllowed)时报错。 sync 命令只同步 hub-server 源文件 + 重启 Hub,跳过 deps install / dashboard build / plist / MCP 注册,比 install 快得多。 维护地图.md 同步更新:源码更新后跑 forge-hub sync 对齐运行时。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per review feedback on PR LinekForge#25: syncCmd missed the cleanDirContents step before cpDir for channels. If a channel file is deleted or renamed in source, the old .ts file would otherwise remain in ~/.forge-hub/channels/ and channel-loader would keep loading it (harmless warning at best, broken channel registration at worst). Mirrors installCmd behavior at L79-82. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
5038153 to
6f83190
Compare
|
Rebased onto current Conflict resolved: Verification:
Ready for re-review. |
LinekForge
left a comment
There was a problem hiding this comment.
感谢 rebase!merge state 已经 clean 了,代码逻辑和意图都很清晰。有两个需要改的问题,改完就可以合。
1. launchctl 参数语法需要修正
当前 kickstart 调用:
execFileSync("launchctl", ["kickstart", "-k", "-p", LAUNCHD_PLIST], { stdio: "ignore" });launchctl kickstart 不接受 -p flag,它的参数是 service target(gui/<uid>/com.forge-hub),不是 plist 路径。这行会直接报错进入 catch。
fallback 里的 bootstrap 也有问题:
execFileSync("launchctl", ["bootstrap", label, LAUNCHD_PLIST], { stdio: "ignore" });label 是 gui/${uid}/com.forge-hub(完整 service label),但 bootstrap 的第一个参数应该是 domain(gui/${uid}),不是完整 label。
结果是两条路径都不 work——sync 完文件后 Hub 不会重启,但没有报错提示。
建议直接复用 installCmd 里已验证的模式:
const uid = os.userInfo().uid;
const domain = `gui/${uid}`;
const label = `${domain}/com.forge-hub`;
try {
execFileSync("launchctl", ["bootout", label], { stdio: "ignore" });
} catch { /* 可能没有在跑 */ }
try {
execFileSync("launchctl", ["bootstrap", domain, LAUNCHD_PLIST], { stdio: "inherit" });
log("✓ Hub 已重启");
} catch {
log(`⚠️ 无法重启 Hub。手动执行:launchctl bootout ${label} && launchctl bootstrap ${domain} ${LAUNCHD_PLIST}`);
}2. cpDir 到 HUB_DIR 时需要排除敏感文件名
当前:
cpDir(serverSrc, HUB_DIR, [".ts", ".json", ".lock"]);这会把 hub-server/ 下所有 .json 文件复制到 ~/.forge-hub/ 根目录。目前 hub-server/ 只有 package.json 和 tsconfig.json,不会冲突。但如果将来 hub-server/ 里加了和运行时同名的 .json(比如测试用的 hub-config.json),就会静默覆盖用户配置。
建议在 cpDir 前加一个排除集:
const SYNC_SKIP = new Set(["hub-config.json", "lock-phrase.json", "lock.json"]);然后在 cpDir 里或调用后过滤掉这些文件名。最简单的做法是 cpDir 之后检查并删除不该被覆盖的文件——但更干净的是在复制时跳过。
其他都没问题:
cleanDirContents(CHANNELS_RUNTIME)无 preserve set 是对的(channels 全清全替换)- 不同步 hub-client / dashboard / engine 的决策合理,help 文本也说清楚了
- chmod 700 的 warn + continue 和 installCmd 一致
- 维护地图.md 的补充很实用
改完这两处我就合。
— Forge
…e configs Per @LinekForge review on LinekForge#25: 1. launchctl syntax in syncCmd was wrong on both paths: - `kickstart -k -p <plist>` — `-p` is not a kickstart flag; kickstart takes a service target (gui/<uid>/com.forge-hub), not a plist path - fallback `bootstrap <full-label> <plist>` — bootstrap's first arg must be the domain (gui/<uid>), not the full label Both paths silently entered catch, so sync never actually restarted Hub. Replaced with installCmd's verified `bootout label` + `bootstrap domain plist` pattern. 2. cpDir to HUB_DIR copied every hub-server/*.json, which would silently overwrite user runtime configs (hub-config.json / lock-phrase.json / lock.json) if those names ever land in hub-server/. Added SYNC_SKIP set, threaded through cpDir as an optional skipNames param (back-compat default empty set, no other call site affected).
|
Both review issues addressed — root cause was the same: syncCmd was mirroring an older installCmd shape. Re-aligned with current main's installCmd. 1. launchctl — replaced the 2. SYNC_SKIP — added Diff: 17/15 in cli.ts, one commit ( CI green (all 8). Ready for re-review. |
|
Merged! 感谢耐心 rebase 和快速修复 launchctl + SYNC_SKIP。
贡献者列表已更新。 — Forge |
Summary
forge-hub synccommand: only syncs hub-server source files (including channels/) from source to runtime, then restarts Hubforge-hub syncinstead of fullforge-hub installaftergit pullMotivation
After
git pull,~/.forge-hub/runtime files don't auto-update. The previous workaround wasforge-hub install, which redoes everything (bun install × 3, dashboard build, plist, MCP reg, etc.) — slow and unnecessary.This caused a real outage:
hub.isAllowed is not a functionin feishu channel, because sourcechannel-loader.tsaddedisAllowed()to HubAPI but runtime wasn't synced.Changes
cli.tssyncCmd()+ wired into dispatch + help text维护地图.mdforge-hub syncafter source updateSelf-test
🤖 Generated with Claude Code