diff --git a/.github/workflows/ghapp-scan.yml b/.github/workflows/ghapp-scan.yml index a2e6cc2..59e8d71 100644 --- a/.github/workflows/ghapp-scan.yml +++ b/.github/workflows/ghapp-scan.yml @@ -17,8 +17,8 @@ name: ghapp-scan # - label `ai` # - marker `easygh-ai` in the title or body, from an OWNER/MEMBER/COLLABORATOR author # Poll cadence: EasyGithub is a PUBLIC repo, so Actions here are free/unmetered. -# */5 gives ~5-minute latency at zero quota cost. For real-time, see docs/realtime.md -# (event-driven via webhook is still needed for sub-minute response). +# */5 gives ~5-minute latency at zero quota cost. Sub-minute latency would need an +# external webhook receiver (not implemented); see docs/usage.md §1 for the modes. on: schedule: - cron: "*/5 * * * *" diff --git a/AGENTS.md b/AGENTS.md index 0473170..e035ac3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ EasyGithub is an AI software-development pipeline: a GitHub Issue tagged `ai` is ## Layout -- `agent-runner/` — TypeScript runner. No runtime dependencies; uses Node built-ins plus the `gh`, `git`, and `pi`/`claude`/`codex` CLIs. Run with Node >= 22.19 (native type stripping). Entry point: `agent-runner/src/main.ts`; cross-repo dispatcher: `agent-runner/src/dispatcher.ts`. Guardrails: `src/verify.ts` (frozen gate), `src/policy.ts` (path/secret audit), `src/risk.ts` (risk tiers + auto-merge), `src/profile.ts` (per-repo profile), `src/env.ts` (agent env allow-list). Providers: `src/providers/` (platform seam; GitHub implemented, others must implement `Provider` and register). Support tools: `src/eval.ts` (frozen tasks), `src/retro.ts` (weekly report), `src/watch.ts` (cross-repo post-merge watchdog), `src/metrics.ts`, `src/learnings.ts`. +- `agent-runner/` — TypeScript runner. No runtime dependencies; uses Node built-ins plus the `gh`, `git`, and `pi`/`claude`/`codex` CLIs. Run with Node >= 22.19 (native type stripping). Entry point: `agent-runner/src/main.ts`; cross-repo dispatcher: `agent-runner/src/dispatcher.ts`. Guardrails: `src/verify.ts` (frozen gate), `src/policy.ts` (path/secret audit), `src/risk.ts` (risk tiers + auto-merge), `src/profile.ts` (per-repo profile), `src/env.ts` (agent env allow-list), `src/git.ts` (git wrapper + rebase/credential hiding), `src/prompt.ts` (template selection/rendering). Providers: `src/providers/` (platform seam; GitHub implemented, others must implement `Provider` and register). Support tools: `src/eval.ts` (frozen tasks), `src/retro.ts` (weekly report), `src/watch.ts` (cross-repo post-merge watchdog), `src/metrics.ts`, `src/learnings.ts`. - `agent-runner/prompts/` — task templates rendered by the runner (bug-fix / feature / review); `zh-cn/` is the built-in translation, per-repo variants are selected with `promptsDir`/`locale` (`AI_LOCALE`). See `prompts/README.md`. - `agent-runner/config/agents.json` — agent routing rules. - `agent-runner/config/repos.json` — per-repository profile (verify commands, protected/blocked paths, dependency manifests, learnings file, default agent/model); see `docs/portability.md`. Legacy `config/verify.json` and the `EASYGH_VERIFY_CMDS` variable still override it. @@ -12,9 +12,9 @@ EasyGithub is an AI software-development pipeline: a GitHub Issue tagged `ai` is - `docs/learnings.md` — curated context injected into `TASK.md` (top matching sections). - `.github/workflows/ai-agent.yml` — the pipeline workflow (self-host). - `.github/workflows/ai-agent-reusable.yml` + `.github/actions/agent-runner` — reusable cross-repo mode (mode 2). -- `.github/workflows/ghapp-scan.yml` + `scripts/ghapp-token.mjs` — GitHub-App zero-file mode (mode 3); `ai-run.yml` — one task on a profile-selected runner (self-hosted macOS/Windows). -- `scripts/` — helper scripts (`dev-run.sh`, `create-labels.sh`, `install-to-repo.sh`). -- `docs/` — `usage.md` (operator manual: how to file a task, read results, run the five human actions), `ai-workflow.md` (end-to-end workflow, risk tiers, human touchpoints), `portability.md` (adapting the pipeline to other projects), `agents.md` (multi-agent + model config), `realtime.md` (event-driven vs polling), `other-orgs.md` (using EasyGithub in other organizations; `ghapp-scan` org is `vars.EASYGH_ORG`). +- `.github/workflows/ghapp-scan.yml` — GitHub-App zero-file mode (mode 3); `ai-run.yml` — one task on a profile-selected runner (self-hosted macOS/Windows); `ai-decide.yml` — the human interface; `ai-watch.yml` / `ai-retro.yml` — watchdog + weekly report. +- `scripts/` — `install-to-repo.sh` (modes 1/2), `dev-run.sh` (local dry run), `create-labels.sh`, `enable-ai-gate.sh` (branch protection), `ghapp-manifest.mjs` (create an org-owned App), `ghapp-token.mjs` (installation token). +- `docs/` — `usage.md` (operator manual), `ai-workflow.md` (end-to-end workflow, risk tiers, human touchpoints), `portability.md` (adapting the pipeline to other projects), `agents.md` (multi-agent + model config), `other-orgs.md` (using EasyGithub in other organizations; org list is `vars.EASYGH_ORGS`). ## Checks @@ -33,7 +33,7 @@ EasyGithub is an AI software-development pipeline: a GitHub Issue tagged `ai` is for credential material. - The agent never inherits `GH_TOKEN`/`GITHUB_TOKEN`/`EASYGH_PR_TOKEN` (`src/env.ts`), and git push credentials are stripped from the worktree while it runs (`src/git.ts`). -- There is no automated test suite yet. +- `npm test` runs the `node:test` suite (93 cases) in `agent-runner/test/`; `npm run check` = typecheck + tests. ## Working in this repo diff --git a/CHANGELOG.md b/CHANGELOG.md index a9986d4..1fe3909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,121 +8,63 @@ ### Added -- Agent Runner 独立验证与失败自动重试:agent 完成后 runner 会独立运行仓库检查 `npm run check`,失败时把输出反馈给 agent 重试,最多 `AI_MAX_ATTEMPTS`=3 次。 -- 变更审计 `agent-runner/src/policy.ts`:提交前做路径白名单(拒绝 `.github/workflows/**`、`.github/actions/**`、`LICENSE`;标记 `ai-core` 供人工审查)、剔除 vendored/生成目录、扫描新增行中的密钥。 -- Agent 环境白名单 `agent-runner/src/env.ts`:子进程不再继承 `GH_TOKEN` / `GITHUB_TOKEN` / `EASYGH_PR_TOKEN`;git push 凭据在 agent 阶段从工作树移除(内存暂存,推送前恢复)。 -- 原子认领锁 `ai-lock-issue-`(Git Data tag ref CAS),支持按 TTL 回收僵尸运行;`finally` 中统一释放锁与更新标签。 -- 时间预算 `AGENT_BUDGET_MS` / `PI_TIMEOUT_MS` / `VERIFY_TIMEOUT_MS` / `DISPATCH_BUDGET_MS`,超预算时给出明确失败评论而不是被 job timeout 砍断。 -- `review` 任务类型落地:只读,输出 Review 报告作为 Issue 评论,不再产生空改动流水线。 -- 新标签:`ai-core`、`ai-verify-changed`。 - -### Added (automation / minimal human intervention) - -- 风险分级 `agent-runner/src/risk.ts`:low/medium/high 三档 + 自动合并谓词;high 风险一律**草稿 PR**。 -- 自动合并 `AI_AUTOMERGE=off|probation|on`:仅 low 风险 + 可信验证时 `gh pr merge --auto`;probation 只信任 docs/测试改动。 -- 结构化阻塞:agent 写 `EASYGH_BLOCKED.md` 即触发 `ai-needs-input`,评论提问并停止,不建 PR。 -- 每日配额 `AI_MAX_PRS_PER_DAY`(默认 10),超限标记 `ai-deferred`。 -- 人工命令入口 `.github/workflows/ai-decide.yml`:retry / cancel / answer / waive / set-automerge,带权限校验与 `easygh-decision` 审计。 -- 合并后看护 `.github/workflows/ai-watch.yml`:main CI 红且来自 AI 合并 → 事故 Issue + 自动 revert PR + 熔断(`AI_AUTOMERGE=off`);检测 24h 内的人工 revert。 -- 周度复盘 `.github/workflows/ai-retro.yml` + `agent-runner/src/retro.ts`:失败签名聚类并开 `retro` Issue(不带 `ai`,由人决定是否执行)。 -- 评测 `agent-runner/src/eval.ts` + `eval/tasks/`:冻结任务 + **隐藏测试**(agent 结束才落盘),输出 pass@1。 -- 经验注入 `docs/learnings.md` → `TASK.md`(按相关性取 2 段,有长度上限)。 -- 运行指标 `metrics.json`(产物 + 单行 JSON 日志)。 -- 测试套件 `agent-runner/test/`(37 个用例,`npm run check` 现在包含测试)。 -- `.github/CODEOWNERS`:`.github/**`、`agent-runner/**`、`scripts/**`、`eval/**`、`LICENSE` 必须 code owner 审查。 -- 新标签:`ai-needs-input`、`ai-deferred`、`ai-automerge`、`ai-incident`、`retro`。 - -### Added (cross-repo automation) - -- 跨仓库看护 `agent-runner/src/watch.ts`:dispatcher 每 5 分钟巡检 App 安装范围内的仓库——若默认分支 head 是 AI 合并且该提交上的 `push` 运行失败,自动开 `ai-incident` + 准备 revert PR。定时/安全扫描(`schedule`)不会误报。 -- 熔断闭锁:`ai-incident` 打开期间该仓库不再自动合并(关闭 Issue 即恢复),`hasOpenIncident()` 在 arm auto-merge 前检查。 -- 周报覆盖多仓库:`retro.ts --repos a/b,c/d` / `EASYGH_RETRO_REPOS`,按仓库分区统计。 -- 开关:`EASYGH_WATCHDOG`(默认 on)。 -- 多组织 `EASYGH_ORGS`(逗号分隔):`ghapp-scan` 按组织做 matrix,每个组织独立签发 installation token。 -- `ai-decide` 新增 `repo` 输入:hub 可直接 retry/cancel/answer 目标组织的 Issue(App token 执行)。 -- 看护在读不到 workflow runs(App 缺 `Actions: read`)时显式 `skipped`,不再静默报健康。 -- hub 的 `ai-watch` 改为调用同一个 `watch.ts`(新增 CLI 与 `--dry-run`),与目标仓库共用一套判定逻辑。 - -### Added (repository permissions) - -- `scripts/enable-ai-gate.sh`:给"已有分支保护"的仓库统一配置必需检查 + 0 批准 + admin 应急绕过; - 已有 ruleset 管检查的仓库不重复叠加,`gh api` 的错误 JSON 不会被当成检查名。 -- 文档补充权限模型:组织默认 `read` + 维护者 `write`,并记录"auto-merge 不认 bypass actor"的实测结论。 - -### Added (portability) - -- 仓库画像 `agent-runner/src/profile.ts` + `config/repos.json`:按仓库配置验证命令、受保护/禁止/敏感/忽略路径、 - 依赖清单、经验文件、默认 agent/model、重试与配额;默认行为不变(不配置就走自动探测)。 -- 自动探测新增 Swift(`Package.swift`)、Gradle(`gradlew`)、Maven(`pom.xml`)、Elixir(`mix.exs`)。 -- 新增 `docs/portability.md`:通用化手册、字段与优先级、验证命令的运行环境约束、新项目接入清单。 -- OrzMCApp(Swift)画像落地:Ubuntu 可跑的 `check-platform-split.sh` + Swift 目录的受保护路径 + 经验文件指向 `docs/iteration-flow.md`。 - -### Added (verifyContainer) - -- 仓库画像支持 `verifyContainer`:验证命令在指定 Docker 镜像内执行(Swift / .NET / 特定 JDK 等 - 宿主没有的工具链),工作区挂载到 `/work`;容器模式下不在宿主预装依赖;Docker 不可用时明确失败。 -- 验证闸门同时冻结 `verifyContainer` 与命令引用脚本的内容哈希。 +**护栏(runner 侧执行,prompt 只是提示)** -### Added (runsOn) - -- 仓库画像支持 `runsOn`(字符串或 label 数组):App 模式下,dispatcher 不再在 hub 上直接执行,而是 - `workflow_dispatch` `ai-run.yml` 到指定 label 的 runner(自托管 macOS/Windows 可用)。 -- `ai-run.yml`:在目标 runner 上签发目标组织的 installation token、克隆目标仓库、运行标准 runner。 -- `ghapp-scan` 增加 `actions: write`(仅用于 dispatch;App token 无法 dispatch hub 工作流)。 -- 无匹配 runner 时任务保持排队(不静默回退 ubuntu),文档给出取消/补 runner 的指引。 - -### Fixed (retry semantics) - -- `ai-decide retry` 之前无效:Issue 重新排队后 dispatcher 仍以"已有 open PR"为由跳过 - (`skip ... (handled/running/pr open)`),只能手动关 PR。 -- 现在以**标签**为准:有 `ai` 且无 `ai-pr`/`ai-failed`/… 就是要求重跑;重跑删除重名分支 - (旧 PR 自动关闭),在新基线上重做并开新 PR。新增 `handledByLabels()` + 测试。 -- 看门狗的自愈结果不再被 dispatcher 过滤掉(`action: none` 但有 healing 时也会打印)。 - -### Added (self-healing branches) - -- 推送前 `git fetch` 基线 + rebase:基线在运行期间前进时不再产出 `DIRTY` PR;rebase 变了就重新验证。 -- 推送被拒(竞态)自动 rebase 并重试一次;推送改用 `--force-with-lease`(只覆盖自己的分支)。 -- 真冲突:abort rebase、列出冲突文件、Issue 打 `ai-needs-input`(`retry` 可在最新基线上重做)。 -- `ai-watch` 自愈:对 `DIRTY`/`BEHIND` 的 `ai/issue-*` 分支自动 "Update branch",真冲突才交给人。 -- 测试:`test/git.test.ts`(真实 bare remote:无变化 / rebase / 冲突 abort / fetch 失败 / force-push)、 - `test/watch.test.ts`(只挑 `ai/issue-` 且过期/冲突的 PR)。 +- 独立验证与失败自动重试:agent 结束后 runner 自己跑仓库检查,失败把输出反馈给 agent 重试(`AI_MAX_ATTEMPTS`,默认 3)。 +- 变更审计 `src/policy.ts`:路径白名单(拒绝 `.github/workflows/**`、`.github/actions/**`、`LICENSE`)、剔除 vendored/生成目录、扫描新增行的密钥;`agent-runner/**`、`.github/**`、`scripts/**` 打 `ai-core` 供人工审查。 +- 环境白名单 `src/env.ts`:agent 子进程拿不到 `GH_TOKEN` / `GITHUB_TOKEN` / `EASYGH_PR_TOKEN`;`git` 推送凭据在 agent 阶段从工作树移除(内存暂存,推送前恢复)。 +- 原子认领锁 `ai-lock-issue-`(tag ref CAS,按 TTL 回收僵尸锁)。 +- 时间预算 `AGENT_BUDGET_MS` / `PI_TIMEOUT_MS` / `VERIFY_TIMEOUT_MS` / `DISPATCH_BUDGET_MS`。 +- `.github/CODEOWNERS`:`.github/**`、`agent-runner/**`、`scripts/**`、`eval/**`、`LICENSE` 必须 code owner 审查。 -### Added (docs) +**自动化(最小人工介入)** -- `docs/usage.md`:使用手册(三种运行方式、怎么写 Issue、状态机、风险分级、五种人工动作、配置速查、故障排查、安全边界)。 -- `README.md` 增加"从这里开始"入口,测试数量与目录结构更新。 +- 风险分级 `src/risk.ts`:low / medium / high + 自动合并谓词;high 一律草稿 PR。 +- `AI_AUTOMERGE=off|probation|on`:仅 low 风险且验证可信时 `gh pr merge --auto`;probation 只信任仅文档/测试的改动。 +- 结构化阻塞:agent 写 `EASYGH_BLOCKED.md` → `ai-needs-input`,评论提问并停止,不建 PR。 +- 每日配额 `AI_MAX_PRS_PER_DAY`(默认 10),超限标 `ai-deferred`。 +- 人工入口 `.github/workflows/ai-decide.yml`:retry / cancel / answer / waive / set-automerge,带权限校验与 `easygh-decision` 审计。 +- 合并后看护 `.github/workflows/ai-watch.yml` + `src/watch.ts`:main CI 红且由 AI 合并且该提交 `push` 失败 → 事故 Issue + revert PR + 熔断(`AI_AUTOMERGE=off`);读不到 workflow runs 时显式 `skipped`。定时/安全扫描不误报。 +- 周度复盘 `ai-retro.yml` + `src/retro.ts`:失败签名聚类开 `retro` Issue(不带 `ai`,由人决定是否执行);`EASYGH_RETRO_REPOS` 支持多仓库。 +- 评测 `src/eval.ts` + `eval/tasks/`:冻结任务 + 隐藏测试,输出 pass@1。 +- 经验注入:`docs/learnings.md`(或画像 `learningsFile`)按相关性取 2 段注入 `TASK.md`。 +- 运行指标 `metrics.json`(artifact + 单行 JSON 日志)。 -### Added (workflow guard) +**通用化(适配任意项目)** -- `test/env-forwarding.test.ts`:workflow 必须转发每一个 hub 配置变量,并反向检查变量表不腐烂。 - 顺带修掉两处真实缺口:`EASYGH_PROVIDER`(三个 workflow 全缺)、`AI_MAX_ATTEMPTS`(`ghapp-scan` 缺)。 -- `prompts/strict/`:示例变体(强制测试、禁新依赖、禁改公共 API),文档说明如何按项目定制。 +- 仓库画像 `src/profile.ts` + `config/repos.json`:验证命令、受保护/禁止/敏感/忽略路径、依赖清单、经验文件、默认 agent/model、重试与配额。 +- `verifyContainer`:验证在指定 Docker 镜像里跑(宿主没有的工具链),工作区挂到 `/work`;Docker 缺失时明确失败。 +- `runsOn`:任务交给指定 label 的 runner(自托管 macOS/Windows),由 `ai-run.yml` 执行;无匹配 runner 时排队、不静默回退。 +- 自动探测新增 Swift / Gradle / Maven / Elixir(原有 npm / cargo / go / pytest)。 +- 提示词变体:`AI_LOCALE` + 画像 `locale` + `promptsDir`/`EASYGH_PROMPTS_DIR`,解析顺序「变体+语言 → 变体+默认 → 共享+语言 → 共享+默认」;内置 `prompts/zh-cn/`,示例变体 `prompts/strict/`。 +- 平台抽象 `src/providers/`:Issue/标签/评论/PR/auto-merge/锁/事故闭锁统一接口 + capabilities;`EASYGH_PROVIDER` 选实现,未实现即报错。 +- 分支自愈:推送前 rebase(基线动过则重新验证)、推送被拒自动重试、`--force-with-lease`;`ai-watch` 对 `DIRTY`/`BEHIND` 的 `ai/issue-*` 自动 "Update branch"。 -### Added (prompt i18n) +**文档与测试** -- `AI_LOCALE`(环境/仓库变量)+ 画像 `locale`:渲染对应语言的 `TASK.md`,未知语言回退英文。 -- 画像 `promptsDir` / `EASYGH_PROMPTS_DIR`:按仓库定制模板变体(`prompts//.md` 优先)。 -- 解析顺序:变体+语言 → 变体+默认 → 共享+语言 → 共享+默认;非法 locale/目录(含 `..`)直接丢弃。 -- 内置简体中文模板 `agent-runner/prompts/zh-cn/`,`prompts/README.md` 说明规则。 -- 测试:locale/目录规范化、回退链、中英 token 集合一致性、渲染替换(79 个用例)。 +- `docs/usage.md`(使用手册)、`docs/portability.md`(画像与接入)、`docs/other-orgs.md`(多组织)、`docs/ai-workflow.md`(端到端设计)。 +- 测试套件 `agent-runner/test/`:93 个用例(`npm run check` = typecheck + 测试),含真实 bare remote 的 git 集成测试与 workflow env 转发守卫。 +- `scripts/enable-ai-gate.sh`:给已有分支保护的仓库统一配置必需检查 + 0 批准 + admin 应急绕过;`scripts/ghapp-manifest.mjs` 创建组织自有 App;`scripts/install-to-repo.sh` 安装 Mode 1/2。 -### Added (provider seam) +### Changed -- `agent-runner/src/providers/`:平台抽象层(`types.ts` 接口 + capabilities、`github.ts` 唯一实现、`index.ts` 注册表)。 -- `main.ts` 所有平台调用改为走 `resolveProvider()`;`EASYGH_PROVIDER` 选择实现,未实现的平台会明确报错,不静默回退。 -- 抽象范围:Issue/标签/评论/PR/auto-merge/认领锁/事故闭锁;GitHub 专属能力(App 发现、workflow dispatch、rulesets)通过 capabilities 标记。 -- 测试:注册表、默认值、环境变量、未实现平台报错、自定义 provider 可注册(63 个用例)。 +- 检查命令在 agent 运行前冻结;检查配置被改动时执行冻结版本并标 `ai-verify-changed`,不再把"跳过验证"当作"验证通过"。 +- App 轮询模式的 `easygh-ai` 标记仅接受 OWNER/MEMBER/COLLABORATOR 作者,防止外部驱动注入。 +- 重新排队以**标签**为准(`ai` 在、`ai-pr`/`ai-failed` 等不在即为重跑),不再因为存在旧 PR 而跳过。 +- 移除 workflow 中无效的 "Skip already-handled issues" 步骤(步骤内 `exit 0` 不会跳过后续步骤),去重统一由 runner 负责。 -### Changed +### Fixed -- 检查命令在 agent 运行前冻结;若检查配置被改动,执行冻结版本并标记 `ai-verify-changed`,不再把"跳过验证"当作"验证通过"。 -- App 轮询模式:`easygh-ai` 标记仅接受 OWNER/MEMBER/COLLABORATOR 作者,防止外部驱动注入。 -- 移除 workflow 中无效的 "Skip already-handled issues" 步骤(步骤内 `exit 0` 并不会跳过后续步骤),去重统一由 runner 负责。 +- `ai-decide retry` 之前无效:dispatcher 以"已有 open PR"为由跳过;现在重跑会删重名分支(旧 PR 随之关闭)、在最新基线上重做并开新 PR。 +- 两个 AI PR 改同一文件后产生 `DIRTY` PR:改为推送前 rebase + 看门狗 "Update branch";真冲突则 `ai-needs-input` 并列出文件。 +- workflow `env:` 漏转发导致变量静默失效:`EASYGH_PROVIDER`(三个 workflow)、`AI_MAX_ATTEMPTS`(`ghapp-scan`)、`AI_LOCALE`(`ghapp-scan`)。 +- 看门狗的自愈结果被 dispatcher 过滤(`action: none`)而不可见。 ### Verified -- `claude` 与 `codex` 两个 agent 已使用 DeepSeek 同一把 key 完成端到端验收(2026-09-09)。 +- `claude` 与 `codex` 使用同一把 DeepSeek key 完成端到端验收(2026-09-09)。 +- 真实链路:EasySticker(Node)、EasyBot(Rust)、OrzMCApp(Swift,画像 + 中文模板)Issue → PR → 零点击合并。 +- `runsOn` 交接链:`ghapp-scan` → `ai-run.yml` → 目标 runner,实测 Issue #168 → PR #169 自动合并。 ## [0.2.0] - 2026-09-09 diff --git a/README.md b/README.md index 0b506bf..da00c2b 100644 --- a/README.md +++ b/README.md @@ -47,19 +47,13 @@ Routing: issue label `agent:` > repo variable `AI_AGENT` > rules in - GitHub Actions minutes (free tier or paid) — the job runs a full Pi session, typically several minutes. - One provider API key stored as a repo secret: `DEEPSEEK_API_KEY` (DeepSeek V4; see below). - Repository variables (optional): `AI_MODEL` (default `deepseek-v4-flash`), `AI_THINKING` (default `high`), - `AI_MAX_ATTEMPTS` (default `3`, verification retries), `VERIFY_CMD` (override the check - command; default: auto-detect `check`/`verify`/`test`/`lint` in `package.json`, then - `cargo test` / `go test ./...` by language), - `AI_AGENT` (force a specific agent for every run; default: auto-route), - `AI_AUTOMERGE` (`off`/`probation`/`on`, default `off`), `AI_MAX_PRS_PER_DAY` (default 10), - `AI_REVIEWER` (cc'd when the agent needs a decision). - On EasyGithub itself (public repo) all of this is already configured; other repos need the - installer (`install-to-repo.sh`) or the App to set it up. -- **Zero-file targets (App mode)** get their verification command from the hub, since the target - has no variables of its own: `agent-runner/config/verify.json` (committed, reviewable), e.g. - `{"EasyIndie/EasyBot": { "cmd": "cargo test", "timeout_ms": 900000 }}`; the hub variable - `EASYGH_VERIFY_CMDS` (same JSON shape) overrides the file when set. + Optional variables (all listed with defaults in [docs/usage.md](docs/usage.md) §6): + `AI_MODEL`, `AI_THINKING`, `AI_AGENT`, `AI_MAX_ATTEMPTS`, `AI_AUTOMERGE`, `AI_MAX_PRS_PER_DAY`, + `AI_REVIEWER`, `AI_LOCALE`. +- **Zero-file targets (App mode)** get their verification command from the hub, because the target + has no variables of its own: `agent-runner/config/repos.json` (profile `verify`, committed and + reviewable) → legacy `config/verify.json` → hub variable `EASYGH_VERIFY_CMDS` (JSON map). + See [docs/portability.md](docs/portability.md). ### Model / provider @@ -80,7 +74,10 @@ compatibility layer needed**: ### Retrying after a failure -Remove the `ai-failed` label, then add `ai` again. Removing `ai-failed` is what re-arms the issue. +Preferred: run the `ai-decide` workflow with `action=retry` (see +[docs/usage.md](docs/usage.md) §5). It re-arms the issue, drops the old branch +(and with it the old PR) and redoes the work on the latest base. +Manually that is: remove `ai-failed`/`ai-needs-input`/`ai-deferred`, then add `ai` again. ### PR CI @@ -92,7 +89,7 @@ Every pull request (including AI pipeline PRs) runs `npm run check` via `.github - **组织内(EasyIndie)成员**:GitHub App 已全组织安装 → 用 **Mode 3**(零文件)。 - **外部/个人仓库**:仓库里不能只写注释就让 App 工作 → 用 **Mode 2**(推荐,1 个文件)或 **Mode 1**。 - (也可以自建同名 GitHub App 后获得 Mode 3,见 `docs/realtime.md`。) + (也可以自建同名 GitHub App 后获得 Mode 3,见 `docs/other-orgs.md`。) **Mode 3 — GitHub App (zero-file; EasyIndie org only).** A GitHub App (`easygithub-ai`, installed org-wide) lets the hub poll org Issues and write @@ -118,36 +115,16 @@ bash scripts/install-to-repo.sh EasyIndie/ # mode 2 caller bash scripts/install-to-repo.sh EasyIndie/ --copy # mode 1 ``` -### 30 秒快速上手(按模式) +### 快速上手 -**Mode 3(零文件 · EasyIndie 成员)** — 什么都不用装: -```bash -# 1) 在任意 EasyIndie 仓库开一个 Issue,标题/正文含 easygh-ai,或打上 ai 标签 -gh issue create -R EasyIndie/ --title "fix: xxx" --body "...\n\n" -# 2) 等 ≤5 分钟,hub 轮询发现后自动开 PR(标签/secret 都不需要你管) -``` - -**Mode 2(1 个文件 · 任何仓库)** — 安装一次即可用: -```bash -# 0) 前置:gh 已登录、对目标仓库有 admin、有 DeepSeek key(或准备手动设 secret) -gh repo clone EasyIndie/EasyGithub ~/easygh -# 1) 自动:建 caller workflow + 标签 + 开 PR(若能读到本地 DeepSeek key 则一并设 secret) -bash ~/easygh/scripts/install-to-repo.sh / -# 若提示跳过 secret:手动补一次 gh secret set DEEPSEEK_API_KEY -R /(值从 platform.deepseek.com 获取) -# 2) 合并安装 PR(gh pr list 找到编号后) -gh pr merge -R / -# 3) 用起来:给任意 Issue 打 ai 标签 -gh issue edit -R / --add-label ai -``` - -**Mode 1(全复制 · 任何仓库,需离线自包含)** — 同 Mode 2,仅安装命令加 `--copy`: -```bash -bash ~/easygh/scripts/install-to-repo.sh / --copy -# 之后同上:合并安装 PR → 打 ai 标签触发 -``` +三种模式的命令、触发方式与验收步骤统一写在 +**[docs/usage.md](docs/usage.md)(使用手册)**,这里只保留模式选型: -> 三种模式都支持:标签 `feature`/`bug` 选模板、`agent:claude`/`agent:codex` 选引擎; -> 验证失败自动重试(`AI_MAX_ATTEMPTS`),通过后才开 PR。更多见 [docs/agents.md](docs/agents.md)。 +| 你的情况 | 用哪个 | +|---|---| +| 就在 EasyIndie 组织内,目标仓库不想放文件 | Mode 3(App,零文件) | +| 任意仓库,允许放 1 个 workflow | Mode 2(caller,秒级触发) | +| 任意仓库,要求完全自包含、不依赖本仓库 | Mode 1(`--copy`,全复制) | Known platform limitation (verified): a reusable workflow invoked cross-repo cannot declare a `permissions` key (fails at queue time); write access comes @@ -173,21 +150,21 @@ Runs the exact same runner code locally (clone → branch → Pi → commit → .github/CODEOWNERS # which changes always need a human agent-runner/ # Agent Runner (TypeScript, zero runtime deps) config/repos.json # per-repo profiles (see docs/portability.md) - prompts/ # task templates (bug-fix / feature / review) + prompts/ # task templates (en + zh-cn + strict example) src/main.ts # orchestration src/risk.ts # risk tiers + auto-merge predicate src/profile.ts # per-repo profile (verify/paths/agent/model/runsOn/locale) src/providers/ # platform seam (github implemented) - src/prompt.ts, prompts/ # task templates (en + zh-cn + per-repo variants) + src/prompt.ts # template selection/rendering (locale + variants) src/git.ts, src/github.ts # git + gh wrappers src/agents/{types,pi,registry}.ts test/ # node:test suite (runs in CI) eval/tasks/ # frozen evaluation tasks (hidden tests) docs/learnings.md # curated context injected into TASK.md -scripts/ # dev-run.sh, create-labels.sh +scripts/ # installer, dev-run, labels, branch protection, App manifest ``` -Run `npm run check` before committing: it type-checks and runs the `node:test` suite (91 cases, +Run `npm run check` before committing: it type-checks and runs the `node:test` suite (93 cases, including a workflow-env forwarding guard). ## 参考文档 @@ -196,7 +173,6 @@ including a workflow-env forwarding guard). - [端到端 AI 开发工作流(自动化边界 / 人机分工)](docs/ai-workflow.md) - [适配不同项目(仓库画像 / 自动探测 / 接入清单)](docs/portability.md) - [多 Agent 启用与模型配置](docs/agents.md) -- [实时响应方案(事件驱动 vs 轮询)](docs/realtime.md) - [在其它组织中使用 EasyGithub](docs/other-orgs.md) ## Status & roadmap diff --git a/docs/agents.md b/docs/agents.md index c1f9eaf..27fb5df 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -101,7 +101,5 @@ DEEPSEEK_API_KEY # DeepSeek 平台 API Key,三个 Agent 共用 `bash scripts/dev-run.sh ` 固定使用 `AGENT=pi`。非 Pi Agent 的 自动安装/配置仅在 CI 中执行,本地运行 `claude` / `codex` 需手动安装并配置对应 CLI。 -## 官方参考 - -- Claude Code 接入(Anthropic 兼容端点): -- Codex 接入(Responses 端点 / ~/.codex 配置): +Codex 侧配置(Responses 端点 / `~/.codex/config.toml`)见 DeepSeek 官方文档: + diff --git a/docs/ai-workflow.md b/docs/ai-workflow.md index 9e270ce..916da31 100644 --- a/docs/ai-workflow.md +++ b/docs/ai-workflow.md @@ -169,6 +169,11 @@ gh api -X PATCH repos/EasyIndie/EasyGithub/branches/main/protection/required_pul | agent 环境白名单 | `agent-runner/src/env.ts` | | 凭据隐藏/恢复、安全提交 | `agent-runner/src/git.ts` | | 原子认领、草稿 PR、auto-merge、配额 | `agent-runner/src/github.ts` | +| 平台抽象(Issue/PR/锁/事故) | `agent-runner/src/providers/` | +| 仓库画像 / 验证环境 / runner 选择 | `agent-runner/src/profile.ts` + `config/repos.json` | +| 提示词选择与渲染(locale/变体) | `agent-runner/src/prompt.ts` + `prompts/` | +| 跨仓库调度与 runner 交接 | `agent-runner/src/dispatcher.ts` + `.github/workflows/ai-run.yml` | +| 分支新鲜度(rebase / force-with-lease) | `agent-runner/src/git.ts` | | 编排(预算、阻塞、分级、交付) | `agent-runner/src/main.ts` | | 指标记录 | `agent-runner/src/metrics.ts` | | 经验注入 | `agent-runner/src/learnings.ts` | @@ -178,24 +183,10 @@ gh api -X PATCH repos/EasyIndie/EasyGithub/branches/main/protection/required_pul | 合并后看护(hub + 目标仓库) | `agent-runner/src/watch.ts`(hub 用 CLI,目标仓库由 dispatcher 调用——同一实现) | | 周度复盘 | `.github/workflows/ai-retro.yml` | -## 10. 操作手册(人只学这几条) +## 10. 操作手册 -| 我想… | 怎么做 | -|---|---| -| 让 AI 做这个 Issue | 打 `ai` 标签(或 App 模式下成员写 `easygh-ai`) | -| 重试失败/阻塞/延后的任务 | Actions → `ai-decide` → `retry` | -| 回答 AI 的问题 | 直接评论(成员/协作者),然后 `ai-decide` → `answer`(附上回答内容) | -| 取消卡住的运行 | `ai-decide` → `cancel`(会删 `ai-running` 与锁) | -| 记录一次人工例外 | `ai-decide` → `waive`(只留审计,不绕过策略) | -| 开启/收紧自动合并 | `ai-decide` → `set-automerge`(`off` / `probation` / `on`;当前为 `on`) | -| 让高风险改动进主干 | 审查草稿 PR → 点 "Ready for review" → 批准合并(code owner 必须) | -| 回滚出事的 AI 合并 | 等 `ai-incident` Issue 里的 revert PR,批准合并即可 | -| 看一周发生了什么 | 每周一自动生成的 `retro` Issue(覆盖 `EASYGH_RETRO_REPOS` 里的仓库) | -| 恢复某个仓库的自动合并 | 关闭该仓库的 `ai-incident` Issue(熔断闭锁随之解除) | -| 度量一次 prompt/model 改动的收益 | `node agent-runner/src/eval.ts --task --model `,看 `pass@1` | - -相关变量:`AI_AUTOMERGE`(默认 off)、`AI_MAX_PRS_PER_DAY`(默认 10)、`AI_REVIEWER`(needs-input 时 cc 的人)、 -`EASYGH_WATCHDOG`(默认 `on`,跨仓库看护开关)、`EASYGH_RETRO_REPOS`(周报覆盖的仓库,逗号分隔)、`AI_AGENT`、`AI_MODEL`、`AI_MAX_ATTEMPTS`、`AGENT_BUDGET_MS`、`PI_TIMEOUT_MS`、`VERIFY_TIMEOUT_MS`。 +日常操作(提任务、读结果、`ai-decide` 五种动作、配置速查、故障排查)全部在 +**[usage.md](usage.md)**,本文不再重复,避免两份文档各自漂移。 ## 分支新鲜度(自愈) diff --git a/docs/other-orgs.md b/docs/other-orgs.md index a016927..9328cc2 100644 --- a/docs/other-orgs.md +++ b/docs/other-orgs.md @@ -75,11 +75,19 @@ gh run list -R / --workflow ai-agent.yml --limit 3 ### 1. 复制 hub Fork `EasyIndie/EasyGithub`,或 `git clone` 后推到自己的组织(public fork → Actions 依然免费)。 -### 2. 建 GitHub App 并安装 -在目标组织(Settings → Developer settings → GitHub Apps → New): -- **Permissions**:`Issues: Read & write`、`Contents: Read & write`、`Pull requests: Read & write`、`Metadata: Read-only` -- **Webhook**:取消勾选(用轮询;要做实时见 `docs/realtime.md` 方案 C) -- 生成 **Private key**,记录 **App ID** +### 2. 建 GitHub App 并安装(用脚本,别手点) + +```bash +node scripts/ghapp-manifest.mjs --org --out .tmp/ghapp --open +``` + +脚本走 App Manifest 流程,在**目标组织内**创建私有 App(必须是组织自有 App:别的组织/个人的 +私有 App 无法装到你的组织,公开 App 需要审核),自动写回 `EASYGH_APP_ID_` 与 +`EASYGH_APP_PRIVATE_KEY_`,并在本地回调页确认。手工创建也行,但要点一样: + +- **Permissions**:`Issues: Read & write`、`Contents: Read & write`、`Pull requests: Read & write`、 + `Actions: Read-only`(看护需要读 workflow runs)、`Metadata: Read-only` +- **Webhook**:不用勾(触发走轮询;实时化需要外部接收端,暂未实现) - **Install** 到目标组织(All repositories) ### 3. 配置 hub 的 secret / variable @@ -89,32 +97,25 @@ Fork `EasyIndie/EasyGithub`,或 `git clone` 后推到自己的组织(public | `EASYGH_APP_PRIVATE_KEY` | secret | App 私钥 PEM 全文 | | `EASYGH_APP_ID` | variable | App ID | | `DEEPSEEK_API_KEY` | secret | 你的 DeepSeek key | -| `EASYGH_ORG` | variable | 目标组织名(**已参数化**,默认 `EasyIndie`) | +| `EASYGH_ORGS` | variable | 组织列表(逗号分隔,如 `EasyIndie,OrzMC`);单组织仍可用 `EASYGH_ORG` | | `EASYGH_REPO_FILTER` | variable(可选) | 逗号分隔仓库白名单,如 `Org/a,Org/b` | | `EASYGH_MAX_ISSUES` | variable(可选) | 每次运行最多处理几个 Issue(默认 4) | -| `EASYGH_VERIFY_CMDS` | variable(可选) | JSON map,零文件仓库的验证命令;覆盖 `agent-runner/config/verify.json` | - -> **验证命令(零文件目标)**:因为目标仓库没有自己的 variables,App 模式从 **hub** 取验证配置: -> 提交在 `agent-runner/config/verify.json`(如 `{"Org/repo":{"cmd":"cargo test","timeout_ms":900000}}`), -> 或用 hub variable `EASYGH_VERIFY_CMDS`(同结构,优先级更高)。 -> 未配置时自动检测:`package.json` 脚本 → `cargo test` → `go test ./...` → `swift test` → 其它(见 `docs/portability.md`)→ 跳过。 -> 推荐把长期配置写进 `agent-runner/config/repos.json`(可 review),`EASYGH_VERIFY_CMDS` 仅作临时覆盖。 -> Mode 2 则在**目标仓库**设 `VERIFY_CMD`(caller 已接好 `vars.VERIFY_CMD`)。 +| `EASYGH_VERIFY_CMDS` | variable(可选) | JSON map,临时覆盖验证命令(首选画像 `config/repos.json`,其次 `config/verify.json`) | + +> **验证命令(零文件目标)**:目标仓库没有自己的 variables,所以验证配置放在 **hub**: +> 首选 `agent-runner/config/repos.json` 里的画像(`verify`,可 review、优先级最高); +> 兼容旧的 `agent-runner/config/verify.json` 与 hub variable `EASYGH_VERIFY_CMDS`(JSON map,临时覆盖)。 +> 都没配时自动探测(`package.json` 脚本 → `cargo test` → `go test ./...` → `swift test` → …), +> 探测不到就标记"未验证",不算通过。Mode 2 则在**目标仓库**设 `VERIFY_CMD`。 > -> **调优(实测数据,EasyBot Rust workspace)**:一次真实运行中 `cargo test` 耗时 -> 首次 ~1 分钟、修复后重跑 ~2.5 分钟;真正的大头是 AI agent(4~23 分钟)。 -> 所以**默认保留全量 `cargo test`**(覆盖最完整)。只有在确认编译确实成为瓶颈时才收窄: -> `cargo test -p `(仅测指定 crate,会漏掉其它 crate/bin 的回归)或 -> `cargo clippy --all-targets -- -D warnings`(静态检查,快但不跑测试)。 -> 大仓也可把 `timeout_ms` 调高(默认 900000 = 15 分钟)。 -> 另外:每次运行都会上传 `ghapp-dispatch-logs` artifact(TASK.md / `pi-*.jsonl` / `verify-*.log`), -> 排查“第一次为什么没过验证”直接下载即可。 +> 每次运行都会上传 artifact(`ai-issue-/`:`TASK.md`、agent 日志、`verify-*.log`), +> 排查"第一次为什么没过验证"直接下载即可。 ```bash gh secret set EASYGH_APP_PRIVATE_KEY -R / < app.private-key.pem gh secret set DEEPSEEK_API_KEY -R / gh variable set EASYGH_APP_ID -R / --body "" -gh variable set EASYGH_ORG -R / --body "" +gh variable set EASYGH_ORGS -R / --body "" ``` ### 4. 触发与验证 @@ -305,7 +306,7 @@ gh api -X PUT repos/OrzMC//branches/main/protection/required_status_checks [ ] 目标仓库有 admin 权限 [ ] DeepSeek key 就位 [ ] 路线 A:安装器已跑 + PR 已合并 + ai 标签可触发 -[ ] 路线 B:App 已建/已装 + 4 个 secret/variable 已配 + EASYGH_ORG 正确 +[ ] 路线 B:App 已建/已装 + 4 个 secret/variable 已配 + EASYGH_ORGS 正确 [ ] 路线 C:`EASYGH_ORGS` 已设 + App 已装到每个组织 + App 有 `Actions: Read-only` [ ] 路线 C:目标仓库已开 `allow_auto_merge` + 0 批准(单人)+ 必需检查 [ ] 验证:Issue 标签流 ai→ai-running→ai-pr,或 ghapp-scan 日志出现 === Org/repo #N === diff --git a/docs/portability.md b/docs/portability.md index 1f47e04..25e679a 100644 --- a/docs/portability.md +++ b/docs/portability.md @@ -232,10 +232,10 @@ providers/ ## 7. 仍然是“项目相关”的部分(有意保留) -- **提示词语气与语言**:`agent-runner/prompts/*.md` 是模板,按需改(属于流水线自身,改它需要走 PR)。 +- **提示词语气**:`agent-runner/prompts//*.md` 按需改(改模板属于改流水线,走 PR)。语言不用改模板:见 `locale` / `AI_LOCALE`。 - **`docs/learnings.md` 的内容**:每个仓库自己积累,流水线不自动写。 - **标签契约**(`ai`、`ai-*`):固定,避免每个仓库一套状态机。 -- **周报/评论的语言**:目前中文;需要多语言时再加 `AI_LOCALE`。 +- **周报/评论的语言**:固定中文(`AI_LOCALE` 只管 `TASK.md`)。 ## 8. 给 EasyGithub 自己加项目时的心态 diff --git a/docs/realtime.md b/docs/realtime.md deleted file mode 100644 index 745f1fc..0000000 --- a/docs/realtime.md +++ /dev/null @@ -1,152 +0,0 @@ -# 实时响应方案(Event-driven vs Polling) - -> EasyGithub 的任务触发与执行架构决策文档。三种"部署模式"见 -> [README](../README.md#deploy-to-another-repository-cross-repo-reuse) 与 [agents.md](agents.md); -> 本文聚焦**触发链路**:如何从"我打 `ai` 标签"最快、最省地走到"AI 开工"。 - -## 1. 一句话现状 - -任务触发有**两种通道**: - -> 2026-09 更新:EasyGithub 已转 **public**,hub 侧轮询与 AI 任务不再消耗私有分钟额度 -> (公共仓库 Actions 免费/无上限)。方案 B 的**配额成本顾虑已消除**,但仍有 ~5 分钟轮询延迟; -> 需要秒级响应仍要走事件驱动(方案 A/C/D)。 - -| 通道 | 延迟 | 成本 | 说明 | -| --- | --- | --- | --- | -| 事件驱动(webhook / 仓库内 workflow) | 秒级 | 只在真正有任务时花 | 理想形态 | -| 轮询(hub schedule) | 30 分钟级(默认) | 每次扫描都计费 | 当前 App 模式 | - -**成本本质**:GitHub 托管 runner 按 job 计费(向上取整≈1 分钟/job);Free 组织私有仓库 -额度 **2000 分钟/月**(同组织所有私有仓库共享,公共仓库无限免费)。轮询意味着"没任务也在烧分钟"。 - ---- - -## 2. 可行方案清单 - -### 方案 A —— 模式 2(caller 文件):仓库内原生事件触发 【实时 · $0 · 轻侵入】 - -目标仓库放置 1 个 ~15 行 workflow,监听自己的 `issues: labeled` 事件,调用 EasyGithub 的 -reusable workflow + composite action(runner 逻辑集中在 hub,`@main` 自动更新)。 - -```text -目标仓库 .github/workflows/ai-agent.yml (15行 caller) - └─ on: issues: [labeled] ← GitHub 原生秒级触发,无需任何外部服务 - └─ job: uses EasyIndie/EasyGithub/.github/workflows/ai-agent-reusable.yml@main -``` - -- **延迟**:秒级(实时) -- **成本**:轮询零开销;仅真实任务消耗(与任何方案相同) -- **侵入**:每仓库 1 个 yml + `DEEPSEEK_API_KEY` secret + 若干标签(installer 可一键完成) -- **前提**:仓库允许 Actions;EasyGithub 需开组织共享(已开) -- **工作量**:已完成并验证(install-to-repo.sh 默认模式) -- **缺点**:新仓库仍要跑一次安装器;secret/标签随仓库走 - -### 方案 B —— App 轮询(现状)【延迟 · 配额成本 · 零侵入】 - -hub 的 `ghapp-scan.yml` 定时跑,用 App 安装令牌跨仓库扫任务。 - -- **延迟**:`*/30` 默认 ≈ 30 分钟(可调) -- **成本**:每次扫描 1 job ≈ 1 分钟私有分钟;`*/30`≈1440 分钟/月(占额度 72%),`*/5`≈8600+/月(严重超支) -- **侵入**:零(目标仓库全零配置) -- **价值**:作为"兜底保险丝"低成本可用(如 `0 * * * *` 每小时 ≈720 分钟/月) - -### 方案 C —— App Webhook → Cloudflare Worker → repository_dispatch 【实时 · $0 · 零侵入 · 推荐终态】 - -唯一缺口是"App 收到 webhook 后把事件送进 hub Actions"需要一个公网接收端。 -用 **Cloudflare Worker(免费层 10 万次请求/天)** 做 40 行薄转发,成本 $0、无服务器常驻。 - -```text -GitHub App (easygithub-ai) - └─ Webhook: issues labeled / edited(+ 可选 issue_comment) - │ - ▼ - Cloudflare Worker(免费) - ├─ 校验 HMAC(webhook secret) - ├─ 过滤:label==ai 或 title/body 含 easygh-ai(仅限 OWNER/MEMBER/COLLABORATOR) - └─ 用 App 私钥(存 Worker secret)签安装令牌 - └─ POST repos/EasyIndie/EasyGithub/dispatches - │ repository_dispatch: ai-issue {repo, issue_number} - ▼ - hub workflow on: repository_dispatch - └─ 复用 dispatcher 的 ISSUE_TARGET 单仓模式直接跑现成 runner -``` - -- **延迟**:秒级 -- **成本**:Worker $0;hub 仅真实任务计费(与 A 相同) -- **侵入**:零 -- **改动**:① App 设置加 Webhook URL+Secret 并订阅 Issues;② 部署 Worker(需 Cloudflare 账号); - ③ hub 加 `repository_dispatch` 工作流 + dispatcher `ISSUE_TARGET` 模式;④ 移除/降频轮询 cron -- **注意**:Webhook 重试自带;worker 可去重;建议保留每小时轮询作保险丝 - -### 方案 D —— App Webhook → 自有小服务(`opc.jokerhub.cn` / EasyGate 隧道)【实时 · 低/免费 · 零侵入】 - -与 C 同构,仅接收端不同:在你们已有域名对应的服务器上跑一个几十行 Node 接收端 -(或经 EasyGate/EasyNet 把内网端口暴露成公网 https)。 - -- 成本:视现有服务器是否已付费(若已有则 ≈$0) -- 工作量大些:部署、守护进程、TLS、可用性责任自己背 -- 适合:已有常驻机器,且不想引入 Cloudflare 依赖时 - -### 方案 E —— 混合(推荐近期落地顺序) - -| 阶段 | 动作 | 结果 | -| --- | --- | --- | -| 现在 | 重要仓库用 **方案 A**(模式 2 caller)→ 秒级 | 主力实时,$0 | -| 现在 | App 轮询降为 **每小时保险丝**(`0 * * * *`) | 兜底,~720 分/月 | -| 之后 | 有空部署 **方案 C**(Worker)→ 全部仓库零文件实时 | 终态,停掉轮询 | - ---- - -## 3. 决策矩阵 - -| 方案 | 实时 | 轮询开销 | 目标仓库侵入 | 新增基础设施 | 工作量 | -| --- | --- | --- | --- | --- | --- | -| A caller 文件 | ✅ 秒级 | 无 | 1 yml+secret+标签 | 无 | ✅ 已完成 | -| B App 轮询 | ❌ 30min | 高(占额度) | 零 | 无 | ✅ 已完成 | -| C Worker 转发 | ✅ 秒级 | 无(可留保险丝) | **零** | Cloudflare(免费) | 中 | -| D 自有小服务 | ✅ 秒级 | 无 | 零 | 已有机器/网关 | 中 | -| E 混合 | ✅ | 低(仅保险丝) | 视阶段 | 可选 | 渐进 | - -**建议默认答案**: -- 要"最省 + 实时 + 接受 1 文件" → **A** -- 要"零文件 + 实时 + $0" → **C**(需要一个 Cloudflare 账号) -- 兜底一律保留 **每小时轮询**(低成本保险丝,防漏事件) - ---- - -## 4. 实施清单(决定后照此执行) - -### 方案 C 具体改动 -1. GitHub App(easygithub-ai)设置: - - Webhook URL = Worker 地址;Webhook secret 生成并同存 hub/Worker - - Subscribe: **Issues**(labeled/opened/edited/unlabeled 足够) -2. Worker:`git clone` 风格部署,代码含:HMAC 校验、事件过滤、JWT→installation token、 - POST repository_dispatch(payload: `repository`, `issue_number`);App 私钥存 Worker secret -3. hub: - - dispatcher 增加 `ISSUE_TARGET="owner/repo#N"` 单任务模式(跳过全仓扫描) - - 新工作流 `ghapp-dispatch.yml`:`on: repository_dispatch: types: [ai-issue]` - → mint token → 跑 dispatcher(ISSUE_TARGET) - - `ghapp-scan.yml` cron 改 `0 * * * *`(保险丝) -4. 实测:零配置新仓库打 `ai` 标签 → 秒级出 PR - -### 方案 A 已可用 -```bash -bash scripts/install-to-repo.sh EasyIndie/ # 默认 caller -bash scripts/install-to-repo.sh EasyIndie/ --copy # 若需全复制 -``` - ---- - -## 5. 附:实测沉淀的平台约束(影响所有方案) - -- 组织内私有仓库共享 **2000 分钟/月**(Free);公共仓库不计费 → 也可考虑把 hub 或目标公开 -- GitHub App 安装令牌 **不支持 Search API**、不支持 `gh --paginate`(dispatcher 用逐仓列 Issue) -- `gh api -f` 在无 `-X` 时会当 POST;查询参数走 URL(如 `?state=open`) -- reusable workflow 跨仓库调用**不能声明 `permissions`**(启动即失败)→ 权限放 caller/仓库默认 -- workflow_call 的 inputs/secrets 标识符**不能用连字符**、不能在 `steps.env` 引用 inputs -- GitHub 会拦截"由 Actions 创建的 PR"所触发的工作流(需人工/API 批准)→ AI 修复循环尽量跑在 - actor 为人类的事件链(issues labeled / repository_dispatch 由人触发时)内 -- cron 最小粒度 5 分钟;schedule 也计入计费 - -> 决策记录:2026-09 于 EasyIndie 组织实测(三种模式均已端到端验证,含轮询与各约束)。 diff --git a/docs/usage.md b/docs/usage.md index 949122d..6b39ba4 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -261,5 +261,5 @@ Secrets:`DEEPSEEK_API_KEY`(模型)、`EASYGH_APP_PRIVATE_KEY[_]`(Ap 改动流水线本身时: - [ ] 只走分支 → PR → 必需检查 → 合并(不要直推 main) -- [ ] `npm run check`(typecheck + 91 个测试)+ `actionlint` +- [ ] `npm run check`(typecheck + 93 个测试)+ `actionlint` - [ ] 改 `.github/workflows/**` 属于高风险,务必人工复核