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,210 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ linear_data_service.py - Linear issue data fetching and caching for HUD
4
+
5
+ Provides cached access to Linear issue data for the Anvil HUD dashboard.
6
+ Uses the linear-skill scripts for API access with 60-second TTL caching.
7
+
8
+ Usage:
9
+ from linear_data_service import LinearDataService
10
+
11
+ service = LinearDataService()
12
+ issue = service.get_issue("ANV-42")
13
+ print(issue["title"], issue["state"])
14
+ """
15
+
16
+ import json
17
+ import subprocess
18
+ import time
19
+ from pathlib import Path
20
+ from typing import Any, Dict, List, Optional, TypedDict
21
+
22
+
23
+ class IssueData(TypedDict, total=False):
24
+ """Linear issue data structure."""
25
+ id: str # Issue UUID
26
+ identifier: str # Issue key (e.g., "ANV-42")
27
+ title: str # Issue title
28
+ state: str # Workflow state name
29
+ state_type: str # State type (backlog, unstarted, started, completed, canceled)
30
+ assignee: Optional[str] # Assignee name
31
+ priority: Optional[int] # Priority (0-4)
32
+ url: str # Linear issue URL
33
+ project: Optional[str] # Project name
34
+ labels: List[str] # Label names
35
+ fetched_at: float # Timestamp when fetched
36
+
37
+
38
+ class CacheEntry(TypedDict):
39
+ """Cache entry with TTL tracking."""
40
+ data: IssueData
41
+ expires_at: float
42
+
43
+
44
+ class LinearDataService:
45
+ """Service for fetching and caching Linear issue data (ANV-100)."""
46
+
47
+ DEFAULT_TTL = 60.0 # 60 seconds cache TTL
48
+ LINEAR_SCRIPT = Path.home() / ".claude" / "skills" / "linear-skill" / "scripts" / "linear.py"
49
+
50
+ def __init__(self, ttl: float = DEFAULT_TTL):
51
+ """Initialize the service.
52
+
53
+ Args:
54
+ ttl: Cache time-to-live in seconds
55
+ """
56
+ self.ttl = ttl
57
+ self._cache: Dict[str, CacheEntry] = {}
58
+
59
+ def get_issue(self, issue_id: str) -> Optional[IssueData]:
60
+ """Fetch a single issue, using cache if available.
61
+
62
+ Args:
63
+ issue_id: Issue identifier (e.g., "ANV-42")
64
+
65
+ Returns:
66
+ Issue data or None if not found/error
67
+ """
68
+ # Check cache first
69
+ cached = self._get_cached(issue_id)
70
+ if cached is not None:
71
+ return cached
72
+
73
+ # Fetch from API
74
+ issue = self._fetch_issue(issue_id)
75
+ if issue:
76
+ self._set_cached(issue_id, issue)
77
+ return issue
78
+
79
+ def get_issues(self, issue_ids: List[str]) -> Dict[str, IssueData]:
80
+ """Fetch multiple issues.
81
+
82
+ Args:
83
+ issue_ids: List of issue identifiers
84
+
85
+ Returns:
86
+ Dictionary mapping issue_id -> IssueData
87
+ """
88
+ results: Dict[str, IssueData] = {}
89
+
90
+ for issue_id in issue_ids:
91
+ if not issue_id:
92
+ continue
93
+ issue = self.get_issue(issue_id)
94
+ if issue:
95
+ results[issue_id] = issue
96
+
97
+ return results
98
+
99
+ def get_issues_for_agents(self, agents: Dict[str, Any]) -> Dict[str, IssueData]:
100
+ """Fetch issues for all agents with assigned issues.
101
+
102
+ Args:
103
+ agents: Agent registry data
104
+
105
+ Returns:
106
+ Dictionary mapping issue_id -> IssueData
107
+ """
108
+ issue_ids = set()
109
+ for agent in agents.values():
110
+ issue_id = agent.get("issue")
111
+ if issue_id:
112
+ issue_ids.add(issue_id)
113
+
114
+ return self.get_issues(list(issue_ids))
115
+
116
+ def clear_cache(self) -> None:
117
+ """Clear all cached data."""
118
+ self._cache.clear()
119
+
120
+ def _get_cached(self, issue_id: str) -> Optional[IssueData]:
121
+ """Get issue from cache if not expired."""
122
+ entry = self._cache.get(issue_id)
123
+ if entry and entry["expires_at"] > time.time():
124
+ return entry["data"]
125
+ return None
126
+
127
+ def _set_cached(self, issue_id: str, data: IssueData) -> None:
128
+ """Store issue in cache."""
129
+ self._cache[issue_id] = {
130
+ "data": data,
131
+ "expires_at": time.time() + self.ttl,
132
+ }
133
+
134
+ def _fetch_issue(self, issue_id: str) -> Optional[IssueData]:
135
+ """Fetch issue from Linear API using linear-skill script."""
136
+ if not self.LINEAR_SCRIPT.exists():
137
+ return None
138
+
139
+ try:
140
+ result = subprocess.run(
141
+ ["python3", str(self.LINEAR_SCRIPT), "get-issue", "--id", issue_id],
142
+ capture_output=True,
143
+ text=True,
144
+ timeout=10,
145
+ )
146
+
147
+ if result.returncode != 0:
148
+ return None
149
+
150
+ data = json.loads(result.stdout)
151
+ return self._parse_issue(data)
152
+
153
+ except (subprocess.TimeoutExpired, json.JSONDecodeError, Exception):
154
+ # Return stale data if available
155
+ entry = self._cache.get(issue_id)
156
+ if entry:
157
+ return entry["data"]
158
+ return None
159
+
160
+ def _parse_issue(self, data: Dict[str, Any]) -> IssueData:
161
+ """Parse Linear API response into IssueData."""
162
+ state = data.get("state", {})
163
+ assignee = data.get("assignee", {})
164
+ project = data.get("project", {})
165
+ labels = data.get("labels", {}).get("nodes", [])
166
+
167
+ return {
168
+ "id": data.get("id", ""),
169
+ "identifier": data.get("identifier", ""),
170
+ "title": data.get("title", ""),
171
+ "state": state.get("name", "Unknown"),
172
+ "state_type": state.get("type", ""),
173
+ "assignee": assignee.get("name") if assignee else None,
174
+ "priority": data.get("priority"),
175
+ "url": data.get("url", ""),
176
+ "project": project.get("name") if project else None,
177
+ "labels": [lbl.get("name", "") for lbl in labels],
178
+ "fetched_at": time.time(),
179
+ }
180
+
181
+
182
+ # Singleton instance
183
+ _service: Optional[LinearDataService] = None
184
+
185
+
186
+ def get_linear_service() -> LinearDataService:
187
+ """Get singleton service instance."""
188
+ global _service
189
+ if _service is None:
190
+ _service = LinearDataService()
191
+ return _service
192
+
193
+
194
+ if __name__ == "__main__":
195
+ # Simple test
196
+ import sys
197
+
198
+ if len(sys.argv) > 1:
199
+ issue_id = sys.argv[1]
200
+ service = LinearDataService()
201
+ issue = service.get_issue(issue_id)
202
+ if issue:
203
+ print(f"Issue: {issue['identifier']}")
204
+ print(f"Title: {issue['title']}")
205
+ print(f"State: {issue['state']}")
206
+ print(f"Assignee: {issue['assignee'] or 'Unassigned'}")
207
+ else:
208
+ print(f"Could not fetch {issue_id}")
209
+ else:
210
+ print("Usage: linear_data_service.py <issue-id>")