anvil-dev-framework 0.1.6

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 (190) hide show
  1. package/README.md +719 -0
  2. package/VERSION +1 -0
  3. package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
  4. package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
  5. package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
  6. package/docs/INSTALLATION.md +984 -0
  7. package/docs/anvil-hud.md +469 -0
  8. package/docs/anvil-init.md +255 -0
  9. package/docs/anvil-state.md +210 -0
  10. package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
  11. package/docs/command-reference.md +2022 -0
  12. package/docs/hooks-tts.md +368 -0
  13. package/docs/implementation-guide.md +810 -0
  14. package/docs/linear-github-integration.md +247 -0
  15. package/docs/local-issues.md +677 -0
  16. package/docs/patterns/README.md +419 -0
  17. package/docs/planning-responsibilities.md +139 -0
  18. package/docs/session-workflow.md +573 -0
  19. package/docs/simplification-plan-template.md +297 -0
  20. package/docs/simplification-principles.md +129 -0
  21. package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
  22. package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
  23. package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
  24. package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
  25. package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
  26. package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
  27. package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
  28. package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
  29. package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
  30. package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
  31. package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
  32. package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
  33. package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
  34. package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
  35. package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
  36. package/docs/sync.md +122 -0
  37. package/global/CLAUDE.md +140 -0
  38. package/global/agents/verify-app.md +164 -0
  39. package/global/commands/anvil-settings.md +527 -0
  40. package/global/commands/anvil-sync.md +121 -0
  41. package/global/commands/change.md +197 -0
  42. package/global/commands/clarify.md +252 -0
  43. package/global/commands/cleanup.md +292 -0
  44. package/global/commands/commit-push-pr.md +207 -0
  45. package/global/commands/decay-review.md +127 -0
  46. package/global/commands/discover.md +158 -0
  47. package/global/commands/doc-coverage.md +122 -0
  48. package/global/commands/evidence.md +307 -0
  49. package/global/commands/explore.md +121 -0
  50. package/global/commands/force-exit.md +135 -0
  51. package/global/commands/handoff.md +191 -0
  52. package/global/commands/healthcheck.md +302 -0
  53. package/global/commands/hud.md +84 -0
  54. package/global/commands/insights.md +319 -0
  55. package/global/commands/linear-setup.md +184 -0
  56. package/global/commands/lint-fix.md +198 -0
  57. package/global/commands/orient.md +510 -0
  58. package/global/commands/plan.md +228 -0
  59. package/global/commands/ralph.md +346 -0
  60. package/global/commands/ready.md +182 -0
  61. package/global/commands/release.md +305 -0
  62. package/global/commands/retro.md +96 -0
  63. package/global/commands/shard.md +166 -0
  64. package/global/commands/spec.md +227 -0
  65. package/global/commands/sprint.md +184 -0
  66. package/global/commands/tasks.md +228 -0
  67. package/global/commands/test-and-commit.md +151 -0
  68. package/global/commands/validate.md +132 -0
  69. package/global/commands/verify.md +251 -0
  70. package/global/commands/weekly-review.md +156 -0
  71. package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
  72. package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
  73. package/global/hooks/anvil_memory_observe.ts +322 -0
  74. package/global/hooks/anvil_memory_session.ts +166 -0
  75. package/global/hooks/anvil_memory_stop.ts +187 -0
  76. package/global/hooks/parse_transcript.py +116 -0
  77. package/global/hooks/post_merge_cleanup.sh +132 -0
  78. package/global/hooks/post_tool_format.sh +215 -0
  79. package/global/hooks/ralph_context_monitor.py +240 -0
  80. package/global/hooks/ralph_stop.sh +502 -0
  81. package/global/hooks/statusline.sh +1110 -0
  82. package/global/hooks/statusline_agent_sync.py +224 -0
  83. package/global/hooks/stop_gate.sh +250 -0
  84. package/global/lib/.claude/anvil-state.json +21 -0
  85. package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
  86. package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
  87. package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
  88. package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
  89. package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
  90. package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
  91. package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
  92. package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
  93. package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
  94. package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
  95. package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
  96. package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
  97. package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
  98. package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
  99. package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
  100. package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
  101. package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
  102. package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
  103. package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
  104. package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
  105. package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
  106. package/global/lib/agent_registry.py +995 -0
  107. package/global/lib/anvil-state.sh +435 -0
  108. package/global/lib/claim_service.py +515 -0
  109. package/global/lib/coderabbit_service.py +314 -0
  110. package/global/lib/config_service.py +423 -0
  111. package/global/lib/coordination_service.py +331 -0
  112. package/global/lib/doc_coverage_service.py +1305 -0
  113. package/global/lib/gate_logger.py +316 -0
  114. package/global/lib/github_service.py +310 -0
  115. package/global/lib/handoff_generator.py +775 -0
  116. package/global/lib/hygiene_service.py +712 -0
  117. package/global/lib/issue_models.py +257 -0
  118. package/global/lib/issue_provider.py +339 -0
  119. package/global/lib/linear_data_service.py +210 -0
  120. package/global/lib/linear_provider.py +987 -0
  121. package/global/lib/linear_provider.py.backup +671 -0
  122. package/global/lib/local_provider.py +486 -0
  123. package/global/lib/orient_fast.py +457 -0
  124. package/global/lib/quality_service.py +470 -0
  125. package/global/lib/ralph_prompt_generator.py +563 -0
  126. package/global/lib/ralph_state.py +1202 -0
  127. package/global/lib/state_manager.py +417 -0
  128. package/global/lib/transcript_parser.py +597 -0
  129. package/global/lib/verification_runner.py +557 -0
  130. package/global/lib/verify_iteration.py +490 -0
  131. package/global/lib/verify_subagent.py +250 -0
  132. package/global/skills/README.md +155 -0
  133. package/global/skills/quality-gates/SKILL.md +252 -0
  134. package/global/skills/skill-template/SKILL.md +109 -0
  135. package/global/skills/testing-strategies/SKILL.md +337 -0
  136. package/global/templates/CHANGE-template.md +105 -0
  137. package/global/templates/HANDOFF-template.md +63 -0
  138. package/global/templates/PLAN-template.md +111 -0
  139. package/global/templates/SPEC-template.md +93 -0
  140. package/global/templates/ralph/PROMPT.md.template +89 -0
  141. package/global/templates/ralph/fix_plan.md.template +31 -0
  142. package/global/templates/ralph/progress.txt.template +23 -0
  143. package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
  144. package/global/tests/test_doc_coverage.py +520 -0
  145. package/global/tests/test_issue_models.py +299 -0
  146. package/global/tests/test_local_provider.py +323 -0
  147. package/global/tools/README.md +178 -0
  148. package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
  149. package/global/tools/anvil-hud.py +3622 -0
  150. package/global/tools/anvil-hud.py.bak +3318 -0
  151. package/global/tools/anvil-issue.py +432 -0
  152. package/global/tools/anvil-memory/CLAUDE.md +49 -0
  153. package/global/tools/anvil-memory/README.md +42 -0
  154. package/global/tools/anvil-memory/bun.lock +25 -0
  155. package/global/tools/anvil-memory/bunfig.toml +9 -0
  156. package/global/tools/anvil-memory/package.json +23 -0
  157. package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
  158. package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
  159. package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
  160. package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
  161. package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
  162. package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
  163. package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
  164. package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
  165. package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
  166. package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
  167. package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
  168. package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
  169. package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
  170. package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
  171. package/global/tools/anvil-memory/src/commands/get.ts +115 -0
  172. package/global/tools/anvil-memory/src/commands/init.ts +94 -0
  173. package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
  174. package/global/tools/anvil-memory/src/commands/search.ts +112 -0
  175. package/global/tools/anvil-memory/src/db.ts +638 -0
  176. package/global/tools/anvil-memory/src/index.ts +205 -0
  177. package/global/tools/anvil-memory/src/types.ts +122 -0
  178. package/global/tools/anvil-memory/tsconfig.json +29 -0
  179. package/global/tools/ralph-loop.sh +359 -0
  180. package/package.json +45 -0
  181. package/scripts/anvil +822 -0
  182. package/scripts/extract_patterns.py +222 -0
  183. package/scripts/init-project.sh +541 -0
  184. package/scripts/install.sh +229 -0
  185. package/scripts/postinstall.js +41 -0
  186. package/scripts/rollback.sh +188 -0
  187. package/scripts/sync.sh +623 -0
  188. package/scripts/test-statusline.sh +248 -0
  189. package/scripts/update_claude_md.py +224 -0
  190. package/scripts/verify.sh +255 -0
