feat(chat-workflow): auto-commit + push after natural finish

Merged
SW
5mo ago
+1877-0

Summary

Closes the auto-commit gap tracked in #605 (Tier 4 #12). When a chat workflow turn finishes naturally (not `tool-calls`) and the session has both `repo_owner` and `repo_name`, the workflow stages sandbox changes, generates a commit message via the gateway, commits, pushes to the session's branch, and emits a `data-commit` UIMessage chunk so the chat UI can show "Committing..." → "Committed at " live.

End-to-end flow

  1. `hasAutoCommitChanges` — fast `git status --porcelain` pre-flight (fail-open on errors)
  2. Emit `data-commit { status: "pending" }` to the SSE stream
  3. `runAutoCommit` → `performAutoCommit`:
    • Set auth URL on origin (`x-access-token:$GITHUB_TOKEN@github.com/...`)
    • `git add -A`
    • LLM commit message from `git diff --cached` (fallback: `chore: update repository changes`)
    • `git commit -m ''`
    • `git rev-parse HEAD` + `git symbolic-ref --short HEAD`
    • `GIT_TERMINAL_PROMPT=0 git push -u origin `
  4. Emit `data-commit { status: "success" | "error", url? }`

New files (TDD, 33 tests)

FileTestsPurpose
`lib/chat/auto-commit/performAutoCommit.ts`14Sandbox.exec orchestration with granular failure modes
`lib/chat/auto-commit/hasAutoCommitChanges.ts`5Fast pre-flight, fail-open on errors
`lib/chat/auto-commit/runAutoCommit.ts`4`"use step"` wrapping performAutoCommit
`lib/chat/auto-commit/buildCommitData.ts`7Pure helper: AutoCommitResult → UI chunk payload
`lib/chat/auto-commit/sendCommitChunk.ts`3`"use step"` writing data-commit chunks to the writable

Plus 5 new tests on `runAgentWorkflow.test.ts` covering the happy path, no-changes skip, missing repo identifiers, intermediate (`tool-calls`) finish, and the error path.

Suite: 3195 → 3233 passing.

Known limitation (separate follow-up)

The data-commit chunks are emitted live to the SSE stream but are NOT re-persisted onto the assistant message's `parts` column. On page refresh the chunk disappears — but the commit itself is permanent on GitHub (the URL in the chunk resolves). Re-persistence needs either:

  • A follow-up `persistAssistantMessage` call with the updated message containing the data-commit part, or
  • A new `updateChatMessageParts(id, parts)` helper since the current `upsertChatMessage` ignores duplicates.

This will be filed as a separate issue.

Test plan

  • 38 new unit tests pass
  • Full suite (3233/3233)
  • Lint / format / tsc clean
  • Preview E2E: trigger a chat that modifies files in the sandbox (e.g., "create a test.md file with hello world"), confirm:
    1. `data-commit { status: "pending" }` chunk in the SSE stream
    2. `data-commit { status: "success", url }` chunk follows
    3. New commit appears on GitHub at the URL in the chunk

🤖 Generated with Claude Code


Summary by cubic

Adds auto-commit and push after a natural chat finish, with live data-commit updates that persist on the assistant message so the Git card survives refresh. Repo owner/name are parsed from session.clone_url to prevent silent skips (Linear #605).

  • New Features

    • Runs only on natural finishes when repoOwner, repoName, and a sandbox exist; skips if no changes.
    • Emits data-commit chunks: { status: "pending" } then { status: "success" | "error", commitSha?, url? }; persists the resolved part to the message.
    • Commit pipeline: git add -A → LLM message from git diff --cached (fallback “chore: update repository changes”) → git commit → SHA + branch → GIT_TERMINAL_PROMPT=0 git push -u origin <branch>; sets origin to x-access-token:$GITHUB_TOKEN when available.
    • runAgentWorkflow forwards sessionTitle, repoOwner, repoName, and a wrapped SandboxState; orchestration lives in autoCommitChatTurn.
  • Refactors

    • Extracted generateCommitMessage, autoCommitChatTurn, and helpers; runAgentWorkflow now delegates via { ...input, ...result }.
    • generateCommitMessage now uses openai/gpt-5.4-nano and trims to 72 chars.
    • Moved the step boundary out of Supabase: updateChatMessage is pure; persistAssistantDataPart merges the part and writes the whole message so resolved data-commit persists across refresh.
    • Added parseGitHubRepoIdentifiers and expanded tests across auto-commit, persistence helpers, and Supabase update.