steerdev 0.4.27__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. steerdev-0.4.27.dist-info/METADATA +224 -0
  2. steerdev-0.4.27.dist-info/RECORD +57 -0
  3. steerdev-0.4.27.dist-info/WHEEL +4 -0
  4. steerdev-0.4.27.dist-info/entry_points.txt +2 -0
  5. steerdev_agent/__init__.py +10 -0
  6. steerdev_agent/api/__init__.py +32 -0
  7. steerdev_agent/api/activity.py +278 -0
  8. steerdev_agent/api/agents.py +145 -0
  9. steerdev_agent/api/client.py +158 -0
  10. steerdev_agent/api/commands.py +399 -0
  11. steerdev_agent/api/configs.py +238 -0
  12. steerdev_agent/api/context.py +306 -0
  13. steerdev_agent/api/events.py +294 -0
  14. steerdev_agent/api/hooks.py +178 -0
  15. steerdev_agent/api/implementation_plan.py +408 -0
  16. steerdev_agent/api/messages.py +231 -0
  17. steerdev_agent/api/prd.py +281 -0
  18. steerdev_agent/api/runs.py +526 -0
  19. steerdev_agent/api/sessions.py +403 -0
  20. steerdev_agent/api/specs.py +321 -0
  21. steerdev_agent/api/tasks.py +659 -0
  22. steerdev_agent/api/workflow_runs.py +351 -0
  23. steerdev_agent/api/workflows.py +191 -0
  24. steerdev_agent/cli.py +2254 -0
  25. steerdev_agent/config/__init__.py +19 -0
  26. steerdev_agent/config/models.py +236 -0
  27. steerdev_agent/config/platform.py +272 -0
  28. steerdev_agent/config/settings.py +62 -0
  29. steerdev_agent/daemon.py +675 -0
  30. steerdev_agent/executor/__init__.py +64 -0
  31. steerdev_agent/executor/base.py +121 -0
  32. steerdev_agent/executor/claude.py +328 -0
  33. steerdev_agent/executor/stream.py +163 -0
  34. steerdev_agent/git/__init__.py +1 -0
  35. steerdev_agent/handlers/__init__.py +5 -0
  36. steerdev_agent/handlers/prd.py +533 -0
  37. steerdev_agent/integration.py +334 -0
  38. steerdev_agent/prompt/__init__.py +10 -0
  39. steerdev_agent/prompt/builder.py +263 -0
  40. steerdev_agent/prompt/templates.py +422 -0
  41. steerdev_agent/py.typed +0 -0
  42. steerdev_agent/runner.py +829 -0
  43. steerdev_agent/setup/__init__.py +5 -0
  44. steerdev_agent/setup/claude_setup.py +560 -0
  45. steerdev_agent/setup/templates/claude_md_section.md +140 -0
  46. steerdev_agent/setup/templates/settings.json +69 -0
  47. steerdev_agent/setup/templates/skills/activity/SKILL.md +160 -0
  48. steerdev_agent/setup/templates/skills/context/SKILL.md +122 -0
  49. steerdev_agent/setup/templates/skills/git-workflow/SKILL.md +218 -0
  50. steerdev_agent/setup/templates/skills/progress-logging/SKILL.md +211 -0
  51. steerdev_agent/setup/templates/skills/specs-management/SKILL.md +161 -0
  52. steerdev_agent/setup/templates/skills/task-management/SKILL.md +343 -0
  53. steerdev_agent/setup/templates/steerdev.yaml +51 -0
  54. steerdev_agent/version.py +149 -0
  55. steerdev_agent/workflow/__init__.py +10 -0
  56. steerdev_agent/workflow/executor.py +494 -0
  57. steerdev_agent/workflow/memory.py +185 -0
