Skip to content

refactor(providers): 统一 Git 与 HTTP 资源后端 - #469

Open
nateEc wants to merge 2 commits into
Tencent:mainfrom
nateEc:refactor/issue-404-clean
Open

nateEc wants to merge 2 commits into
Tencent:mainfrom
nateEc:refactor/issue-404-clean

Conversation

@nateEc

@nateEc nateEc commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

现有 ClawPro HTTP 分发以全局 local-agent 单例存在,和 Git source 使用不同生命周期,无法安全挂载多个后端。本 PR 引入统一 ResourceProvider、capability、registry 与故障隔离调度,并将 ClawPro 协议实现迁入独立 HTTP adapter。

主要行为:

  • 支持具名 Git/HTTP Provider 及 provider add/list/sync/remove/set-primary/migrate-legacy 命令。
  • 每个 HTTP Provider 独立存放凭据、绑定、manifest、插件状态、缓存和日志;凭据使用 0600 权限。
  • 一次 hook 调度每个启用的 HTTP Provider 一次,单个失败不影响其他来源。
  • Git 同名 skill 按 priority 选主并在来源删除后回退;HTTP 同步按低到高优先级执行。
  • 保留旧 local-agentrepo.kind: http 和 source HTTP 命令的迁移兼容路径。
  • push 与 set-primary 拒绝不可写目标。

#404 中跨 HTTP Provider 的持久 ownership ledger,以及删除 active HTTP 来源后的全资源类型自动回退仍适合在后续小 PR 中完成,因此这里引用 issue,不自动关闭。

验证:

  • npm run typecheck
  • npm run build
  • 209 个单测文件、2929 项测试通过
  • 22 个 E2E 文件、110 项测试通过;25 项外部凭据 live 测试跳过

Refs #404

- 新增统一 ResourceProvider、capability、registry 与故障隔离调度,并将现有 Git source 接入同一同步生命周期。
- 将 ClawPro 协议实现迁入独立 HTTP adapter,保留 local-agent 兼容门面和旧版 HTTP 初始化路径。
- 支持多个具名 HTTP Provider;配置、凭据、绑定、manifest、插件、缓存与日志均按 Provider 隔离,凭据使用 0600 权限单独保存。
- 增加 provider add/list/sync/remove/set-primary/migrate-legacy 命令,push 校验可写目标,并为旧 source HTTP 命令保留带弃用提示的兼容入口。
- 为 Git 同名 skill 增加 priority 选择与来源删除回退;通过 2928 项单元测试、3 项 E2E、构建及双 HTTP 后端真实 CLI 验证。
- HTTP Provider 按优先级从低到高同步,确保冲突资源最终由最高优先级的成功来源生效。
- 在 set-primary 时直接拒绝不可写的 HTTP Provider 与 Git 订阅源。
- 增加多 HTTP Provider 调度顺序的端到端覆盖,并通过类型检查和定向回归测试。
@jeff-r2026

Copy link
Copy Markdown
Collaborator

这个改动比较复杂,需要做时间更久的 review 和 端到端验证。


// Existing ~/.teamai/local-agent installs remain live throughout migration.
let legacyOutput: string | null = null;
if (await loadLocalAgentConfig()) legacyOutput = await reportAndSyncFromHook(stdin, tool);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[阻塞] 命名 provider 与遗留单例会在每次 hook 重复上报/同步

syncHttpProvidersFromHook 跑完所有命名 provider 后,只要 loadLocalAgentConfig() 非空就无条件再跑一次遗留路径:

if (await loadLocalAgentConfig()) legacyOutput = await reportAndSyncFromHook(stdin, tool);

main 上每次 hook 只 dispatch 单例一次;本 PR 变成两次——命名后端 + 遗留后端各收到一轮 report+sync+get-config,且遗留(未 scope)快照会覆盖写盘。

触发条件(任一即中):

  1. ~/.teamai/local-agent/config.json 存在且无 migrated-to 标记;
  2. ~/.teamai/config.yamlkind: http——正是 init.ts:369init --http 写的,所以「先 init --httpprovider add http」必中;
  3. 设了 TEAMAI_HTTP_ENDPOINT / TEAMAI_ENDPOINT / TEAMAI_API_BASE_URL

client.ts:575migrated-to 护栏只覆盖条件 1,且 migrate-legacy 只往 local-agent/ 写标记、从不清理 config.yamlkind: http,条件 2 会一直重复。本 PR 自带的 http-provider-multi-e2e 里那行无 [provider:*] 前缀的 sync FAILED: 未登录,就是这条遗留路径真实打到后端的证据。

建议:注册了命名 HTTP provider 时,若其 endpoint 与遗留单例相同则按 endpoint 去重跳过遗留路径;或把 backfill / env 两条 fallback 也纳入迁移标记门控,而不只是 local-agent/ 目录那条。

已本地复现(回归测试 + 隔离子进程各一,均能稳定重现重复 /sync)。

...(await listHttpProviderConfigs()).map((item) => item.name),
]);
if (!names.has(name)) throw new Error(`Resource provider "${name}" was not found.`);
if (name !== 'main' || !writableMain) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[建议] provider set-primary <name> 实际只接受 main,命令签名有误导

providerSetPrimaryif (name !== 'main' || !writableMain) throw,任何非 main 目标都被拒;getPrimaryProvider 也只被 push 消费,而 push 同样硬编码只认 main(push.ts:283)。等于当前整套 primary 机制只能表达 "main" 一个值,但命令签名 set-primary <name> 却接收任意 <name>,用户会以为能把命名 provider 设为主。

建议:要么在 help/文档里注明「当前仅 main 可写、可作 primary」,要么明确标注这是 #404 后续 PR 的前置桩,避免误导。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants