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,432 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Anvil Issue CLI - Local issue tracking for Anvil Framework.
4
+
5
+ Commands:
6
+ list - List issues (optionally filtered by status)
7
+ create - Create a new issue
8
+ show - Show issue details
9
+ update - Update an existing issue
10
+ move - Change issue status
11
+ assign - Assign issue to an agent
12
+ stats - Show issue statistics
13
+
14
+ Examples:
15
+ anvil-issue list
16
+ anvil-issue list --status todo
17
+ anvil-issue create --title "Fix bug" --priority high
18
+ anvil-issue show LOCAL-001
19
+ anvil-issue move LOCAL-001 --to in_progress
20
+ anvil-issue assign LOCAL-001 --agent agent-xyz
21
+ """
22
+
23
+ import argparse
24
+ import sys
25
+ from pathlib import Path
26
+
27
+ # Add lib directory to path
28
+ sys.path.insert(0, str(Path(__file__).parent.parent / "lib"))
29
+
30
+ from issue_models import IssueStatus, Priority
31
+ from local_provider import LocalJsonProvider
32
+
33
+
34
+ def get_provider() -> LocalJsonProvider:
35
+ """Get the local provider instance."""
36
+ return LocalJsonProvider()
37
+
38
+
39
+ def format_priority(priority: Priority) -> str:
40
+ """Format priority with color indicators."""
41
+ icons = {
42
+ Priority.URGENT: "P0",
43
+ Priority.HIGH: "P1",
44
+ Priority.MEDIUM: "P2",
45
+ Priority.LOW: "P3",
46
+ Priority.NONE: "P4"
47
+ }
48
+ return icons.get(priority, "P?")
49
+
50
+
51
+ def format_status(status: IssueStatus) -> str:
52
+ """Format status for display."""
53
+ icons = {
54
+ IssueStatus.BACKLOG: "[ ]",
55
+ IssueStatus.TODO: "[·]",
56
+ IssueStatus.IN_PROGRESS: "[→]",
57
+ IssueStatus.IN_REVIEW: "[?]",
58
+ IssueStatus.DONE: "[✓]",
59
+ IssueStatus.CANCELLED: "[✗]"
60
+ }
61
+ return icons.get(status, "[?]")
62
+
63
+
64
+ def cmd_list(args):
65
+ """List issues."""
66
+ provider = get_provider()
67
+
68
+ # Parse status filter
69
+ status_filter = None
70
+ if args.status:
71
+ try:
72
+ status_filter = IssueStatus(args.status.lower().replace("-", "_"))
73
+ except ValueError:
74
+ print(f"Unknown status: {args.status}")
75
+ print(f"Valid: {', '.join(s.value for s in IssueStatus)}")
76
+ return 1
77
+
78
+ issues = provider.list_issues(status=status_filter, limit=args.limit)
79
+
80
+ if not issues:
81
+ print("No issues found.")
82
+ return 0
83
+
84
+ # Print header
85
+ print(f"\n{'ID':<12} {'Pri':<4} {'Status':<12} {'Title':<40}")
86
+ print("-" * 72)
87
+
88
+ for issue in issues:
89
+ status_str = issue.status.value.replace("_", " ").title()
90
+ title = issue.title[:38] + ".." if len(issue.title) > 40 else issue.title
91
+ print(f"{issue.identifier:<12} {format_priority(issue.priority):<4} {status_str:<12} {title:<40}")
92
+
93
+ print(f"\nTotal: {len(issues)} issue(s)")
94
+ return 0
95
+
96
+
97
+ def cmd_create(args):
98
+ """Create a new issue."""
99
+ provider = get_provider()
100
+
101
+ # Parse priority
102
+ priority = Priority.MEDIUM
103
+ if args.priority:
104
+ priority_map = {
105
+ "urgent": Priority.URGENT, "p0": Priority.URGENT,
106
+ "high": Priority.HIGH, "p1": Priority.HIGH,
107
+ "medium": Priority.MEDIUM, "p2": Priority.MEDIUM,
108
+ "low": Priority.LOW, "p3": Priority.LOW,
109
+ "none": Priority.NONE, "p4": Priority.NONE
110
+ }
111
+ priority = priority_map.get(args.priority.lower(), Priority.MEDIUM)
112
+
113
+ # Parse labels
114
+ labels = []
115
+ if args.labels:
116
+ labels = [lbl.strip() for lbl in args.labels.split(",")]
117
+
118
+ issue = provider.create_issue(
119
+ title=args.title,
120
+ description=args.description or "",
121
+ priority=priority,
122
+ labels=labels,
123
+ parent_id=args.parent
124
+ )
125
+
126
+ print(f"\nCreated: {issue.identifier}")
127
+ print(f" Title: {issue.title}")
128
+ print(f" Priority: {format_priority(issue.priority)}")
129
+ print(f" Status: {issue.status.value}")
130
+ if issue.labels:
131
+ print(f" Labels: {', '.join(issue.labels)}")
132
+
133
+ return 0
134
+
135
+
136
+ def cmd_show(args):
137
+ """Show issue details."""
138
+ provider = get_provider()
139
+ issue = provider.get_issue(args.identifier)
140
+
141
+ if not issue:
142
+ print(f"Issue not found: {args.identifier}")
143
+ return 1
144
+
145
+ print(f"\n{issue.identifier}: {issue.title}")
146
+ print("-" * 50)
147
+ print(f"Status: {issue.status.value.replace('_', ' ').title()}")
148
+ print(f"Priority: {format_priority(issue.priority)} ({issue.priority.to_display()})")
149
+
150
+ if issue.description:
151
+ print(f"\nDescription:\n{issue.description}")
152
+
153
+ if issue.labels:
154
+ print(f"\nLabels: {', '.join(issue.labels)}")
155
+
156
+ if issue.assigned_agent:
157
+ print(f"Assigned: {issue.assigned_agent}")
158
+
159
+ if issue.parent_id:
160
+ print(f"Parent: {issue.parent_id}")
161
+
162
+ print(f"\nCreated: {issue.created_at.strftime('%Y-%m-%d %H:%M') if issue.created_at else 'N/A'}")
163
+ print(f"Updated: {issue.updated_at.strftime('%Y-%m-%d %H:%M') if issue.updated_at else 'N/A'}")
164
+
165
+ if issue.completed_at:
166
+ print(f"Completed: {issue.completed_at.strftime('%Y-%m-%d %H:%M')}")
167
+
168
+ return 0
169
+
170
+
171
+ def cmd_update(args):
172
+ """Update an existing issue."""
173
+ provider = get_provider()
174
+
175
+ # Check issue exists
176
+ existing = provider.get_issue(args.identifier)
177
+ if not existing:
178
+ print(f"Issue not found: {args.identifier}")
179
+ return 1
180
+
181
+ # Parse priority if provided
182
+ priority = None
183
+ if args.priority:
184
+ priority_map = {
185
+ "urgent": Priority.URGENT, "p0": Priority.URGENT,
186
+ "high": Priority.HIGH, "p1": Priority.HIGH,
187
+ "medium": Priority.MEDIUM, "p2": Priority.MEDIUM,
188
+ "low": Priority.LOW, "p3": Priority.LOW,
189
+ "none": Priority.NONE, "p4": Priority.NONE
190
+ }
191
+ priority = priority_map.get(args.priority.lower())
192
+
193
+ # Parse labels if provided
194
+ labels = None
195
+ if args.labels:
196
+ labels = [lbl.strip() for lbl in args.labels.split(",")]
197
+
198
+ issue = provider.update_issue(
199
+ identifier=args.identifier,
200
+ title=args.title,
201
+ description=args.description,
202
+ priority=priority,
203
+ labels=labels
204
+ )
205
+
206
+ print(f"\nUpdated: {issue.identifier}")
207
+ print(f" Title: {issue.title}")
208
+ print(f" Priority: {format_priority(issue.priority)}")
209
+ print(f" Status: {issue.status.value}")
210
+
211
+ return 0
212
+
213
+
214
+ def cmd_move(args):
215
+ """Change issue status."""
216
+ provider = get_provider()
217
+
218
+ # Check issue exists
219
+ existing = provider.get_issue(args.identifier)
220
+ if not existing:
221
+ print(f"Issue not found: {args.identifier}")
222
+ return 1
223
+
224
+ # Parse target status
225
+ status_map = {
226
+ "backlog": IssueStatus.BACKLOG,
227
+ "todo": IssueStatus.TODO,
228
+ "in-progress": IssueStatus.IN_PROGRESS,
229
+ "in_progress": IssueStatus.IN_PROGRESS,
230
+ "inprogress": IssueStatus.IN_PROGRESS,
231
+ "in-review": IssueStatus.IN_REVIEW,
232
+ "in_review": IssueStatus.IN_REVIEW,
233
+ "inreview": IssueStatus.IN_REVIEW,
234
+ "done": IssueStatus.DONE,
235
+ "cancelled": IssueStatus.CANCELLED,
236
+ "canceled": IssueStatus.CANCELLED
237
+ }
238
+
239
+ target_status = status_map.get(args.to.lower())
240
+ if not target_status:
241
+ print(f"Unknown status: {args.to}")
242
+ print("Valid: backlog, todo, in-progress, in-review, done, cancelled")
243
+ return 1
244
+
245
+ old_status = existing.status.value
246
+ issue = provider.update_issue(args.identifier, status=target_status)
247
+
248
+ print(f"\n{issue.identifier}: {old_status} → {issue.status.value}")
249
+
250
+ return 0
251
+
252
+
253
+ def cmd_assign(args):
254
+ """Assign issue to an agent."""
255
+ provider = get_provider()
256
+
257
+ # Check issue exists
258
+ existing = provider.get_issue(args.identifier)
259
+ if not existing:
260
+ print(f"Issue not found: {args.identifier}")
261
+ return 1
262
+
263
+ if args.unassign:
264
+ issue = provider.unassign_agent(args.identifier)
265
+ print(f"\n{issue.identifier}: Unassigned")
266
+ else:
267
+ if not args.agent:
268
+ print("Error: --agent required (or use --unassign)")
269
+ return 1
270
+ issue = provider.assign_to_agent(args.identifier, args.agent)
271
+ print(f"\n{issue.identifier}: Assigned to {args.agent}")
272
+
273
+ return 0
274
+
275
+
276
+ def cmd_stats(args):
277
+ """Show issue statistics."""
278
+ provider = get_provider()
279
+ stats = provider.get_statistics()
280
+
281
+ print("\n=== Issue Statistics ===\n")
282
+ print(f"Total Issues: {stats['total']}")
283
+ print(f"Assigned: {stats['assigned']}")
284
+ print(f"Unassigned: {stats['unassigned']}")
285
+
286
+ print("\n--- By Status ---")
287
+ for status, count in sorted(stats['by_status'].items()):
288
+ print(f" {status.replace('_', ' ').title():<15} {count}")
289
+
290
+ print("\n--- By Priority ---")
291
+ for priority, count in sorted(stats['by_priority'].items()):
292
+ print(f" {priority:<15} {count}")
293
+
294
+ return 0
295
+
296
+
297
+ def cmd_ready(args):
298
+ """Show issues ready to work on."""
299
+ provider = get_provider()
300
+ issues = provider.get_ready_issues()
301
+
302
+ if not issues:
303
+ print("\nNo issues ready to work on.")
304
+ return 0
305
+
306
+ print("\n=== Ready to Work ===\n")
307
+ print(f"{'ID':<12} {'Pri':<4} {'Title':<50}")
308
+ print("-" * 68)
309
+
310
+ for issue in issues[:args.limit]:
311
+ title = issue.title[:48] + ".." if len(issue.title) > 50 else issue.title
312
+ print(f"{issue.identifier:<12} {format_priority(issue.priority):<4} {title:<50}")
313
+
314
+ print(f"\nShowing {min(len(issues), args.limit)} of {len(issues)} ready issue(s)")
315
+ return 0
316
+
317
+
318
+ def cmd_delete(args):
319
+ """Delete an issue."""
320
+ provider = get_provider()
321
+
322
+ # Check issue exists
323
+ existing = provider.get_issue(args.identifier)
324
+ if not existing:
325
+ print(f"Issue not found: {args.identifier}")
326
+ return 1
327
+
328
+ if args.hard:
329
+ success = provider.hard_delete_issue(args.identifier)
330
+ action = "Deleted permanently"
331
+ else:
332
+ success = provider.delete_issue(args.identifier)
333
+ action = "Cancelled"
334
+
335
+ if success:
336
+ print(f"\n{args.identifier}: {action}")
337
+ return 0
338
+ else:
339
+ print(f"\nFailed to delete {args.identifier}")
340
+ return 1
341
+
342
+
343
+ def main():
344
+ parser = argparse.ArgumentParser(
345
+ description="Anvil Issue CLI - Local issue tracking",
346
+ formatter_class=argparse.RawDescriptionHelpFormatter,
347
+ epilog="""
348
+ Examples:
349
+ anvil-issue list List all issues
350
+ anvil-issue list --status todo List todo issues
351
+ anvil-issue create --title "Fix bug" Create new issue
352
+ anvil-issue show LOCAL-001 Show issue details
353
+ anvil-issue move LOCAL-001 --to done Change status
354
+ anvil-issue assign LOCAL-001 --agent xyz Assign to agent
355
+ anvil-issue stats Show statistics
356
+ anvil-issue ready Show ready work
357
+ """
358
+ )
359
+
360
+ subparsers = parser.add_subparsers(dest="command", help="Command to run")
361
+
362
+ # list command
363
+ list_parser = subparsers.add_parser("list", help="List issues")
364
+ list_parser.add_argument("--status", "-s", help="Filter by status")
365
+ list_parser.add_argument("--limit", "-n", type=int, default=50, help="Max issues to show")
366
+
367
+ # create command
368
+ create_parser = subparsers.add_parser("create", help="Create an issue")
369
+ create_parser.add_argument("--title", "-t", required=True, help="Issue title")
370
+ create_parser.add_argument("--description", "-d", help="Issue description")
371
+ create_parser.add_argument("--priority", "-p", help="Priority (urgent/high/medium/low)")
372
+ create_parser.add_argument("--labels", "-l", help="Comma-separated labels")
373
+ create_parser.add_argument("--parent", help="Parent issue identifier")
374
+
375
+ # show command
376
+ show_parser = subparsers.add_parser("show", help="Show issue details")
377
+ show_parser.add_argument("identifier", help="Issue identifier (e.g., LOCAL-001)")
378
+
379
+ # update command
380
+ update_parser = subparsers.add_parser("update", help="Update an issue")
381
+ update_parser.add_argument("identifier", help="Issue identifier")
382
+ update_parser.add_argument("--title", "-t", help="New title")
383
+ update_parser.add_argument("--description", "-d", help="New description")
384
+ update_parser.add_argument("--priority", "-p", help="New priority")
385
+ update_parser.add_argument("--labels", "-l", help="New labels (comma-separated)")
386
+
387
+ # move command
388
+ move_parser = subparsers.add_parser("move", help="Change issue status")
389
+ move_parser.add_argument("identifier", help="Issue identifier")
390
+ move_parser.add_argument("--to", required=True, help="Target status")
391
+
392
+ # assign command
393
+ assign_parser = subparsers.add_parser("assign", help="Assign issue to agent")
394
+ assign_parser.add_argument("identifier", help="Issue identifier")
395
+ assign_parser.add_argument("--agent", "-a", help="Agent ID to assign")
396
+ assign_parser.add_argument("--unassign", "-u", action="store_true", help="Remove assignment")
397
+
398
+ # stats command
399
+ subparsers.add_parser("stats", help="Show statistics")
400
+
401
+ # ready command
402
+ ready_parser = subparsers.add_parser("ready", help="Show ready work")
403
+ ready_parser.add_argument("--limit", "-n", type=int, default=10, help="Max issues")
404
+
405
+ # delete command
406
+ delete_parser = subparsers.add_parser("delete", help="Delete an issue")
407
+ delete_parser.add_argument("identifier", help="Issue identifier")
408
+ delete_parser.add_argument("--hard", action="store_true", help="Permanently delete")
409
+
410
+ args = parser.parse_args()
411
+
412
+ if not args.command:
413
+ parser.print_help()
414
+ return 0
415
+
416
+ commands = {
417
+ "list": cmd_list,
418
+ "create": cmd_create,
419
+ "show": cmd_show,
420
+ "update": cmd_update,
421
+ "move": cmd_move,
422
+ "assign": cmd_assign,
423
+ "stats": cmd_stats,
424
+ "ready": cmd_ready,
425
+ "delete": cmd_delete
426
+ }
427
+
428
+ return commands[args.command](args)
429
+
430
+
431
+ if __name__ == "__main__":
432
+ sys.exit(main())
@@ -0,0 +1,49 @@
1
+ # Anvil Memory
2
+
3
+ > Persistent memory system for the Anvil framework.
4
+
5
+ ## Overview
6
+
7
+ Anvil Memory provides SQLite-backed persistent storage for observations, sessions, checkpoints, and Ralph iterations. It replaces Claude-Mem with a proprietary solution integrated into the Anvil framework.
8
+
9
+ ## Tech Stack
10
+
11
+ - **Runtime**: Bun (use `bun` instead of `node`)
12
+ - **Database**: SQLite via `bun:sqlite`
13
+ - **Language**: TypeScript (strict mode)
14
+
15
+ ## Commands
16
+
17
+ ```bash
18
+ bun run dev # Run from source
19
+ bun run build # Compile to dist/anvil-memory
20
+ bun run test # Run tests
21
+ bun run typecheck # Check types
22
+ ```
23
+
24
+ ## Architecture
25
+
26
+ ```
27
+ src/
28
+ ├── index.ts # CLI entry point
29
+ ├── types.ts # Type definitions
30
+ ├── db.ts # Database operations
31
+ └── commands/ # Command handlers
32
+ ├── init.ts
33
+ ├── observe.ts
34
+ ├── search.ts
35
+ └── ...
36
+ ```
37
+
38
+ ## Database
39
+
40
+ - Location: `~/.anvil/memory.db`
41
+ - Schema: See `src/db.ts` for migrations
42
+ - Uses FTS5 for full-text search
43
+
44
+ ## Key Patterns
45
+
46
+ 1. **Use bun:sqlite** - Don't use better-sqlite3 or other libraries
47
+ 2. **FTS5 sync** - Triggers keep FTS tables in sync
48
+ 3. **JSON for arrays** - Store concepts/files as JSON arrays
49
+ 4. **ISO timestamps** - All timestamps in ISO 8601 format
@@ -0,0 +1,42 @@
1
+ # Anvil Memory
2
+
3
+ Persistent memory system for the Anvil framework.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ cd global/tools/anvil-memory
9
+ bun install
10
+ bun run build
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ # Initialize database
17
+ anvil-memory init
18
+
19
+ # Create observation
20
+ anvil-memory observe --type feature --title "Added auth" --content "Details..."
21
+
22
+ # Search
23
+ anvil-memory search "authentication" --limit 10
24
+
25
+ # Get by ID
26
+ anvil-memory get 42
27
+
28
+ # Generate context
29
+ anvil-memory context --limit 20 --format inject
30
+ ```
31
+
32
+ ## Development
33
+
34
+ ```bash
35
+ bun run dev # Run from source
36
+ bun run test # Run tests
37
+ bun run typecheck # Type check
38
+ ```
39
+
40
+ ## License
41
+
42
+ MIT
@@ -0,0 +1,25 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "workspaces": {
4
+ "": {
5
+ "name": "anvil-memory",
6
+ "devDependencies": {
7
+ "@types/bun": "latest",
8
+ },
9
+ "peerDependencies": {
10
+ "typescript": "^5",
11
+ },
12
+ },
13
+ },
14
+ "packages": {
15
+ "@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
16
+
17
+ "@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="],
18
+
19
+ "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
20
+
21
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
22
+
23
+ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
24
+ }
25
+ }
@@ -0,0 +1,9 @@
1
+ # Bun configuration for anvil-memory
2
+
3
+ [test]
4
+ # Test configuration
5
+ root = "./src"
6
+
7
+ [install]
8
+ # Package installation settings
9
+ optional = true
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "anvil-memory",
3
+ "version": "0.1.0",
4
+ "description": "Persistent memory system for Anvil framework",
5
+ "module": "src/index.ts",
6
+ "type": "module",
7
+ "private": true,
8
+ "bin": {
9
+ "anvil-memory": "./dist/anvil-memory"
10
+ },
11
+ "scripts": {
12
+ "dev": "bun run src/index.ts",
13
+ "build": "bun build src/index.ts --compile --outfile dist/anvil-memory",
14
+ "test": "bun test",
15
+ "typecheck": "tsc --noEmit"
16
+ },
17
+ "devDependencies": {
18
+ "@types/bun": "latest"
19
+ },
20
+ "peerDependencies": {
21
+ "typescript": "^5"
22
+ }
23
+ }