@fifine/aim-studio 0.0.1

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 (289) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +159 -0
  3. package/bin/aim.js +3 -0
  4. package/dist/cli/index.d.ts +3 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +89 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/commands/init.d.ts +13 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +513 -0
  11. package/dist/commands/init.js.map +1 -0
  12. package/dist/commands/update.d.ts +27 -0
  13. package/dist/commands/update.d.ts.map +1 -0
  14. package/dist/commands/update.js +1275 -0
  15. package/dist/commands/update.js.map +1 -0
  16. package/dist/configurators/claude.d.ts +32 -0
  17. package/dist/configurators/claude.d.ts.map +1 -0
  18. package/dist/configurators/claude.js +98 -0
  19. package/dist/configurators/claude.js.map +1 -0
  20. package/dist/configurators/index.d.ts +51 -0
  21. package/dist/configurators/index.d.ts.map +1 -0
  22. package/dist/configurators/index.js +113 -0
  23. package/dist/configurators/index.js.map +1 -0
  24. package/dist/configurators/shared.d.ts +12 -0
  25. package/dist/configurators/shared.d.ts.map +1 -0
  26. package/dist/configurators/shared.js +21 -0
  27. package/dist/configurators/shared.js.map +1 -0
  28. package/dist/configurators/workflow.d.ts +28 -0
  29. package/dist/configurators/workflow.d.ts.map +1 -0
  30. package/dist/configurators/workflow.js +147 -0
  31. package/dist/configurators/workflow.js.map +1 -0
  32. package/dist/constants/paths.d.ts +68 -0
  33. package/dist/constants/paths.d.ts.map +1 -0
  34. package/dist/constants/paths.js +77 -0
  35. package/dist/constants/paths.js.map +1 -0
  36. package/dist/constants/version.d.ts +9 -0
  37. package/dist/constants/version.d.ts.map +1 -0
  38. package/dist/constants/version.js +15 -0
  39. package/dist/constants/version.js.map +1 -0
  40. package/dist/index.d.ts +9 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +9 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/migrations/index.d.ts +54 -0
  45. package/dist/migrations/index.d.ts.map +1 -0
  46. package/dist/migrations/index.js +160 -0
  47. package/dist/migrations/index.js.map +1 -0
  48. package/dist/migrations/manifests/0.0.1.json +9 -0
  49. package/dist/migrations/manifests/0.1.9.json +30 -0
  50. package/dist/migrations/manifests/0.2.0.json +49 -0
  51. package/dist/migrations/manifests/0.2.12.json +9 -0
  52. package/dist/migrations/manifests/0.2.13.json +9 -0
  53. package/dist/migrations/manifests/0.2.14.json +175 -0
  54. package/dist/migrations/manifests/0.2.15.json +33 -0
  55. package/dist/migrations/manifests/0.3.0-beta.0.json +278 -0
  56. package/dist/migrations/manifests/0.3.0-beta.1.json +9 -0
  57. package/dist/migrations/manifests/0.3.0-beta.10.json +9 -0
  58. package/dist/migrations/manifests/0.3.0-beta.11.json +9 -0
  59. package/dist/migrations/manifests/0.3.0-beta.12.json +9 -0
  60. package/dist/migrations/manifests/0.3.0-beta.13.json +9 -0
  61. package/dist/migrations/manifests/0.3.0-beta.14.json +9 -0
  62. package/dist/migrations/manifests/0.3.0-beta.15.json +9 -0
  63. package/dist/migrations/manifests/0.3.0-beta.16.json +9 -0
  64. package/dist/migrations/manifests/0.3.0-beta.2.json +9 -0
  65. package/dist/migrations/manifests/0.3.0-beta.3.json +9 -0
  66. package/dist/migrations/manifests/0.3.0-beta.4.json +9 -0
  67. package/dist/migrations/manifests/0.3.0-beta.5.json +9 -0
  68. package/dist/migrations/manifests/0.3.0-beta.6.json +9 -0
  69. package/dist/migrations/manifests/0.3.0-beta.7.json +11 -0
  70. package/dist/migrations/manifests/0.3.0-beta.8.json +9 -0
  71. package/dist/migrations/manifests/0.3.0-beta.9.json +9 -0
  72. package/dist/migrations/manifests/0.3.0-rc.0.json +9 -0
  73. package/dist/migrations/manifests/0.3.0-rc.1.json +9 -0
  74. package/dist/migrations/manifests/0.3.0-rc.2.json +9 -0
  75. package/dist/templates/CLAUDE.md +71 -0
  76. package/dist/templates/aim/gitignore.txt +29 -0
  77. package/dist/templates/aim/index.d.ts +49 -0
  78. package/dist/templates/aim/index.d.ts.map +1 -0
  79. package/dist/templates/aim/index.js +92 -0
  80. package/dist/templates/aim/index.js.map +1 -0
  81. package/dist/templates/aim/scripts/__init__.py +5 -0
  82. package/dist/templates/aim/scripts/add_session.py +392 -0
  83. package/dist/templates/aim/scripts/common/__init__.py +80 -0
  84. package/dist/templates/aim/scripts/common/cli_adapter.py +435 -0
  85. package/dist/templates/aim/scripts/common/developer.py +190 -0
  86. package/dist/templates/aim/scripts/common/git_context.py +383 -0
  87. package/dist/templates/aim/scripts/common/paths.py +347 -0
  88. package/dist/templates/aim/scripts/common/phase.py +253 -0
  89. package/dist/templates/aim/scripts/common/registry.py +366 -0
  90. package/dist/templates/aim/scripts/common/task_queue.py +255 -0
  91. package/dist/templates/aim/scripts/common/task_utils.py +178 -0
  92. package/dist/templates/aim/scripts/common/worktree.py +219 -0
  93. package/dist/templates/aim/scripts/create_bootstrap.py +290 -0
  94. package/dist/templates/aim/scripts/get_context.py +16 -0
  95. package/dist/templates/aim/scripts/get_developer.py +26 -0
  96. package/dist/templates/aim/scripts/init_developer.py +51 -0
  97. package/dist/templates/aim/scripts/multi_agent/__init__.py +5 -0
  98. package/dist/templates/aim/scripts/multi_agent/cleanup.py +403 -0
  99. package/dist/templates/aim/scripts/multi_agent/create_pr.py +329 -0
  100. package/dist/templates/aim/scripts/multi_agent/plan.py +233 -0
  101. package/dist/templates/aim/scripts/multi_agent/start.py +461 -0
  102. package/dist/templates/aim/scripts/multi_agent/status.py +817 -0
  103. package/dist/templates/aim/scripts/task.py +1068 -0
  104. package/dist/templates/aim/scripts-shell-archive/add-session.sh +384 -0
  105. package/dist/templates/aim/scripts-shell-archive/common/developer.sh +129 -0
  106. package/dist/templates/aim/scripts-shell-archive/common/git-context.sh +263 -0
  107. package/dist/templates/aim/scripts-shell-archive/common/paths.sh +208 -0
  108. package/dist/templates/aim/scripts-shell-archive/common/phase.sh +150 -0
  109. package/dist/templates/aim/scripts-shell-archive/common/registry.sh +247 -0
  110. package/dist/templates/aim/scripts-shell-archive/common/task-queue.sh +142 -0
  111. package/dist/templates/aim/scripts-shell-archive/common/task-utils.sh +151 -0
  112. package/dist/templates/aim/scripts-shell-archive/common/worktree.sh +128 -0
  113. package/dist/templates/aim/scripts-shell-archive/create-bootstrap.sh +299 -0
  114. package/dist/templates/aim/scripts-shell-archive/get-context.sh +7 -0
  115. package/dist/templates/aim/scripts-shell-archive/get-developer.sh +15 -0
  116. package/dist/templates/aim/scripts-shell-archive/init-developer.sh +34 -0
  117. package/dist/templates/aim/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
  118. package/dist/templates/aim/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
  119. package/dist/templates/aim/scripts-shell-archive/multi-agent/plan.sh +207 -0
  120. package/dist/templates/aim/scripts-shell-archive/multi-agent/start.sh +317 -0
  121. package/dist/templates/aim/scripts-shell-archive/multi-agent/status.sh +828 -0
  122. package/dist/templates/aim/scripts-shell-archive/task.sh +1204 -0
  123. package/dist/templates/aim/tasks/.gitkeep +0 -0
  124. package/dist/templates/aim/workflow.md +258 -0
  125. package/dist/templates/aim/worktree.yaml +47 -0
  126. package/dist/templates/claude/agents/check.md +122 -0
  127. package/dist/templates/claude/agents/debug.md +106 -0
  128. package/dist/templates/claude/agents/dispatch.md +230 -0
  129. package/dist/templates/claude/agents/implement.md +96 -0
  130. package/dist/templates/claude/agents/plan.md +396 -0
  131. package/dist/templates/claude/agents/research.md +120 -0
  132. package/dist/templates/claude/agents/story.md +53 -0
  133. package/dist/templates/claude/commands/aim/before-backend-dev.md +13 -0
  134. package/dist/templates/claude/commands/aim/before-frontend-dev.md +13 -0
  135. package/dist/templates/claude/commands/aim/break-loop.md +153 -0
  136. package/dist/templates/claude/commands/aim/check-backend.md +13 -0
  137. package/dist/templates/claude/commands/aim/check-cross-layer.md +153 -0
  138. package/dist/templates/claude/commands/aim/check-frontend.md +13 -0
  139. package/dist/templates/claude/commands/aim/check-story.md +59 -0
  140. package/dist/templates/claude/commands/aim/create-command.md +154 -0
  141. package/dist/templates/claude/commands/aim/export.md +187 -0
  142. package/dist/templates/claude/commands/aim/finish-work.md +104 -0
  143. package/dist/templates/claude/commands/aim/integrate-skill.md +219 -0
  144. package/dist/templates/claude/commands/aim/onboard.md +358 -0
  145. package/dist/templates/claude/commands/aim/parallel.md +217 -0
  146. package/dist/templates/claude/commands/aim/portrait.md +170 -0
  147. package/dist/templates/claude/commands/aim/record-session.md +92 -0
  148. package/dist/templates/claude/commands/aim/start.md +112 -0
  149. package/dist/templates/claude/commands/aim/story.md +140 -0
  150. package/dist/templates/claude/commands/aim/update-spec.md +285 -0
  151. package/dist/templates/claude/commands/aim/visualize.md +182 -0
  152. package/dist/templates/claude/commands/trellis/before-backend-dev.md +13 -0
  153. package/dist/templates/claude/commands/trellis/before-frontend-dev.md +13 -0
  154. package/dist/templates/claude/commands/trellis/break-loop.md +125 -0
  155. package/dist/templates/claude/commands/trellis/check-backend.md +13 -0
  156. package/dist/templates/claude/commands/trellis/check-cross-layer.md +153 -0
  157. package/dist/templates/claude/commands/trellis/check-frontend.md +13 -0
  158. package/dist/templates/claude/commands/trellis/create-command.md +154 -0
  159. package/dist/templates/claude/commands/trellis/finish-work.md +129 -0
  160. package/dist/templates/claude/commands/trellis/integrate-skill.md +219 -0
  161. package/dist/templates/claude/commands/trellis/onboard.md +358 -0
  162. package/dist/templates/claude/commands/trellis/parallel.md +193 -0
  163. package/dist/templates/claude/commands/trellis/record-session.md +62 -0
  164. package/dist/templates/claude/commands/trellis/start.md +280 -0
  165. package/dist/templates/claude/commands/trellis/update-spec.md +285 -0
  166. package/dist/templates/claude/hooks/inject-subagent-context.py +772 -0
  167. package/dist/templates/claude/hooks/ralph-loop.py +388 -0
  168. package/dist/templates/claude/hooks/session-start.py +142 -0
  169. package/dist/templates/claude/index.d.ts +54 -0
  170. package/dist/templates/claude/index.d.ts.map +1 -0
  171. package/dist/templates/claude/index.js +85 -0
  172. package/dist/templates/claude/index.js.map +1 -0
  173. package/dist/templates/claude/settings.json +41 -0
  174. package/dist/templates/extract.d.ts +68 -0
  175. package/dist/templates/extract.d.ts.map +1 -0
  176. package/dist/templates/extract.js +128 -0
  177. package/dist/templates/extract.js.map +1 -0
  178. package/dist/templates/markdown/agents.md +25 -0
  179. package/dist/templates/markdown/gitignore.txt +12 -0
  180. package/dist/templates/markdown/index.d.ts +32 -0
  181. package/dist/templates/markdown/index.d.ts.map +1 -0
  182. package/dist/templates/markdown/index.js +58 -0
  183. package/dist/templates/markdown/index.js.map +1 -0
  184. package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
  185. package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
  186. package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
  187. package/dist/templates/markdown/spec/backend/index.md +40 -0
  188. package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
  189. package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
  190. package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
  191. package/dist/templates/markdown/spec/backend/script-conventions.md +467 -0
  192. package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
  193. package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
  194. package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
  195. package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
  196. package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
  197. package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
  198. package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
  199. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md +118 -0
  200. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +92 -0
  201. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +94 -0
  202. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md +394 -0
  203. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +319 -0
  204. package/dist/templates/markdown/spec/guides/index.md.txt +89 -0
  205. package/dist/templates/markdown/spec/story/character.md.txt +95 -0
  206. package/dist/templates/markdown/spec/story/index.md.txt +31 -0
  207. package/dist/templates/markdown/spec/story/script.md.txt +313 -0
  208. package/dist/templates/markdown/spec/story/world.md.txt +92 -0
  209. package/dist/templates/markdown/workspace-index.md +123 -0
  210. package/dist/templates/markdown/worktree.yaml.txt +58 -0
  211. package/dist/templates/trellis/gitignore.txt +29 -0
  212. package/dist/templates/trellis/index.d.ts +49 -0
  213. package/dist/templates/trellis/index.d.ts.map +1 -0
  214. package/dist/templates/trellis/index.js +92 -0
  215. package/dist/templates/trellis/index.js.map +1 -0
  216. package/dist/templates/trellis/scripts/__init__.py +5 -0
  217. package/dist/templates/trellis/scripts/add_session.py +392 -0
  218. package/dist/templates/trellis/scripts/common/__init__.py +80 -0
  219. package/dist/templates/trellis/scripts/common/cli_adapter.py +435 -0
  220. package/dist/templates/trellis/scripts/common/developer.py +190 -0
  221. package/dist/templates/trellis/scripts/common/git_context.py +383 -0
  222. package/dist/templates/trellis/scripts/common/paths.py +347 -0
  223. package/dist/templates/trellis/scripts/common/phase.py +253 -0
  224. package/dist/templates/trellis/scripts/common/registry.py +366 -0
  225. package/dist/templates/trellis/scripts/common/task_queue.py +255 -0
  226. package/dist/templates/trellis/scripts/common/task_utils.py +178 -0
  227. package/dist/templates/trellis/scripts/common/worktree.py +219 -0
  228. package/dist/templates/trellis/scripts/create_bootstrap.py +290 -0
  229. package/dist/templates/trellis/scripts/get_context.py +16 -0
  230. package/dist/templates/trellis/scripts/get_developer.py +26 -0
  231. package/dist/templates/trellis/scripts/init_developer.py +51 -0
  232. package/dist/templates/trellis/scripts/multi_agent/__init__.py +5 -0
  233. package/dist/templates/trellis/scripts/multi_agent/cleanup.py +403 -0
  234. package/dist/templates/trellis/scripts/multi_agent/create_pr.py +329 -0
  235. package/dist/templates/trellis/scripts/multi_agent/plan.py +233 -0
  236. package/dist/templates/trellis/scripts/multi_agent/start.py +461 -0
  237. package/dist/templates/trellis/scripts/multi_agent/status.py +817 -0
  238. package/dist/templates/trellis/scripts/task.py +1056 -0
  239. package/dist/templates/trellis/scripts-shell-archive/add-session.sh +384 -0
  240. package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +129 -0
  241. package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +263 -0
  242. package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +208 -0
  243. package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +150 -0
  244. package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +247 -0
  245. package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +142 -0
  246. package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +151 -0
  247. package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +128 -0
  248. package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +299 -0
  249. package/dist/templates/trellis/scripts-shell-archive/get-context.sh +7 -0
  250. package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +15 -0
  251. package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +34 -0
  252. package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
  253. package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
  254. package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +207 -0
  255. package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +317 -0
  256. package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +828 -0
  257. package/dist/templates/trellis/scripts-shell-archive/task.sh +1204 -0
  258. package/dist/templates/trellis/tasks/.gitkeep +0 -0
  259. package/dist/templates/trellis/workflow.md +416 -0
  260. package/dist/templates/trellis/worktree.yaml +47 -0
  261. package/dist/types/ai-tools.d.ts +48 -0
  262. package/dist/types/ai-tools.d.ts.map +1 -0
  263. package/dist/types/ai-tools.js +32 -0
  264. package/dist/types/ai-tools.js.map +1 -0
  265. package/dist/types/migration.d.ts +86 -0
  266. package/dist/types/migration.d.ts.map +1 -0
  267. package/dist/types/migration.js +8 -0
  268. package/dist/types/migration.js.map +1 -0
  269. package/dist/utils/compare-versions.d.ts +12 -0
  270. package/dist/utils/compare-versions.d.ts.map +1 -0
  271. package/dist/utils/compare-versions.js +76 -0
  272. package/dist/utils/compare-versions.js.map +1 -0
  273. package/dist/utils/file-writer.d.ts +23 -0
  274. package/dist/utils/file-writer.d.ts.map +1 -0
  275. package/dist/utils/file-writer.js +140 -0
  276. package/dist/utils/file-writer.js.map +1 -0
  277. package/dist/utils/project-detector.d.ts +16 -0
  278. package/dist/utils/project-detector.d.ts.map +1 -0
  279. package/dist/utils/project-detector.js +188 -0
  280. package/dist/utils/project-detector.js.map +1 -0
  281. package/dist/utils/template-fetcher.d.ts +51 -0
  282. package/dist/utils/template-fetcher.d.ts.map +1 -0
  283. package/dist/utils/template-fetcher.js +174 -0
  284. package/dist/utils/template-fetcher.js.map +1 -0
  285. package/dist/utils/template-hash.d.ts +78 -0
  286. package/dist/utils/template-hash.d.ts.map +1 -0
  287. package/dist/utils/template-hash.js +239 -0
  288. package/dist/utils/template-hash.js.map +1 -0
  289. package/package.json +87 -0
