Commit Graph

912 Commits

Author SHA1 Message Date
alex 3c96c7b153 Merge branch 'fix/remove-workspace-working-dir' into dev 2026-06-19 12:10:48 +02:00
alex 10955dfe8e fix(tool): stop defaulting manifest working_dir to /workspace
The /workspace compatibility symlink was removed from the manifest
compiler/entrypoint in 3e59a25. Tool definitions that still set
runtime.working_dir to /workspace therefore start in an empty directory
instead of /home/user/{repo_name}.

- manifest-editor.tsx: default working_dir to empty instead of /workspace;
  update startup-script placeholder to reference /home/alex/.
- Add Alembic migration 2026_06_19_113000 that clears the stale
  runtime.working_dir = /workspace from the built-in pi-agent manifest.
- Add migration import test.

Quality gates: pytest tests/api tests/services/test_terminal_manager_multi.py tests/unit (248 passed), ruff check (clean), npx tsc --noEmit (clean), eslint (clean).
2026-06-19 12:10:42 +02:00
alex 6d7f538a79 Merge branch 'fix/terminal-manifest-lazyload' into dev 2026-06-19 11:48:59 +02:00
alex b32fea671f fix(terminal): avoid lazy-loading tool manifest in async websocket handler
The container-user resolver introduced in 9f72093 accessed
'tool_type.manifest', which triggers a SQLAlchemy lazy load inside the
async WebSocket coroutine and raises MissingGreenlet. Fetch the manifest
explicitly with db_session.get() instead, matching the pattern used in
instance_service.py.

- Replace relationship access with explicit async loads in
  _resolve_container_user().
- Add unit tests covering manifest, base-definition, legacy, and missing
  manifest cases.
- Update project map artifacts.

Quality gates: pytest tests/api tests/services/test_terminal_manager_multi.py tests/unit (247 passed), ruff check (clean).
2026-06-19 11:48:53 +02:00
Developer 19f91c085e Merge branch 'dev' of ssh://git.commumedia.org:2222/alex/headquarter into dev 2026-06-17 20:57:27 +00:00
Developer 155d950556 Merge branch 'fix/pi-container-terminal-root-user' into dev 2026-06-17 20:52:02 +00:00
Developer 9f720930ea fix: run tool terminal sessions as container user instead of root
- Remove compose-level user: 0:0 override from manifest_compiler.py so the
  entrypoint can start as root, fix mount ownership, and drop privileges to
  the container user internally.
- Add get_manifest_container_user() helper to resolve the manifest-declared
  container user (with uid:gid fallback).
- Pass container user through TerminalSession, TerminalManager, and the
  terminal WebSocket handler so docker exec is invoked with --user <user>.
- Update and add unit tests for the manifest compiler and terminal session.
- Record the additional root-user fix in the fix-pi-container-mount-permissions
  OpenSpec change/tasks.

Quality gates: pytest tests/unit/ (226 passed), pytest tests/services/test_terminal_manager_multi.py (7 passed), ruff check on changed files (clean), mypy on changed files (clean)
2026-06-17 20:51:46 +00:00
alex 428c70beaa fix: resolve project variable in create_tool_instance 2026-06-17 16:12:37 +02:00
alex 1c6dbcede8 fix: resolve project variable in create_tool_instance
create_tool_instance fetched `project` only inside the auto-display-name
branch, so callers supplying display_name left it unbound and the
manifest/dockerfile/compose branches crashed with UnboundLocalError at
_get_repository_mount_name (in-container layout /home/user/{project_name}).

Resolve project unconditionally after repo validation with a not-found
guard (narrowing Project|None -> Project), and drop the now-redundant
fetch from the auto-name branch. Add a regression test covering the
manifest + display_name path.

