- Add mappings array support to git_mount entries - Clone repository once per git_mount entry, mount multiple subdirectories - Normalize legacy source_path+target_path to mappings on read - Update _merge_git_mounts to dedup by (remote_url, branch) and concatenate mappings - Add _normalize_git_mount, _clone_git_repo, _resolve_git_mount_mappings helpers - Update GitMountItem Pydantic model with GitMountMapping and model_validator - Update frontend GitMountEditor component with mappings UI - Auto-convert legacy git mount entries to mappings format on load - Add 15 backend unit tests for normalization, resolution, and glob expansion - Update existing config profile resolver tests for new merge behavior Quality gates: pytest 167 passed, frontend typecheck clean Addresses: config-profile-multi-repo-mounts
4.4 KiB
Tasks: Config Profile Multi-Repo Mounts
T1: Backend — Refactor git mount resolution for mappings
T1.1: Normalize legacy git mount format
File: apps/api/src/api/tool_instances.py
- Add
_normalize_git_mount(entry: dict) -> dicthelper - Converts
{"source_path": "...", "target_path": "..."}to{"mappings": [{...}]} - Call normalization at the start of
_resolve_single_git_mount
T1.2: Extract clone logic
File: apps/api/src/api/tool_instances.py
- Create
_clone_git_repo(remote_url, branch, clone_parent) -> strfunction - Move clone/pull logic from
_resolve_single_git_mountinto it - Returns
repo_path(path torepo-clone)
T1.3: Resolve mappings from cloned repo
File: apps/api/src/api/tool_instances.py
- Create
_resolve_git_mount_mappings(repo_path, mappings, working_directory) -> list[dict] - Iterates over mappings, expands globs, resolves targets
- Returns flat list of volume mount dicts
T1.4: Wire it together
File: apps/api/src/api/tool_instances.py
- Update
_resolve_single_git_mountto:- Normalize entry
- Clone repo once
- Resolve all mappings
- Return flat volume mounts
T1.5: Update merge logic
File: apps/api/src/services/config_profile_resolver.py
- Change
_merge_git_mountsmerge key from(remote_url, target_path)to(remote_url, branch) - When same repo+branch: concatenate
mappingsarrays - When different: append as separate entry
T1.6: Add validation
File: apps/api/src/api/config_profiles.py
- Validate
git_mountson create/update:remote_urlrequired- Either
mappings(non-empty array) OR (source_path+target_path) - Each mapping has
source_pathandtarget_path
T1.7: Unit tests
File: apps/api/tests/unit/test_git_mounts.py (new)
- Test normalization: legacy → mappings
- Test single clone with 3 mappings → 3 volume mounts
- Test glob expansion within mapping
- Test relative target resolution
File: apps/api/tests/unit/test_config_profile_resolver.py
- Update merge tests for new dedup key
T2: Frontend — Git mount mappings editor
T2.1: Update types
File: apps/web/src/api/config_profiles.ts
- Add
GitMountMappinginterface - Update
GitMountEntryto havemappings: GitMountMapping[] - Keep optional
source_path/target_pathfor backward compat
T2.2: Auto-convert legacy entries on load
File: apps/web/src/components/config-profile-editor.tsx or new GitMountEditor.tsx
- On loading a profile, normalize any git_mount entries that lack
mappings
T2.3: Build mappings UI
File: apps/web/src/components/GitMountEditor.tsx (new)
- Render table/list of mappings per git mount entry
- "Add mapping" button appends empty row
- "Remove" button deletes a mapping row
- Source path and target path inputs
T2.4: Integrate into ConfigProfileEditor
File: apps/web/src/components/config-profile-editor.tsx
- Replace existing git_mounts flat form with GitMountEditor component
- Ensure save sends correct JSON shape
T2.5: Frontend tests
File: apps/web/src/components/GitMountEditor.test.tsx (new)
- Render with 2 mappings
- Add mapping increases count
- Remove mapping decreases count
- Legacy entry auto-converts
T3: Integration & Verification
T3.1: Integration test
File: apps/api/tests/integration/test_config_profiles_git_mounts.py (new)
- Create profile with 2 mappings from same repo
- Start instance
- Verify single clone directory exists
- Verify 2 bind mounts in compose file
T3.2: Manual verification
- Create a Config Profile with a monorepo git mount + 3 mappings
- Create and start a pi-agent instance with the profile
- Verify all 3 directories are mounted correctly
- Verify legacy profile (single mapping) still works
T3.3: Typecheck & tests
cd apps/web && npm run typecheck
cd apps/api && pytest tests/unit/test_git_mounts.py tests/unit/test_config_profile_resolver.py
Estimation
| Task | Effort | Files |
|---|---|---|
| T1.1-T1.4 | 2h | 1 |
| T1.5 | 1h | 1 |
| T1.6 | 1h | 1 |
| T1.7 | 2h | 2 |
| T2.1-T2.4 | 3h | 3 |
| T2.5 | 1h | 1 |
| T3.1-T3.3 | 2h | 2 |
| Total | 12h | 11 |
PR Strategy
Single PR (~400 lines estimated, within review budget):
- Backend changes (T1)
- Frontend changes (T2)
- Tests (T1.7, T2.5, T3.1)
All changes are tightly coupled (backend schema + frontend UI + tests) so a single PR is appropriate.