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).
This commit is contained in:
2026-06-19 12:10:42 +02:00
parent 6d7f538a79
commit 10955dfe8e
28 changed files with 235 additions and 123 deletions
@@ -2,7 +2,7 @@
dir: apps/web/src/components/features
## role
Reusable UI feature components that compose domain-specific functionality for the web application.
Reusable UI components organized by domain-specific feature areas for the web application frontend.
## parent
index: apps/web/src/components/.pi-map.index.md
map: apps/web/src/components/.pi-map.md
+2 -2
View File
@@ -4,10 +4,10 @@ dir: apps/web/src/components/features
index: apps/web/src/components/features/.pi-map.index.md
## role
Reusable UI feature components that compose domain-specific functionality for the web application.
Reusable UI components organized by domain-specific feature areas for the web application frontend.
## files
## arch
Feature-based component organization with domain-driven design patterns, likely combining presentational components with localized state and business logic.
Feature-based component colocation pattern with domain-driven folder structure, separating shared/common components from page-specific feature implementations.
## tags
-
## symbols
@@ -2,7 +2,7 @@
dir: apps/web/src/components/features/tool
## role
Provides UI components for managing containerized development tools, including instance lifecycle management, manifest configuration, and workspace-integrated tool launching.
Provides UI components for managing containerized development tools, including starting, configuring, monitoring, and editing tool instances across workspaces.
## parent
index: apps/web/src/components/features/.pi-map.index.md
map: apps/web/src/components/features/.pi-map.md
@@ -4,18 +4,18 @@ dir: apps/web/src/components/features/tool
index: apps/web/src/components/features/tool/.pi-map.index.md
## role
Provides UI components for managing containerized development tools, including instance lifecycle management, manifest configuration, and workspace-integrated tool launching.
Provides UI components for managing containerized development tools, including starting, configuring, monitoring, and editing tool instances across workspaces.
## files
- instance-list.tsx | React component that displays and manages a list of tool instances with CRUD operations, real-time status updates, and configuration profile selection. | exp: InstanceList | dep: react, react-router-dom, ../../icon, ../../loading-overlay, ../../../api/sessions, ../../../api/tool-types, ../session/create-session-form, ../../../api/config-profiles, ../../../api/ssh-keys, ../../../state/events, ../../../state/sessions
- manifest-editor.tsx | A React component that provides a form-based UI for editing container manifest configurations including base images, packages, environment variables, scripts, mounts, and runtime settings, with live preview generation capability. | exp: ManifestEditor | dep: react, ../../icon, ../../../utils/errors, ../../../api/tool-definitions, icon, errors utils, tool-definitions API
- start-tool-fab.tsx | Renders a floating action button that opens a modal to select a workspace and start a tool. | exp: func:StartToolFAB(), call:useState, call:setOpen, call:setWorkspacesLoading, call:listAllWorkspaces, call:setWorkspaces, call:setSelectedWorkspace, call:e.stopPropagation, call:workspaces.find, call:workspaces.map | dep: react, ../../icon, ./tool-starter, ../../../types/workspace, ../../../api/workspaces, icon, tool-starter, workspace types, workspaces api
- start-tool-modal.tsx | React modal component for selecting a tool type and optional config profile to start a tool on a workspace | exp: StartToolModalProps, func:StartToolModal({ workspace, onClose, onStart, }: StartToolModalProps), call:useState, call:useAsyncData, call:e.preventDefault, call:setError, call:setSubmitting, call:onStart, call:onClose, call:e.stopPropagation, call:setToolTypeId, call:toolTypes?.map, call:setConfigProfileId | dep: react, ../../icon, ../../../api/tool-types, ../../../hooks/use-async-data, ../../../types/workspace
- tool-starter.tsx | React component for starting a tool instance within a workspace with configurable tool types, profiles, and SSH keys | exp: ToolStarterProps, func:ToolStarter({ workspace, onStarted, onCancel, }: ToolStarterProps), call:useSessions, call:useState, call:useEffect, call:listToolTypes, call:setToolTypes, call:setToolTypesError, call:setToolTypesLoading, call:load, call:setProfiles, call:setSelectedProfileId, call:setProfilesLoading, call:listConfigProfiles, call:data.find, call:listSSHKeys, call:setSshKeys, call:setSelectedSshKeyIds, call:console.error, call:setSshKeysLoading, call:sshKeys.find, call:useCallback, call:setError, call:setStarting, call:createInstance, call:displayName.trim, call:startInstance, call:addOrUpdateSession, call:onStarted, call:setSelectedToolTypeId, call:toolTypes.find, call:setDisplayName, call:toolTypes.map, call:setNameEdited, call:profiles.map, call:sshKeys.map, call:selectedSshKeyIds.includes, call:prev.filter | dep: react, ../../icon, ../../loading-overlay, ../../../api/tool-types, ../../../api/config-profiles, ../../../api/ssh-keys, ../../../state/sessions, ../../../types/workspace, ../../../api/sessions, icon, loading-overlay, tool-types, config-profiles, ssh-keys, sessions, workspace types, sessions api
- instance-list.tsx | Displays and manages tool instances for a project/repo with start/stop/restart/delete actions, config profile selection, SSH key selection, and real-time status updates. | exp: InstanceList | dep: react, react-router-dom, ../../icon, ../../loading-overlay, ../../../api/sessions, ../../../api/tool-types, ../session/create-session-form, ../../../api/config-profiles, ../../../api/ssh-keys, ../../../state/events, ../../../state/sessions, Icon, LoadingOverlay, sessions API, config-profiles API, ssh-keys API, events state, sessions state
- manifest-editor.tsx | A React component that provides a form-based UI for editing container manifest configurations including base images, packages, environment variables, scripts, mounts, and runtime settings, with live preview compilation. | exp: ManifestEditor | dep: react, ../../icon, ../../../utils/errors, ../../../api/tool-definitions, icon, errors utils, tool-definitions API
- start-tool-fab.tsx | Renders a floating action button that opens a modal for selecting a workspace and starting a tool. | exp: func:StartToolFAB(), call:useState, call:setOpen, call:setWorkspacesLoading, call:listAllWorkspaces, call:setWorkspaces, call:setSelectedWorkspace, call:e.stopPropagation, call:workspaces.find, call:workspaces.map | dep: react, ../../icon, ./tool-starter, ../../../types/workspace, ../../../api/workspaces
- start-tool-modal.tsx | A React modal component that allows users to select a tool type and optional configuration profile to start a tool on a specific workspace. | exp: StartToolModalProps, func:StartToolModal({ workspace, onClose, onStart, }: StartToolModalProps), call:useState, call:useAsyncData, call:e.preventDefault, call:setError, call:setSubmitting, call:onStart, call:onClose, call:e.stopPropagation, call:setToolTypeId, call:toolTypes?.map, call:setConfigProfileId | dep: react, ../../icon, ../../../api/tool-types, ../../../hooks/use-async-data, ../../../types/workspace, icon, tool-types, use-async-data, workspace
- tool-starter.tsx | React component for starting a tool instance within a workspace context, fetching and configuring tool types, profiles, and SSH keys. | exp: ToolStarterProps, func:ToolStarter({ workspace, onStarted, onCancel, }: ToolStarterProps), call:useSessions, call:useState, call:useEffect, call:listToolTypes, call:setToolTypes, call:setToolTypesError, call:setToolTypesLoading, call:load, call:setProfiles, call:setSelectedProfileId, call:setProfilesLoading, call:listConfigProfiles, call:data.find, call:listSSHKeys, call:setSshKeys, call:setSelectedSshKeyIds, call:console.error, call:setSshKeysLoading, call:sshKeys.find, call:useCallback, call:setError, call:setStarting, call:createInstance, call:displayName.trim, call:startInstance, call:addOrUpdateSession, call:onStarted, call:setSelectedToolTypeId, call:toolTypes.find, call:setDisplayName, call:toolTypes.map, call:setNameEdited, call:profiles.map, call:sshKeys.map, call:selectedSshKeyIds.includes, call:prev.filter | dep: react, ../../icon, ../../loading-overlay, ../../../api/tool-types, ../../../api/config-profiles, ../../../api/ssh-keys, ../../../state/sessions, ../../../types/workspace, ../../../api/sessions, icon, loading-overlay, tool-types, config-profiles, ssh-keys, sessions, workspace
- tools-bottom-sheet.tsx | Renders a mobile bottom sheet navigation menu for tools with active route highlighting | exp: ToolsBottomSheet | dep: react-router-dom, ../../icon, icon
## arch
Feature-based React component architecture with modal/bottom-sheet mobile-responsive patterns, form-driven configuration editing with live preview, and workspace-contextual tool orchestration.
React component-based architecture with feature-specific composition, using modal/bottom-sheet patterns for mobile-responsive navigation, form-based configuration editors with live preview, and real-time status polling for instance management.
## tags
call:set, tool, types, start, call:use, ssh, react, loading
call:set, tool, types, start, ssh, call:use, icon, loading
## symbols
- StartToolFAB
- StartToolModal
@@ -49,7 +49,7 @@ export const ManifestEditor = ({
const [startupScripts, setStartupScripts] = useState<string[]>([""]);
const [mounts, setMounts] = useState<MountEntry[]>([]);
const [command, setCommand] = useState<string[]>([""]);
const [workingDir, setWorkingDir] = useState("/workspace");
const [workingDir, setWorkingDir] = useState("");
const [stdinOpen, setStdinOpen] = useState(true);
const [tty, setTty] = useState(true);
@@ -94,7 +94,7 @@ export const ManifestEditor = ({
const runtime = (manifest.runtime as Record<string, unknown>) || {};
setCommand((runtime.command as string[]) || [""]);
setWorkingDir((runtime.working_dir as string) || "/workspace");
setWorkingDir((runtime.working_dir as string) || "");
setStdinOpen((runtime.stdin_open as boolean) ?? true);
setTty((runtime.tty as boolean) ?? true);
}, [manifest]);
@@ -561,7 +561,8 @@ export const ManifestEditor = ({
<textarea
value={script}
onChange={(e) => updateStartupScript(idx, e.target.value)}
placeholder="chown -R user:user /workspace"
placeholder="chown -R user:user $HOME/$WORKSPACE_NAME"
className="form-input font-mono text-sm flex-1"
rows={2}
/>
@@ -723,7 +724,7 @@ export const ManifestEditor = ({
type="text"
value={workingDir}
onChange={(e) => setWorkingDir(e.target.value)}
placeholder="/workspace"
placeholder="e.g., /workspace or ~/code"
className="form-input"
/>
</div>