Quality gates: ruff, mypy, pytest (74 unit tests passed)
2026-06-17 16:12:22 +02:00
Developer 3e59a257dc feat(terminal): use project name for in-container cwd and clone directory 2026-06-17 13:26:16 +00:00
Developer 93da9b42a2 chore(project-map): regenerate .pi-map artifacts across the repo 2026-06-17 11:31:24 +00:00
Developer 0dd5f2317b fix(web/ui): improve nav-item hover contrast 2026-06-17 09:53:33 +00:00
Developer ab93863ea9 fix(web/ui): restore nav-item anchor styling for live session items 2026-06-17 09:47:37 +00:00
Developer 85627793b4 merge: fix/ui-padding-issues 2026-06-16 21:55:07 +00:00
Developer 8b6a4f7712 fix(web/ui): resolve padding and dialog layout issues from audit
- Remove conflicting .dialog/.dialog-body rules from utilities.css
- Fix live-session sidebar alignment and padding
- Wrap ProjectDialog, RepositoryCreateDialog, WorkspacesPage modals in .dialog-header/.dialog-body
- Migrate SessionsPage dirty-delete modal from .modal-* to .dialog-*
- Add padding to .project-card
- Fix session-card-actions border token (var(--border))
- Remove duplicate .dialog-actions rule in global.css
- Add pb-20 bottom clearance to ConfigProfile/ToolType editor scroll containers
- Add .card-md padding to ErrorState
2026-06-16 21:54:55 +00:00
Developer bf698b3ff2 feat(web/ui): unify session opening and add repo card in project list
- Add openSession utility with tab deduplication/focus
- Use openSession in navbar live sessions, use-instance-actions, and project tool links
- Pass onAddRepository to ProjectListItem and add dashed 'Add Repository' card
- Style add-repo card in projects.css
2026-06-16 21:31:38 +00:00
Developer d5119f29f6 feat(web/ui): merge project pane rework into dev 2026-06-16 21:20:15 +00:00
Developer 563ff13969 feat(web/ui): rework project pane into flat list with repo/workspace/tool hierarchy
- Add ProjectListItem component with project header actions
- Show repositories horizontally with branch labels
- List workspaces vertically under each repo
- Show running tools per workspace from useSessions
- Link workspace names to /workspaces/:id
- Link tool names to web URL or terminal page
- Keep existing mobile view and dialogs unchanged
2026-06-16 21:20:04 +00:00
Developer 39bac24100 fix(web/ui): align project heading left and keep add-repo button near title 2026-06-16 21:00:47 +00:00
Developer 889c598129 fix(web/ui): make config-section-actions sticky for both editors 2026-06-16 16:25:23 +00:00
Developer ac56c5e391 fix(web/ui): correct project card layout and unify config section actions
- Fix .project-card flex direction so expanded repos align left
- Add .config-section-actions for consistent save bars
- Replace sticky footer in Config Profiles with config-section-actions
- Replace dialog-actions in Tool Type editor with config-section-actions
- Convert manifest editor preview block to .config-section
2026-06-16 16:06:08 +00:00
Developer 17f4e91a84 feat(web/ui): merge ui polish round into dev 2026-06-16 15:56:13 +00:00
Developer b3f47310c3 docs(openspec): add ui polish round proposal, spec, and tasks 2026-06-16 15:56:06 +00:00
Developer 972dae64f2 feat(web/ui): unify config sections, restore home padding, improve project repos
- Add shared .config-section component class and migrate Tool Workshop
  and Config Profiles editors to use it.
- Restore --space-4 padding on home hero, summary cards, and sections
  with --space-3 on mobile.
- Restructure expandable project card: add 'Repositories' header with
  repo count and move 'Add Repository' button into the section header.
- Left-align repository blocks so they fill from the project detail edge.
2026-06-16 15:55:58 +00:00
Developer cbd5533adf feat(web/ui): merge Pass 3 consolidation and polish into dev 2026-06-16 15:27:58 +00:00
Developer 6e419f815d feat(web/ui): consolidate dialogs, cards, and breakpoints (Pass 3)
- Unify modal/dialog system; .modal-* are now aliases of .dialog-*
- Migrate WorkspacesPage, start-tool-modal, merge-dialog, workspace-tools-panel to .dialog-*
- Add .card-sm/.card-md/.card-lg/.card-elevated/.card-borderless modifiers
- Apply card utilities across workspaces, projects, ssh-keys, workspace-detail, git-history
- Remove duplicated card-like background/border/padding from page CSS
- Remove 860px breakpoint; standardize on 767px/768px mobile split
- Add docs/development/ui-review-checklist.md
- Archive web-ui-spacing-typography-rework OpenSpec change
2026-06-16 15:27:45 +00:00
Developer 4f4939406f docs(openspec): note push pending status in pass 2 report 2026-06-16 15:03:54 +00:00
Developer f47cf27720 feat(web/ui): merge pass 2 component cleanup into dev 2026-06-16 14:48:37 +00:00
Developer 6559c2a1d9 docs(openspec): add pass 2 spec, tasks, and completion report 2026-06-16 14:48:30 +00:00
Developer 5d5b39bec1 feat(web/ui): refactor component inline styles into utility classes
Pass 2 of the web UI spacing/typography/visual-rhythm rework.

