Commit Graph

13 Commits

Author SHA1 Message Date
Developer 6e33e8e4e9 fix: remove explicit repo mount from pi-agent manifest and derive workspace name from remote URL
The pi-agent manifest still declared an explicit repo mount with
{{WORKSPACE_NAME}}, making the mount target dependent on tool config. The
instance service now synthesizes the repo mount, so the manifest no longer
needs the explicit mount.

- Add Alembic migration 2026_06_15_090500 to remove the source_type: repo
  mount from the built-in pi-agent manifest
- Add _get_repository_mount_name() helper to derive the workspace directory
  name from the repository remote URL (matching git clone behavior) and
  fall back to the user-provided repository name
- Use the helper for WORKSPACE_NAME/REPO_NAME in manifest, legacy dockerfile,
  and legacy compose template paths
- Update unit tests for the new migration and helper

Quality gates:
- pytest tests/unit: 218 passed
- ruff: clean on changed files
- mypy: clean on changed files
- alembic heads: single head
2026-06-15 09:10:05 +00:00
Developer f0ae9483f3 fix: use repository name for workspace mount target
WORKSPACE_NAME was computed from os.path.basename(repo_path), so when a
workspace path ended in a directory like 'main', the container mount target
became /home/user/main instead of /home/user/{repo-name}.

- Use GitRepository.name for WORKSPACE_NAME/REPO_NAME in manifest and
  legacy dockerfile flows
- Add unit test verifying prepare_manifest_instance uses repo.name even
  when the workspace path basename differs

Quality gates:
- pytest tests/unit: 213 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 08:54:01 +00:00
Developer 90992e46a8 fix: remove stale {{WORKSPACE_NAME}} directory from container home
Older cached images still contain a literal /home/user/{{WORKSPACE_NAME}}
directory baked in by the previous Dockerfile generation. Even though new
images no longer create it, existing images leave the placeholder folder
alongside the real repo-named mount.

- Add entrypoint cleanup that removes /{{WORKSPACE_NAME}} if it
  exists before creating the real workspace target and /workspace symlink
- Update unit tests to assert the stale placeholder removal

Quality gates:
- pytest tests/unit: 212 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 08:41:27 +00:00
Developer 41f9427224 fix: avoid literal {{WORKSPACE_NAME}} directories in built images
When a manifest mount target uses ~/{{WORKSPACE_NAME}}, the Dockerfile was
building a literal directory named {{WORKSPACE_NAME}} into the image and
creating a broken /workspace symlink. The runtime mount then created the
correct repo-named folder alongside the placeholder folder.

- Only create static mount target directories in the Dockerfile; skip any
  target containing {{WORKSPACE_NAME}}
- Only create the /workspace compatibility symlink at image-build time when
  the workspace name is known; otherwise let the entrypoint create it from
  the WORKSPACE_NAME environment variable
- Update unit tests to cover both build-time workspace names and runtime
  placeholders

Quality gates:
- pytest tests/unit: 211 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 08:29:03 +00:00
Developer a4e6c46a47 fix: run manifest containers as root and drop privileges in entrypoint
The compose file was forcing the container to run as uid 1001, so the
entrypoint could not create /workspace even with sudo configured.

- Remove Dockerfile USER directive so containers start as root
- Make compile_compose use user: 0:0 when the manifest declares a user
- Make the entrypoint drop to the container user via  after setup,
  preserving environment variables and command arguments
- Update unit tests to assert root startup and privilege drop

Quality gates:
- pytest tests/unit: 210 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-14 21:32:27 +00:00
Developer 47de2a0133 fix: check root before sudo when creating /workspace symlink
The previous ordering checked SUDO before checking if the process was
already running as root. When Docker starts the container with a
non-root user, SUDO may be empty, but the real fix is that the
entrypoint should try root first (e.g. when the image is started as
root) and only then fall back to sudo.

- Reorder symlink creation logic: root first, then sudo, then best-effort
- Update unit test to assert root is checked before sudo

Quality gates:
- pytest tests/unit: 208 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-14 21:25:41 +00:00
Developer bd94cc9bbf fix: use sudo/root to create /workspace symlink in manifest entrypoint
The previous commit moved the pi-agent repo mount from /workspace to
/home/user/{repo_name}. This exposed a permission bug: the Dockerfile
creates /workspace as a root-owned symlink in the image, and the
non-root entrypoint could not replace it because / is owned by root.

- Update compile_entrypoint to recreate /workspace via sudo when running
  as the container user, or directly when running as root
- Add unit test covering sudo/root symlink creation
- Update OpenSpec change docs with the additional root cause

