Skip to content

feat(dashboard): Git panel with repo status/log + auto-open Git and folder tabs - #1636

Merged
bolichen97 merged 1 commit into
kirodotdev:mainfrom
alejacre:feature/git-panel-file-explorer
Aug 13, 2026
Merged

feat(dashboard): Git panel with repo status/log + auto-open Git and folder tabs#1636
bolichen97 merged 1 commit into
kirodotdev:mainfrom
alejacre:feature/git-panel-file-explorer

Conversation

@alejacre

@alejacre alejacre commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Problem

When a session's project directory is set to a git repository, there is no way to see the repo's git state in the dashboard. The existing "Changes" panel shows PR links the agent mentioned, and the session file list shows files the agent touched - neither shows the repository's actual branch, uncommitted changes, or history. To know the git state of the folder they are working in, users must drop to a terminal.

Why it matters

Developing against a specific folder without visible git context means users start work on the wrong branch, miss uncommitted changes left by a previous session, and cannot sanity-check what the agent changed against the real working tree. Surfacing the repo state at a glance, automatically when the folder is opened, removes a constant context switch.

Fix (symptoms -> root cause -> change)

Symptom: no git visibility. Root cause: the dashboard has no endpoint exposing working-tree status/history, and no side-panel view bound to the session's project dir. Change:

  • Backend - two new endpoints next to the existing /api/project/git, following its exact security pattern (known-project allow-list, is_sensitive_path guard, SEL audit, sandboxed git env with textconv/fsmonitor disabled, asyncio.to_thread, per-call timeouts):
    • GET /api/project/git/status - branch, ahead/behind, per-file status with +/- line counts (git status --porcelain=v1 -b + git diff --numstat HEAD), file list capped at 500 with a truncated flag.
    • GET /api/project/git/log?limit=N - recent commits (sha, subject, author, ISO date, HEAD marker), limit clamped 1-100.
  • Frontend - new GitPanel component (branch header, ahead/behind pill, uncommitted-count pill, CHANGES section with status letters and +/- counts opening the existing diff viewer, COMMITS section) rendered through ActivityViewer as a new 'git' view kind, with a "+" menu entry. Status polls every 5s while visible; log refetches on branch change. All strings go through the i18n catalog (translated in all 10 locales, pseudo-locale regenerated, context-sidecar entries for the short "Git" strings).
  • Auto-open - when the active slot's project dir is a git repo, ChatPage opens the Git view and the existing folder tab once per slot+path (localStorage marker), and expands the activity panel. Users who close them are not re-forced.

Tests

  • test/test_project_git_status_log.py (10 cases): non-repo dir, unknown dir refused by the allow-list, staged+unstaged+untracked classification, clean repo, numstat merge, log content, limit clamping.
  • website/src/test/usePanelTabs.test.ts (+2): 'git' view kind registration and closability.
  • website/src/test/gitPanelAutoOpen.test.ts (5): once-per-slot+path auto-open marker logic.

Manual verification

Ran the full stack from source (gateway on an isolated dev home + built frontend), set a project dir on a slot via the API, and drove the UI headless: both tabs auto-open, the Git panel renders branch/changes/commits from the real repo, the folder tab shows the project tree. Screenshots below are from that run.

Gates: isort/flake8/mypy (same findings as origin/main, none in touched files), npm --prefix website run build clean, vitest 699/699 files passing (electron suite fails identically on origin/main on Linux - macOS contracts).

Screenshots

Git panel (auto-opened, populated from this branch's own working tree):

Git panel

Folder tab auto-opened for the project dir:

Folder panel

@alejacre
alejacre requested a review from a team as a code owner August 5, 2026 14:13
@github-actions github-actions Bot added fork Pull request from a fork (external contributor) readiness: checking Automated validation is still running merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 5, 2026
@iamwhatever iamwhatever added the needs-pr-triage PR scanner: awaiting automated triage label Aug 12, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]: This PR has been inactive for 7+ days with failing CI. I've assessed the blockers and they appear resolvable — I'll rebase, fix the CI issues, and address any straightforward review comments. I will NOT change your design approach.

Assessment: Merge conflicts with main + test_no_new_error_response_without_a_code failure (new endpoints in handlers/files.py need machine-readable error codes per project convention) + downstream Coverage Gate cascade. All fixable mechanically after rebase.

If you'd prefer I don't touch this PR, add the pr-no-autofix label.

