Skip to content

refactor: dissolve single-file folders (21 → 14)#51

Merged
kuchmenko merged 10 commits into
mainfrom
refactor/dissolve-single-file-folders
May 26, 2026
Merged

refactor: dissolve single-file folders (21 → 14)#51
kuchmenko merged 10 commits into
mainfrom
refactor/dissolve-single-file-folders

Conversation

@kuchmenko
Copy link
Copy Markdown
Owner

@kuchmenko kuchmenko commented May 20, 2026

Criterion: a single-file folder (internal/auth/auth.go, internal/doctor/doctor.go, …) buys a directory + import path + mental boundary for zero structural benefit. Fold it into the consumer unless the package is foundational (multi-consumer leaf) or a Go convention (testutil).

By that yardstick nine packages were wrong: alias + aliasmgr, auth, bootstrap, branchprompt, conflict, doctor, migrate, setup. Each fold preserves the consumer relationship that already existed and is gated by [[top-to-bottom-readability]] — every merged file still walks as one narrative.

21 folders → 14. Production file count holds at 45 (folds consolidate but repo/ adds back one). Binary 14 MB unchanged. TUI seam intact: 0 charmbracelet imports outside internal/tui/. All tests + go vet + golangci-lint + gofmt green at every commit.

Where things went: alias + aliasmgr → alias/ (same domain, manager joins generator); auth → github/ (auth is github auth — feeds github.Client); bootstrap + migrate → repo/ (both transition a repo into the bare+worktree layout — new package); branchprompt → tui/ (TUI primitive belongs with the others); conflict → daemon/ (daemon owns the conflict store, cli + doctor already imported daemon); doctor → cli/ and setup → cli/ (cli-only consumers, each gets its own cli/doctor.go / cli/setup.go to keep root.go from growing past readability).

Collision renames (made explicit so future readers can grep): branchprompt.Modeltui.BranchPromptModel (the existing tui.Model is an interface); conflict.Store/Open/Path/Kinddaemon.ConflictStore/OpenConflictStore/ConflictPath/ConflictKind; bootstrap & migrate both exported Sidecar/DoneEntry/New/Load/Save/Delete/IsAlive — each gets a Bootstrap/Migrate prefix in repo/; aliasmgr.Model/New/Resultalias.ManagerModel/NewManagerModel/ManagerResult; setup.Model/NewModel/Resultcli.SetupModel/NewSetupModel/SetupResult; one private-helper collision humanizeTime (different formatting) → humanizeTimeShort in setup, contains (different signature) → containsSubstr in doctor's system test.

The lint config commit at the end updates path-keyed gocognit waivers to point at the new file homes (same functions, same justified-complex waivers, just new paths).

go build, go test ./..., go vet, golangci-lint run, gofmt -l . all green. TUI seam check returns 0. Smoke remaining: ws agent, ws alias, ws add, ws status, ws sync on a real workspace.

Summary by CodeRabbit

  • Refactor
    • Internal reorganization of CLI/TUI and daemon components for consistency; no API surface changes.
  • User-visible UI
    • Branch selection prompt preserved but integrated into the main TUI framework.
    • Repo list "pushed" time now uses a shorter, more compact duration format.
    • Bootstrap/migrate flows and notifications updated—resume/discard and progress notifications now use the unified notification system.

Review Change Stack

kuchmenko added 9 commits May 20, 2026 10:45
Prepare branchprompt for folding into internal/tui where Model is
already an interface. Renames the exported symbols to avoid the
collision; call sites in internal/add and internal/cli adjusted.

  Model        -> BranchPromptModel
  NewModel     -> NewBranchPromptModel
  PickedMsg    -> BranchPromptPickedMsg
  CancelledMsg -> BranchPromptCancelledMsg

No behavior change. Folding into tui happens in the next commit.
Branchprompt is a TUI primitive (default-branch picker model). Moving
it inside the internal/tui package eliminates the standalone folder
without crossing the seam — branchprompt already imported tui for its
KeyMsg/Cmd/Model/Style primitives.

Renamed symbols (from prior commit) keep BranchPrompt-prefixed names
to avoid collision with the existing tui.Model interface.

Net: -1 folder, file moves only.
The conflict store is daemon-owned: the reconciler writes, ws sync
resolve reads. cli and doctor already import daemon for unrelated
reasons; the import direction stays the same after the fold.