@@ -0,0 +1,388 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Ralph Loop - SubagentStop Hook for Check Agent Loop Control
5
+
6
+ Based on the Ralph Wiggum technique for autonomous agent loops.
7
+ Uses completion promises to control when the check agent can stop.
8
+
9
+ Mechanism:
10
+ - Intercepts when check subagent tries to stop (SubagentStop event)
11
+ - If verify commands configured in worktree.yaml, runs them to verify
12
+ - Otherwise, reads check.jsonl to get dynamic completion markers ({reason}_FINISH)
13
+ - Blocks stopping until verification passes or all markers found
14
+ - Has max iterations as safety limit
15
+
16
+ State file: .aim-studio/.ralph-state.json
17
+ - Tracks current iteration count per session
18
+ - Resets when task changes
19
+ """
20
+
21
+ # IMPORTANT: Suppress all warnings FIRST
22
+ import warnings
23
+ warnings.filterwarnings("ignore")
24
+
25
+ import json
26
+ import os
27
+ import subprocess
28
+ import sys
29
+ from datetime import datetime
30
+ from pathlib import Path
31
+
32
+ # IMPORTANT: Force stdout to use UTF-8 on Windows
33
+ # This fixes UnicodeEncodeError when outputting non-ASCII characters
34
+ if sys.platform == "win32":
35
+ import io as _io
36
+ if hasattr(sys.stdout, "reconfigure"):
37
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
38
+ elif hasattr(sys.stdout, "detach"):
39
+ sys.stdout = _io.TextIOWrapper(sys.stdout.detach(), encoding="utf-8", errors="replace") # type: ignore[union-attr]
40
+
41
+ # =============================================================================
42
+ # Configuration
43
+ # =============================================================================
44
+
45
+ MAX_ITERATIONS = 5 # Safety limit to prevent infinite loops
46
+ STATE_TIMEOUT_MINUTES = 30 # Reset state if older than this
47
+ STATE_FILE = ".aim-studio/.ralph-state.json"
48
+ WORKTREE_YAML = ".aim-studio/worktree.yaml"
49
+ DIR_WORKFLOW = ".aim-studio"
50
+ FILE_CURRENT_TASK = ".current-task"
51
+
52
+ # Only control loop for check agent
53
+ TARGET_AGENT = "check"
54
+
55
+
56
+ def find_repo_root(start_path: str) -> str | None:
57
+ """Find git repo root from start_path upwards"""
58
+ current = Path(start_path).resolve()
59
+ while current != current.parent:
60
+ if (current / ".git").exists():
61
+ return str(current)
62
+ current = current.parent
63
+ return None
64
+
65
+
66
+ def get_current_task(repo_root: str) -> str | None:
67
+ """Read current task directory path"""
68
+ current_task_file = os.path.join(repo_root, DIR_WORKFLOW, FILE_CURRENT_TASK)
69
+ if not os.path.exists(current_task_file):
70
+ return None
71
+
72
+ try:
73
+ with open(current_task_file, "r", encoding="utf-8") as f:
74
+ content = f.read().strip()
75
+ return content if content else None
76
+ except Exception:
77
+ return None
78
+
79
+
80
+ def get_verify_commands(repo_root: str) -> list[str]:
81
+ """
82
+ Read verify commands from worktree.yaml.
83
+
84
+ Returns list of commands to run, or empty list if not configured.
85
+ Uses simple YAML parsing without external dependencies.
86
+ """
87
+ yaml_path = os.path.join(repo_root, WORKTREE_YAML)
88
+ if not os.path.exists(yaml_path):
89
+ return []
90
+
91
+ try:
92
+ with open(yaml_path, "r", encoding="utf-8") as f:
93
+ content = f.read()
94
+
95
+ # Simple YAML parsing for verify section
96
+ # Look for "verify:" followed by list items
97
+ lines = content.split("\n")
98
+ in_verify_section = False
99
+ commands = []
100
+
101
+ for line in lines:
102
+ stripped = line.strip()
103
+
104
+ # Check for section start
105
+ if stripped.startswith("verify:"):
106
+ in_verify_section = True
107
+ continue
108
+
109
+ # Check for new section (not indented, ends with :)
110
+ if (
111
+ not line.startswith(" ")
112
+ and not line.startswith("\t")
113
+ and stripped.endswith(":")
114
+ and stripped != ""
115
+ ):
116
+ in_verify_section = False
117
+ continue
118
+
119
+ # If in verify section, look for list items
120
+ if in_verify_section:
121
+ # Skip comments and empty lines
122
+ if stripped.startswith("#") or stripped == "":
123
+ continue
124
+ # Parse list item (- command)
125
+ if stripped.startswith("- "):
126
+ cmd = stripped[2:].strip()
127
+ if cmd:
128
+ commands.append(cmd)
129
+
130
+ return commands
131
+ except Exception:
132
+ return []
133
+
134
+
135
+ def run_verify_commands(repo_root: str, commands: list[str]) -> tuple[bool, str]:
136
+ """
137
+ Run verify commands and return (success, message).
138
+
139
+ All commands must pass for success.
140
+ """
141
+ for cmd in commands:
142
+ try:
143
+ result = subprocess.run(
144
+ cmd,
145
+ shell=True,
146
+ cwd=repo_root,
147
+ capture_output=True,
148
+ timeout=120, # 2 minute timeout per command
149
+ )
150
+ if result.returncode != 0:
151
+ stderr = result.stderr.decode("utf-8", errors="replace")
152
+ stdout = result.stdout.decode("utf-8", errors="replace")
153
+ error_output = stderr or stdout
154
+ # Truncate long output
155
+ if len(error_output) > 500:
156
+ error_output = error_output[:500] + "..."
157
+ return False, f"Command failed: {cmd}\n{error_output}"
158
+ except subprocess.TimeoutExpired:
159
+ return False, f"Command timed out: {cmd}"
160
+ except Exception as e:
161
+ return False, f"Command error: {cmd} - {str(e)}"
162
+
163
+ return True, "All verify commands passed"
164
+
165
+
166
+ def get_completion_markers(repo_root: str, task_dir: str) -> list[str]:
167
+ """
168
+ Read check.jsonl and generate completion markers from reasons.
169
+
170
+ Each entry's "reason" field becomes {REASON}_FINISH marker.
171
+ Example: {"file": "...", "reason": "TypeCheck"} -> "TYPECHECK_FINISH"
172
+ """
173
+ check_jsonl_path = os.path.join(repo_root, task_dir, "check.jsonl")
174
+ markers = []
175
+
176
+ if not os.path.exists(check_jsonl_path):
177
+ # Fallback: if no check.jsonl, use default marker
178
+ return ["ALL_CHECKS_FINISH"]
179
+
180
+ try:
181
+ with open(check_jsonl_path, "r", encoding="utf-8") as f:
182
+ for line in f:
183
+ line = line.strip()
184
+ if not line:
185
+ continue
186
+ try:
187
+ item = json.loads(line)
188
+ reason = item.get("reason", "")
189
+ if reason:
190
+ # Convert to uppercase and add _FINISH suffix
191
+ marker = f"{reason.upper().replace(' ', '_')}_FINISH"
192
+ if marker not in markers:
193
+ markers.append(marker)
194
+ except json.JSONDecodeError:
195
+ continue
196
+ except Exception:
197
+ pass
198
+
199
+ # If no markers found, use default
200
+ if not markers:
201
+ markers = ["ALL_CHECKS_FINISH"]
202
+
203
+ return markers
204
+
205
+
206
+ def load_state(repo_root: str) -> dict:
207
+ """Load Ralph Loop state from file"""
208
+ state_path = os.path.join(repo_root, STATE_FILE)
209
+ if not os.path.exists(state_path):
210
+ return {"task": None, "iteration": 0, "started_at": None}
211
+
212
+ try:
213
+ with open(state_path, "r", encoding="utf-8") as f:
214
+ return json.load(f)
215
+ except Exception:
216
+ return {"task": None, "iteration": 0, "started_at": None}
217
+
218
+
219
+ def save_state(repo_root: str, state: dict) -> None:
220
+ """Save Ralph Loop state to file"""
221
+ state_path = os.path.join(repo_root, STATE_FILE)
222
+ try:
223
+ # Ensure directory exists
224
+ os.makedirs(os.path.dirname(state_path), exist_ok=True)
225
+ with open(state_path, "w", encoding="utf-8") as f:
226
+ json.dump(state, f, indent=2, ensure_ascii=False)
227
+ except Exception:
228
+ pass
229
+
230
+
231
+ def check_completion(agent_output: str, markers: list[str]) -> tuple[bool, list[str]]:
232
+ """
233
+ Check if all completion markers are present in agent output.
234
+
235
+ Returns:
236
+ (all_complete, missing_markers)
237
+ """
238
+ missing = []
239
+ for marker in markers:
240
+ if marker not in agent_output:
241
+ missing.append(marker)
242
+
243
+ return len(missing) == 0, missing
244
+
245
+
246
+ def main():
247
+ try:
248
+ input_data = json.load(sys.stdin)
249
+ except json.JSONDecodeError:
250
+ # If can't parse input, allow stop
251
+ sys.exit(0)
252
+
253
+ # Get event info
254
+ hook_event = input_data.get("hook_event_name", "")
255
+
256
+ # Only handle SubagentStop event
257
+ if hook_event != "SubagentStop":
258
+ sys.exit(0)
259
+
260
+ # Get subagent info
261
+ subagent_type = input_data.get("subagent_type", "")
262
+ agent_output = input_data.get("agent_output", "")
263
+ original_prompt = input_data.get("prompt", "")
264
+ cwd = input_data.get("cwd", os.getcwd())
265
+
266
+ # Only control check agent
267
+ if subagent_type != TARGET_AGENT:
268
+ sys.exit(0)
269
+
270
+ # Skip Ralph Loop for finish phase (already verified in check phase)
271
+ if "[finish]" in original_prompt.lower():
272
+ sys.exit(0)
273
+
274
+ # Find repo root
275
+ repo_root = find_repo_root(cwd)
276
+ if not repo_root:
277
+ sys.exit(0)
278
+
279
+ # Get current task
280
+ task_dir = get_current_task(repo_root)
281
+ if not task_dir:
282
+ sys.exit(0)
283
+
284
+ # Load state
285
+ state = load_state(repo_root)
286
+
287
+ # Reset state if task changed or state is too old
288
+ should_reset = False
289
+ if state.get("task") != task_dir:
290
+ should_reset = True
291
+ elif state.get("started_at"):
292
+ try:
293
+ started = datetime.fromisoformat(state["started_at"])
294
+ if (datetime.now() - started).total_seconds() > STATE_TIMEOUT_MINUTES * 60:
295
+ should_reset = True
296
+ except (ValueError, TypeError):
297
+ should_reset = True
298
+
299
+ if should_reset:
300
+ state = {
301
+ "task": task_dir,
302
+ "iteration": 0,
303
+ "started_at": datetime.now().isoformat(),
304
+ }
305
+
306
+ # Increment iteration
307
+ state["iteration"] = state.get("iteration", 0) + 1
308
+ current_iteration = state["iteration"]
309
+
310
+ # Save state
311
+ save_state(repo_root, state)
312
+
313
+ # Safety check: max iterations
314
+ if current_iteration >= MAX_ITERATIONS:
315
+ # Allow stop, reset state for next run
316
+ state["iteration"] = 0
317
+ save_state(repo_root, state)
318
+ output = {
319
+ "decision": "allow",
320
+ "reason": f"Max iterations ({MAX_ITERATIONS}) reached. Stopping to prevent infinite loop.",
321
+ }
322
+ print(json.dumps(output, ensure_ascii=False))
323
+ sys.exit(0)
324
+
325
+ # Check if verify commands are configured
326
+ verify_commands = get_verify_commands(repo_root)
327
+
328
+ if verify_commands:
329
+ # Use programmatic verification
330
+ passed, message = run_verify_commands(repo_root, verify_commands)
331
+
332
+ if passed:
333
+ # All verify commands passed, allow stop
334
+ state["iteration"] = 0
335
+ save_state(repo_root, state)
336
+ output = {
337
+ "decision": "allow",
338
+ "reason": "All verify commands passed. Check phase complete.",
339
+ }
340
+ print(json.dumps(output, ensure_ascii=False))
341
+ sys.exit(0)
342
+ else:
343
+ # Verification failed, block stop
344
+ output = {
345
+ "decision": "block",
346
+ "reason": f"Iteration {current_iteration}/{MAX_ITERATIONS}. Verification failed:\n{message}\n\nPlease fix the issues and try again.",
347
+ }
348
+ print(json.dumps(output, ensure_ascii=False))
349
+ sys.exit(0)
350
+ else:
351
+ # No verify commands, fall back to completion markers
352
+ markers = get_completion_markers(repo_root, task_dir)
353
+ all_complete, missing = check_completion(agent_output, markers)
354
+
355
+ if all_complete:
356
+ # All checks complete, allow stop
357
+ state["iteration"] = 0
358
+ save_state(repo_root, state)
359
+ output = {
360
+ "decision": "allow",
361
+ "reason": "All completion markers found. Check phase complete.",
362
+ }
363
+ print(json.dumps(output, ensure_ascii=False))
364
+ sys.exit(0)
365
+ else:
366
+ # Missing markers, block stop and continue
367
+ output = {
368
+ "decision": "block",
369
+ "reason": f"""Iteration {current_iteration}/{MAX_ITERATIONS}. Missing completion markers: {", ".join(missing)}.
370
+
371
+ IMPORTANT: You must ACTUALLY run the checks, not just output the markers.
372
+ - Did you run lint? What was the output?
373
+ - Did you run typecheck? What was the output?
374
+ - Did they actually pass with zero errors?
375
+
376
+ Only output a marker (e.g., LINT_FINISH) AFTER:
377
+ 1. You have executed the corresponding command
378
+ 2. The command completed with zero errors
379
+ 3. You have shown the command output in your response
380
+
381
+ Do NOT output markers just to escape the loop. The loop exists to ensure quality.""",
382
+ }
383
+ print(json.dumps(output, ensure_ascii=False))
384
+ sys.exit(0)
385
+
386
+
387
+ if __name__ == "__main__":
388
+ main()
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Session Start Hook - Inject structured context
5
+ """
6
+
7
+ # IMPORTANT: Suppress all warnings FIRST
8
+ import warnings
9
+ warnings.filterwarnings("ignore")
10
+
11
+ import json
12
+ import os
13
+ import subprocess
14
+ import sys
15
+ from io import StringIO
16
+ from pathlib import Path
17
+
18
+ # IMPORTANT: Force stdout to use UTF-8 on Windows
19
+ # This fixes UnicodeEncodeError when outputting non-ASCII characters
20
+ if sys.platform == "win32":
21
+ import io as _io
22
+ if hasattr(sys.stdout, "reconfigure"):
23
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
24
+ elif hasattr(sys.stdout, "detach"):
25
+ sys.stdout = _io.TextIOWrapper(sys.stdout.detach(), encoding="utf-8", errors="replace") # type: ignore[union-attr]
26
+
27
+
28
+ def should_skip_injection() -> bool:
29
+ return (
30
+ os.environ.get("CLAUDE_NON_INTERACTIVE") == "1"
31
+ or os.environ.get("OPENCODE_NON_INTERACTIVE") == "1"
32
+ )
33
+
34
+
35
+ def read_file(path: Path, fallback: str = "") -> str:
36
+ try:
37
+ return path.read_text(encoding="utf-8")
38
+ except (FileNotFoundError, PermissionError):
39
+ return fallback
40
+
41
+
42
+ def run_script(script_path: Path) -> str:
43
+ try:
44
+ if script_path.suffix == ".py":
45
+ # Add PYTHONIOENCODING to force UTF-8 in subprocess
46
+ env = os.environ.copy()
47
+ env["PYTHONIOENCODING"] = "utf-8"
48
+ cmd = [sys.executable, "-W", "ignore", str(script_path)]
49
+ else:
50
+ env = os.environ
51
+ cmd = [str(script_path)]
52
+
53
+ result = subprocess.run(
54
+ cmd,
55
+ capture_output=True,
56
+ text=True,
57
+ encoding="utf-8",
58
+ errors="replace",
59
+ timeout=5,
60
+ cwd=script_path.parent.parent.parent,
61
+ env=env,
62
+ )
63
+ return result.stdout if result.returncode == 0 else "No context available"
64
+ except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError):
65
+ return "No context available"
66
+
67
+
68
+ def main():
69
+ if should_skip_injection():
70
+ sys.exit(0)
71
+
72
+ project_dir = Path(os.environ.get("CLAUDE_PROJECT_DIR", ".")).resolve()
73
+ trellis_dir = project_dir / ".aim-studio"
74
+ claude_dir = project_dir / ".claude"
75
+
76
+ output = StringIO()
77
+
78
+ output.write("""<session-context>
79
+ You are starting a new session in a Trellis-managed project.
80
+ Read and follow all instructions below carefully.
81
+ </session-context>
82
+
83
+ """)
84
+
85
+ output.write("<current-state>\n")
86
+ context_script = trellis_dir / "scripts" / "get_context.py"
87
+ output.write(run_script(context_script))
88
+ output.write("\n</current-state>\n\n")
89
+
90
+ output.write("<workflow>\n")
91
+ workflow_content = read_file(trellis_dir / "workflow.md", "No workflow.md found")
92
+ output.write(workflow_content)
93
+ output.write("\n</workflow>\n\n")
94
+
95
+ output.write("<guidelines>\n")
96
+
97
+ output.write("## Frontend\n")
98
+ frontend_index = read_file(
99
+ trellis_dir / "spec" / "frontend" / "index.md", "Not configured"
100
+ )
101
+ output.write(frontend_index)
102
+ output.write("\n\n")
103
+
104
+ output.write("## Backend\n")
105
+ backend_index = read_file(
106
+ trellis_dir / "spec" / "backend" / "index.md", "Not configured"
107
+ )
108
+ output.write(backend_index)
109
+ output.write("\n\n")
110
+
111
+ output.write("## Guides\n")
112
+ guides_index = read_file(
113
+ trellis_dir / "spec" / "guides" / "index.md", "Not configured"
114
+ )
115
+ output.write(guides_index)
116
+
117
+ output.write("\n</guidelines>\n\n")
118
+
119
+ output.write("<instructions>\n")
120
+ start_md = read_file(
121
+ claude_dir / "commands" / "trellis" / "start.md", "No start.md found"
122
+ )
123
+ output.write(start_md)
124
+ output.write("\n</instructions>\n\n")
125
+
126
+ output.write("""<ready>
127
+ Context loaded. Wait for user's first message, then follow <instructions> to handle their request.
128
+ </ready>""")
129
+
130
+ result = {
131
+ "hookSpecificOutput": {
132
+ "hookEventName": "SessionStart",
133
+ "additionalContext": output.getvalue(),
134
+ }
135
+ }
136
+
137
+ # Output JSON - stdout is already configured for UTF-8
138
+ print(json.dumps(result, ensure_ascii=False), flush=True)
139
+
140
+
141
+ if __name__ == "__main__":
142
+ main()
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Claude Code templates
3
+ *
4
+ * These are GENERIC templates for user projects.
5
+ * Do NOT use Trellis project's own .claude/ directory (which may be customized).
6
+ *
7
+ * Directory structure:
8
+ * claude/
9
+ * ├── commands/ # Slash commands
10
+ * ├── agents/ # Multi-agent pipeline agents
11
+ * ├── hooks/ # Context injection hooks
12
+ * └── settings.json # Settings configuration
13
+ */
14
+ export declare const settingsTemplate: string;
15
+ /**
16
+ * Command template with name and content
17
+ */
18
+ export interface CommandTemplate {
19
+ name: string;
20
+ content: string;
21
+ }
22
+ /**
23
+ * Agent template with name and content
24
+ */
25
+ export interface AgentTemplate {
26
+ name: string;
27
+ content: string;
28
+ }
29
+ /**
30
+ * Hook template with target path and content
31
+ */
32
+ export interface HookTemplate {
33
+ targetPath: string;
34
+ content: string;
35
+ }
36
+ /**
37
+ * Get all command templates
38
+ * Commands are stored in commands/aim/ subdirectory
39
+ * This creates commands like /aim:start, /aim:finish-work, etc.
40
+ */
41
+ export declare function getAllCommands(): CommandTemplate[];
42
+ /**
43
+ * Get all agent templates
44
+ */
45
+ export declare function getAllAgents(): AgentTemplate[];
46
+ /**
47
+ * Get all hook templates
48
+ */
49
+ export declare function getAllHooks(): HookTemplate[];
50
+ /**
51
+ * Get settings template
52
+ */
53
+ export declare function getSettingsTemplate(): HookTemplate;
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/claude/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAsBH,eAAO,MAAM,gBAAgB,QAAgC,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,eAAe,EAAE,CAalD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAa9C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,YAAY,EAAE,CAU5C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,CAKlD"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Claude Code templates
3
+ *
4
+ * These are GENERIC templates for user projects.
5
+ * Do NOT use Trellis project's own .claude/ directory (which may be customized).
6
+ *
7
+ * Directory structure:
8
+ * claude/
9
+ * ├── commands/ # Slash commands
10
+ * ├── agents/ # Multi-agent pipeline agents
11
+ * ├── hooks/ # Context injection hooks
12
+ * └── settings.json # Settings configuration
13
+ */
14
+ import { readdirSync, readFileSync } from "node:fs";
15
+ import { dirname, join } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = dirname(__filename);
19
+ function readTemplate(relativePath) {
20
+ return readFileSync(join(__dirname, relativePath), "utf-8");
21
+ }
22
+ function listFiles(dir) {
23
+ try {
24
+ return readdirSync(join(__dirname, dir));
25
+ }
26
+ catch {
27
+ return [];
28
+ }
29
+ }
30
+ // Settings
31
+ export const settingsTemplate = readTemplate("settings.json");
32
+ /**
33
+ * Get all command templates
34
+ * Commands are stored in commands/aim/ subdirectory
35
+ * This creates commands like /aim:start, /aim:finish-work, etc.
36
+ */
37
+ export function getAllCommands() {
38
+ const commands = [];
39
+ const files = listFiles("commands/aim");
40
+ for (const file of files) {
41
+ if (file.endsWith(".md")) {
42
+ const name = file.replace(".md", "");
43
+ const content = readTemplate(`commands/aim/${file}`);
44
+ commands.push({ name, content });
45
+ }
46
+ }
47
+ return commands;
48
+ }
49
+ /**
50
+ * Get all agent templates
51
+ */
52
+ export function getAllAgents() {
53
+ const agents = [];
54
+ const files = listFiles("agents");
55
+ for (const file of files) {
56
+ if (file.endsWith(".md")) {
57
+ const name = file.replace(".md", "");
58
+ const content = readTemplate(`agents/${file}`);
59
+ agents.push({ name, content });
60
+ }
61
+ }
62
+ return agents;
63
+ }
64
+ /**
65
+ * Get all hook templates
66
+ */
67
+ export function getAllHooks() {
68
+ const hooks = [];
69
+ const files = listFiles("hooks");
70
+ for (const file of files) {
71
+ const content = readTemplate(`hooks/${file}`);
72
+ hooks.push({ targetPath: `hooks/${file}`, content });
73
+ }
74
+ return hooks;
75
+ }
76
+ /**
77
+ * Get settings template
78
+ */
79
+ export function getSettingsTemplate() {
80
+ return {
81
+ targetPath: "settings.json",
82
+ content: settingsTemplate,
83
+ };
84
+ }
85
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/claude/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,WAAW;AACX,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AA0B9D;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC;IAExC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,YAAY,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;YACrD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAmB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,UAAU,EAAE,eAAe;QAC3B,OAAO,EAAE,gBAAgB;KAC1B,CAAC;AACJ,CAAC"}