Quality gates:
- pytest tests/unit: 208 passed
- ruff: clean on changed files
- mypy: clean on changed files
- alembic heads: single head
2026-06-14 20:29:03 +00:00
Developer fe82a248ec fix: pi container repo mount target and npm update permissions
- Add Alembic migration to update built-in pi-agent manifest:
  * repo mount target from /workspace to ~/{{WORKSPACE_NAME}}
  * keep /workspace as compatibility symlink via working_dir
  * update startup chown target to $HOME/$WORKSPACE_NAME
- Pass REPO_NAME and WORKSPACE_NAME to compile_compose from instance_service
- Substitute {{WORKSPACE_NAME}} in manifest mount targets and expose it as
  a container env var so the entrypoint can create the /workspace symlink
- Generate entrypoint workspace symlink from runtime WORKSPACE_NAME env var
- Install npm_global packages into {home_dir}/.npm-global with PATH so the
  non-root container user can update global packages
- Update manifest compiler unit tests for the new behavior

Quality gates:
- pytest tests/unit: 207 passed
- ruff: clean on changed files
- mypy: clean on changed files
- alembic heads: single head
2026-06-14 18:45:32 +00:00
Developer ddd92e3dd4 feat: implement configurable tool container home directory
- Add ToolType.home_directory column with default /home/user
- Add Alembic migration to add column, set existing rows, and rewrite
  /workspace to /home/user/{{WORKSPACE_NAME}} in legacy templates
- Add merge migration fc8f1a20cbf6 to resolve Alembic multiple heads
- Update manifest compiler to honor manifest.home_directory for HOME,
  WORKDIR, /workspace symlink, and default repo mount target
- Update legacy dockerfile/compose instance generation to use
  tool_type.home_directory
- Thread resolved home_dir through config profile and git mount expansion
- Generate entrypoint permission fixer to chown home/mounts at startup
- Update base.dockerfile with sudo/passwordless sudo for permission fixer
- Add unit tests for manifest compiler, instance service, and migrations
- Add placeholder integration test for container lifecycle
- Update openspec/tasks/home-path-expansion.md task checkboxes
- Update project maps for modified files

Quality gates: py_compile, ruff, mypy, pytest tests/unit (205 passed),
pytest tests/integration (110 passed, 35 skipped). Alembic round-trip
and container lifecycle integration tests require Docker/PostgreSQL.
2026-06-14 13:09:41 +00:00
Developer d395aaf574 fix: stage config-profile mounts as directories so ~/.config stays writable
- Switch apply_resolved_profile from per-file bind mounts to one
  directory-level bind mount per ResolvedMount target.
- Stage all configured files under instance_dir/mounts/<sanitized_target>
  and bind-mount that directory, so Docker no longer creates a root-owned
  parent directory such as ~/.config.
- Propagate read-only mode ('ro') as the 'readonly' flag on volume entries.
- Update unit tests to expect directory-level mounts and add coverage for
  readonly/writable flags.

Quality gates: python3 -m py_compile, pytest (313 passed, 34 skipped),
npm run typecheck, npm run lint.
2026-06-13 11:56:48 +00:00
Developer 7ef8b0eb36 chore: patch project maps after stale backend test cleanup
Regenerate .pi-map*.md artifacts for source changes in:
- apps/api/src/api/tool/tool_types_validation.py
- apps/api/src/schemas/tool/tool_type.py
- apps/api/tests/integration/test_tool_types_api_extended.py
- and all affected test files from backend-frontend refactoring cleanup
2026-06-12 20:36:31 +00:00
Developer c26e9eacfa feat: complete workspace-first-ui cleanup and tests
- Delete dead repo-workspace code: RepoWorkspacePage, useRepoWorkspace,
  WorkspaceLayout, FileBrowser, old git components (git-toolbar, file-editor,
  commit-panel), and repo-workspace.css.
- Fix stale backend test imports for moved models/services.
- Add GitOperations unit tests.
- Add integration tests for workspace files, git, and instances endpoints.
- Add frontend tests for WorkspaceDetailPage and ProjectCard.
- Update OpenSpec workspace-first-ui tasks and mark change completed.
- Regenerate project maps.

Quality gates: npm run typecheck, npm run lint, npm test -- --run (87 passed),
python3 -m py_compile on changed backend files, pytest backend workspace tests.
2026-06-12 17:25:09 +00:00
Developer 070cd4d5a5 chore: track all project map and index files
Add generated .pi-map.md and .pi-map.index.md files across the repository
so the project navigation maps are shared and versioned. These artifacts
are maintained by project_map_init/patch/validate and must be kept in
sync with source edits.

Note: .cache/ remains ignored (added in previous commit).
2026-06-12 13:46:23 +00:00