- Add layout, spacing, typography, visual, card, and component utilities
- Add form-section, form-row, form-help, text-error, alert-success
- Unify .form-group and .form-field; add .status-badge family
- Alias legacy button classes to .btn primitives
- Refactor ToolTypeListSidebar and ConfigProfileListSidebar to use .sidebar
  and var(--sidebar-width) instead of hardcoded 280px
- Refactor ToolTypeEditorPanel, ConfigProfileEditorPanel,
  git-mount-editor, and manifest-editor to use utility classes

Quality gates: npm run typecheck, npm run lint, npm run build pass.
Inline style blocks in target components reduced from 198 to 11.
2026-06-16 14:47:37 +00:00
Developer 38d116dcf7 docs(openspec): mark pass 1 tasks complete 2026-06-16 12:24:31 +00:00
Developer da3f8da3ac docs(openspec): add web ui spacing/typography proposal, spec, tasks and audit 2026-06-16 12:24:10 +00:00
Developer 454a7845bb feat(web/ui): replace inline font-size violations and use new primitives in components 2026-06-16 12:24:04 +00:00
Developer 50e3af0d91 feat(web/ui): add mobile detail/search, ssh/profile utilities and nav-height tokens 2026-06-16 12:23:59 +00:00
Developer 8e1af41cd3 feat(web/ui): expand design tokens and add primitive component styles 2026-06-16 12:23:53 +00:00
Developer 355b471067 feat(web): redesign navbar live session items for scanability
Restructure live session nav entries into a 3-line layout:
- workspace/repository context on top
- session display name in the middle
- tool type and project on the bottom

Tool icon now has a status-dot badge, and the tooltip lists
display name, tool, project, context, and status.
2026-06-16 11:13:10 +00:00
Developer a2f0847aad Merge branch 'fix/terminal-session-callbacks' into dev 2026-06-15 13:53:15 +00:00
Developer 82ff8b8801 fix: route terminal callbacks and status per session
The recent redraw fix keeps all xterm instances mounted (display:none)
when switching sessions. However, sendData/focus/font-size refs and the
header connection status were still stored globally, so the last-mounted
hidden session could own keyboard input, font-size buttons, and the
status dot for the active session.

- Pass sessionId to onTerminalReady from TerminalComponent.
- Store terminal callbacks and status keyed by sessionId in use-terminal-page.
- Use activeSessionId to route special-key input, font-size changes, and header status.
- Clean up per-session refs and status when sessions are closed.
- Update MobileTerminalWrapper signature for the new callback shape.

Quality gates: npm run typecheck, npm run lint, npm test (87 passed)
2026-06-15 13:53:09 +00:00
Developer a6ad8268b9 fix: preserve terminal buffer across tab switches and focus regain
Render all terminal sessions and hide inactive ones with display:none so
xterm instances are no longer unmounted/remounted when switching tabs.

Remove terminal.clear() on the connected status message: the server keeps
the session buffer, and clearing was erasing visible content when the tab
regained focus or reconnected.

- Keep TerminalComponent instances alive in both Desktop and Mobile views.
- Only refit/resize on reconnect instead of clearing.

Closes terminal redraw on focus regain.
2026-06-15 13:11:08 +00:00
Developer 3358af57c2 fix: stack profile file mounts onto profile git-mounts to avoid masking
When a config profile declares both a git_mount and a mounts entry for the
same directory (e.g. ~/.pi), the generated bind-mounts would mask each other
inside the container. Instead, copy the static profile files into the
instance-scoped git-mount source directory so the container sees both the
cloned repo contents and the static files through a single bind-mount.

- Add _stack_profile_mounts_with_git_mounts helper to merge overlapping
  profile mounts into git-mount sources.
- Integrate stacking into start_tool_instance after resolving both mount
  types.
- Add unit tests for exact, descendant, non-overlapping, and file cases.
2026-06-15 12:50:19 +00:00
Developer 6a61669294 fix: git repo mount race and path resolution
- Include branch in git-mount clone dir hash so different branches of the
  same repo get separate directories and no longer race.
- Resolve profile working_directory before git mounts so relative targets
  are not silently skipped.
- Fall back to tool_type.home_directory for non-manifest tools.
- Fix glob target calculation to avoid duplicate directory segment.
- Add exc_info logging for git mount clone failures.
2026-06-15 12:15:50 +00:00
Developer 29e48cdb65 fix: force interactive login shell for bash containers
Detached containers with tty: true still exited immediately because a
plain /bin/bash invocation exits with code 0 when stdin is not connected.

- Detect when the container CMD is /bin/bash or bash and exec an
  interactive login shell () after dropping privileges
- Keep the generic  path for non-shell commands
- Bump compiler_version to v4 to force a fresh image build