Renamed to disambiguate inside package daemon:
  conflict.Store  -> daemon.ConflictStore
  conflict.Open   -> daemon.OpenConflictStore
  conflict.Path   -> daemon.ConflictPath
  conflict.Kind   -> daemon.ConflictKind
  conflict.Conflict, Notify, NotifyNew, Kind* constants keep their names

Call sites updated: cli/{bootstrap,migrate,sync}.go,
daemon/reconciler.go, doctor/doctor.go, doctor/system_test.go,
daemon/conflict_bench_test.go.
auth is GitHub auth — device flow + PAT exist only to feed github.Client.
Folding makes github.NewProvider() self-contained instead of forcing
every caller to wire auth separately.

No symbol collisions; names stay (Token, LoadToken, SaveToken, etc.)
and become github.Token, github.LoadToken, etc. at call sites.

Call sites updated: cli/root.go, daemon/daemon.go, github/github.go
(self-references drop the auth. prefix).
Both packages transition a repo into the bare+worktree layout: migrate
upgrades an existing plain clone; bootstrap materializes from
workspace.toml. Same operation, different starting state.

Combined into internal/repo/ with two files (bootstrap.go, migrate.go).
Collision symbols renamed with Bootstrap/Migrate prefix to keep each
flow's state and lifecycle separate (no premature shared abstraction):

  bootstrap: Sidecar -> BootstrapSidecar, DoneEntry -> BootstrapDoneEntry,
             New/Load/Save/Delete -> NewBootstrapSidecar/etc.,
             IsAlive -> BootstrapSidecarIsAlive
  migrate:   Sidecar -> MigrateSidecar, DoneEntry -> MigrateDoneEntry,
             Options/Result -> MigrateOptions/MigrateResult,
             New/Load/Save/Delete -> NewMigrateSidecar/etc.,
             IsAlive -> MigrateSidecarIsAlive

Non-colliding symbols keep their names (Plan, PlanItem, State, ScanPlan,
Check, CheckResult, MigrateProject, ErrAlreadyMigrated).

Call sites updated in cli/bootstrap.go and cli/migrate.go. Tests
repackaged to repo_test.
aliasmgr is the interactive manager for the same alias domain that
internal/alias's generator/installer/resolver operates on. Same domain,
same workspace.toml surface, no reason for separate packages.

Renamed to disambiguate inside the merged package:
  aliasmgr.Model  -> alias.ManagerModel
  aliasmgr.New    -> alias.NewManagerModel
  aliasmgr.Result -> alias.ManagerResult

manager.go drops the alias. prefix on internal references (no longer
cross-package). Call sites in cli/root.go updated.

The package now reads as alias.go (generator + resolver + installer) +
manager.go (interactive picker).
Doctor is consumed only by cli; the folder added an import path for
zero structural benefit. Folded as cli/doctor.go + three test files
(doctor_test, doctor_project_test, doctor_system_test).

No symbol collisions on exported names. One private helper renamed to
avoid duplicate: contains() in doctor_system_test.go conflicts with
contains() in worktree_test.go (different signatures) — doctor's
becomes containsSubstr.
Setup is the first-run wizard, consumed only by cli. Folded as
cli/setup.go.

Renamed to disambiguate inside cli:
  setup.Model    -> SetupModel
  setup.NewModel -> NewSetupModel
  setup.Result   -> SetupResult

Private helper humanizeTime renamed to humanizeTimeShort — collides
with cli's existing humanizeTime which uses different formatting and
bucket boundaries; the two utilities serve different display contexts.
The exclusion globs in .golangci.yml were keyed to pre-dissolution
paths (internal/aliasmgr, internal/setup, internal/migrate). After
folding those into alias/, cli/, and repo/, the exclusions no longer
matched and 8 long-standing complex funcs (MigrateProject,
buildTree, etc.) started failing the gate.

Paths updated to match new homes; same functions, same waivers, no
new debt.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7caad9c2-d3fe-4de3-bad8-06bbe47d2090

📥 Commits

Reviewing files that changed from the base of the PR and between 0b44dba and 4cfa213.

📒 Files selected for processing (3)
  • internal/cli/bootstrap.go
  • internal/cli/migrate.go
  • internal/cli/sync.go

📝 Walkthrough

Walkthrough