@bolichen97 bolichen97 added drive-to-green PR claimed by drive-to-green pipeline and removed needs-pr-triage PR scanner: awaiting automated triage labels Aug 12, 2026
@bolichen97
bolichen97 force-pushed the feature/git-panel-file-explorer branch from 07e8850 to de68b42 Compare August 13, 2026 00:30
@bolichen97
bolichen97 requested a review from a team August 13, 2026 00:30
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]

Rebased onto current main (6825ee17) and drove the branch through local gates + a two-model review pass. All changes below are on the existing branch as a single squashed commit de68b42a. No design or scope changes — the panel, endpoints, and auto-open behavior are exactly as authored.

Conflict resolution (rebase)

  • SidePanel.tsx: main replaced the flat NEW_MENU with grouped NEW_MENU_GROUPS and moved Terminal out of the + menu. Kept main's structure and slotted the Git entry into the session-output group; label/desc key maps gain only git (no terminal re-add). sidePanelAddMenu.test.tsx partition expectations updated accordingly.
  • ActivityViewer.tsx: kept main's signature (incl. onFolderOpen) and added this PR's projectDir param.
  • 9 translated locale catalogs + en.context.json: re-merged this PR's new keys into main's evolved files; en-XA regenerated via npm run i18n:pseudo.

CI-failure fixes

  • test_no_new_error_response_without_a_code: the 6 error responses in the two new endpoints now carry machine-readable codes (path_required, unknown_project_dir, access_denied).
  • Catalog parity: ja/ko locales landed on main after this PR was written — added the 13 new keys with translations.

Review-pass fixes (GPT 5.6 + Opus 4.8 local mirror, then verified)

  • Bounded git output: status/numstat/log now run through a _run_git_bounded helper (8 MB cap, kill on overflow/timeout) instead of unbounded capture_output=True — these endpoints are polled every 5s and repo content sizes the output.
  • Egress redaction: repoRoot, branch, file paths, commit message/author pass through the canonical redact() before the response, matching the sibling api_project_git contract.
  • ChatPage auto-open effects: a localStorage.setItem quota failure now skips the auto-open instead of re-opening on every tabsCtl change (unbounded render loop).
  • GitPanel file rows: clicking now opens repoRoot-anchored absolute paths (repo-relative paths could resolve against a different project's dir when slots use different projects), and row keys are path:staged (a staged+unstaged file previously produced duplicate React keys).
  • SEL audit: the allowed-outcome audit event moved ahead of the not-a-dir/not-a-repo early returns so every authorized access is logged, as api_project_git does.
  • Hardening/UX: --no-textconv --no-ext-diff on the numstat call (belt-and-braces; numstat verified not to invoke drivers) and -c core.quotePath=false so non-ASCII filenames render and open correctly.
  • Commits list now also refetches when the branch moves ahead of upstream (new local commit), not only on branch switch.

Verified: isort/flake8/mypy clean, full backend pytest (49,771 passed; 107 failures reproduced on pristine main — environment-only), tsc -b clean, vitest 17,722 passed incl. this PR's tests, i18n gate chain green.

@bolichen97

Copy link
Copy Markdown
Collaborator

Local pre-push review pass on prior SHA b508ec1b (GPT 5.6 Sol + Opus 4.8 mirrors); dispositions carried into de68b42a:

  1. textconv/ext-diff command execution via git diff --numstatrebutted, then hardened anyway: empirically verified --numstat never invokes textconv or external diff drivers (binary files report -), and the handlers already pin diff.textconv=, core.attributesFile=/dev/null, GIT_ATTR_NOSYSTEM=1. Added --no-textconv --no-ext-diff regardless (zero-cost defense in depth).
  2. Cross-project file open from GitPanel rows — fixed: rows now pass repoRoot-anchored absolute paths to onFileOpen.
  3. QuotaExceeded → infinite auto-open render loop in ChatPage — fixed: both effects return from the storage catch instead of opening.
  4. Unbounded subprocess capture on polled endpoints — fixed: _run_git_bounded (8 MB cap, kill on overflow/timeout, nonzero rc on truncation; callers degrade to empty data).
  5. Repo-controlled metadata bypassing egress redaction — fixed: redact() applied to repoRoot, branch, file paths, commit message/author.
  6. Advisory, stale commits list on new commit — fixed: log refetch also triggers on ahead-count movement.
  7. Advisory, porcelain quoting breaks non-ASCII filenames — fixed for the common case via -c core.quotePath=false; pathological control-char filenames (newline/tab) still parse as quoted display form — accepted-and-deferred as a cosmetic edge.

Opus advisories: duplicate React keys (fixed, path:staged composite), unredacted repoRoot (fixed, item 5), SEL audit gap on early returns (fixed, allow-log moved ahead of them), folder-tab auto-open broader than git gating (rebutted: matches the PR's stated scope "auto-open Git and folder tabs when project is set"), renamed files show no +/- counts (accepted-and-deferred, cosmetic).

@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 13, 2026
@bolichen97
bolichen97 force-pushed the feature/git-panel-file-explorer branch from de68b42 to 5d55fa2 Compare August 13, 2026 00:56
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]

Iteration 2 (5d55fa2c, rebased onto f2afb535): fixed the 3 CI failures from the first full run — all three were introduced by iteration 1's own additions, not by the original PR code.

  • jaStyle/koStyle punctuation gates: the components.gitPanel.loading strings I added for the new ja/ko catalogs used ASCII ...; now the required .
  • test_spawn_audit (both backend shards): the new _run_git_bounded helper moved the git Popen out of the already-allowlisted files.py::_run closures, tripping the unrouted-spawn tripwire. Added files.py::_run_git_bounded to BENIGN_SPAWNS with justification: fixed git list-argv, cwd from the known-project allow-list behind the sensitive-path gate — the same trust story as the sibling _run entry; it is a separate function only so the 8 MB stdout cap can kill an overflowing child.
  • Frontend Coverage Merge failure was the downstream cascade of the style-test shards.

Local verification: spawn audit 9/9, ja/ko style + catalog parity 120/120.

@github-actions github-actions Bot added readiness: checking Automated validation is still running merge conflict Branch has merge conflicts with its base — author must resolve before merge and removed readiness: action required A blocking check or review needs attention labels Aug 13, 2026
@bolichen97
bolichen97 force-pushed the feature/git-panel-file-explorer branch from 5d55fa2 to 0962766 Compare August 13, 2026 01:16
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 13, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]

