feat(git): route independent-clone reports onto teamai-reports - #489
feat(git): route independent-clone reports onto teamai-reports#489jimpablo wants to merge 2 commits into
Conversation
Independent git clones currently push members/sessions/votes/stats onto the default branch, so every member needs write access on main. Reuse the existing orphan-branch worktree writer: git-kind reports live beside the clone on teamai-reports; self stays nested under .teamai/; HTTP is unchanged. Empty-repo init may still seed teamai.yaml on the default branch; leftover report files on main are ignored. Closes Tencent#484
Review: one blocking bug — stale sibling reports worktree causes silent data lossNice work overall — Where: // Already a valid worktree — nothing to do.
if (await isGitRepo(wt)) {
return wt;
}Root cause: for git-kind, Trigger — a routine flow: Impact: every git op in the stale worktree throws Reproduction (real git, run against this PR head — fails):
Suggested fix (verified: turns the repro green, full suite still passes): if (await isGitRepo(wt)) {
try {
await createGit(wt).revparse(['--is-inside-work-tree']);
return wt;
} catch {
// stale/dangling worktree link (clone was re-cloned/pruned) — recreate below.
}
}The existing |
isGitRepo only checks that reports-wt has a .git file. After init replaces the clone, that file still exists but the backing gitdir is gone, so ensureReportsWorktree returned the husk and commitAndPushReports failed silently. Probe revparse --is-inside-work-tree and fall through to the existing remove+recreate path.
|
Thanks for the review and the repro. Fixed in d11e101: Added a real-git regression in CI on that commit is green. |
Summary
Independent git clones currently write
members/sessions/votes/stats/onto the default branch viapushRepoDirectly, so every member needs write access onmain. This reuses the existingteamai-reportsorphan-branch worktree writer that single-repo mode already uses.<dirname(localPath)>/reports-wt), so clonereset --hardcannot nest-destroy it.kind: selfkeeps today's nested<knowledgeDir>/reports-wt.kind: httpis unchanged (no git reports branch).initmay still pushteamai.yaml+ gitkeeps to the default branch so the knowledge tree exists; member YAML goes toteamai-reports.mainare not copied, not deleted, and not used as the source of truth after the switch.learnings/to ateamai-learningsbranch (direct push, no PR) #485 is separate).Closes #484
Type of Change
Test Plan
npx tsc --noEmit— cleannpx vitest runfocused suites — 117 tests passed, including:src/__tests__/git-kind-reports.test.ts(real git: write toorigin/teamai-reports, leftover clonemembers/ignored, empty-repo skeleton on default branch, dedicated-root guard)src/__tests__/self-mode-no-business-reset.test.ts(git-kind no longerreset --hards the clone)src/__tests__/members.test.ts(listMembersreads reports worktree; leftover clone YAML is not listed)src/__tests__/team-push-interventions.test.ts(git-kind auto-report usescommitAndPushReports, notpushRepoDirectly)npm run buildthen built CLI (dist/index.js) against a local bare remote whoseupdatehook rejects default-branch pushes:teamai init https://git.example.test/acme/team.git --scope user --force— English success;Member registered on the teamai-reports branchteamai session save --push --force --session-id s1 --scope user—Pushed: sessions/alice/2026-09.mdteamai pull— auto-report wrotestats/alice.yamlgit ls-tree origin/teamai-reportscontainedmembers/alice.yaml,sessions/alice/2026-09.md,stats/alice.yamlteamai.yaml+ knowledge gitkeeps (no new report files)~/.teamai/reports-wt); clone had nomembers/stats/sessions/docs/usage-guide.mdupdated so independent git clones also write reports toteamai-reports(learnings still on the default branch)Related Issues
Closes #484
Notes for Reviewers
initmember registration,session save --push, pull auto-report, Stop-hook votes.members,digest,stats,viz,pullvotes/stats index,recall,maintenance/paths,projects members(manifest still from knowledge clone).reportUsageToTeamstill has a no-config fallback thatpushRepoDirectlys the clone; productionpullnow always passesselfConfigfor non-HTTP repos.learnings/to ateamai-learningsbranch (direct push, no PR) #485 (learnings/→teamai-learnings) and Document branch layout and minimum Git permissions after reports/learnings leavemain#486 (permission-matrix docs).