@@ -0,0 +1,185 @@
1
+ """Phase memory storage for workflow execution."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from loguru import logger
8
+ from pydantic import BaseModel, Field
9
+
10
+
11
+ class PhaseMemory(BaseModel):
12
+ """Memory stored for a completed phase."""
13
+
14
+ phase_id: str
15
+ phase_name: str
16
+ phase_type: str
17
+ input_context: dict[str, Any] = Field(default_factory=dict)
18
+ output_context: dict[str, Any] = Field(default_factory=dict)
19
+ result_summary: str | None = None
20
+
21
+
22
+ class WorkflowMemoryManager:
23
+ """Manages local storage for phase context between executions.
24
+
25
+ Stores phase memory in `.steerdev/phases/{workflow_id}/{run_id}/{phase_id}.json`
26
+ to enable context propagation between phases. The two-level directory structure
27
+ ensures that multiple runs of the same workflow don't overwrite each other,
28
+ and allows debugging of failed runs by preserving their memory.
29
+ """
30
+
31
+ def __init__(self, working_directory: str | Path) -> None:
32
+ """Initialize the memory manager.
33
+
34
+ Args:
35
+ working_directory: Base directory for the project.
36
+ """
37
+ self.working_directory = Path(working_directory)
38
+ self.base_path = self.working_directory / ".steerdev" / "phases"
39
+
40
+ def _get_workflow_path(self, workflow_id: str) -> Path:
41
+ """Get the path for a workflow's memory directory."""
42
+ return self.base_path / workflow_id
43
+
44
+ def _get_run_path(self, workflow_id: str, run_id: str) -> Path:
45
+ """Get the path for a workflow run's memory files."""
46
+ return self._get_workflow_path(workflow_id) / run_id
47
+
48
+ def _get_phase_path(self, workflow_id: str, run_id: str, phase_id: str) -> Path:
49
+ """Get the path for a specific phase's memory file."""
50
+ return self._get_run_path(workflow_id, run_id) / f"{phase_id}.json"
51
+
52
+ def save_phase_memory(
53
+ self,
54
+ workflow_id: str,
55
+ run_id: str,
56
+ memory: PhaseMemory,
57
+ ) -> Path:
58
+ """Save phase memory after completion.
59
+
60
+ Args:
61
+ workflow_id: The workflow definition ID.
62
+ run_id: The workflow run ID.
63
+ memory: Phase memory to save.
64
+
65
+ Returns:
66
+ Path to the saved memory file.
67
+ """
68
+ run_path = self._get_run_path(workflow_id, run_id)
69
+ run_path.mkdir(parents=True, exist_ok=True)
70
+
71
+ phase_path = self._get_phase_path(workflow_id, run_id, memory.phase_id)
72
+ phase_path.write_text(memory.model_dump_json(indent=2))
73
+
74
+ logger.debug(f"Saved phase memory: {phase_path}")
75
+ return phase_path
76
+
77
+ def load_phase_memory(
78
+ self,
79
+ workflow_id: str,
80
+ run_id: str,
81
+ phase_id: str,
82
+ ) -> PhaseMemory | None:
83
+ """Load memory for a specific phase.
84
+
85
+ Args:
86
+ workflow_id: The workflow definition ID.
87
+ run_id: The workflow run ID.
88
+ phase_id: The phase ID to load.
89
+
90
+ Returns:
91
+ Phase memory or None if not found.
92
+ """
93
+ phase_path = self._get_phase_path(workflow_id, run_id, phase_id)
94
+
95
+ if not phase_path.exists():
96
+ return None
97
+
98
+ try:
99
+ data = json.loads(phase_path.read_text())
100
+ return PhaseMemory(**data)
101
+ except (json.JSONDecodeError, ValueError) as e:
102
+ logger.error(f"Failed to load phase memory: {e}")
103
+ return None
104
+
105
+ def load_all_phase_memories(
106
+ self,
107
+ workflow_id: str,
108
+ run_id: str,
109
+ ) -> list[PhaseMemory]:
110
+ """Load all phase memories for a workflow run.
111
+
112
+ Args:
113
+ workflow_id: The workflow definition ID.
114
+ run_id: The workflow run ID.
115
+
116
+ Returns:
117
+ List of phase memories, ordered by file modification time.
118
+ """
119
+ run_path = self._get_run_path(workflow_id, run_id)
120
+
121
+ if not run_path.exists():
122
+ return []
123
+
124
+ memories = []
125
+ for phase_file in sorted(run_path.glob("*.json"), key=lambda p: p.stat().st_mtime):
126
+ try:
127
+ data = json.loads(phase_file.read_text())
128
+ memories.append(PhaseMemory(**data))
129
+ except (json.JSONDecodeError, ValueError) as e:
130
+ logger.warning(f"Skipping invalid phase memory {phase_file}: {e}")
131
+
132
+ return memories
133
+
134
+ def build_accumulated_context(
135
+ self,
136
+ workflow_id: str,
137
+ run_id: str,
138
+ ) -> dict[str, Any]:
139
+ """Build accumulated context from all completed phases.
140
+
141
+ Merges output contexts from all phases, with later phases
142
+ taking precedence for duplicate keys.
143
+
144
+ Args:
145
+ workflow_id: The workflow definition ID.
146
+ run_id: The workflow run ID.
147
+
148
+ Returns:
149
+ Merged context dictionary.
150
+ """
151
+ memories = self.load_all_phase_memories(workflow_id, run_id)
152
+
153
+ accumulated: dict[str, Any] = {}
154
+ for memory in memories:
155
+ accumulated.update(memory.output_context)
156
+
157
+ return accumulated
158
+
159
+ def cleanup_run(self, workflow_id: str, run_id: str) -> bool:
160
+ """Remove memory files for a completed workflow run.
161
+
162
+ Note: This should only be called for successful workflow runs.
163
+ Failed runs should preserve their memory for debugging.
164
+
165
+ Args:
166
+ workflow_id: The workflow definition ID.
167
+ run_id: The workflow run ID to clean up.
168
+
169
+ Returns:
170
+ True if cleanup was successful.
171
+ """
172
+ run_path = self._get_run_path(workflow_id, run_id)
173
+
174
+ if not run_path.exists():
175
+ return True
176
+
177
+ try:
178
+ import shutil
179
+
180
+ shutil.rmtree(run_path)
181
+ logger.debug(f"Cleaned up workflow memory: {run_path}")
182
+ return True
183
+ except OSError as e:
184
+ logger.error(f"Failed to cleanup workflow memory: {e}")
185
+ return False