Iteration 3 (09627660): re-resolved against main's route-table refactor (#3160), which moved the dashboard route registrations out of server.py into dashboard/routes/ slices and had made the PR CONFLICTING mid-CI-run.

  • server.py: took main's version (register_all over the routes package); this PR's two route lines no longer belong there.
  • dashboard/routes/taskrunner.py: registered GET /api/project/git/status and GET /api/project/git/log immediately after the sibling /api/project/git route, matching the slice that owns project-git surface.
  • No other changes; rebased onto b8719891.

Verified: test_dashboard_route_table.py (the refactor's ordering guards) 4/4, test_project_git_status_log.py 10/10, handlers import cleanly.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 13, 2026
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 13, 2026
@bolichen97
bolichen97 force-pushed the feature/git-panel-file-explorer branch from 02ac53d to ad4176c Compare August 13, 2026 06:54
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 13, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]

Iteration 7 (ad4176c0, rebased onto 3600a10e) — a restructure round for the files.py git-spawn span (3rd consecutive blocking round there), porting worktree.py's complete invariant instead of another point-patch: no git subcommand runs against a repo whose own config names a program.

Dispositions for the GPT review of 02ac53de:

  1. BLOCKING, status executes repo-configured clean/process filters — fixed with the requested mechanism: _repo_declares_filter_driver() ports worktree.py::_checkout_filter — probes --local and (when extensions.worktreeConfig is on) --worktree scopes with --includes, refuses on any filter.*.(clean|smudge|process) key, and fails closed on an unreadable scope. Both endpoints return a degraded empty answer for such repos, uniformly (log too, so the invariant is auditable without per-subcommand carve-outs). Regression tests: clean-filter refusal, process-filter refusal, and a non-filter config key not refused.
  2. BLOCKING, arrow-containing filenames resolve to another file — fixed exactly as suggested: the rename split now requires R/C in the status letters. Writing the regression test surfaced an adjacent defect in the same parser: porcelain v1 C-quotes paths containing quotes/backslashes/control chars, so a quoted path was returned in display form (pointing opens at a nonexistent file). Added _porcelain_unquote() applied to status rows and numstat keys. Tests: a modified file literally named foo -> bar survives intact; a real rename still reports the new name.
  3. Advisory, folder tab auto-opens for non-git projects — rebutted (third consistent disposition). The PR's stated scope is "auto-open Git and folder tabs when project is set": the folder tab is deliberately project-gated, not repo-gated. This is the author's designed behavior, not an oversight; narrowing it would remove the feature for non-git projects.

