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.
- package/README.md +719 -0
- package/VERSION +1 -0
- package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
- package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
- package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
- package/docs/INSTALLATION.md +984 -0
- package/docs/anvil-hud.md +469 -0
- package/docs/anvil-init.md +255 -0
- package/docs/anvil-state.md +210 -0
- package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
- package/docs/command-reference.md +2022 -0
- package/docs/hooks-tts.md +368 -0
- package/docs/implementation-guide.md +810 -0
- package/docs/linear-github-integration.md +247 -0
- package/docs/local-issues.md +677 -0
- package/docs/patterns/README.md +419 -0
- package/docs/planning-responsibilities.md +139 -0
- package/docs/session-workflow.md +573 -0
- package/docs/simplification-plan-template.md +297 -0
- package/docs/simplification-principles.md +129 -0
- package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
- package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
- package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
- package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
- package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
- package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
- package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
- package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
- package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
- package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
- package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
- package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
- package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
- package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
- package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
- package/docs/sync.md +122 -0
- package/global/CLAUDE.md +140 -0
- package/global/agents/verify-app.md +164 -0
- package/global/commands/anvil-settings.md +527 -0
- package/global/commands/anvil-sync.md +121 -0
- package/global/commands/change.md +197 -0
- package/global/commands/clarify.md +252 -0
- package/global/commands/cleanup.md +292 -0
- package/global/commands/commit-push-pr.md +207 -0
- package/global/commands/decay-review.md +127 -0
- package/global/commands/discover.md +158 -0
- package/global/commands/doc-coverage.md +122 -0
- package/global/commands/evidence.md +307 -0
- package/global/commands/explore.md +121 -0
- package/global/commands/force-exit.md +135 -0
- package/global/commands/handoff.md +191 -0
- package/global/commands/healthcheck.md +302 -0
- package/global/commands/hud.md +84 -0
- package/global/commands/insights.md +319 -0
- package/global/commands/linear-setup.md +184 -0
- package/global/commands/lint-fix.md +198 -0
- package/global/commands/orient.md +510 -0
- package/global/commands/plan.md +228 -0
- package/global/commands/ralph.md +346 -0
- package/global/commands/ready.md +182 -0
- package/global/commands/release.md +305 -0
- package/global/commands/retro.md +96 -0
- package/global/commands/shard.md +166 -0
- package/global/commands/spec.md +227 -0
- package/global/commands/sprint.md +184 -0
- package/global/commands/tasks.md +228 -0
- package/global/commands/test-and-commit.md +151 -0
- package/global/commands/validate.md +132 -0
- package/global/commands/verify.md +251 -0
- package/global/commands/weekly-review.md +156 -0
- package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
- package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
- package/global/hooks/anvil_memory_observe.ts +322 -0
- package/global/hooks/anvil_memory_session.ts +166 -0
- package/global/hooks/anvil_memory_stop.ts +187 -0
- package/global/hooks/parse_transcript.py +116 -0
- package/global/hooks/post_merge_cleanup.sh +132 -0
- package/global/hooks/post_tool_format.sh +215 -0
- package/global/hooks/ralph_context_monitor.py +240 -0
- package/global/hooks/ralph_stop.sh +502 -0
- package/global/hooks/statusline.sh +1110 -0
- package/global/hooks/statusline_agent_sync.py +224 -0
- package/global/hooks/stop_gate.sh +250 -0
- package/global/lib/.claude/anvil-state.json +21 -0
- package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
- package/global/lib/agent_registry.py +995 -0
- package/global/lib/anvil-state.sh +435 -0
- package/global/lib/claim_service.py +515 -0
- package/global/lib/coderabbit_service.py +314 -0
- package/global/lib/config_service.py +423 -0
- package/global/lib/coordination_service.py +331 -0
- package/global/lib/doc_coverage_service.py +1305 -0
- package/global/lib/gate_logger.py +316 -0
- package/global/lib/github_service.py +310 -0
- package/global/lib/handoff_generator.py +775 -0
- package/global/lib/hygiene_service.py +712 -0
- package/global/lib/issue_models.py +257 -0
- package/global/lib/issue_provider.py +339 -0
- package/global/lib/linear_data_service.py +210 -0
- package/global/lib/linear_provider.py +987 -0
- package/global/lib/linear_provider.py.backup +671 -0
- package/global/lib/local_provider.py +486 -0
- package/global/lib/orient_fast.py +457 -0
- package/global/lib/quality_service.py +470 -0
- package/global/lib/ralph_prompt_generator.py +563 -0
- package/global/lib/ralph_state.py +1202 -0
- package/global/lib/state_manager.py +417 -0
- package/global/lib/transcript_parser.py +597 -0
- package/global/lib/verification_runner.py +557 -0
- package/global/lib/verify_iteration.py +490 -0
- package/global/lib/verify_subagent.py +250 -0
- package/global/skills/README.md +155 -0
- package/global/skills/quality-gates/SKILL.md +252 -0
- package/global/skills/skill-template/SKILL.md +109 -0
- package/global/skills/testing-strategies/SKILL.md +337 -0
- package/global/templates/CHANGE-template.md +105 -0
- package/global/templates/HANDOFF-template.md +63 -0
- package/global/templates/PLAN-template.md +111 -0
- package/global/templates/SPEC-template.md +93 -0
- package/global/templates/ralph/PROMPT.md.template +89 -0
- package/global/templates/ralph/fix_plan.md.template +31 -0
- package/global/templates/ralph/progress.txt.template +23 -0
- package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
- package/global/tests/test_doc_coverage.py +520 -0
- package/global/tests/test_issue_models.py +299 -0
- package/global/tests/test_local_provider.py +323 -0
- package/global/tools/README.md +178 -0
- package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
- package/global/tools/anvil-hud.py +3622 -0
- package/global/tools/anvil-hud.py.bak +3318 -0
- package/global/tools/anvil-issue.py +432 -0
- package/global/tools/anvil-memory/CLAUDE.md +49 -0
- package/global/tools/anvil-memory/README.md +42 -0
- package/global/tools/anvil-memory/bun.lock +25 -0
- package/global/tools/anvil-memory/bunfig.toml +9 -0
- package/global/tools/anvil-memory/package.json +23 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
- package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
- package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
- package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
- package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
- package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
- package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
- package/global/tools/anvil-memory/src/commands/get.ts +115 -0
- package/global/tools/anvil-memory/src/commands/init.ts +94 -0
- package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
- package/global/tools/anvil-memory/src/commands/search.ts +112 -0
- package/global/tools/anvil-memory/src/db.ts +638 -0
- package/global/tools/anvil-memory/src/index.ts +205 -0
- package/global/tools/anvil-memory/src/types.ts +122 -0
- package/global/tools/anvil-memory/tsconfig.json +29 -0
- package/global/tools/ralph-loop.sh +359 -0
- package/package.json +45 -0
- package/scripts/anvil +822 -0
- package/scripts/extract_patterns.py +222 -0
- package/scripts/init-project.sh +541 -0
- package/scripts/install.sh +229 -0
- package/scripts/postinstall.js +41 -0
- package/scripts/rollback.sh +188 -0
- package/scripts/sync.sh +623 -0
- package/scripts/test-statusline.sh +248 -0
- package/scripts/update_claude_md.py +224 -0
- 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>")
|