Quality gates:
- pytest tests/unit: 219 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 11:18:28 +00:00
Developer ed1f7805f6 fix: bump compiler version to v3 for runuser entrypoint
The previous compiler_version v2 already produced an image tag
(3d34c636) for the su-based fix. Images built under v2 still had the
broken su entrypoint that exited immediately. Bump to v3 so the runuser
change forces a fresh image build with the corrected privilege drop.

Quality gates:
- pytest tests/unit: 219 passed
2026-06-15 11:09:20 +00:00
Developer 1d345eba32 fix: use runuser for privilege drop and capture container stderr in logs
The container still exited immediately after the su-based fix.  can
interfere with TTY/stdin handling for interactive shells. Switch to
, which is root-only, skips PAM, and preserves file descriptors so
bash stays interactive.

Also improve container failure diagnostics:
-  now combines stdout and stderr
- This helps surface the real reason when a container exits with code 0

Quality gates:
- pytest tests/unit: 219 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 10:41:37 +00:00
Developer e35e605914 fix: bump manifest image tag when compiler logic changes
compute_image_tag hashed only the manifest JSON, so cached images built
before the entrypoint fix were reused even though compile_entrypoint() now
produces a different entrypoint. This caused containers to keep using the
old (broken) entrypoint that exited immediately.

- Include a compiler_version token in the hash input so manifest compiler
  changes invalidate previously built images
- This forces a fresh image build for new instances after any change to
  compile_dockerfile, compile_entrypoint, or compile_compose

Quality gates:
- pytest tests/unit: 219 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 10:22:36 +00:00
Developer 94137c6586 fix: use login shell when dropping privileges in manifest entrypoint
The generated entrypoint used a brittle  invocation that could
spawn a non-interactive bash and exit immediately, causing containers to
stop with exit code 0 right after startup.

- Switch to  so the
  container user gets a login shell and stdin/tty are preserved
- Update the unit test assertion for the new drop-privileges command

Quality gates:
- pytest tests/unit: 219 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 10:18:52 +00:00
Developer 1658767cf4 fix: clone workspace into repo-named subdirectory directly
Git clone with an explicit destination puts the working copy directly into
that directory; it does not create a repo-named subdirectory. The previous
change assumed the opposite, so workspaces ended up at
/data/working-copies/{workspace_id}/ with the repo contents mixed in,
causing a 500 when the expected repo-named subdirectory was missing.

- Build the target path as /data/working-copies/{workspace_id}/{repo_name}/
  and pass it directly to GitService.clone
- Remove stale directory detection and fallback logic that is no longer
  needed
- Keep diagnostic logging around git clone failures

Quality gates:
- pytest tests/unit: 219 passed
- mypy: clean on changed files
2026-06-15 10:09:30 +00:00
Developer 83928d0f02 chore: add diagnostic logging around workspace git clone
The workspace creation endpoint returns 500 but the actual error is not
visible. Add explicit error logging when GitService.clone fails and info
logging when git creates a directory name different from the one derived
from the remote URL.

Quality gates:
- pytest tests/unit: 219 passed
- mypy: clean on changed files
2026-06-15 10:04:34 +00:00
Developer 8f648264f1 fix: surface real workspace creation errors instead of generic 409
The create-workspace endpoints caught every exception and returned 409
"Workspace name already exists", hiding the actual failure (e.g. git
clone errors, remote URL problems, or filesystem issues).

- Distinguish ValueError -> 400, unexpected exceptions -> 500 with detail
- Preserve HTTPException re-raise for existing FastAPI error paths

Quality gates:
- pytest tests/unit: 219 passed
- mypy: clean on changed files
2026-06-15 09:46:55 +00:00
Developer b26ed7c3e4 refactor: store workspaces as {workspace_id}/{repo_name} for natural git clone layout
Working copies were stored as /data/working-copies/{repo_id}/{workspace_name}/,
so git clone was forced into a user-named directory. That meant the container
mount basename was the workspace name (e.g. main) instead of the repo name.

- Generate the workspace UUID before cloning and clone into
  /data/working-copies/{workspace_id}/ so git creates {repo_name}/ naturally
- Set workspace.path to /data/working-copies/{workspace_id}/{repo_name}/
- Update _migrate_clone_into_workspace() to use the same layout
- _get_repository_mount_name() now prefers workspace.path basename and only
  falls back to remote URL / repo.name for legacy repo-only instances
- Update unit tests to assert workspace path basename is used for mounts

Quality gates:
- pytest tests/unit: 219 passed
- ruff: clean on changed files
- mypy: clean on changed files
2026-06-15 09:40:59 +00:00