This PR consolidates multiple internal Go packages into larger namespaces and systematically renames public APIs with clearer purpose-driven prefixes. internal/bootstrap, internal/migrate, internal/conflict, internal/branchprompt, internal/auth, and CLI-adjacent packages move into internal/repo, internal/daemon, internal/tui, internal/github, and internal/cli with coordinated type and function renames. All import paths and consumers are updated accordingly.

Changes

Package and API consolidation

Layer / File(s) Summary
Conflict system consolidation into daemon package
internal/daemon/conflict.go, internal/daemon/conflict_bench_test.go, internal/daemon/reconciler.go, internal/cli/doctor.go, internal/cli/doctor_system_test.go, internal/cli/sync.go
internal/conflict moves to internal/daemon/conflict.go under package daemon. Public types rename: KindConflictKind, StoreConflictStore. Functions rename: Path()ConflictPath(), Open()OpenConflictStore(). All consumers (reconciler, doctor, sync CLI, benchmarks) update their receiver types and const references accordingly.
Sidecar consolidation into repo package
internal/repo/bootstrap.go, internal/repo/bootstrap_test.go, internal/repo/migrate.go, internal/repo/migrate_test.go, internal/cli/bootstrap.go, internal/cli/migrate.go
internal/bootstrap and internal/migrate sidecars move to internal/repo/ under package repo. Types rename: SidecarBootstrapSidecar/MigrateSidecar, DoneEntryBootstrapDoneEntry/MigrateDoneEntry. Functions rename: New()NewBootstrapSidecar()/NewMigrateSidecar(), Load()/Save()/Delete()/IsAlive() likewise renamed with BootstrapSidecar/MigrateSidecar prefixes. Migration types rename: OptionsMigrateOptions, ResultMigrateResult. All call sites updated.
Branch-prompt model consolidation into tui package
internal/tui/branchprompt.go, internal/tui/branchprompt_test.go, internal/add/sources.go, internal/add/tui.go, internal/cli/bootstrap.go
internal/branchprompt moves to internal/tui/branchprompt.go under package tui. Public model/message types rename: ModelBranchPromptModel, PickedMsgBranchPromptPickedMsg, CancelledMsgBranchPromptCancelledMsg, NewModel()NewBranchPromptModel(). Methods now use local Cmd/Msg types. All consumers in add and bootstrap flows updated.
Auth consolidation into github package
internal/github/auth.go, internal/github/github.go, internal/daemon/daemon.go, internal/cli/root.go
internal/auth moves to internal/github/auth.go under package github (namespace only; no implementation changes). internal/github/github.go updated to use local LoadToken() instead of auth.LoadToken(). Daemon and root.go updated to call github.* functions instead of auth.*.
CLI package consolidation and type renames
internal/cli/setup.go, internal/cli/doctor.go, internal/cli/doctor_*_test.go, internal/cli/bootstrap.go, internal/cli/migrate.go
internal/setup and internal/doctor packages integrated into internal/cli with namespace migration. Setup types rename: ModelSetupModel, ResultSetupResult, NewModel()NewSetupModel(). Doctor test package changes from doctor to cli and uses daemon conflict APIs. Bootstrap and migrate commands updated to use repo.* sidecars/options and daemon.Notify() instead of old notifiers. Time formatting helper added: humanizeTimeShort().
Alias manager type renaming
internal/alias/manager.go, internal/cli/root.go
internal/alias/aliasmgr.go renamed to internal/alias/manager.go with package rename aliasmgralias. Public types rename: ModelManagerModel, ResultManagerResult, New()NewManagerModel(). All method receivers and return types updated. Alias function references changed from qualified (e.g., alias.Generate) to unqualified. Root.go consumer updated to use alias.NewManagerModel() and cast result to alias.ManagerModel.
Root command consolidation of all API changes
internal/cli/root.go
Updates root.go to wire all refactored modules: removes legacy imports (aliasmgr, auth, doctor, setup) and adds internal/github; uses alias.NewManagerModel() for alias commands, github.* functions for auth login/logout/status, new doctor runner/report APIs, and NewSetupModel() for setup commands.
Lint configuration update for package layout
.golangci.yml
Updates linter exclusion globs: TUI exclusions from `internal/(agent
Add command TUI consumers
internal/add/sources.go, internal/add/tui.go
ws add and its internal AddModel switch branch-prompt usage to tui.NewBranchPromptModel and handle tui.BranchPromptPickedMsg/tui.BranchPromptCancelledMsg. AddModel.branchPrompt type updated to tui.BranchPromptModel.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • kuchmenko/workspace#25: Introduced the earlier branch-prompt Bubble Tea model that is consolidated into internal/tui here.
  • kuchmenko/workspace#50: Related branch-prompt API/type changes that intersect with this refactor.

Poem

🐰 I hopped through packages, tidy and bright,
Renamed each struct in the soft moonlight.
From branch prompts to daemons, the pathways align,
A neat little garden of code — all in a line.
🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.16% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main refactoring objective: consolidating single-file packages and reducing the folder structure from 21 to 14.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/dissolve-single-file-folders

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
internal/tui/branchprompt.go (1)

1-13: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Refresh module comments to match renamed package and symbols.

The header still references branchprompt, Model, PickedMsg, and CancelledMsg, but the file now exposes tui, BranchPromptModel, BranchPromptPickedMsg, and BranchPromptCancelledMsg.

Suggested doc-only update
-// Package branchprompt provides a standalone bubbletea model for picking
+// Package tui provides a standalone bubbletea model for picking
 // a default branch when clone.CloneIntoLayout cannot auto-resolve one.
@@
-// Callers embed Model inside their own tea.Model and delegate Update/View
+// Callers embed BranchPromptModel inside their own tea.Model and delegate Update/View
 // when the parent step is "branch-prompt". When the user picks a branch
-// or cancels, the model emits PickedMsg / CancelledMsg; the parent is
+// or cancels, the model emits BranchPromptPickedMsg / BranchPromptCancelledMsg; the parent is
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/branchprompt.go` around lines 1 - 13, Update the package header
comment to reflect the renamed package and exported symbols: replace references
to "branchprompt", "Model", "PickedMsg", and "CancelledMsg" with "tui",
"BranchPromptModel", "BranchPromptPickedMsg", and "BranchPromptCancelledMsg"
respectively, and ensure the comment text explains that callers embed
BranchPromptModel and expect BranchPromptPickedMsg / BranchPromptCancelledMsg;
keep the existing intent and phrasing but update identifiers to match the
current code.
internal/cli/bootstrap.go (1)

