55f8d9f81f
C-port the upstream /chats/{id}/project-dirs feature so the chat-scoped
project directory binding is fully functional on the cloud backend:
- services/project_directory.py (new): lean cloud adaptation of the
upstream module — normalize (dedupe/resolve/max 10), meta read for the
persisted override, effective resolution (session > agent > workspace),
nesting detection.
- chats/manager.py: set_session_project_dirs + get_session_project_dirs
persist the override in ChatSpec.meta[runtime_context] under the lock
(one-way migration: list supersedes legacy scalar).
- chats/api.py: GET/PUT/DELETE /{chat_id}/project-dirs + deprecated
/{chat_id}/project-dir views, with 422 on missing dirs and response
models matching the merged frontend (exists/nested_with/is_workspace).
- runtime/builder.py: session override feeds the per-turn coding project
dir (weakest source; fork/ACP still win), so bound directories actually
take effect for the chat's tools.
- Fix A: frontend projectDirectoryApi paths /workspace/project-directory*
-> /workspace/coding-project* (cloud backend already exposes these).
- Fix B: add POST /workspace/coding-project/browse-dirs/create for the
file-browser 'new folder' action (validated name, 409/403/500 mapping).
- Tauri system directory picker: 'Choose folder' button in the project
directory panel calls the @tauri-apps/plugin-dialog native directory
dialog (capability dialog:allow-open already granted), queueing the
pick as a session binding or the agent draft; hidden outside the Tauri
runtime; i18n across all 6 locales.
Verified: backend restart + curl (GET/PUT/DELETE project-dirs, deprecated
views, browse-dirs/create, 422/409/400 cases), dev-proxy end-to-end,
frontend tsc clean, vitest 25/25, production build 2m06s.