Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .beads/issues.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
{"id":"agentspaces-u7i","title":"Add E2E tests for project create command","description":"## Context\nThe agentspaces CLI has a `project create` command (src/agentspaces/cli/project.py) that initializes new projects with templates. It:\n- Works in current directory (requires empty or git-only directory)\n- Runs `git init` if not already a git repo\n- Creates skeleton files (CLAUDE.md, README.md, docs/, .claude/)\n- Optionally creates Python pack files with `--python` flag\n\n## Goal\nAdd comprehensive E2E/integration tests that exercise the full command flow with real git operations in isolated temporary directories.\n\n## Deliverables\n1. pytest marker configuration in pyproject.toml\n2. Integration test fixtures in tests/integration/cli/conftest.py\n3. Test implementation in tests/integration/cli/test_project_create.py (~22 tests)\n\n## Test Categories\n- Basic creation (empty dir, existing git, --python flag)\n- Python package naming (edge cases for name derivation)\n- Error handling (non-empty dir, confirmation prompt)\n- Content validation (project info in generated files)\n- Git integration (valid repo, untracked files)\n- Edge cases (special chars, unicode, nested dirs)\n\n## Safety Requirements\n- All tests use temporary directories (auto-cleanup)\n- Tests marked with @pytest.mark.integration for selective runs\n- No modifications to host environment or ~/.agentspaces","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-09T07:56:26.870453-05:00","created_by":"ckrough","updated_at":"2026-01-09T09:58:34.334635-05:00","closed_at":"2026-01-09T09:58:34.334635-05:00","close_reason":"All subtasks completed: pytest markers, fixtures, 23 tests, CLAUDE.md updated"}
{"id":"agentspaces-um3","title":"Phase 2: Extend Project CLAUDE.md with Beads section","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-08T14:52:51.261354-05:00","created_by":"ckrough","updated_at":"2026-01-08T14:54:02.518158-05:00","closed_at":"2026-01-08T14:54:02.518158-05:00","close_reason":"Added Beads workflow and Learned Patterns sections to project CLAUDE.md"}
{"id":"agentspaces-w0j","title":"Phase 8: Add PostToolUse auto-format hook","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-08T14:52:52.768009-05:00","created_by":"ckrough","updated_at":"2026-01-08T15:30:39.116749-05:00","closed_at":"2026-01-08T15:30:39.116749-05:00","close_reason":"Created PostToolUse auto-format hook for Python files"}
{"id":"agentspaces-yjh","title":"Simplify workspace navigation and venv activation after creation","description":"## Context\nAfter running 'agentspaces workspace create', users see a 'Next Steps' section with commands to cd and activate venv. This requires copying/pasting long paths.\n\n## Goal\nProvide a simpler way for users to navigate to workspace and activate venv without manual copying/pasting.\n\n## Current Behavior\nUsers must copy/paste:\n1. cd /Users/ckrough/.agentspaces/agentspaces/sleepy-fermat\n2. source .venv/bin/activate\n\n## Desired Behavior\nSingle command or automated navigation that minimizes user effort.\n\n## Files Involved\n- src/agentspaces/cli/workspace.py - workspace create command\n- src/agentspaces/modules/workspace/service.py - workspace creation logic\n\n## Verification\n1. Create a new workspace\n2. Verify simplified navigation/activation works\n3. uv run pytest tests/ -k workspace","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-09T14:52:35.442563-05:00","created_by":"ckrough","updated_at":"2026-01-09T15:21:26.303403-05:00","closed_at":"2026-01-09T15:21:26.303403-05:00","close_reason":"Implemented: Combined cd and venv activation into single command, removed workspace remove step, added path quoting for safety"}
14 changes: 9 additions & 5 deletions src/agentspaces/cli/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import shlex
from datetime import UTC, datetime
from typing import TYPE_CHECKING