134-141: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Always delete the bootstrap sidecar after a completed run.

The sidecar is saved before cloning starts, but this cleanup only runs when at least one project reaches Done. If every clone fails, the next ws bootstrap run will still find a dead sidecar and prompt for resume/discard even though there is nothing resumable.

Suggested cleanup
-	if final.sidecar != nil && len(final.sidecar.Done) > 0 {
-		if err := commitBootstrap(final.sidecar); err != nil {
-			return fmt.Errorf("commit bootstrap: %w", err)
-		}
-
-		if err := repo.DeleteBootstrapSidecar(wsRoot); err != nil {
-			fmt.Fprintf(os.Stderr, "warning: could not remove sidecar: %v\n", err)
-		}
-	}
+	if final.sidecar != nil {
+		if len(final.sidecar.Done) > 0 {
+			if err := commitBootstrap(final.sidecar); err != nil {
+				return fmt.Errorf("commit bootstrap: %w", err)
+			}
+		}
+		if err := repo.DeleteBootstrapSidecar(wsRoot); err != nil {
+			fmt.Fprintf(os.Stderr, "warning: could not remove sidecar: %v\n", err)
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/bootstrap.go` around lines 134 - 141, The code only calls
repo.DeleteBootstrapSidecar(wsRoot) when final.sidecar != nil &&
len(final.sidecar.Done) > 0, leaving stale sidecars if all clones fail; change
the logic so DeleteBootstrapSidecar(wsRoot) is invoked whenever final.sidecar !=
nil (regardless of final.sidecar.Done), i.e., move or add the
repo.DeleteBootstrapSidecar(wsRoot) call outside/after the Done check so the
sidecar is always removed after the run; preserve existing error handling
behavior (print a non-fatal warning to stderr) and keep
commitBootstrap(final.sidecar) as-is when at least one project reached Done.
internal/cli/migrate.go (1)

611-618: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Delete the migrate sidecar even when nothing completed.

repo.SaveMigrateSidecar runs before processing starts, but the final cleanup only removes it when at least one project was marked done. A run with only skips or failures will therefore leave a dead sidecar behind and trigger a bogus resume/discard prompt next time.

Suggested cleanup
-	if final.sidecar != nil && len(final.sidecar.Done) > 0 {
-		if err := commitMigrate(final.sidecar); err != nil {
-			return fmt.Errorf("commit migrate: %w", err)
-		}
-		if err := repo.DeleteMigrateSidecar(wsRoot); err != nil {
-			fmt.Fprintf(os.Stderr, "warning: could not remove sidecar: %v\n", err)
-		}
-	}
+	if final.sidecar != nil {
+		if len(final.sidecar.Done) > 0 {
+			if err := commitMigrate(final.sidecar); err != nil {
+				return fmt.Errorf("commit migrate: %w", err)
+			}
+		}
+		if err := repo.DeleteMigrateSidecar(wsRoot); err != nil {
+			fmt.Fprintf(os.Stderr, "warning: could not remove sidecar: %v\n", err)
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/migrate.go` around lines 611 - 618, The current cleanup only
calls repo.DeleteMigrateSidecar(wsRoot) when final.sidecar != nil &&
len(final.sidecar.Done) > 0, leaving a sidecar when nothing completed; change
the logic so repo.DeleteMigrateSidecar(wsRoot) is always attempted if
final.sidecar != nil (regardless of len(final.sidecar.Done)). Keep the
commitMigrate(final.sidecar) call only when len(final.sidecar.Done) > 0, but
ensure DeleteMigrateSidecar(wsRoot) runs even if commitMigrate returns an error
(e.g., call DeleteMigrateSidecar in a defer or after handling commitMigrate
error and still return the commit error), referencing final.sidecar,
commitMigrate, repo.DeleteMigrateSidecar, repo.SaveMigrateSidecar, and wsRoot to
locate the code.
🧹 Nitpick comments (1)
.golangci.yml (1)

189-193: ⚡ Quick win

Narrow the TUI waiver to the moved TUI files.

This regex now disables gocyclo/gocognit/funlen for every Go file in internal/alias and internal/repo, while the comment only justifies alias/manager.go and repo orchestration files. That broadens the lint blind spot beyond the code this PR actually moved.

♻️ Suggested scope tightening
-      - path: internal/(agent|add|alias|create|repo|tui)/.*\.go
+      - path: internal/(agent|add|create|tui)/.*\.go
+      - path: internal/alias/manager\.go
+      - path: internal/repo/bootstrap\.go
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.golangci.yml around lines 189 - 193, The current .golangci.yml path glob
disables gocyclo/gocognit/funlen for all files under internal/alias and
internal/repo; narrow it to only the moved TUI-related files by replacing the
broad pattern (internal/(agent|add|alias|create|repo|tui)/.*\.go) with a pattern
that continues to match the full packages that actually need waivers (e.g.,
internal/agent, internal/add, internal/create, internal/tui) but explicitly
lists the moved files in alias and repo (for example internal/alias/manager\.go
and the specific orchestration file in internal/repo such as bootstrap\.go) so
only those exact files are exempted; update the path entry in .golangci.yml
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/cli/bootstrap.go`:
- Line 55: Replace the misleading empty-state text in internal/cli/bootstrap.go:
locate the fmt.Println call that prints "No active projects to repo." and change
the message to clearly reflect the command behavior (e.g. "No active projects to
bootstrap." or "No active projects to clone."). Update only the literal string
in that fmt.Println so the CLI shows the correct action word (“bootstrap” or
“clone”) instead of "repo."

In `@internal/cli/migrate.go`:
- Line 167: The user-facing empty-state string currently prints fmt.Println("No
active projects to repo.") which exposes an internal namespace; update both
occurrences in internal/cli/migrate.go (the print statements in the migrate
command handler) to use "migrate" in the message, e.g. replace with
fmt.Println("No active projects to migrate.") so the CLI describes the command
rather than the internal package name.

In `@internal/cli/sync.go`:
- Around line 162-175: The resolver dispatch in handleConflict currently covers
only a subset of conflict kinds; add explicit case branches for
daemon.KindNeedsBootstrap, daemon.KindPathBlocked, and daemon.KindCloneFailed in
the switch inside handleConflict(c daemon.Conflict) so those conflicts are
routed to appropriate handlers (e.g., resolveNeedsBootstrap, resolvePathBlocked,
resolveCloneFailed) or to a common resolver function as appropriate; ensure you
reference these new handler function names and update the switch to return their
results so ws sync resolve can handle those conflict kinds instead of falling
through to the unknown path.

---

Outside diff comments:
In `@internal/cli/bootstrap.go`:
- Around line 134-141: The code only calls repo.DeleteBootstrapSidecar(wsRoot)
when final.sidecar != nil && len(final.sidecar.Done) > 0, leaving stale sidecars
if all clones fail; change the logic so DeleteBootstrapSidecar(wsRoot) is
invoked whenever final.sidecar != nil (regardless of final.sidecar.Done), i.e.,
move or add the repo.DeleteBootstrapSidecar(wsRoot) call outside/after the Done
check so the sidecar is always removed after the run; preserve existing error
handling behavior (print a non-fatal warning to stderr) and keep
commitBootstrap(final.sidecar) as-is when at least one project reached Done.

In `@internal/cli/migrate.go`:
- Around line 611-618: The current cleanup only calls
repo.DeleteMigrateSidecar(wsRoot) when final.sidecar != nil &&
len(final.sidecar.Done) > 0, leaving a sidecar when nothing completed; change
the logic so repo.DeleteMigrateSidecar(wsRoot) is always attempted if
final.sidecar != nil (regardless of len(final.sidecar.Done)). Keep the
commitMigrate(final.sidecar) call only when len(final.sidecar.Done) > 0, but
ensure DeleteMigrateSidecar(wsRoot) runs even if commitMigrate returns an error
(e.g., call DeleteMigrateSidecar in a defer or after handling commitMigrate
error and still return the commit error), referencing final.sidecar,
commitMigrate, repo.DeleteMigrateSidecar, repo.SaveMigrateSidecar, and wsRoot to
locate the code.

In `@internal/tui/branchprompt.go`:
- Around line 1-13: Update the package header comment to reflect the renamed
package and exported symbols: replace references to "branchprompt", "Model",
"PickedMsg", and "CancelledMsg" with "tui", "BranchPromptModel",
"BranchPromptPickedMsg", and "BranchPromptCancelledMsg" respectively, and ensure
the comment text explains that callers embed BranchPromptModel and expect
BranchPromptPickedMsg / BranchPromptCancelledMsg; keep the existing intent and
phrasing but update identifiers to match the current code.

---

Nitpick comments:
In @.golangci.yml:
- Around line 189-193: The current .golangci.yml path glob disables
gocyclo/gocognit/funlen for all files under internal/alias and internal/repo;
narrow it to only the moved TUI-related files by replacing the broad pattern
(internal/(agent|add|alias|create|repo|tui)/.*\.go) with a pattern that
continues to match the full packages that actually need waivers (e.g.,
internal/agent, internal/add, internal/create, internal/tui) but explicitly
lists the moved files in alias and repo (for example internal/alias/manager\.go
and the specific orchestration file in internal/repo such as bootstrap\.go) so
only those exact files are exempted; update the path entry in .golangci.yml
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 46e03fd6-e485-4879-b343-b389eba2ed2c

📥 Commits

Reviewing files that changed from the base of the PR and between ccc1b25 and 0b44dba.

📒 Files selected for processing (25)
  • .golangci.yml
  • internal/add/sources.go
  • internal/add/tui.go
  • internal/alias/manager.go
  • internal/cli/bootstrap.go
  • internal/cli/doctor.go
  • internal/cli/doctor_project_test.go
  • internal/cli/doctor_system_test.go
  • internal/cli/doctor_test.go
  • internal/cli/migrate.go
  • internal/cli/root.go
  • internal/cli/setup.go
  • internal/cli/sync.go
  • internal/daemon/conflict.go
  • internal/daemon/conflict_bench_test.go
  • internal/daemon/daemon.go
  • internal/daemon/reconciler.go
  • internal/github/auth.go
  • internal/github/github.go
  • internal/repo/bootstrap.go
  • internal/repo/bootstrap_test.go
  • internal/repo/migrate.go
  • internal/repo/migrate_test.go
  • internal/tui/branchprompt.go
  • internal/tui/branchprompt_test.go

Comment thread internal/cli/bootstrap.go Outdated
Comment thread internal/cli/migrate.go Outdated
Comment thread internal/cli/sync.go
Three empty-state messages printed "No active projects to repo." after the
package rename sweep — restore "bootstrap" / "migrate" verbs.

handleConflict switch only covered 5 of 8 daemon.Kind* values. Add cases
for KindNeedsBootstrap, KindPathBlocked, KindCloneFailed with guidance
handlers matching the resolveNeedsMigration pattern (print the next step,
return false so the daemon re-evaluates on next sync).
@kuchmenko kuchmenko merged commit 2d671d6 into main May 26, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant