Add project-aware chat startup defaults

Make repo-root chat startup native by letting MCP servers carry a default project source for workspace creation. When a chat host starts from a Git checkout, workspace_create can now omit seed_path and inherit the server startup source; explicit --project-path and clean-clone --repo-url/--repo-ref paths are supported as fallbacks.

Add project startup resolution and materialization, surface origin_kind/origin_ref in workspace_seed, update chat-host docs and the repro/fix smoke to use project-aware workspace creation, and switch dist-check to uv run pyro so verification stays stable after uv reinstalls.

Validated with uv lock, focused startup/server/CLI pytest coverage, UV_CACHE_DIR=.uv-cache make check, UV_CACHE_DIR=.uv-cache make dist-check, and real guest-backed smokes for both explicit project_path and bare repo-root auto-detection.
This commit is contained in:
Thales Maciel 2026-03-13 15:51:47 -03:00
parent 9b9b83ebeb
commit 535efc6919
28 changed files with 968 additions and 67 deletions

View file

@ -436,6 +436,36 @@ class _FakePyro:
workspace.shells.pop(shell_id, None)
return {"workspace_id": workspace_id, "shell_id": shell_id, "closed": True}
def create_server(self, *, profile: str, project_path: Path) -> Any:
assert profile == "workspace-core"
seed_path = Path(project_path)
outer = self
class _FakeServer:
async def call_tool(
self,
tool_name: str,
arguments: dict[str, Any],
) -> tuple[None, dict[str, Any]]:
if tool_name != "workspace_create":
raise AssertionError(f"unexpected tool call: {tool_name}")
result = outer.create_workspace(
environment=cast(str, arguments["environment"]),
seed_path=seed_path,
name=cast(str | None, arguments.get("name")),
labels=cast(dict[str, str] | None, arguments.get("labels")),
)
created = outer.status_workspace(cast(str, result["workspace_id"]))
created["workspace_seed"] = {
"mode": "directory",
"seed_path": str(seed_path.resolve()),
"origin_kind": "project_path",
"origin_ref": str(seed_path.resolve()),
}
return None, created
return _FakeServer()
def test_use_case_registry_has_expected_scenarios() -> None:
expected = (