@@ -0,0 +1,417 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ state_manager.py - Anvil Session State Management (ANV-176)
4
+
5
+ Manages the local .claude/anvil-state.json file and syncs changes
6
+ to the global agent registry for multi-agent visibility.
7
+
8
+ This module solves the "stale statusline" problem where issue/phase
9
+ indicators show outdated information. By calling update_state() from
10
+ workflow commands (/orient, /explore, /spec, etc.), the statusline
11
+ always reflects the current workflow state.
12
+
13
+ Usage:
14
+ from global.lib.state_manager import update_state, get_state
15
+
16
+ # Update phase when running /explore
17
+ update_state(phase="explore", last_command="/explore")
18
+
19
+ # Update issue when claiming Linear work
20
+ update_state(active_issue="ANV-180", phase="implement")
21
+
22
+ # Clear issue when starting fresh
23
+ update_state(active_issue=None, phase="orient")
24
+
25
+ # Read current state
26
+ state = get_state()
27
+ print(state.get("session", {}).get("phase"))
28
+ """
29
+
30
+ import json
31
+ import os
32
+ import tempfile
33
+ from datetime import datetime, timezone
34
+ from pathlib import Path
35
+ from typing import Any, Dict, Optional
36
+
37
+ # Try to import agent registry for sync
38
+ try:
39
+ from agent_registry import update_agent
40
+ REGISTRY_AVAILABLE = True
41
+ except ImportError:
42
+ try:
43
+ # Try relative import for when run as module
44
+ from .agent_registry import update_agent
45
+ REGISTRY_AVAILABLE = True
46
+ except ImportError:
47
+ REGISTRY_AVAILABLE = False
48
+
49
+
50
+ # =============================================================================
51
+ # Configuration
52
+ # =============================================================================
53
+
54
+ STATE_FILE = Path(".claude/anvil-state.json")
55
+
56
+
57
+ # =============================================================================
58
+ # State Operations
59
+ # =============================================================================
60
+
61
+ def _atomic_write(filepath: Path, data: Dict[str, Any]) -> None:
62
+ """Write data to file atomically (write temp, then rename)."""
63
+ dir_path = filepath.parent
64
+ dir_path.mkdir(parents=True, exist_ok=True)
65
+
66
+ with tempfile.NamedTemporaryFile(
67
+ mode='w',
68
+ dir=str(dir_path),
69
+ delete=False,
70
+ suffix='.tmp'
71
+ ) as tmp:
72
+ json.dump(data, tmp, indent=2)
73
+ tmp_path = tmp.name
74
+
75
+ os.rename(tmp_path, str(filepath))
76
+
77
+
78
+ def _read_state() -> Dict[str, Any]:
79
+ """Read state file, creating default structure if missing."""
80
+ if not STATE_FILE.exists():
81
+ return {
82
+ "version": "1.0",
83
+ "session": {},
84
+ "cache": {"git": {}},
85
+ "meta": {
86
+ "createdAt": datetime.now(timezone.utc).isoformat(),
87
+ "updatedAt": datetime.now(timezone.utc).isoformat(),
88
+ }
89
+ }
90
+
91
+ try:
92
+ with open(STATE_FILE, 'r') as f:
93
+ return json.load(f)
94
+ except (json.JSONDecodeError, IOError):
95
+ # Corrupted file, return fresh
96
+ return {
97
+ "version": "1.0",
98
+ "session": {},
99
+ "cache": {"git": {}},
100
+ "meta": {
101
+ "createdAt": datetime.now(timezone.utc).isoformat(),
102
+ "updatedAt": datetime.now(timezone.utc).isoformat(),
103
+ }
104
+ }
105
+
106
+
107
+ def _write_state(state: Dict[str, Any]) -> None:
108
+ """Write state file atomically."""
109
+ state.setdefault("meta", {})
110
+ state["meta"]["updatedAt"] = datetime.now(timezone.utc).isoformat()
111
+ _atomic_write(STATE_FILE, state)
112
+
113
+
114
+ def _sync_to_registry(session: Dict[str, Any]) -> None:
115
+ """Sync session state to agent registry for HUD visibility."""
116
+ if not REGISTRY_AVAILABLE:
117
+ return
118
+
119
+ agent_id = session.get("agentId")
120
+ if not agent_id:
121
+ return
122
+
123
+ try:
124
+ update_agent(
125
+ agent_id=agent_id,
126
+ phase=session.get("phase"),
127
+ issue=session.get("activeIssue"),
128
+ )
129
+ except Exception:
130
+ # Don't fail if registry update fails
131
+ pass
132
+
133
+
134
+ def get_state() -> Dict[str, Any]:
135
+ """Get the current state.
136
+
137
+ Returns:
138
+ Complete state dictionary
139
+ """
140
+ return _read_state()
141
+
142
+
143
+ def get_session() -> Dict[str, Any]:
144
+ """Get the session portion of state.
145
+
146
+ Returns:
147
+ Session dictionary with agentId, phase, activeIssue, etc.
148
+ """
149
+ state = _read_state()
150
+ return state.get("session", {})
151
+
152
+
153
+ def update_state(
154
+ phase: Optional[str] = None,
155
+ active_issue: Optional[str] = None,
156
+ active_spec: Optional[str] = None,
157
+ active_plan: Optional[str] = None,
158
+ last_command: Optional[str] = None,
159
+ clear_issue: bool = False,
160
+ ) -> None:
161
+ """Update anvil-state.json with new values and sync to registry.
162
+
163
+ Args:
164
+ phase: Workflow phase (orient, explore, spec, plan, tasks, implement, verify, handoff)
165
+ active_issue: Linear issue key (e.g., "ANV-180") or None to clear
166
+ active_spec: Active spec file path or None to clear
167
+ active_plan: Active plan file path or None to clear
168
+ last_command: Name of command that triggered this update
169
+ clear_issue: If True, explicitly clears activeIssue (vs None meaning no change)
170
+
171
+ Example:
172
+ # When running /explore
173
+ update_state(phase="explore", last_command="/explore")
174
+
175
+ # When claiming an issue
176
+ update_state(active_issue="ANV-180", phase="implement")
177
+
178
+ # When starting fresh with /orient
179
+ update_state(phase="orient", clear_issue=True)
180
+ """
181
+ state = _read_state()
182
+ session = state.setdefault("session", {})
183
+
184
+ # Update fields if provided
185
+ if phase is not None:
186
+ session["phase"] = phase
187
+
188
+ if active_issue is not None:
189
+ session["activeIssue"] = active_issue
190
+ elif clear_issue:
191
+ session["activeIssue"] = None
192
+
193
+ if active_spec is not None:
194
+ session["activeSpec"] = active_spec if active_spec else None
195
+
196
+ if active_plan is not None:
197
+ session["activePlan"] = active_plan if active_plan else None
198
+
199
+ if last_command is not None:
200
+ session["lastCommand"] = last_command
201
+ session["lastCommandAt"] = datetime.now(timezone.utc).isoformat()
202
+
203
+ # Write state and sync to registry
204
+ _write_state(state)
205
+ _sync_to_registry(session)
206
+
207
+
208
+ def set_issue(issue_key: str) -> None:
209
+ """Convenience function to set the active issue.
210
+
211
+ Args:
212
+ issue_key: Linear issue key (e.g., "ANV-180")
213
+ """
214
+ update_state(active_issue=issue_key)
215
+
216
+
217
+ def clear_issue() -> None:
218
+ """Convenience function to clear the active issue."""
219
+ update_state(clear_issue=True)
220
+
221
+
222
+ def set_phase(phase: str) -> None:
223
+ """Convenience function to set the workflow phase.
224
+
225
+ Args:
226
+ phase: Workflow phase name
227
+ """
228
+ update_state(phase=phase)
229
+
230
+
231
+ # =============================================================================
232
+ # Command-specific helpers
233
+ # =============================================================================
234
+
235
+ def on_orient() -> None:
236
+ """Called when /orient command runs."""
237
+ update_state(phase="orient", clear_issue=True, last_command="/orient")
238
+
239
+
240
+ def on_explore() -> None:
241
+ """Called when /explore command runs."""
242
+ update_state(phase="explore", last_command="/explore")
243
+
244
+
245
+ def on_spec(spec_path: Optional[str] = None) -> None:
246
+ """Called when /spec command runs.
247
+
248
+ Args:
249
+ spec_path: Path to the created spec file
250
+ """
251
+ update_state(phase="spec", active_spec=spec_path, last_command="/spec")
252
+
253
+
254
+ def on_plan(plan_path: Optional[str] = None) -> None:
255
+ """Called when /plan command runs.
256
+
257
+ Args:
258
+ plan_path: Path to the created plan file
259
+ """
260
+ update_state(phase="plan", active_plan=plan_path, last_command="/plan")
261
+
262
+
263
+ def on_tasks() -> None:
264
+ """Called when /tasks command runs."""
265
+ update_state(phase="tasks", last_command="/tasks")
266
+
267
+
268
+ def on_evidence() -> None:
269
+ """Called when /evidence command runs."""
270
+ update_state(phase="verify", last_command="/evidence")
271
+
272
+
273
+ def on_handoff() -> None:
274
+ """Called when /handoff command runs."""
275
+ update_state(phase="handoff", last_command="/handoff")
276
+
277
+
278
+ def on_claim_issue(issue_key: str) -> None:
279
+ """Called when an issue is claimed from Linear.
280
+
281
+ Args:
282
+ issue_key: Linear issue key (e.g., "ANV-180")
283
+ """
284
+ update_state(active_issue=issue_key, phase="implement")
285
+
286
+
287
+ def on_doc_coverage(
288
+ percent: float,
289
+ total: int,
290
+ documented: int,
291
+ status: str,
292
+ ) -> None:
293
+ """Called when /doc-coverage command runs.
294
+
295
+ Stores coverage snapshot for tracking over time.
296
+
297
+ Note: This function directly manipulates state rather than using update_state()
298
+ because doc-coverage is a reporting command (not a workflow phase change) and
299
+ requires storing structured data (docCoverage object) not supported by update_state().
300
+ Registry sync is intentionally skipped since coverage reports don't affect agent status.
301
+
302
+ Args:
303
+ percent: Coverage percentage (0-100)
304
+ total: Total number of exports
305
+ documented: Number of documented exports
306
+ status: Coverage status (healthy, warning, critical)
307
+ """
308
+ state = _read_state()
309
+ session = state.setdefault("session", {})
310
+
311
+ session["docCoverage"] = {
312
+ "percent": percent,
313
+ "total": total,
314
+ "documented": documented,
315
+ "status": status,
316
+ "timestamp": datetime.now(timezone.utc).isoformat(),
317
+ }
318
+ session["lastCommand"] = "/doc-coverage"
319
+ session["lastCommandAt"] = datetime.now(timezone.utc).isoformat()
320
+
321
+ _write_state(state)
322
+
323
+
324
+ # =============================================================================
325
+ # CLI Interface
326
+ # =============================================================================
327
+
328
+ if __name__ == "__main__":
329
+ import sys
330
+
331
+ if len(sys.argv) < 2:
332
+ print("Usage: state_manager.py <command> [args...]")
333
+ print("Commands:")
334
+ print(" get - Show current state")
335
+ print(" set-phase <phase> - Set workflow phase")
336
+ print(" set-issue <key> - Set active issue")
337
+ print(" clear-issue - Clear active issue")
338
+ print(" orient - Run orient handler")
339
+ print(" explore - Run explore handler")
340
+ print(" spec [path] - Run spec handler")
341
+ print(" plan [path] - Run plan handler")
342
+ print(" tasks - Run tasks handler")
343
+ print(" evidence - Run evidence handler")
344
+ print(" handoff - Run handoff handler")
345
+ print(" doc-coverage <p> <t> <d> <s> - Store coverage snapshot")
346
+ sys.exit(1)
347
+
348
+ cmd = sys.argv[1]
349
+
350
+ if cmd == "get":
351
+ state = get_state()
352
+ print(json.dumps(state, indent=2))
353
+
354
+ elif cmd == "set-phase":
355
+ if len(sys.argv) < 3:
356
+ print("Error: phase required")
357
+ sys.exit(1)
358
+ set_phase(sys.argv[2])
359
+ print(f"Phase set to: {sys.argv[2]}")
360
+
361
+ elif cmd == "set-issue":
362
+ if len(sys.argv) < 3:
363
+ print("Error: issue key required")
364
+ sys.exit(1)
365
+ set_issue(sys.argv[2])
366
+ print(f"Active issue set to: {sys.argv[2]}")
367
+
368
+ elif cmd == "clear-issue":
369
+ clear_issue()
370
+ print("Active issue cleared")
371
+
372
+ elif cmd == "orient":
373
+ on_orient()
374
+ print("Orient handler executed")
375
+
376
+ elif cmd == "explore":
377
+ on_explore()
378
+ print("Explore handler executed")
379
+
380
+ elif cmd == "spec":
381
+ path = sys.argv[2] if len(sys.argv) > 2 else None
382
+ on_spec(path)
383
+ print(f"Spec handler executed{f' with path: {path}' if path else ''}")
384
+
385
+ elif cmd == "plan":
386
+ path = sys.argv[2] if len(sys.argv) > 2 else None
387
+ on_plan(path)
388
+ print(f"Plan handler executed{f' with path: {path}' if path else ''}")
389
+
390
+ elif cmd == "tasks":
391
+ on_tasks()
392
+ print("Tasks handler executed")
393
+
394
+ elif cmd == "evidence":
395
+ on_evidence()
396
+ print("Evidence handler executed")
397
+
398
+ elif cmd == "handoff":
399
+ on_handoff()
400
+ print("Handoff handler executed")
401
+
402
+ elif cmd == "doc-coverage":
403
+ if len(sys.argv) < 6:
404
+ print("Error: doc-coverage requires percent total documented status")
405
+ print("Usage: state_manager.py doc-coverage <percent> <total> <documented> <status>")
406
+ sys.exit(1)
407
+ on_doc_coverage(
408
+ percent=float(sys.argv[2]),
409
+ total=int(sys.argv[3]),
410
+ documented=int(sys.argv[4]),
411
+ status=sys.argv[5],
412
+ )
413
+ print(f"Doc coverage recorded: {sys.argv[2]}%")
414
+
415
+ else:
416
+ print(f"Unknown command: {cmd}")
417
+ sys.exit(1)