feat(conductor): Use project-specific conductor directory in project_manager and app_controller
This commit is contained in:
@@ -430,6 +430,12 @@ class AppController:
|
|||||||
if hasattr(self, 'perf_monitor'):
|
if hasattr(self, 'perf_monitor'):
|
||||||
self.perf_monitor.enabled = value
|
self.perf_monitor.enabled = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def active_project_root(self) -> str:
|
||||||
|
if self.active_project_path:
|
||||||
|
return str(Path(self.active_project_path).parent)
|
||||||
|
return self.ui_files_base_dir
|
||||||
|
|
||||||
def _update_inject_preview(self) -> None:
|
def _update_inject_preview(self) -> None:
|
||||||
"""Updates the preview content based on the selected file and injection mode."""
|
"""Updates the preview content based on the selected file and injection mode."""
|
||||||
if not self._inject_file_path:
|
if not self._inject_file_path:
|
||||||
@@ -1859,7 +1865,7 @@ class AppController:
|
|||||||
agent_tools_cfg = proj.get("agent", {}).get("tools", {})
|
agent_tools_cfg = proj.get("agent", {}).get("tools", {})
|
||||||
self.ui_agent_tools = {t: agent_tools_cfg.get(t, True) for t in models.AGENT_TOOL_NAMES}
|
self.ui_agent_tools = {t: agent_tools_cfg.get(t, True) for t in models.AGENT_TOOL_NAMES}
|
||||||
# MMA Tracks
|
# MMA Tracks
|
||||||
self.tracks = project_manager.get_all_tracks(self.ui_files_base_dir)
|
self.tracks = project_manager.get_all_tracks(self.active_project_root)
|
||||||
# Restore MMA state
|
# Restore MMA state
|
||||||
mma_sec = proj.get("mma", {})
|
mma_sec = proj.get("mma", {})
|
||||||
self.ui_epic_input = mma_sec.get("epic", "")
|
self.ui_epic_input = mma_sec.get("epic", "")
|
||||||
@@ -1889,7 +1895,7 @@ class AppController:
|
|||||||
self.active_tickets = []
|
self.active_tickets = []
|
||||||
# Load track-scoped history if track is active
|
# Load track-scoped history if track is active
|
||||||
if self.active_track:
|
if self.active_track:
|
||||||
track_history = project_manager.load_track_history(self.active_track.id, self.ui_files_base_dir)
|
track_history = project_manager.load_track_history(self.active_track.id, self.active_project_root)
|
||||||
if track_history:
|
if track_history:
|
||||||
with self._disc_entries_lock:
|
with self._disc_entries_lock:
|
||||||
self.disc_entries = models.parse_history_entries(track_history, self.disc_roles)
|
self.disc_entries = models.parse_history_entries(track_history, self.disc_roles)
|
||||||
@@ -1962,7 +1968,7 @@ class AppController:
|
|||||||
|
|
||||||
|
|
||||||
def _cb_load_track(self, track_id: str) -> None:
|
def _cb_load_track(self, track_id: str) -> None:
|
||||||
state = project_manager.load_track_state(track_id, self.ui_files_base_dir)
|
state = project_manager.load_track_state(track_id, self.active_project_root)
|
||||||
if state:
|
if state:
|
||||||
try:
|
try:
|
||||||
# Convert list[Ticket] or list[dict] to list[Ticket] for Track object
|
# Convert list[Ticket] or list[dict] to list[Ticket] for Track object
|
||||||
@@ -1980,7 +1986,7 @@ class AppController:
|
|||||||
# Keep dicts for UI table (or convert models.Ticket objects back to dicts if needed)
|
# Keep dicts for UI table (or convert models.Ticket objects back to dicts if needed)
|
||||||
self.active_tickets = [asdict(t) if not isinstance(t, dict) else t for t in tickets]
|
self.active_tickets = [asdict(t) if not isinstance(t, dict) else t for t in tickets]
|
||||||
# Load track-scoped history
|
# Load track-scoped history
|
||||||
history = project_manager.load_track_history(track_id, self.ui_files_base_dir)
|
history = project_manager.load_track_history(track_id, self.active_project_root)
|
||||||
with self._disc_entries_lock:
|
with self._disc_entries_lock:
|
||||||
if history:
|
if history:
|
||||||
self.disc_entries = models.parse_history_entries(history, self.disc_roles)
|
self.disc_entries = models.parse_history_entries(history, self.disc_roles)
|
||||||
@@ -2650,7 +2656,7 @@ class AppController:
|
|||||||
if not name: return
|
if not name: return
|
||||||
date_suffix = datetime.now().strftime("%Y%m%d")
|
date_suffix = datetime.now().strftime("%Y%m%d")
|
||||||
track_id = f"{name.lower().replace(' ', '_')}_{date_suffix}"
|
track_id = f"{name.lower().replace(' ', '_')}_{date_suffix}"
|
||||||
track_dir = paths.get_tracks_dir() / track_id
|
track_dir = paths.get_track_state_dir(track_id, project_path=self.active_project_root)
|
||||||
track_dir.mkdir(parents=True, exist_ok=True)
|
track_dir.mkdir(parents=True, exist_ok=True)
|
||||||
spec_file = track_dir / "spec.md"
|
spec_file = track_dir / "spec.md"
|
||||||
with open(spec_file, "w", encoding="utf-8") as f:
|
with open(spec_file, "w", encoding="utf-8") as f:
|
||||||
@@ -2669,7 +2675,7 @@ class AppController:
|
|||||||
"progress": 0.0
|
"progress": 0.0
|
||||||
}, f, indent=1)
|
}, f, indent=1)
|
||||||
# Refresh tracks from disk
|
# Refresh tracks from disk
|
||||||
self.tracks = project_manager.get_all_tracks(self.ui_files_base_dir)
|
self.tracks = project_manager.get_all_tracks(self.active_project_root)
|
||||||
|
|
||||||
def _push_mma_state_update(self) -> None:
|
def _push_mma_state_update(self) -> None:
|
||||||
if not self.active_track:
|
if not self.active_track:
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ def save_track_state(track_id: str, state: 'TrackState', base_dir: Union[str, Pa
|
|||||||
"""
|
"""
|
||||||
Saves a TrackState object to conductor/tracks/<track_id>/state.toml.
|
Saves a TrackState object to conductor/tracks/<track_id>/state.toml.
|
||||||
"""
|
"""
|
||||||
track_dir = Path(base_dir) / paths.get_track_state_dir(track_id)
|
track_dir = paths.get_track_state_dir(track_id, project_path=str(base_dir))
|
||||||
track_dir.mkdir(parents=True, exist_ok=True)
|
track_dir.mkdir(parents=True, exist_ok=True)
|
||||||
state_file = track_dir / "state.toml"
|
state_file = track_dir / "state.toml"
|
||||||
data = clean_nones(state.to_dict())
|
data = clean_nones(state.to_dict())
|
||||||
@@ -257,7 +257,7 @@ def load_track_state(track_id: str, base_dir: Union[str, Path] = ".") -> Optiona
|
|||||||
Loads a TrackState object from conductor/tracks/<track_id>/state.toml.
|
Loads a TrackState object from conductor/tracks/<track_id>/state.toml.
|
||||||
"""
|
"""
|
||||||
from src.models import TrackState
|
from src.models import TrackState
|
||||||
state_file = Path(base_dir) / paths.get_track_state_dir(track_id) / "state.toml"
|
state_file = paths.get_track_state_dir(track_id, project_path=str(base_dir)) / 'state.toml'
|
||||||
if not state_file.exists():
|
if not state_file.exists():
|
||||||
return None
|
return None
|
||||||
with open(state_file, "rb") as f:
|
with open(state_file, "rb") as f:
|
||||||
@@ -302,7 +302,7 @@ def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[dict[str, Any]]:
|
|||||||
Handles missing or malformed metadata.json or state.toml by falling back
|
Handles missing or malformed metadata.json or state.toml by falling back
|
||||||
to available info or defaults.
|
to available info or defaults.
|
||||||
"""
|
"""
|
||||||
tracks_dir = Path(base_dir) / paths.get_tracks_dir()
|
tracks_dir = paths.get_tracks_dir(project_path=str(base_dir))
|
||||||
if not tracks_dir.exists():
|
if not tracks_dir.exists():
|
||||||
return []
|
return []
|
||||||
results: list[dict[str, Any]] = []
|
results: list[dict[str, Any]] = []
|
||||||
|
|||||||
Reference in New Issue
Block a user