stuff that was not comitted.
This commit is contained in:
@@ -105,11 +105,11 @@ This file tracks all major tracks for the project. Each track has its own detail
|
|||||||
|
|
||||||
### Path Configuration
|
### Path Configuration
|
||||||
|
|
||||||
1. [ ] **Track: Project-Specific Conductor Directory**
|
1. [x] **Track: Project-Specific Conductor Directory**
|
||||||
*Link: [./tracks/project_conductor_dir_20260308/](./tracks/project_conductor_dir_20260308/)*
|
*Link: [./tracks/project_conductor_dir_20260308/](./tracks/project_conductor_dir_20260308/)*
|
||||||
*Goal: Make conductor directory per-project. Each project TOML can specify custom conductor dir for isolated track/state management.*
|
*Goal: Make conductor directory per-project. Each project TOML can specify custom conductor dir for isolated track/state management.*
|
||||||
|
|
||||||
2. [ ] **Track: GUI Path Configuration in Context Hub**
|
2. [x] **Track: GUI Path Configuration in Context Hub**
|
||||||
*Link: [./tracks/gui_path_config_20260308/](./tracks/gui_path_config_20260308/)*
|
*Link: [./tracks/gui_path_config_20260308/](./tracks/gui_path_config_20260308/)*
|
||||||
*Goal: Add path configuration UI to Context Hub. Allow users to view and edit configurable paths directly from the GUI.*
|
*Goal: Add path configuration UI to Context Hub. Allow users to view and edit configurable paths directly from the GUI.*
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
# Implementation Plan: External MCP Server Support
|
# Implementation Plan: External MCP Server Support
|
||||||
|
|
||||||
## Phase 1: Configuration & Data Modeling
|
## Phase 1: Configuration & Data Modeling [checkpoint: 4ba1bd9]
|
||||||
- [x] Task: Define the schema for external MCP server configuration. [1c863f0]
|
- [x] Task: Define the schema for external MCP server configuration. [1c863f0]
|
||||||
- [x] Update `src/models.py` to include `MCPServerConfig` and `MCPConfiguration` classes.
|
- [x] Update `src/models.py` to include `MCPServerConfig` and `MCPConfiguration` classes.
|
||||||
- [x] Implement logic to load `mcp_config.json` from global and project-specific paths.
|
- [x] Implement logic to load `mcp_config.json` from global and project-specific paths.
|
||||||
- [x] Task: Integrate configuration loading into `AppController`. [c09e0f5]
|
- [x] Task: Integrate configuration loading into `AppController`. [c09e0f5]
|
||||||
- [x] Ensure the MCP config path is correctly resolved from `config.toml` and `manual_slop.toml`.
|
- [x] Ensure the MCP config path is correctly resolved from `config.toml` and `manual_slop.toml`.
|
||||||
- [x] Task: Write unit tests for configuration loading and validation. [c09e0f5]
|
- [x] Task: Write unit tests for configuration loading and validation. [c09e0f5]
|
||||||
- [ ] Task: Conductor - User Manual Verification 'Phase 1: Configuration & Data Modeling' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Phase 1: Configuration & Data Modeling' [4ba1bd9]
|
||||||
|
|
||||||
## Phase 2: MCP Client Extension
|
## Phase 2: MCP Client Extension [checkpoint: 828fadf]
|
||||||
- [ ] Task: Implement `ExternalMCPManager` in `src/mcp_client.py`.
|
- [x] Task: Implement `ExternalMCPManager` in `src/mcp_client.py`. [828fadf]
|
||||||
- [ ] Add support for managing multiple MCP server sessions.
|
- [x] Add support for managing multiple MCP server sessions.
|
||||||
- [ ] Implement the `StdioMCPClient` for local subprocess communication.
|
- [x] Implement the `StdioMCPClient` for local subprocess communication.
|
||||||
- [ ] Implement the `RemoteMCPClient` for SSE/WebSocket communication.
|
- [x] Implement the `RemoteMCPClient` for SSE/WebSocket communication (stub).
|
||||||
- [ ] Task: Update Tool Discovery.
|
- [x] Task: Update Tool Discovery. [828fadf]
|
||||||
- [ ] Implement `list_external_tools()` to aggregate tools from all active external servers.
|
- [x] Implement `list_external_tools()` to aggregate tools from all active external servers.
|
||||||
- [ ] Task: Update Tool Dispatch.
|
- [x] Task: Update Tool Dispatch. [828fadf]
|
||||||
- [ ] Modify `mcp_client.dispatch()` and `mcp_client.async_dispatch()` to route tool calls to either native tools or the appropriate external server.
|
- [x] Modify `mcp_client.dispatch()` and `mcp_client.async_dispatch()` to route tool calls to either native tools or the appropriate external server.
|
||||||
- [ ] Task: Write integration tests for stdio and remote MCP client communication (using mock servers).
|
- [x] Task: Write integration tests for stdio and remote MCP client communication (using mock servers). [828fadf]
|
||||||
- [ ] Task: Conductor - User Manual Verification 'Phase 2: MCP Client Extension' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Phase 2: MCP Client Extension' [828fadf]
|
||||||
|
|
||||||
## Phase 3: GUI Integration & Lifecycle
|
## Phase 3: GUI Integration & Lifecycle [checkpoint: 3b2588a]
|
||||||
- [ ] Task: Update the **Operations** panel in `src/gui_2.py`.
|
- [x] Task: Update the **Operations** panel in `src/gui_2.py`. [3b2588a]
|
||||||
- [ ] Create a new "External Tools" section.
|
- [x] Create a new "External Tools" section.
|
||||||
- [ ] List discovered tools from active external servers.
|
- [x] List discovered tools from active external servers.
|
||||||
- [ ] Add a "Refresh External MCPs" button to reload configuration and rediscover tools.
|
- [x] Add a "Refresh External MCPs" button to reload configuration and rediscover tools.
|
||||||
- [ ] Task: Implement Lifecycle Management.
|
- [x] Task: Implement Lifecycle Management. [3b2588a]
|
||||||
- [ ] Add the "Auto-start on Project Load" logic to start servers when a project is initialized.
|
- [x] Add the "Auto-start on Project Load" logic to start servers when a project is initialized.
|
||||||
- [ ] Add status indicators (e.g., color-coded dots) for each external server in the GUI.
|
- [x] Add status indicators (e.g., color-coded dots) for each external server in the GUI.
|
||||||
- [ ] Task: Write visual regression tests or simulation scripts to verify the updated Operations panel.
|
- [x] Task: Write visual regression tests or simulation scripts to verify the updated Operations panel. [3b2588a]
|
||||||
- [ ] Task: Conductor - User Manual Verification 'Phase 3: GUI Integration & Lifecycle' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Phase 3: GUI Integration & Lifecycle' [3b2588a]
|
||||||
|
|
||||||
## Phase 4: Agent Integration & HITL
|
## Phase 4: Agent Integration & HITL [checkpoint: f4c5a0b]
|
||||||
- [ ] Task: Update AI tool declarations.
|
- [x] Task: Update AI tool declarations. [f4c5a0b]
|
||||||
- [ ] Ensure `ai_client.py` includes external tools in the tool definitions sent to Gemini/Anthropic.
|
- [x] Ensure `ai_client.py` includes external tools in the tool definitions sent to Gemini/Anthropic.
|
||||||
- [ ] Task: Verify HITL Approval Flow.
|
- [x] Task: Verify HITL Approval Flow. [f4c5a0b]
|
||||||
- [ ] Ensure that calling an external tool correctly triggers the `ConfirmDialog` modal.
|
- [x] Ensure that calling an external tool correctly triggers the `ConfirmDialog` modal.
|
||||||
- [ ] Verify that approved external tool results are correctly returned to the AI.
|
- [x] Verify that approved external tool results are correctly returned to the AI.
|
||||||
- [ ] Task: Perform a final end-to-end verification with a real external MCP server.
|
- [x] Task: Perform a final end-to-end verification with a real external MCP server. [f4c5a0b]
|
||||||
- [ ] Task: Conductor - User Manual Verification 'Phase 4: Agent Integration & HITL' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Phase 4: Agent Integration & HITL' [f4c5a0b]
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
## Phase 1: Path Info Display
|
## Phase 1: Path Info Display
|
||||||
Focus: Show current path resolution in GUI
|
Focus: Show current path resolution in GUI
|
||||||
|
|
||||||
- [ ] Task 1.1: Add path info functions to paths.py
|
- [x] Task 1.1: Add path info functions to paths.py [d237d3b]
|
||||||
- WHERE: src/paths.py
|
- WHERE: src/paths.py
|
||||||
- WHAT: Add functions to get path resolution source (default/env/config)
|
- WHAT: Add functions to get path resolution source (default/env/config)
|
||||||
- HOW: Return tuple of (resolved_path, source)
|
- HOW: Return tuple of (resolved_path, source)
|
||||||
- SAFETY: New functions, no modifications
|
- SAFETY: New functions, no modifications
|
||||||
|
|
||||||
- [ ] Task 1.2: Create path display helper
|
- [x] Task 1.2: Create path display helper [d237d3b]
|
||||||
- WHERE: src/paths.py
|
- WHERE: src/paths.py
|
||||||
- WHAT: Function to get all paths with resolution info
|
- WHAT: Function to get all paths with resolution info
|
||||||
- HOW: Returns dict of path_name -> (resolved, source)
|
- HOW: Returns dict of path_name -> (resolved, source)
|
||||||
@@ -18,25 +18,25 @@ Focus: Show current path resolution in GUI
|
|||||||
## Phase 2: Context Hub Panel
|
## Phase 2: Context Hub Panel
|
||||||
Focus: Add Path Configuration panel to GUI
|
Focus: Add Path Configuration panel to GUI
|
||||||
|
|
||||||
- [ ] Task 2.1: Add Paths tab to Context Hub
|
- [x] Task 2.1: Add Paths tab to Context Hub [d237d3b]
|
||||||
- WHERE: src/gui_2.py (Context Hub section)
|
- WHERE: src/gui_2.py (Context Hub section)
|
||||||
- WHAT: New tab/section for path configuration
|
- WHAT: New tab/section for path configuration
|
||||||
- HOW: Add ImGui tab item, follow existing panel patterns
|
- HOW: Add ImGui tab item, follow existing panel patterns
|
||||||
- SAFETY: New panel, no modifications to existing
|
- SAFETY: New panel, no modifications to existing
|
||||||
|
|
||||||
- [ ] Task 2.2: Display current paths
|
- [x] Task 2.2: Display current paths [d237d3b]
|
||||||
- WHERE: src/gui_2.py (new paths panel)
|
- WHERE: src/gui_2.py (new paths panel)
|
||||||
- WHAT: Show resolved paths and their sources
|
- WHAT: Show resolved paths and their sources
|
||||||
- HOW: Call paths.py functions, display in read-only text
|
- HOW: Call paths.py functions, display in read-only text
|
||||||
- SAFETY: New code
|
- SAFETY: New code
|
||||||
|
|
||||||
- [ ] Task 2.3: Add path text inputs
|
- [x] Task 2.3: Add path text inputs [d237d3b]
|
||||||
- WHERE: src/gui_2.py (paths panel)
|
- WHERE: src/gui_2.py (paths panel)
|
||||||
- WHAT: Editable text inputs for each path
|
- WHAT: Editable text inputs for each path
|
||||||
- HOW: ImGui input_text for conductor_dir, logs_dir, scripts_dir
|
- HOW: ImGui input_text for conductor_dir, logs_dir, scripts_dir
|
||||||
- SAFETY: New code
|
- SAFETY: New code
|
||||||
|
|
||||||
- [ ] Task 2.4: Add browse buttons
|
- [x] Task 2.4: Add browse buttons [d237d3b]
|
||||||
- WHERE: src/gui_2.py (paths panel)
|
- WHERE: src/gui_2.py (paths panel)
|
||||||
- WHAT: File dialog buttons to browse for directories
|
- WHAT: File dialog buttons to browse for directories
|
||||||
- HOW: Use existing file dialog patterns in gui_2.py
|
- HOW: Use existing file dialog patterns in gui_2.py
|
||||||
@@ -45,19 +45,19 @@ Focus: Add Path Configuration panel to GUI
|
|||||||
## Phase 3: Persistence
|
## Phase 3: Persistence
|
||||||
Focus: Save path changes to config.toml
|
Focus: Save path changes to config.toml
|
||||||
|
|
||||||
- [ ] Task 3.1: Add config write function
|
- [x] Task 3.1: Add config write function [d237d3b]
|
||||||
- WHERE: src/gui_2.py or new utility
|
- WHERE: src/gui_2.py or new utility
|
||||||
- WHAT: Write [paths] section to config.toml
|
- WHAT: Write [paths] section to config.toml
|
||||||
- HOW: Read existing config, update paths section, write back
|
- HOW: Read existing config, update paths section, write back
|
||||||
- SAFETY: Backup before write, handle errors
|
- SAFETY: Backup before write, handle errors
|
||||||
|
|
||||||
- [ ] Task 3.2: Add Apply button
|
- [x] Task 3.2: Add Apply button [d237d3b]
|
||||||
- WHERE: src/gui_2.py (paths panel)
|
- WHERE: src/gui_2.py (paths panel)
|
||||||
- WHAT: Button to save changes
|
- WHAT: Button to save changes
|
||||||
- HOW: Call config write function, show success/error message
|
- HOW: Call config write function, show success/error message
|
||||||
- SAFETY: Confirmation dialog
|
- SAFETY: Confirmation dialog
|
||||||
|
|
||||||
- [ ] Task 3.3: Add Reset button
|
- [x] Task 3.3: Add Reset button [d237d3b]
|
||||||
- WHERE: src/gui_2.py (paths panel)
|
- WHERE: src/gui_2.py (paths panel)
|
||||||
- WHAT: Reset paths to defaults
|
- WHAT: Reset paths to defaults
|
||||||
- HOW: Clear custom values, show confirmation
|
- HOW: Clear custom values, show confirmation
|
||||||
@@ -66,13 +66,13 @@ Focus: Save path changes to config.toml
|
|||||||
## Phase 4: UX Polish
|
## Phase 4: UX Polish
|
||||||
Focus: Improve user experience
|
Focus: Improve user experience
|
||||||
|
|
||||||
- [ ] Task 4.1: Add restart warning
|
- [x] Task 4.1: Add restart warning [d237d3b]
|
||||||
- WHERE: src/gui_2.py (paths panel)
|
- WHERE: src/gui_2.py (paths panel)
|
||||||
- WHAT: Show warning that changes require restart
|
- WHAT: Show warning that changes require restart
|
||||||
- HOW: Text label after Apply
|
- HOW: Text label after Apply
|
||||||
- SAFETY: New code
|
- SAFETY: New code
|
||||||
|
|
||||||
- [ ] Task 4.2: Add tooltips
|
- [x] Task 4.2: Add tooltips [d237d3b]
|
||||||
- WHERE: src/gui_2.py (paths panel)
|
- WHERE: src/gui_2.py (paths panel)
|
||||||
- WHAT: Explain each path and resolution order
|
- WHAT: Explain each path and resolution order
|
||||||
- HOW: ImGui set_tooltip on hover
|
- HOW: ImGui set_tooltip on hover
|
||||||
@@ -81,7 +81,7 @@ Focus: Improve user experience
|
|||||||
## Phase 5: Tests
|
## Phase 5: Tests
|
||||||
Focus: Verify GUI path configuration
|
Focus: Verify GUI path configuration
|
||||||
|
|
||||||
- [ ] Task 5.1: Test path display
|
- [x] Task 5.1: Test path display [d237d3b]
|
||||||
- WHERE: tests/test_gui_paths.py (new file)
|
- WHERE: tests/test_gui_paths.py (new file)
|
||||||
- WHAT: Verify paths panel shows correct values
|
- WHAT: Verify paths panel shows correct values
|
||||||
- HOW: Mock paths.py, verify display
|
- HOW: Mock paths.py, verify display
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
## Phase 1: Extend paths.py
|
## Phase 1: Extend paths.py
|
||||||
Focus: Add project-specific path resolution
|
Focus: Add project-specific path resolution
|
||||||
|
|
||||||
- [ ] Task 1.1: Add project-aware conductor path functions
|
- [x] Task 1.1: Add project-aware conductor path functions [48e2ed8]
|
||||||
- WHERE: src/paths.py
|
- WHERE: src/paths.py
|
||||||
- WHAT: Add optional project_path parameter to get_conductor_dir, get_tracks_dir, get_track_state_dir
|
- WHAT: Add optional project_path parameter to get_conductor_dir, get_tracks_dir, get_track_state_dir
|
||||||
- HOW: If project_path provided, resolve relative to project root; otherwise use global
|
- HOW: If project_path provided, resolve relative to project root; otherwise use global
|
||||||
- SAFETY: Maintain backward compatibility with no-arg calls
|
- SAFETY: Maintain backward compatibility with no-arg calls
|
||||||
|
|
||||||
- [ ] Task 1.2: Add project conductor path resolution
|
- [x] Task 1.2: Add project conductor path resolution [48e2ed8]
|
||||||
- WHERE: src/paths.py
|
- WHERE: src/paths.py
|
||||||
- WHAT: New function `_resolve_project_conductor_dir(project_path)` that reads from project TOML
|
- WHAT: New function `_resolve_project_conductor_dir(project_path)` that reads from project TOML
|
||||||
- HOW: Load project TOML, check `[conductor].dir` key
|
- HOW: Load project TOML, check `[conductor].dir` key
|
||||||
@@ -18,18 +18,18 @@ Focus: Add project-specific path resolution
|
|||||||
## Phase 2: Update project_manager.py
|
## Phase 2: Update project_manager.py
|
||||||
Focus: Use project-specific paths for track operations
|
Focus: Use project-specific paths for track operations
|
||||||
|
|
||||||
- [ ] Task 2.1: Update save_track_state to use project conductor dir
|
- [x] Task 2.1: Update save_track_state to use project conductor dir [3999e9c]
|
||||||
- WHERE: src/project_manager.py (around line 240)
|
- WHERE: src/project_manager.py (around line 240)
|
||||||
- WHAT: Pass project base_dir to paths.get_track_state_dir()
|
- WHAT: Pass project base_dir to paths.get_track_state_dir()
|
||||||
- HOW: Get base_dir from project_path, call paths with project_path param
|
- HOW: Get base_dir from project_path, call paths with project_path param
|
||||||
- SAFETY: Maintain existing function signature compatibility
|
- SAFETY: Maintain existing function signature compatibility
|
||||||
|
|
||||||
- [ ] Task 2.2: Update load_track_state to use project conductor dir
|
- [x] Task 2.2: Update load_track_state to use project conductor dir [3999e9c]
|
||||||
- WHERE: src/project_manager.py (around line 252)
|
- WHERE: src/project_manager.py (around line 252)
|
||||||
- WHAT: Load track state from project-specific directory
|
- WHAT: Load track state from project-specific directory
|
||||||
- HOW: Same as above
|
- HOW: Same as above
|
||||||
|
|
||||||
- [ ] Task 2.3: Update get_all_tracks to use project conductor dir
|
- [x] Task 2.3: Update get_all_tracks to use project conductor dir [3999e9c]
|
||||||
- WHERE: src/project_manager.py (around line 297)
|
- WHERE: src/project_manager.py (around line 297)
|
||||||
- WHAT: List tracks from project-specific directory
|
- WHAT: List tracks from project-specific directory
|
||||||
- HOW: Accept optional project_path param
|
- HOW: Accept optional project_path param
|
||||||
@@ -37,7 +37,7 @@ Focus: Use project-specific paths for track operations
|
|||||||
## Phase 3: Update app_controller.py
|
## Phase 3: Update app_controller.py
|
||||||
Focus: Pass project path to track operations
|
Focus: Pass project path to track operations
|
||||||
|
|
||||||
- [ ] Task 3.1: Update track creation to use project conductor dir
|
- [x] Task 3.1: Update track creation to use project conductor dir [3999e9c]
|
||||||
- WHERE: src/app_controller.py (around line 1907, 1937)
|
- WHERE: src/app_controller.py (around line 1907, 1937)
|
||||||
- WHAT: Pass active_project_path to track path functions
|
- WHAT: Pass active_project_path to track path functions
|
||||||
- HOW: Get active_project_path, pass to paths.get_tracks_dir()
|
- HOW: Get active_project_path, pass to paths.get_tracks_dir()
|
||||||
@@ -46,13 +46,13 @@ Focus: Pass project path to track operations
|
|||||||
## Phase 4: Tests
|
## Phase 4: Tests
|
||||||
Focus: Verify project-specific behavior
|
Focus: Verify project-specific behavior
|
||||||
|
|
||||||
- [ ] Task 4.1: Write test for project-specific conductor dir
|
- [x] Task 4.1: Write test for project-specific conductor dir [48e2ed8]
|
||||||
- WHERE: tests/test_project_paths.py (new file)
|
- WHERE: tests/test_project_paths.py (new file)
|
||||||
- WHAT: Create mock project with custom conductor dir, verify tracks saved there
|
- WHAT: Create mock project with custom conductor dir, verify tracks saved there
|
||||||
- HOW: Mock project_manager, verify path resolution
|
- HOW: Mock project_manager, verify path resolution
|
||||||
- SAFETY: New test file
|
- SAFETY: New test file
|
||||||
|
|
||||||
- [ ] Task 4.2: Test backward compatibility
|
- [x] Task 4.2: Test backward compatibility [3999e9c]
|
||||||
- WHERE: tests/test_project_paths.py
|
- WHERE: tests/test_project_paths.py
|
||||||
- WHAT: Verify global paths still work without project_path
|
- WHAT: Verify global paths still work without project_path
|
||||||
- HOW: Call functions without project_path, verify defaults
|
- HOW: Call functions without project_path, verify defaults
|
||||||
|
|||||||
@@ -1,25 +1,17 @@
|
|||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
import tomllib
|
import json
|
||||||
import tomli_w
|
import tomli_w
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from src import paths
|
from src import paths
|
||||||
|
from src import project_manager
|
||||||
|
|
||||||
def test_get_conductor_dir_default():
|
def test_get_conductor_dir_default():
|
||||||
paths.reset_resolved()
|
paths.reset_resolved()
|
||||||
# Should return default "conductor" relative to root
|
# Should return absolute path to "conductor" in project root
|
||||||
expected = Path(__file__).resolve().parent.parent / "conductor"
|
expected = Path(__file__).resolve().parent.parent / "conductor"
|
||||||
assert paths.get_conductor_dir() == expected
|
assert paths.get_conductor_dir() == expected
|
||||||
|
|
||||||
def test_get_conductor_dir_project_specific_no_toml(tmp_path):
|
|
||||||
paths.reset_resolved()
|
|
||||||
project_root = tmp_path / "my_project"
|
|
||||||
project_root.mkdir()
|
|
||||||
|
|
||||||
# Should default to project_root / "conductor" if no manual_slop.toml
|
|
||||||
res = paths.get_conductor_dir(project_path=str(project_root))
|
|
||||||
assert res == project_root / "conductor"
|
|
||||||
|
|
||||||
def test_get_conductor_dir_project_specific_with_toml(tmp_path):
|
def test_get_conductor_dir_project_specific_with_toml(tmp_path):
|
||||||
paths.reset_resolved()
|
paths.reset_resolved()
|
||||||
project_root = tmp_path / "my_project"
|
project_root = tmp_path / "my_project"
|
||||||
@@ -38,18 +30,59 @@ def test_get_conductor_dir_project_specific_with_toml(tmp_path):
|
|||||||
res = paths.get_conductor_dir(project_path=str(project_root))
|
res = paths.get_conductor_dir(project_path=str(project_root))
|
||||||
assert res == project_root / "custom_tracks"
|
assert res == project_root / "custom_tracks"
|
||||||
|
|
||||||
def test_get_tracks_dir_project_specific(tmp_path):
|
def test_get_all_tracks_project_specific(tmp_path):
|
||||||
paths.reset_resolved()
|
paths.reset_resolved()
|
||||||
project_root = tmp_path / "my_project"
|
project_root = tmp_path / "my_project"
|
||||||
project_root.mkdir()
|
project_root.mkdir()
|
||||||
|
|
||||||
res = paths.get_tracks_dir(project_path=str(project_root))
|
# Custom conductor dir
|
||||||
assert res == project_root / "conductor" / "tracks"
|
custom_dir = project_root / "my_conductor"
|
||||||
|
custom_dir.mkdir()
|
||||||
|
tracks_dir = custom_dir / "tracks"
|
||||||
|
tracks_dir.mkdir()
|
||||||
|
|
||||||
|
# Create a dummy track
|
||||||
|
track_dir = tracks_dir / "test_track_20260312"
|
||||||
|
track_dir.mkdir()
|
||||||
|
with open(track_dir / "metadata.json", "w") as f:
|
||||||
|
json.dump({"id": "test_track", "title": "Test Track"}, f)
|
||||||
|
|
||||||
|
# Setup manual_slop.toml
|
||||||
|
toml_path = project_root / "manual_slop.toml"
|
||||||
|
config = {"conductor": {"dir": "my_conductor"}}
|
||||||
|
with open(toml_path, "wb") as f:
|
||||||
|
f.write(tomli_w.dumps(config).encode())
|
||||||
|
|
||||||
|
# project_manager.get_all_tracks(base_dir) should now find it
|
||||||
|
tracks = project_manager.get_all_tracks(str(project_root))
|
||||||
|
assert len(tracks) == 1
|
||||||
|
assert tracks[0]["title"] == "Test Track"
|
||||||
|
|
||||||
def test_get_track_state_dir_project_specific(tmp_path):
|
def test_get_all_tracks_global_fallback(tmp_path):
|
||||||
paths.reset_resolved()
|
paths.reset_resolved()
|
||||||
project_root = tmp_path / "my_project"
|
|
||||||
project_root.mkdir()
|
|
||||||
|
|
||||||
res = paths.get_track_state_dir("track-123", project_path=str(project_root))
|
# Create a directory without manual_slop.toml
|
||||||
assert res == project_root / "conductor" / "tracks" / "track-123"
|
empty_dir = tmp_path / "empty_project"
|
||||||
|
empty_dir.mkdir()
|
||||||
|
|
||||||
|
# Setup a fake global conductor
|
||||||
|
global_conductor = tmp_path / "global_conductor"
|
||||||
|
global_conductor.mkdir()
|
||||||
|
global_tracks = global_conductor / "tracks"
|
||||||
|
global_tracks.mkdir()
|
||||||
|
|
||||||
|
track_dir = global_tracks / "global_track"
|
||||||
|
track_dir.mkdir()
|
||||||
|
with open(track_dir / "metadata.json", "w") as f:
|
||||||
|
json.dump({"id": "global_track", "title": "Global Track"}, f)
|
||||||
|
|
||||||
|
# Override global conductor dir via env var
|
||||||
|
os.environ["SLOP_CONDUCTOR_DIR"] = str(global_conductor)
|
||||||
|
try:
|
||||||
|
paths.reset_resolved()
|
||||||
|
# Pass project_path pointing to a dir without TOML
|
||||||
|
tracks = project_manager.get_all_tracks(str(empty_dir))
|
||||||
|
# paths.get_conductor_dir(str(empty_dir)) should fall back to global
|
||||||
|
assert any(t["id"] == "global_track" for t in tracks)
|
||||||
|
finally:
|
||||||
|
del os.environ["SLOP_CONDUCTOR_DIR"]
|
||||||
|
|||||||
Reference in New Issue
Block a user