| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat: 适配 GitHub 开源 - 双 provider + 双渠道发布 (merge request !156) Squash merge branch 'feat/github-adapt' into 'master' ## 目标 让 `teamai-cli` 同时支持 **GitHub** 和腾讯工蜂(TGit)两种 git provider,并支持双渠道发布到公网 npm (`teamai-cli`) 和内网 tnpm (`@tencent/teamai-cli`)。 ## 主要改动 ### 1. Provider 抽象 - 新增 `src/providers/github/` 完整实现 GitHubProvider - `gh-cli.ts` 支持 `gh` CLI 和 `GITHUB_TOKEN` 两种认证 - `createRepo` 通过 REST API (`/user/repos` 或 `/orgs/:org/repos`) - `createPullRequest` 优先用 gh CLI,fallback 到 REST API - `registry.ts` 注册 GitHubProvider,bare `owner/repo` 默认改为 github - `createPullRequest` 接口改为 `Promise<string>`(GitHub REST 异步需要) ### 2. 发布配置 - 主包名改为 `teamai-cli`(公网 npm) - 删除 `publishConfig.registry`,改由 workflow 控制 - `src/update.ts` 从 `package.json` 动态读包名,按 `@tencent/` 前缀切换 tnpm vs 公网 npm;支持 `TEAMAI_NPM_REGISTRY` 环境变量覆盖 - `.coding-ci.yaml` 发布前用 `npm pkg set name` 改名为 `@tencent/teamai-cli` 再发 tnpm,保留内网镜像包能力 - `package.json` `files` 字段排除 source map,包体积 275KB → 105KB ### 3. CI - 新增 `.github/workflows/ci.yml`(Node 20/22 × ubuntu/macos 矩阵 + 可选 e2e job) - 新增 `.github/workflows/release.yml`(tag `v*.*.*` 触发发布到公网 npm) - 保留 `.coding-ci.yaml` 给腾讯 Coding CI 继续发 tnpm ### 4. 测试 - 新增 30 个 GitHub provider 单元测试,覆盖 URL 解析、token 解析、clone、createRepo、createPR(CLI + API fallback) - `init.test.ts` TGit 专用用例改用完整 URL,避免被新 github 默认拦截 - `e2e.test.ts` 通过 `TEAMAI_TEST_PROVIDER` 支持 GitHub clone ### 5. 文档 + 开源标配 - README 改开源视角(公网 npm 为主,tnpm 收进折叠块) - 新增 `docs/providers.md` 详细说明 GitHub / TGit 两个 provider 的差异与认证 - 更新 `CLAUDE.md` 说明双包策略 - 新增 `LICENSE`(MIT) - 新增 `.github/CONTRIBUTING.md` / PR 模板 / 2 个 issue 模板 - `.gitignore` 增加 `.npmrc` / `.env` ### 6. 其他 - `src/source.ts` 订阅源名字推断改为通用 URL 解析,兼容 github.com 等 - `package.json` 新增 `homepage` / `bugs` / `author` email 字段 ## 修复(来自 e2e 测试反馈) 最后一个 commit `9b98edd` 修了端到端测试发现的 3 个 GitHub provider 回归 bug: | # | 文件 | 问题 | 修复 | |---|------|------|------| | 1 | `src/doctor.ts` | 不识别 project scope 配置,永远读 `~/.teamai/config.yaml`,导致 GitHub 项目下 doctor 把 provider 误判为 tgit,触发 "gf CLI is installed/authenticated" 错误检查 | 改用 `detectProjectConfig() ?? loadLocalConfig()` 模式,配置路径标签改为实际路径 | | 2 | `src/utils/git.ts` + `src/push.ts` + `src/team-push.ts` + `src/roles-cmd.ts` | `master` 分支硬编码 5+ 处。GitHub 默认 `main` 仓 push 100% 失败,PR 创建报 `Base ref must be a branch / No commits between master and...` | 新增 `getDefaultBranch(localPath)` helper(优先 `origin/HEAD`,其次试 `origin/main` → `origin/master`,兜底 `main`),所有调用点统一动态解析。结果按 `localPath` 缓存避免重复 git 调用 | | 3 | `src/source.ts` | `source add` 直接 `git.clone(source.repo, ...)`,对 owner/repo 短格式或私有 GitHub 仓都会失败 | 改为 `detectProvider() → provider.cloneRepo()`,复用主仓 clone 同一套认证逻辑 | 测试侧同步: - `git.test.ts` 改造 6 个用例使用参数感知的 revparse mock,新增 1 个 "默认分支为 main" 用例 - `doctor.test.ts` 补 `detectProjectConfig` 的 mock 默认值 ## 兼容性 - 现网存量用户的 `teamai.yaml` 里 `provider: tgit` 会继续走 TGit 路径,零影响 - tnpm 包 `@tencent/teamai-cli` 继续发布,腾讯内部用户安装命令不变 - 只有全新 init 且传 bare `owner/repo` 短格式时默认走 github(原来默认 tgit) ## 验证 ### 自动化 - `npx tsc --noEmit` — 0 错误 - `npx vitest run` — **834 passed** - `npm run build` — 成功 ### 端到端测试 (人工) 测试环境(完全隔离,零污染本机 ~/.teamai): ```bash # 1. 打公网包 + 装到隔离 prefix npm pack mkdir -p /tmp/teamai-test-install && cd /tmp/teamai-test-install npm install --no-save /path/to/teamai-cli-0.14.3.tgz TBIN=/tmp/teamai-test-install/node_modules/.bin/teamai # 2. 创建 GitHub 私有测试仓 gh repo create hsuchifeng/teamai-cli-test --private --add-readme # 3. 沙盒目录 + project scope(隔离的关键) mkdir -p /tmp/teamai-gh-e2e && cd /tmp/teamai-gh-e2e git init && echo "# sandbox" > README.md && git add . && git commit -m initial # 4. init(核心:测试 provider 识别 + clone + 注册 member + push main) $TBIN init --scope project --repo hsuchifeng/teamai-cli-test # 5. 跑通 14+ 个命令(详见下表) ``` | 命令 | 结果 | 备注 | |------|------|------| | `init` | ✅ | provider 自动识别 github,gh CLI 认证,clone + 默认 teamai.yaml + member 注册 + push main | | `status` / `list` / `members` | ✅ | 读类命令正确显示 project scope | | `doctor` | ✅ (修 bug 1 后) | 正确识别 GitHub provider,不再误检 gf | | `push --all` | ✅ (修 bug 2 后) | 创建真实 GitHub PR #1 base=main | | `pull` | ✅ | 双 scope 同步:user(TGit 78 skills) + project(GitHub 1 skill) | | `env add/list` + push | ✅ | 创建 GitHub PR #2 | | `tags add/list/subscribe` | ✅ | 标签管理正常 | | `source add/list/browse/remove` | ✅ (修 bug 3 后) | GitHub 跨团队订阅 | | `remove --dry-run` | ✅ | 预览正常;交互模式按设计 cancel | | `stats` / `digest` / `recall` / `contribute` / `save-session` | ✅ | help 与基本流程通过 | | `update --check` | ✅ | 正确去 `https://registry.npmjs.org` 查 `teamai-cli`(404 因未发布,验证双 registry 切换) | | `uninstall --force` | ✅ (有越权 bug,见下方 follow-up B) | 沙盒清理成功 | 测试产物:GitHub 仓 [hsuchifeng/teamai-cli-test](https://github.com/hsuchifeng/teamai-cli-test) PR #1 #2 已 merge,commits 完整保留作为证据。 ## 后续待补(不阻塞本次合入) 发布相关: - [ ] 公网 npm 账号注册 + 首次 `npm publish` 占坑(包名 `teamai-cli` 已确认可用) - [ ] 生成 npm Automation token 填到 GitHub Secrets `NPM_TOKEN` 供 `release.yml` 使用 - [ ] 确认最终开源 org(当前占位 `github.com/Tencent/teamai-cli`,可一行改) - [ ] 腾讯开源审批流程(push 到 `github.com/Tencent` 前置) - [ ] CLA-assistant 集成(接受外部贡献者前) 已知小问题(e2e 测试发现,未在本次修): - [ ] **A. token 写进 git remote URL** — `gh repo clone` 默认把 `gho_...` token 拼进 origin 的 https URL,建议 clone 完成后 sanitize remote - [ ] **B. uninstall 越权** — `--force` 在 project scope 下会清理 `~/.zshrc` 里 user 级的 env 注入块(应只清当前 scope 的 sentinel) - [ ] **C. roles init / tags add 等 admin 操作未自动 push** — 当前需手动 `teamai push`,符合现有设计但首次用户体验不够顺滑 | 5 个月前 | |
ci: add informational code-erosion (slop metrics) workflow (#588) * ci: add informational code-erosion (slop metrics) workflow Report SlopCodeBench verbosity/erosion metrics on every PR using the official scb-check tool, pinned to 0.2.0 (the first release with TypeScript support; 0.1.3 is Python-only). The workflow is informational and never blocks a merge: scb-check's exit code is swallowed, and the numbers are posted as a deduplicated PR comment with the run's job summary as a fallback (so fork PRs, whose token is read-only, still surface the report). Tests are excluded via scb-check.toml so metrics reflect the product surface. On TypeScript the ast-grep verbosity rule component is Python-only and contributes 0, so verbosity reflects clone + wrapper detection only; erosion is fully faithful. This caveat is documented in the bilingual docs/ci-code-erosion.{md,zh-CN.md}. * ci(code-erosion): add independent TS verbosity rule layer scb-check only runs its ast-grep rules on Python files, so on this TypeScript repo its verbosity rule component is always 0. This adds a standalone ast-grep pass with a small, hand-ported rule set to fill that gap, reported as a separate "Rule hits (TS verbosity layer)" section in the same non-blocking PR comment. Only purely structural rules are ported. Rules that hinge on truthiness or type semantics (len==0, ==True, redundant template strings) were tried and deliberately dropped: they are false positives in TypeScript, where arr.length>0 is idiomatic and x!==true is not equivalent to x===false (TS has undefined). Ported rules verified against src/ for false positives: unnecessary-else-after-return, empty-catch-block, redundant-ternary-same, if-return-boolean-literal, return-ternary-boolean-literal, duplicated-if-condition, self-assignment. Rules use severity: hint and the scan step has `|| true`, so the layer never blocks CI. Bilingual docs updated with the honest scope: this is an extra signal, not a reproduction of the paper's verbosity number. * ci(code-erosion): slim down the PR comment, defer detail to docs The comment carried long inline explanations (verbosity footnote, rule-layer paragraph). Move the prose to docs/ci-code-erosion.md and keep the comment to numbers plus a one-line pointer. Also replace the ambiguous "(informational)" tag with plain "never blocks the merge". * ci(code-erosion): drop the two repeated doc links in the comment The top line already points to docs/ci-code-erosion.md; the verbosity footnote and rule-layer note repeated the same link. Keep one pointer. | 20 天前 | |
ci: add informational code-erosion (slop metrics) workflow (#588) * ci: add informational code-erosion (slop metrics) workflow Report SlopCodeBench verbosity/erosion metrics on every PR using the official scb-check tool, pinned to 0.2.0 (the first release with TypeScript support; 0.1.3 is Python-only). The workflow is informational and never blocks a merge: scb-check's exit code is swallowed, and the numbers are posted as a deduplicated PR comment with the run's job summary as a fallback (so fork PRs, whose token is read-only, still surface the report). Tests are excluded via scb-check.toml so metrics reflect the product surface. On TypeScript the ast-grep verbosity rule component is Python-only and contributes 0, so verbosity reflects clone + wrapper detection only; erosion is fully faithful. This caveat is documented in the bilingual docs/ci-code-erosion.{md,zh-CN.md}. * ci(code-erosion): add independent TS verbosity rule layer scb-check only runs its ast-grep rules on Python files, so on this TypeScript repo its verbosity rule component is always 0. This adds a standalone ast-grep pass with a small, hand-ported rule set to fill that gap, reported as a separate "Rule hits (TS verbosity layer)" section in the same non-blocking PR comment. Only purely structural rules are ported. Rules that hinge on truthiness or type semantics (len==0, ==True, redundant template strings) were tried and deliberately dropped: they are false positives in TypeScript, where arr.length>0 is idiomatic and x!==true is not equivalent to x===false (TS has undefined). Ported rules verified against src/ for false positives: unnecessary-else-after-return, empty-catch-block, redundant-ternary-same, if-return-boolean-literal, return-ternary-boolean-literal, duplicated-if-condition, self-assignment. Rules use severity: hint and the scan step has `|| true`, so the layer never blocks CI. Bilingual docs updated with the honest scope: this is an extra signal, not a reproduction of the paper's verbosity number. * ci(code-erosion): slim down the PR comment, defer detail to docs The comment carried long inline explanations (verbosity footnote, rule-layer paragraph). Move the prose to docs/ci-code-erosion.md and keep the comment to numbers plus a one-line pointer. Also replace the ambiguous "(informational)" tag with plain "never blocks the merge". * ci(code-erosion): drop the two repeated doc links in the comment The top line already points to docs/ci-code-erosion.md; the verbosity footnote and rule-layer note repeated the same link. Keep one pointer. | 20 天前 | |
fix(code-knowledge): keep tree-sitter grammars off V8's optimizing Wasm tier on Node 24 (#860) (#861) On Node 24, V8's Turboshaft Wasm compiler exhausts its Zone memory while tiering up tree-sitter grammar code and aborts the process with "Fatal process out of memory: Zone" (nodejs/node#63421). The Swift grammar added in #842 hits it right after its first parse, so `teamai codebase --extract` on a repo with .swift files died with exit 133 and no fallback. Set --wasm-tier-up-filter to an index no grammar has before the WASM runtime starts, on Node 24 and later only. --liftoff-only has the same effect but Node 24 ignores it when set at runtime. Node 20 and 22 keep tier-up, which parses about 1.6x faster there. Add Node 24 to the CI matrix so the regression test runs where it can fail. Closes #860 Refs #842 | 9 天前 | |
ci(lint): add oxlint and fail CI on any warning (#828) (#839) * fix(tags,roles): honor --dry-run in tags subscribe, tags unsubscribe and roles set (#836) The three commands saved the local config and reset lastPullRev even under the global --dry-run, which is documented as "Preview mode, no changes made". Their siblings (tags add/remove, roles init/add/remove/ update) already return early with a [dry-run] message. The roles set preview names the additional roles it would save, including none, because a real run replaces the existing list. oxlint reported the unused options parameter in tagsSubscribe and tagsUnsubscribe; rolesSet has the same bug but reads options.add. * chore(lint): add oxlint with its default rules Pinned to an exact version so a new default rule arrives in its own PR, not as a CI failure on an unrelated one. The no-unused-vars options keep oxlint's _ ignore patterns and add ignoreRestSiblings, which the rest-omit in dashboard.ts relies on to keep config and roots out of /api/workspaces. * style(lint): apply oxlint safe fixes Drop redundant escapes in regex character classes and template literals, empty-object fallbacks in object spreads (spreading undefined adds nothing), and anchored regexes that are plain startsWith/endsWith checks. No behavior change. * refactor(lint): remove unused imports and an unused catch binding Applied with oxlint --fix-suggestions and reviewed by hand. Every removed whole import is a library module with no import-time side effects. * refactor(lint): remove dead code reported by no-unused-vars Each hit was checked against its callers and git history; none is missing wiring (the two that were, tags subscribe/unsubscribe, are fixed in the preceding commit). Removed: unused locals and functions, the options parameter of tagsList, rolesList and generateDigest (read-only commands), the never-read interactive option of importFromRepo, the empty test/e2e.mjs left over from the E2E migration, and a try/catch that only rethrew. new Array(n) becomes Array.from. No behavior change. * test(lint): fix lint hits in tests - contribute dry-run test asserted nothing; it now checks that the run leaves the repo/HOME tree unchanged (verified to fail when the dry-run early return is removed). - Drop a no-op expect(result).not.toThrow on a string. - Keep undefined in two optional-chain casts so a regression fails the assertion instead of throwing a TypeError. - Remove unused locals, helpers and imports; new Array(n) becomes Array.from. * refactor(lint): write control-character classes as \p{Cc} no-control-regex flags literal control ranges. \p{Cc} names the same set (C0, DEL, C1) and reads as what it means. Checked against the old classes on every code point from U+0000 to U+10FFFF: manifest-schema and agent-format match exactly, and contribute-check's normalization pipeline produces the same output. The test assertion is now stricter and checks every control character the sanitizer removes. * refactor(lint): remove disable directives for rules that are not enabled Four eslint-disable comments named rules this repo never ran (no-await-in-loop, @typescript-eslint/no-explicit-any), so they suppressed nothing. * ci(lint): fail CI on any oxlint warning (#828) npm run lint runs oxlint --deny-warnings and runs before the type check in both GitHub Actions and Coding CI. The repo is at zero warnings, so new code must stay clean. --report-unused-disable-directives also fails on a disable comment that suppresses nothing, so a suppression cannot outlive the code it was written for. CLAUDE.md, AGENTS.md, CONTRIBUTING.md and the PR template list the command so contributors and agents run it before opening a PR. Closes #828 * chore(lint): pin oxlint 1.16.0, the newest release that accepts Node 20.0 oxlint 1.17.0 and later declare engines.node ^20.19.0 || >=22.12.0, while the repo supports Node >=20. 1.16.0 declares >=8, supports --deny-warnings and --report-unused-disable-directives, and reports 0 warnings on this branch. * Revert "fix(tags,roles): honor --dry-run in tags subscribe, tags unsubscribe and roles set (#836)" This reverts commit 224d459c99de25e21c02e9109d467e3f2cacd19d. * refactor(lint): mark the unused options parameter of tags subscribe and unsubscribe With the #837 dry-run fix reverted out of this PR, both functions no longer read options. The underscore prefix keeps the signature and call sites unchanged, so #837 can rebase onto it by renaming the parameter back. * chore(lint): restore oxlint 1.85.0 This reverts commit e2347efa. oxlint is a devDependency, so its Node requirement (^20.19.0 || >=22.12.0) never reaches users installing teamai-cli, and CI's node-version 20 resolves to the latest 20.x. Staying on 1.85.0 keeps the #836 warning counts and the planned type-aware follow-up on the same version. * docs(contributing): note the Node version npm run lint needs * docs(agents): note the Node version npm run lint needs | 11 天前 | |
ci(lint): add oxlint and fail CI on any warning (#828) (#839) * fix(tags,roles): honor --dry-run in tags subscribe, tags unsubscribe and roles set (#836) The three commands saved the local config and reset lastPullRev even under the global --dry-run, which is documented as "Preview mode, no changes made". Their siblings (tags add/remove, roles init/add/remove/ update) already return early with a [dry-run] message. The roles set preview names the additional roles it would save, including none, because a real run replaces the existing list. oxlint reported the unused options parameter in tagsSubscribe and tagsUnsubscribe; rolesSet has the same bug but reads options.add. * chore(lint): add oxlint with its default rules Pinned to an exact version so a new default rule arrives in its own PR, not as a CI failure on an unrelated one. The no-unused-vars options keep oxlint's _ ignore patterns and add ignoreRestSiblings, which the rest-omit in dashboard.ts relies on to keep config and roots out of /api/workspaces. * style(lint): apply oxlint safe fixes Drop redundant escapes in regex character classes and template literals, empty-object fallbacks in object spreads (spreading undefined adds nothing), and anchored regexes that are plain startsWith/endsWith checks. No behavior change. * refactor(lint): remove unused imports and an unused catch binding Applied with oxlint --fix-suggestions and reviewed by hand. Every removed whole import is a library module with no import-time side effects. * refactor(lint): remove dead code reported by no-unused-vars Each hit was checked against its callers and git history; none is missing wiring (the two that were, tags subscribe/unsubscribe, are fixed in the preceding commit). Removed: unused locals and functions, the options parameter of tagsList, rolesList and generateDigest (read-only commands), the never-read interactive option of importFromRepo, the empty test/e2e.mjs left over from the E2E migration, and a try/catch that only rethrew. new Array(n) becomes Array.from. No behavior change. * test(lint): fix lint hits in tests - contribute dry-run test asserted nothing; it now checks that the run leaves the repo/HOME tree unchanged (verified to fail when the dry-run early return is removed). - Drop a no-op expect(result).not.toThrow on a string. - Keep undefined in two optional-chain casts so a regression fails the assertion instead of throwing a TypeError. - Remove unused locals, helpers and imports; new Array(n) becomes Array.from. * refactor(lint): write control-character classes as \p{Cc} no-control-regex flags literal control ranges. \p{Cc} names the same set (C0, DEL, C1) and reads as what it means. Checked against the old classes on every code point from U+0000 to U+10FFFF: manifest-schema and agent-format match exactly, and contribute-check's normalization pipeline produces the same output. The test assertion is now stricter and checks every control character the sanitizer removes. * refactor(lint): remove disable directives for rules that are not enabled Four eslint-disable comments named rules this repo never ran (no-await-in-loop, @typescript-eslint/no-explicit-any), so they suppressed nothing. * ci(lint): fail CI on any oxlint warning (#828) npm run lint runs oxlint --deny-warnings and runs before the type check in both GitHub Actions and Coding CI. The repo is at zero warnings, so new code must stay clean. --report-unused-disable-directives also fails on a disable comment that suppresses nothing, so a suppression cannot outlive the code it was written for. CLAUDE.md, AGENTS.md, CONTRIBUTING.md and the PR template list the command so contributors and agents run it before opening a PR. Closes #828 * chore(lint): pin oxlint 1.16.0, the newest release that accepts Node 20.0 oxlint 1.17.0 and later declare engines.node ^20.19.0 || >=22.12.0, while the repo supports Node >=20. 1.16.0 declares >=8, supports --deny-warnings and --report-unused-disable-directives, and reports 0 warnings on this branch. * Revert "fix(tags,roles): honor --dry-run in tags subscribe, tags unsubscribe and roles set (#836)" This reverts commit 224d459c99de25e21c02e9109d467e3f2cacd19d. * refactor(lint): mark the unused options parameter of tags subscribe and unsubscribe With the #837 dry-run fix reverted out of this PR, both functions no longer read options. The underscore prefix keeps the signature and call sites unchanged, so #837 can rebase onto it by renaming the parameter back. * chore(lint): restore oxlint 1.85.0 This reverts commit e2347efa. oxlint is a devDependency, so its Node requirement (^20.19.0 || >=22.12.0) never reaches users installing teamai-cli, and CI's node-version 20 resolves to the latest 20.x. Staying on 1.85.0 keeps the #836 warning counts and the planned type-aware follow-up on the same version. * docs(contributing): note the Node version npm run lint needs * docs(agents): note the Node version npm run lint needs | 11 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 5 个月前 | ||
| 20 天前 | ||
| 20 天前 | ||
| 9 天前 | ||
| 11 天前 | ||
| 11 天前 |