Local gates: 30/30 across the three contract suites (5 new regression tests), isort/flake8/mypy clean.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Aug 13, 2026
@bolichen97
bolichen97 force-pushed the feature/git-panel-file-explorer branch from ad4176c to ee495a0 Compare August 13, 2026 07:09
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]

Iteration 8 (ee495a03, rebased onto df3065e3): one-line test fix. The new TestArrowFilename regression test from iteration 7 fails on Windows because > is not a legal NTFS filename character — the scenario it guards cannot exist there. Added @pytest.mark.skipif(os.name == "nt", ...). The production parser change is untouched and its real-rename companion test still runs on all platforms. Rest of the round was green when this was caught (only red was that shard).

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running and removed readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention labels Aug 13, 2026
…older tabs when project is set

When a session's project directory is a git repository, the side panel now
auto-opens a Git view (branch, ahead/behind, uncommitted changes with +/-
line counts, recent commits) and the existing folder tab for the project
dir - once per slot+path, so a user who closes them is not re-forced.

Backend: GET /api/project/git/status and GET /api/project/git/log, following
the existing /api/project/git security pattern (known-project allow-list,
sensitive-path guard, SEL audit, sandboxed git env, asyncio.to_thread).

Frontend: new GitPanel component rendered via ActivityViewer ('git' view
kind), pinned menu entry, auto-open effects in ChatPage.
@bolichen97
bolichen97 force-pushed the feature/git-panel-file-explorer branch from ee495a0 to 469c747 Compare August 13, 2026 07:40
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 13, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]

Iteration 9 (469c7472) — dispositions for the GPT review of ee495a03. Note: the security-invariant span (filter drivers / sandbox routing) got no new finding this round — the restructure held. These are a different class:

  1. BLOCKING, project removal crashes both polling endpoints — fixed. Valid TOCTOU: the dir can vanish between the isdir gate and the spawn, and Popen raises FileNotFoundError → 500. _run_git_bounded now catches OSError at the spawn (degraded no-data return, covering an absent git binary too) and the wrapper-file unlink moved into a finally so no exit path leaks it. Regression test: TestVanishedDirectory deletes the repo inside a patched isdir and asserts a 200 {repo: false}.
  2. Advisory, untracked directories collapse to one row — fixed with the suggested --untracked-files=all (a directory-only row also defeated the file-open contract).
  3. Advisory, folder auto-open for non-git projects — rebutted, fourth consistent disposition: the PR's stated behavior is "auto-open Git and folder tabs when project is set"; the folder tab is deliberately project-gated. Author-designed scope, not an oversight.

Local gates: 31/31 across the three contract suites (1 new regression test), isort/flake8/mypy clean.

@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: passed Eligible automated validation passed for the current revision and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Aug 13, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97]

Review-ready at 469c7472: all 57 checks green, readiness: passed, MERGEABLE, zero unresolved threads. GPT 5.6 and Opus 4.8 both report no blocking findings on this head.

Dispositions for the two advisory CONCERNS verdicts (both center on the same design point):

  • Design Review 🟡 + UX Review 🟡, degraded states render as "clean" — accepted-and-deferred → git-panel: degraded/refused status states must not render as a green clean pill (+ review follow-ups) #3254. The concern is legitimate: the fail-closed answers this PR's security hardening added (filter-driver refusal, sandbox-unavailable, overflow/timeout) are indistinguishable from a healthy clean repo, and truncated is computed but never rendered. Deferred rather than fixed here because the remedy is a response-contract extension plus new UI states and strings across 12 locales — fresh review surface on a PR at iteration 9/10 that is finally green. The follow-up issue carries the complete worklist from both reviews: unavailable / not-a-repo / truncated states, staged-row presentation and unique-path counting, D-row dead-end, commit-row hover affordance, per-poll subprocess cost, the shared handler prologue extraction, and the auto-open pure-helper extraction.

Summary of what this drive-to-green added on top of the original contribution (all explained in prior comments): rebase across 4 main evolutions (grouped side-panel menu, route-table slices, ja/ko locales, error-code contract), OS-sandboxed + bounded + redacted git execution with filter-driver refusal, TOCTOU crash guard, porcelain quoting/rename parsing fixes, quota-loop and cross-project file-open fixes in the frontend, SEL audit coverage, and 11 new regression tests.

Awaiting human review and merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fork Pull request from a fork (external contributor)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants