34ed127653
New <toast-host> overlay: components post 'toast' CustomEvents ({message, kind: success|error|info}) and it shows brief, auto-dismissing, bottom-right toasts (errors linger). <repo-menu> (git + coordination actions) and <pr-list> (create/merge) now post friendly success/error toasts instead of alert(); the activity feed still logs everything. Also adds the slice 11 CHANGELOG entry. Verified live: 'Checked for updates' toast shown.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
263 lines
17 KiB
Markdown
263 lines
17 KiB
Markdown
# Changelog
|
|
|
|
Append-only running history of all changes (AGENT.md §9.1). Newest last.
|
|
|
|
## 2026-09-19 — Project scaffold
|
|
- **What:** Initial runnable skeleton for the GitManager multi-repo dashboard.
|
|
Added the Go backend (`cmd/server/main.go` + `internal/{config,logging,git,repos,render}`),
|
|
the Echo HTTP server with `/`, `/help`, `/healthz`, and `/api/repos`, a
|
|
read-only repo scanner that discovers repositories under `GIT_REPO_ROOTS` and
|
|
keeps an in-memory index, the `<repo-list>` web component, shared design tokens
|
|
(`web/static/app.css`), page shells (`web/templates/{index,help}.html`), and the
|
|
dev tooling: `Dockerfile` (build/dev/runtime stages), `docker-compose.yml`,
|
|
`.air.toml`, `.env.example`, `.gitignore`, `go.mod`.
|
|
- **Why:** Stand up the architecture defined in AGENT.md so feature work can begin.
|
|
- **Affects:** whole repo (foundation); `components/repo-list`.
|
|
|
|
## 2026-09-19 — Repo detail panel
|
|
- **What:** Added the `<repo-detail>` component (right dock) that listens for
|
|
`repo:select` and shows a repo's remotes, local branches (current + upstream),
|
|
and 20 most recent commits. Backed by a new `GET /api/repo?path=` endpoint
|
|
(restricted to indexed repos) and new read-only git readers
|
|
(`LocalBranches`, `RecentCommits`, `RemoteDetails`) plus `repos.BuildDetail`
|
|
and `Index.Get`. `<repo-list>` now highlights the selected repo; `index.html`
|
|
lays the two panels out left/right; help page documents the detail view.
|
|
- **Why:** Make the dashboard drill into a single repository (the detail half of
|
|
the list+detail default in AGENT.md §4).
|
|
- **Affects:** `components/repo-detail`, `components/repo-list`,
|
|
`internal/git`, `internal/repos`, `cmd/server`, `web/templates`.
|
|
|
|
### Notes to confirm (from AGENT.md §11)
|
|
- **Go module path** is the placeholder `gitmanager`; change it if this gets a
|
|
canonical import path (e.g. a GitHub URL).
|
|
- All items in AGENT.md §11 (discovery strategy, background fetch, forge
|
|
providers, listen address, container credentials) remain open.
|
|
|
|
## 2026-09-19 — Redefine the app as a two-way Claude companion (contract only)
|
|
- **What:** Updated AGENT.md to make the Claude integration the defining pillar,
|
|
no code yet. §0 now states the two-way purpose (Claude↔app) and the
|
|
non-expert, GUI-first goal; added law §1.7 (one service layer behind both the
|
|
GUI and the MCP server); stack table gained MCP server (Go SDK over Streamable
|
|
HTTP at `/mcp`), SSE (app→browser), and flipped forge to Gitea-first read+write;
|
|
layout added `internal/{service,mcp,activity}`; §6 added the right-click
|
|
plain-language command vocabulary; **§8 rewritten** into "Claude integration"
|
|
(8.1 MCP server, 8.2 activity feed + active project, 8.3 graceful project
|
|
handoff, 8.4 forge read+write with "Merge & clean up"); §10 step 4 and §11
|
|
updated (three decisions resolved, new open items). `.env.example` now documents
|
|
`GITEA_TOKEN` (read+write scope).
|
|
- **Why:** Thomas described the real vision — the app should act as an extension
|
|
of Claude: usable like an MCP by Claude, notifying Claude of in-app actions to
|
|
stay in sync, cooperative project handoff when he's interrupted, plain-language
|
|
right-click commands for non-experts, and one-click "merge & clean up" so PRs
|
|
stop cluttering repos. Decisions locked: cooperative pull-first handoff; Gitea
|
|
writes enabled (confirmed per §1.4); MCP over HTTP `/mcp`.
|
|
- **Affects:** `AGENT.md`, `.env.example` (architecture/contract only — no code).
|
|
|
|
## 2026-09-19 — Service layer + MCP server (Claude integration, read tools)
|
|
- **What:** Slice 1 — extracted `internal/service`, the one capability layer both
|
|
the HTTP API and the MCP server call (§1.7); the `/api/repos` and `/api/repo`
|
|
handlers now route through it. Slice 2 — added `internal/mcp`: an MCP server
|
|
(`github.com/modelcontextprotocol/go-sdk` v1.8.0) served over Streamable HTTP at
|
|
`/mcp`, with read tools `list_repos` and `get_repo` as thin adapters over the
|
|
service. Added a round-trip test (`internal/mcp/mcp_test.go`) using a real temp
|
|
git repo + the in-memory MCP transport. Verified the HTTP `/mcp` handshake
|
|
locally and in Docker.
|
|
- **Why:** First step of the two-way Claude integration (AGENT.md §8.1) — prove
|
|
Claude can connect to the app over MCP before building deeper features on it.
|
|
- **Affects:** `internal/service` (new), `internal/mcp` (new), `cmd/server/main.go`,
|
|
`go.mod`/`go.sum`, `.air.toml`.
|
|
- **Gotcha:** Docker-on-Windows bind mounts do NOT deliver filesystem events, so
|
|
air's watch-based reload silently never fired. Fixed by enabling air polling
|
|
(`poll = true`, `poll_interval = 500` in `.air.toml`).
|
|
|
|
## 2026-09-20 — HTTPS for the MCP connector (local TLS via mkcert)
|
|
- **What:** Added an optional HTTPS listener alongside HTTP. New config
|
|
`HTTPS_ADDR`, `TLS_CERT_FILE`, `TLS_KEY_FILE`; when set, `cmd/server` starts
|
|
`e.StartTLS` on the same Echo app (best-effort — a missing cert logs a warning
|
|
and stays HTTP-only). docker-compose publishes `127.0.0.1:8443` and points the
|
|
TLS vars at `certs/localhost.pem` (mounted via the existing source mount).
|
|
`.gitignore` ignores `/certs/`; `.env.example` documents the mkcert steps.
|
|
- **Why:** Claude Desktop's custom MCP connector only accepts `https://` URLs.
|
|
Local TLS with an mkcert-trusted cert lets `https://localhost:8443/mcp` work
|
|
without exposing the unauthenticated app via a public tunnel (AGENT.md §8.1).
|
|
- **Affects:** `internal/config`, `cmd/server/main.go`, `docker-compose.yml`,
|
|
`.gitignore`, `.env.example`, `AGENT.md` (§8.1, §11).
|
|
- **Host setup (user-run):** the local CA install (`mkcert -install`) is a
|
|
security-settings change performed by the user, not the app.
|
|
|
|
## 2026-09-20 — Connect Claude Desktop via local stdio bridge (mcp-remote)
|
|
- **What:** Corrected the Claude Desktop connection method in AGENT.md (§8.1, §11).
|
|
The GUI "Add custom connector" flow can NOT reach a localhost server — it probes
|
|
and calls tools from Anthropic's cloud, so `https://127.0.0.1:8443/mcp` fails
|
|
"couldn't reach the server" even though a local browser reaches it. The working
|
|
path is a local stdio bridge in `claude_desktop_config.json`:
|
|
`mcpServers.gitmanager = cmd /c npx -y mcp-remote http://127.0.0.1:8080/mcp`.
|
|
Added that entry to the user's Claude Desktop config (backup saved alongside).
|
|
- **Why:** Keep the app localhost-only + unauthenticated (§0) while still letting
|
|
Claude Desktop drive it. `mcp-remote` runs locally, so it reaches the local
|
|
endpoint directly — no public exposure, no HTTPS needed for this path.
|
|
- **Affects:** `AGENT.md` (§8.1, §11); user's `claude_desktop_config.json` (outside
|
|
the repo). HTTPS/`:8443` from the prior entry stays available but is now optional.
|
|
|
|
## 2026-09-20 — Slice 3: activity feed + active project (§8.2)
|
|
- **What:** Added `internal/activity` (thread-safe active project + bounded event
|
|
feed with subscriber fan-out, mirrored to logs, no datastore). Service gained
|
|
`ActiveProject`/`SetActiveProject`/`RecordActivity`/`Activity`/`SubscribeActivity`
|
|
(and `service.New` now takes the feed). New MCP tools `get_active_project`,
|
|
`set_active_project`, `get_activity` (object-wrapped outputs). New HTTP:
|
|
`GET/POST /api/active-project`, `GET /api/activity`, and `GET /events` (SSE).
|
|
New `<activity-feed>` component (live via EventSource); `<repo-list>` now sets
|
|
the active project on selection (a user action). Extended the MCP test to cover
|
|
the new tools; help page documents the feature.
|
|
- **Why:** The coordination foundation for the graceful project handoff (§8.3):
|
|
the app and Claude share one active-project + activity view. User actions are
|
|
recorded as `actor:user`, Claude's as `actor:claude`, so each side can see what
|
|
the other did.
|
|
- **Affects:** `internal/activity` (new), `internal/service`, `internal/mcp`
|
|
(+test), `cmd/server/main.go`, `components/activity-feed` (new),
|
|
`components/repo-list`, `web/templates/{index,help}.html`.
|
|
|
|
## 2026-09-20 — Slice 4: graceful project handoff (§8.3)
|
|
- **What:** `internal/activity` gained a pending-switch model
|
|
(`RequestSwitch`/`PendingSwitch`/`AckSwitch`/`CancelSwitch`); `AckSwitch`
|
|
atomically sets the active project to the requested target and records a
|
|
`switch-completed` event with Claude's summary. Service methods added. New MCP
|
|
tools `get_pending_switch` and `ack_switch` (request is user-only — no MCP tool
|
|
raises it). HTTP: `GET/POST/DELETE /api/switch`. New `<handoff-bar>` component:
|
|
"Ask Claude to switch to <active>", the "waiting for a good stopping point"
|
|
state with Cancel, and the completion notice; `<activity-feed>` also updates the
|
|
active project on `switch-completed`. Extended the MCP test to cover the full
|
|
request→ack→clear flow. Help page + AGENT.md §8.3 updated.
|
|
- **Why:** The headline feature — the user asks Claude to switch projects; Claude
|
|
finishes to a safe stopping point, then `ack_switch` completes it and the app
|
|
notifies the user over SSE. The switch is Claude-completed at a checkpoint,
|
|
never app-forced (§1.4-class rule).
|
|
- **Affects:** `internal/activity`, `internal/service`, `internal/mcp` (+test),
|
|
`cmd/server/main.go`, `components/handoff-bar` (new), `components/activity-feed`,
|
|
`web/templates/{index,help}.html`, `AGENT.md` (§8.3).
|
|
- **Verified live:** request → "waiting" → cancel, all over SSE with activity
|
|
logging. The ack/completion path is covered by the test; its live ✅ notice
|
|
needs the two new MCP tools, which appear after the next Claude Desktop restart.
|
|
|
|
## 2026-09-20 — Slice 5: Gitea forge — PRs + "Merge & clean up" (§8.4)
|
|
- **What:** New `internal/forge` — provider-abstracted forge boundary with a Gitea
|
|
impl (`code.gitea.io/sdk/gitea`), a remote-URL parser (`ParseRemote`, tested),
|
|
and read+write ops: `ListPullRequests` and `MergeAndCleanup` (squash-merge +
|
|
delete the head branch, only when head/base share a repo). Service resolves a
|
|
repo → owner/repo via its remotes (prefers origin) and records a `pr-merged`
|
|
activity event. New config `GITEA_URL` + `GITEA_TOKEN` (forge is nil/disabled
|
|
without both). New MCP tools `list_prs` and `merge_and_cleanup_pr` (the merge
|
|
tool's description tells Claude to confirm first, §1.4). HTTP
|
|
`GET /api/repo/prs`, `POST /api/repo/pr/merge`. New `<pr-list>` component with a
|
|
confirming "Merge & clean up" button; hidden when no forge is configured.
|
|
- **Why:** The feature Thomas asked for — make PRs usable by merging and removing
|
|
the branch in one tidy step, from the app or via Claude.
|
|
- **Affects:** `internal/forge` (new, +test), `internal/config`,
|
|
`internal/service`, `internal/mcp`, `cmd/server/main.go`,
|
|
`components/pr-list` (new), `web/templates/{index,help}.html`, `.env.example`,
|
|
`go.mod`.
|
|
- **Not yet live-tested:** needs `GITEA_URL`+`GITEA_TOKEN` set and a real PR;
|
|
build/vet/tests pass and the parser is unit-tested. A real merge is irreversible
|
|
— will only run one against a PR Thomas designates, with confirmation.
|
|
|
|
## 2026-09-20 — Forge live-tested (Merge & clean up)
|
|
- **What:** With `GITEA_URL`+`GITEA_TOKEN` set, verified end-to-end against
|
|
git.nilles.net: created an isolated throwaway PR via the Gitea API (on a
|
|
dedicated base branch so `main` was untouched), listed it through `GET
|
|
/api/repo/prs`, then ran `POST /api/repo/pr/merge` → `{merged:true,
|
|
branchDeleted:true}`; confirmed the branch was gone (404), the PR list emptied,
|
|
and the feed logged `pr-merged`. Cleaned up the base branch afterward.
|
|
- **Why:** Prove the write path with real auth before relying on it.
|
|
- **Affects:** none (runtime verification only; no code change).
|
|
|
|
## 2026-09-20 — Slice 6: right-click command menu + git write actions (§6)
|
|
- **What:** git boundary gained `Pull`/`Push`/`Commit`/`DiscardAll` (the last is
|
|
§1.4-destructive). Scanner got `RefreshRepo` (single-repo re-scan). Service
|
|
gained `GitFetch/GitPull/GitPush/GitCommit/GitDiscard` — each records a `git-*`
|
|
activity event (ok/failed) and refreshes the repo after success; `service.New`
|
|
takes a refresh hook. New HTTP `POST /api/repo/git {path, op, message?}`. New
|
|
`<repo-menu>` overlay (plain-language commands: Get latest, Publish, Check for
|
|
updates, Save my work…, Set as active project, Ask Claude to switch here, Copy
|
|
path, and the confirmed Discard all changes…); `<repo-list>` emits
|
|
`repo:contextmenu` on right-click. Added `internal/service` test covering
|
|
commit/discard on a temp repo.
|
|
- **Why:** The GUI-first reason the app exists (§0) — run git in plain language
|
|
without a terminal. Logic lives in the shared service (§1.7) so the same ops can
|
|
be exposed to Claude via MCP next.
|
|
- **Affects:** `internal/git`, `internal/repos`, `internal/service` (+test),
|
|
`cmd/server/main.go`, `components/repo-menu` (new), `components/repo-list`,
|
|
`web/templates/{index,help}.html`.
|
|
- **Next:** expose these git ops as MCP tools so Claude can run them too.
|
|
|
|
## 2026-09-20 — Slice 7: git commands as MCP tools (§1.7 symmetry)
|
|
- **What:** Added MCP tools `git_fetch`, `git_pull`, `git_push`, `git_commit`,
|
|
and `git_discard_changes` — thin adapters over the existing service methods
|
|
(actor=claude), so Claude can run the same commands as the right-click menu.
|
|
`git_discard_changes`'s description flags it destructive and tells Claude to
|
|
confirm first (§1.4). Extended the MCP test with a `git_commit` round-trip.
|
|
Synced AGENT.md §8.1's tool list to the actual names.
|
|
- **Why:** Complete the §1.7 symmetry — every capability reachable from both the
|
|
GUI and Claude.
|
|
- **Affects:** `internal/mcp` (+test), `AGENT.md` (§8.1).
|
|
- **Note:** the new tools appear in Claude Desktop only after its next restart
|
|
(tool list cached per connection); network ops still need container git creds.
|
|
|
|
## 2026-09-20 — Slice 8: git credentials + identity in the container (§11)
|
|
- **What:** On startup the app configures the container's git (`git config
|
|
--global`): a commit identity (`GIT_USER_NAME`/`GIT_USER_EMAIL`),
|
|
`safe.directory=*` for host-owned mounts, and — when `GITEA_URL`+`GITEA_TOKEN`
|
|
are set — `http.<url>.extraheader: Authorization: token …` so push/fetch/pull
|
|
authenticate over HTTPS with no SSH key. New `git.CLI.SetGlobalConfig`; new
|
|
config `GIT_USER_NAME`/`GIT_USER_EMAIL`; `.env.example` documents them.
|
|
- **Why:** Make the network git commands (menu + MCP) actually work from Docker,
|
|
and let commits have an author.
|
|
- **Affects:** `internal/config`, `internal/git`, `cmd/server/main.go`,
|
|
`.env.example`, `AGENT.md` (§11).
|
|
- **Verified:** startup logs "git remote auth configured"; container git identity
|
|
set; `http.extraheader` present; `git_fetch` via the app returned ok.
|
|
- **Security note:** the token is written to the container's ephemeral gitconfig
|
|
and passed in a `git config` argv — acceptable for a localhost dev container.
|
|
|
|
## 2026-09-20 — Slice 9: git_checkout + create_branch
|
|
- **What:** git boundary `Checkout` (switch existing branch) and `CreateBranch`
|
|
(git checkout -b). Service `GitCheckout`/`GitCreateBranch` (feed detail names
|
|
the branch; `gitAction` now takes an ok-detail). HTTP `/api/repo/git` gained
|
|
ops `checkout` and `create-branch` (+`branch` field). MCP tools `git_checkout`
|
|
and `create_branch`. `<repo-menu>` gained "Switch branch…" and "New branch…"
|
|
(prompt for the name). Service test covers create+switch+existing-branch-fails.
|
|
- **Why:** Round out the everyday git commands in both front doors (§1.7).
|
|
- **Affects:** `internal/git`, `internal/service` (+test), `internal/mcp`,
|
|
`cmd/server/main.go`, `components/repo-menu`, `web/templates/help.html`,
|
|
`AGENT.md` (§8.1). Checkout isn't §1.4-destructive — git refuses if it would
|
|
overwrite uncommitted changes.
|
|
|
|
## 2026-09-20 — Slice 10: create_pr
|
|
- **What:** forge `CreatePullRequest` (Gitea; empty base → repo default branch,
|
|
via GetRepo). Service `CreatePR` (records `pr-created`). HTTP
|
|
`POST /api/repo/pr/create`. MCP tool `create_pr`. `<pr-list>` gained a
|
|
"New pull request…" button (head = selected repo's current branch, base =
|
|
default). AGENT.md §8.1 lists `create_pr` in Act.
|
|
- **Why:** Open PRs from the app or Claude — the front half of the PR workflow
|
|
whose back half is "Merge & clean up".
|
|
- **Affects:** `internal/forge`, `internal/service`, `internal/mcp`,
|
|
`cmd/server/main.go`, `components/pr-list`, `web/templates/help.html`,
|
|
`AGENT.md`.
|
|
- **Note:** the head branch must already exist on the remote (push first).
|
|
|
|
## 2026-09-20 — Slice 11: branch-picker submenu
|
|
- **What:** `<repo-menu>` "Switch branch" is now a flyout submenu populated from
|
|
`GET /api/repo` (the repo's branches; current one disabled), flipping leftward
|
|
near the viewport edge; clicking a branch checks it out. "New branch…" still
|
|
prompts. No backend change.
|
|
- **Affects:** `components/repo-menu`, `web/templates/help.html`.
|
|
|
|
## 2026-09-20 — Slice 12: inline command-result toasts
|
|
- **What:** New `<toast-host>` overlay — components post `toast` CustomEvents
|
|
(`{message, kind}`; success/error/info) and it shows brief, auto-dismissing,
|
|
bottom-right toasts. `<repo-menu>` (git ops + coordination actions) and
|
|
`<pr-list>` (create/merge) now post success/error toasts with friendly labels
|
|
instead of `alert()`. Activity feed still logs everything.
|
|
- **Why:** Immediate, legible feedback for the non-expert audience (§6 polish).
|
|
- **Affects:** `components/toast-host` (new), `components/repo-menu`,
|
|
`components/pr-list`, `web/templates/index.html`.
|