Expand Down Expand Up @@ -97,18 +98,21 @@ def print_workspace_created(
console.print(panel)


def print_next_steps(workspace_name: str, workspace_path: str, has_venv: bool) -> None:
def print_next_steps(workspace_path: str, has_venv: bool) -> None:
"""Print actionable next steps after workspace creation.

Args:
workspace_name: Name of the created workspace.
workspace_path: Path to the workspace directory.
has_venv: Whether a virtual environment was created.
"""
steps = [f"cd {workspace_path}"]
# Quote path for shell safety
quoted_path = shlex.quote(workspace_path)

# Combine cd and venv activation into single command
if has_venv:
steps.append("source .venv/bin/activate")
steps.append(f"agentspaces workspace remove {workspace_name}")
steps = [f"cd {quoted_path} && source .venv/bin/activate"]
else:
steps = [f"cd {quoted_path}"]

lines = [f" {i + 1}. [cyan]{step}[/cyan]" for i, step in enumerate(steps)]
panel = Panel(
Expand Down
1 change: 0 additions & 1 deletion src/agentspaces/cli/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ def create(
)

print_next_steps(
workspace_name=workspace.name,
workspace_path=str(workspace.path),
has_venv=workspace.has_venv,
)
Expand Down
31 changes: 24 additions & 7 deletions tests/unit/cli/test_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class TestPrintNextSteps:
def test_prints_cd_step(self) -> None:
"""Should include cd to workspace path."""
with patch("agentspaces.cli.formatters.console") as mock_console:
print_next_steps("test-ws", "/path/to/workspace", has_venv=False)
print_next_steps("/path/to/workspace", has_venv=False)
mock_console.print.assert_called()
# Get all printed content - find the Panel with "Next Steps"
panel = _find_next_steps_panel(mock_console)
Expand All @@ -67,23 +67,40 @@ def test_prints_cd_step(self) -> None:
def test_includes_venv_activation_when_has_venv(self) -> None:
"""Should include venv activation when has_venv is True."""
with patch("agentspaces.cli.formatters.console") as mock_console:
print_next_steps("test-ws", "/path/to/workspace", has_venv=True)
print_next_steps("/path/to/workspace", has_venv=True)
panel = _find_next_steps_panel(mock_console)
assert "source .venv/bin/activate" in panel.renderable

def test_excludes_venv_activation_when_no_venv(self) -> None:
"""Should not include venv activation when has_venv is False."""
with patch("agentspaces.cli.formatters.console") as mock_console:
print_next_steps("test-ws", "/path/to/workspace", has_venv=False)
print_next_steps("/path/to/workspace", has_venv=False)
panel = _find_next_steps_panel(mock_console)
assert "source .venv/bin/activate" not in panel.renderable

def test_includes_remove_step(self) -> None:
"""Should include workspace remove step with workspace name."""
def test_combines_cd_and_activation(self) -> None:
"""Should combine cd and activation into single command with &&."""
with patch("agentspaces.cli.formatters.console") as mock_console:
print_next_steps("test-ws", "/path/to/workspace", has_venv=False)
print_next_steps("/path/to/workspace", has_venv=True)
panel = _find_next_steps_panel(mock_console)
assert "agentspaces workspace remove test-ws" in panel.renderable
assert "cd" in panel.renderable
assert "&&" in panel.renderable
assert "source .venv/bin/activate" in panel.renderable

def test_does_not_include_remove_command(self) -> None:
"""Should not include workspace remove command."""
with patch("agentspaces.cli.formatters.console") as mock_console:
print_next_steps("/path/to/workspace", has_venv=False)
panel = _find_next_steps_panel(mock_console)
assert "remove" not in panel.renderable

def test_quotes_path_with_spaces(self) -> None:
"""Should properly quote paths containing spaces."""
with patch("agentspaces.cli.formatters.console") as mock_console:
print_next_steps("/path/with spaces/workspace", has_venv=False)
panel = _find_next_steps_panel(mock_console)
# shlex.quote adds single quotes around paths with spaces
assert "'/path/with spaces/workspace'" in panel.renderable


class TestPrintDidYouMean:
Expand Down