claudecode-omc 5.6.7 → 5.9.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 (242) hide show
  1. package/.local/skills/THIRD_PARTY_LICENSES/AvdLee-SwiftUI-Agent-Skill.LICENSE +21 -0
  2. package/.local/skills/THIRD_PARTY_LICENSES/Dimillian-Skills.LICENSE +21 -0
  3. package/.local/skills/THIRD_PARTY_LICENSES/README.md +36 -0
  4. package/.local/skills/THIRD_PARTY_LICENSES/twostraws-swiftui-agent-skill.LICENSE +21 -0
  5. package/.local/skills/ios-debugger-agent/SKILL.md +51 -0
  6. package/.local/skills/ios-debugger-agent/agents/openai.yaml +4 -0
  7. package/.local/skills/prompt-optimizer/SKILL.md +262 -19
  8. package/.local/skills/swift-concurrency-expert/SKILL.md +105 -0
  9. package/.local/skills/swift-concurrency-expert/agents/openai.yaml +4 -0
  10. package/.local/skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
  11. package/.local/skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
  12. package/.local/skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
  13. package/.local/skills/swiftui-expert-skill/SKILL.md +162 -0
  14. package/.local/skills/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
  15. package/.local/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
  16. package/.local/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  17. package/.local/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  18. package/.local/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
  19. package/.local/skills/swiftui-expert-skill/references/charts.md +602 -0
  20. package/.local/skills/swiftui-expert-skill/references/focus-patterns.md +299 -0
  21. package/.local/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
  22. package/.local/skills/swiftui-expert-skill/references/latest-apis.md +488 -0
  23. package/.local/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
  24. package/.local/skills/swiftui-expert-skill/references/liquid-glass.md +423 -0
  25. package/.local/skills/swiftui-expert-skill/references/list-patterns.md +446 -0
  26. package/.local/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
  27. package/.local/skills/swiftui-expert-skill/references/macos-views.md +357 -0
  28. package/.local/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
  29. package/.local/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
  30. package/.local/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
  31. package/.local/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
  32. package/.local/skills/swiftui-expert-skill/references/state-management.md +388 -0
  33. package/.local/skills/swiftui-expert-skill/references/text-patterns.md +32 -0
  34. package/.local/skills/swiftui-expert-skill/references/trace-analysis.md +295 -0
  35. package/.local/skills/swiftui-expert-skill/references/trace-recording.md +134 -0
  36. package/.local/skills/swiftui-expert-skill/references/view-structure.md +780 -0
  37. package/.local/skills/swiftui-expert-skill/scripts/__pycache__/analyze_trace.cpython-313.pyc +0 -0
  38. package/.local/skills/swiftui-expert-skill/scripts/__pycache__/record_trace.cpython-313.pyc +0 -0
  39. package/.local/skills/swiftui-expert-skill/scripts/analyze_trace.py +301 -0
  40. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__init__.py +1 -0
  41. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/__init__.cpython-313.pyc +0 -0
  42. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/causes.cpython-313.pyc +0 -0
  43. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/correlate.cpython-313.pyc +0 -0
  44. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/events.cpython-313.pyc +0 -0
  45. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hangs.cpython-313.pyc +0 -0
  46. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hitches.cpython-313.pyc +0 -0
  47. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/summary.cpython-313.pyc +0 -0
  48. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/swiftui.cpython-313.pyc +0 -0
  49. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/time_profiler.cpython-313.pyc +0 -0
  50. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xctrace.cpython-313.pyc +0 -0
  51. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xml_utils.cpython-313.pyc +0 -0
  52. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/causes.py +187 -0
  53. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/correlate.py +179 -0
  54. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/events.py +291 -0
  55. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hangs.py +108 -0
  56. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hitches.py +145 -0
  57. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/summary.py +243 -0
  58. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/swiftui.py +195 -0
  59. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/time_profiler.py +135 -0
  60. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +117 -0
  61. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +224 -0
  62. package/.local/skills/swiftui-expert-skill/scripts/record_trace.py +252 -0
  63. package/.local/skills/swiftui-liquid-glass/SKILL.md +90 -0
  64. package/.local/skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
  65. package/.local/skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
  66. package/.local/skills/swiftui-performance-audit/SKILL.md +106 -0
  67. package/.local/skills/swiftui-performance-audit/agents/openai.yaml +4 -0
  68. package/.local/skills/swiftui-performance-audit/references/code-smells.md +150 -0
  69. package/.local/skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
  70. package/.local/skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
  71. package/.local/skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
  72. package/.local/skills/swiftui-performance-audit/references/report-template.md +47 -0
  73. package/.local/skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
  74. package/.local/skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
  75. package/.local/skills/swiftui-pro/SKILL.md +108 -0
  76. package/.local/skills/swiftui-pro/agents/openai.yaml +10 -0
  77. package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
  78. package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
  79. package/.local/skills/swiftui-pro/references/accessibility.md +13 -0
  80. package/.local/skills/swiftui-pro/references/api.md +39 -0
  81. package/.local/skills/swiftui-pro/references/data.md +43 -0
  82. package/.local/skills/swiftui-pro/references/design.md +32 -0
  83. package/.local/skills/swiftui-pro/references/hygiene.md +9 -0
  84. package/.local/skills/swiftui-pro/references/navigation.md +14 -0
  85. package/.local/skills/swiftui-pro/references/performance.md +46 -0
  86. package/.local/skills/swiftui-pro/references/swift.md +56 -0
  87. package/.local/skills/swiftui-pro/references/views.md +36 -0
  88. package/.local/skills/swiftui-ui-patterns/SKILL.md +95 -0
  89. package/.local/skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
  90. package/.local/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
  91. package/.local/skills/swiftui-ui-patterns/references/async-state.md +96 -0
  92. package/.local/skills/swiftui-ui-patterns/references/components-index.md +50 -0
  93. package/.local/skills/swiftui-ui-patterns/references/controls.md +57 -0
  94. package/.local/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
  95. package/.local/skills/swiftui-ui-patterns/references/focus.md +90 -0
  96. package/.local/skills/swiftui-ui-patterns/references/form.md +97 -0
  97. package/.local/skills/swiftui-ui-patterns/references/grids.md +71 -0
  98. package/.local/skills/swiftui-ui-patterns/references/haptics.md +71 -0
  99. package/.local/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  100. package/.local/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  101. package/.local/skills/swiftui-ui-patterns/references/list.md +86 -0
  102. package/.local/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  103. package/.local/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
  104. package/.local/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  105. package/.local/skills/swiftui-ui-patterns/references/media.md +73 -0
  106. package/.local/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
  107. package/.local/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
  108. package/.local/skills/swiftui-ui-patterns/references/overlay.md +45 -0
  109. package/.local/skills/swiftui-ui-patterns/references/performance.md +62 -0
  110. package/.local/skills/swiftui-ui-patterns/references/previews.md +48 -0
  111. package/.local/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  112. package/.local/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
  113. package/.local/skills/swiftui-ui-patterns/references/searchable.md +71 -0
  114. package/.local/skills/swiftui-ui-patterns/references/sheets.md +155 -0
  115. package/.local/skills/swiftui-ui-patterns/references/split-views.md +72 -0
  116. package/.local/skills/swiftui-ui-patterns/references/tabview.md +114 -0
  117. package/.local/skills/swiftui-ui-patterns/references/theming.md +71 -0
  118. package/.local/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
  119. package/.local/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
  120. package/.local/skills/swiftui-view-refactor/SKILL.md +202 -0
  121. package/.local/skills/swiftui-view-refactor/agents/openai.yaml +4 -0
  122. package/.local/skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
  123. package/.omc-curation/ecc-selection.json +80 -0
  124. package/.omc-curation/governance.json +113 -0
  125. package/.omc-curation/sources.lock.json +25 -0
  126. package/README.md +69 -4
  127. package/bundled/manifest.json +5 -5
  128. package/bundled/upstream/anthropic-skills/.omc-source/bundle.json +18 -0
  129. package/bundled/upstream/anthropic-skills/.omc-source/provenance.json +399 -0
  130. package/bundled/upstream/anthropic-skills/skills/claude-api/SKILL.md +18 -17
  131. package/bundled/upstream/anthropic-skills/skills/claude-api/curl/examples.md +9 -9
  132. package/bundled/upstream/anthropic-skills/skills/claude-api/curl/managed-agents.md +4 -4
  133. package/bundled/upstream/anthropic-skills/skills/claude-api/go/managed-agents/README.md +2 -2
  134. package/bundled/upstream/anthropic-skills/skills/claude-api/java/claude-api.md +2 -2
  135. package/bundled/upstream/anthropic-skills/skills/claude-api/java/managed-agents/README.md +2 -2
  136. package/bundled/upstream/anthropic-skills/skills/claude-api/php/claude-api.md +10 -10
  137. package/bundled/upstream/anthropic-skills/skills/claude-api/php/managed-agents/README.md +2 -2
  138. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/README.md +16 -16
  139. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/batches.md +3 -3
  140. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/files-api.md +3 -3
  141. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/streaming.md +7 -7
  142. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/tool-use.md +19 -19
  143. package/bundled/upstream/anthropic-skills/skills/claude-api/python/managed-agents/README.md +3 -3
  144. package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/claude-api.md +4 -4
  145. package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/managed-agents/README.md +2 -2
  146. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/error-codes.md +5 -5
  147. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/live-sources.md +3 -1
  148. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-api-reference.md +10 -4
  149. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-core.md +19 -1
  150. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-environments.md +6 -2
  151. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-multiagent.md +1 -1
  152. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-onboarding.md +3 -3
  153. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-overview.md +3 -2
  154. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +173 -0
  155. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-tools.md +10 -4
  156. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/model-migration.md +113 -13
  157. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/models.md +14 -11
  158. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/prompt-caching.md +2 -2
  159. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/tool-use-concepts.md +4 -4
  160. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/README.md +15 -15
  161. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/batches.md +2 -2
  162. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/files-api.md +1 -1
  163. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/streaming.md +5 -5
  164. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/tool-use.md +15 -15
  165. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/managed-agents/README.md +3 -3
  166. package/bundled/upstream/ecc/.omc-source/bundle.json +2 -1
  167. package/bundled/upstream/ecc/.omc-source/last-plan-apply.json +108 -24
  168. package/bundled/upstream/ecc/.omc-source/manifests/.claude-plugin/marketplace.json +3 -3
  169. package/bundled/upstream/ecc/.omc-source/provenance.json +563 -0
  170. package/bundled/upstream/ecc/agents/marketing-agent.md +159 -0
  171. package/bundled/upstream/ecc/agents/react-build-resolver.md +215 -0
  172. package/bundled/upstream/ecc/agents/react-reviewer.md +167 -0
  173. package/bundled/upstream/ecc/agents/typescript-reviewer.md +3 -0
  174. package/bundled/upstream/ecc/commands/harness-audit.md +17 -10
  175. package/bundled/upstream/ecc/commands/marketing-campaign.md +129 -0
  176. package/bundled/upstream/ecc/commands/react-build.md +187 -0
  177. package/bundled/upstream/ecc/commands/react-review.md +170 -0
  178. package/bundled/upstream/ecc/commands/react-test.md +265 -0
  179. package/bundled/upstream/ecc/skills/benchmark-optimization-loop/SKILL.md +69 -0
  180. package/bundled/upstream/ecc/skills/blender-motion-state-inspection/SKILL.md +164 -0
  181. package/bundled/upstream/ecc/skills/canary-watch/SKILL.md +9 -1
  182. package/bundled/upstream/ecc/skills/continuous-learning-v2/hooks/observe.sh +31 -9
  183. package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/detect-project.sh +38 -4
  184. package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/instinct-cli.py +319 -12
  185. package/bundled/upstream/ecc/skills/data-throughput-accelerator/SKILL.md +72 -0
  186. package/bundled/upstream/ecc/skills/dynamic-workflow-mode/SKILL.md +123 -0
  187. package/bundled/upstream/ecc/skills/frontend-a11y/SKILL.md +446 -0
  188. package/bundled/upstream/ecc/skills/ito-basket-compare/SKILL.md +63 -0
  189. package/bundled/upstream/ecc/skills/ito-data-atlas-agent/SKILL.md +63 -0
  190. package/bundled/upstream/ecc/skills/ito-market-intelligence/SKILL.md +60 -0
  191. package/bundled/upstream/ecc/skills/ito-trade-planner/SKILL.md +67 -0
  192. package/bundled/upstream/ecc/skills/latency-critical-systems/SKILL.md +73 -0
  193. package/bundled/upstream/ecc/skills/marketing-campaign/SKILL.md +113 -0
  194. package/bundled/upstream/ecc/skills/nextjs-turbopack/SKILL.md +13 -0
  195. package/bundled/upstream/ecc/skills/parallel-execution-optimizer/SKILL.md +72 -0
  196. package/bundled/upstream/ecc/skills/prediction-market-oracle-research/SKILL.md +63 -0
  197. package/bundled/upstream/ecc/skills/prediction-market-risk-review/SKILL.md +60 -0
  198. package/bundled/upstream/ecc/skills/react-patterns/SKILL.md +341 -0
  199. package/bundled/upstream/ecc/skills/react-performance/SKILL.md +574 -0
  200. package/bundled/upstream/ecc/skills/react-testing/SKILL.md +423 -0
  201. package/bundled/upstream/ecc/skills/recsys-pipeline-architect/SKILL.md +114 -0
  202. package/bundled/upstream/ecc/skills/recursive-decision-ledger/SKILL.md +79 -0
  203. package/bundled/upstream/ecc/skills/social-publisher/SKILL.md +115 -0
  204. package/bundled/upstream/ecc/skills/team-agent-orchestration/SKILL.md +110 -0
  205. package/bundled/upstream/ecc/skills/uncloud/SKILL.md +343 -0
  206. package/bundled/upstream/ecc/skills/windows-desktop-e2e/SKILL.md +99 -0
  207. package/bundled/upstream/oh-my-claudecode/.omc-source/bundle.json +2 -1
  208. package/bundled/upstream/oh-my-claudecode/.omc-source/provenance.json +116 -0
  209. package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +7 -0
  210. package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +1 -0
  211. package/bundled/upstream/oh-my-claudecode/skills/deep-interview/SKILL.md +39 -5
  212. package/bundled/upstream/oh-my-claudecode/skills/hud/SKILL.md +1 -0
  213. package/bundled/upstream/oh-my-claudecode/skills/local-build-reminder/SKILL.md +78 -0
  214. package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/SKILL.md +1 -1
  215. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/SKILL.md +26 -10
  216. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/01-install-claude-md.md +3 -3
  217. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +6 -4
  218. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +1 -1
  219. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +2 -2
  220. package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +6 -6
  221. package/bundled/upstream/oh-my-claudecode/skills/plan/SKILL.md +44 -32
  222. package/bundled/upstream/oh-my-claudecode/skills/ralph/SKILL.md +45 -21
  223. package/bundled/upstream/oh-my-claudecode/skills/ralplan/SKILL.md +1 -1
  224. package/bundled/upstream/oh-my-claudecode/skills/self-improve/SKILL.md +7 -0
  225. package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/resolve-paths.mjs +39 -15
  226. package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +132 -90
  227. package/bundled/upstream/oh-my-claudecode/skills/ultragoal/SKILL.md +93 -0
  228. package/bundled/upstream/oh-my-claudecode/skills/ultraqa/SKILL.md +28 -13
  229. package/bundled/upstream/oh-my-claudecode/skills/ultrawork/SKILL.md +7 -0
  230. package/bundled/upstream/superpowers/.omc-source/bundle.json +2 -1
  231. package/bundled/upstream/superpowers/.omc-source/provenance.json +63 -0
  232. package/package.json +2 -1
  233. package/src/catalog/source-catalog.js +10 -4
  234. package/src/cli/index.js +4 -0
  235. package/src/cli/plan.js +14 -2
  236. package/src/cli/setup.js +52 -13
  237. package/src/cli/skill.js +1 -1
  238. package/src/cli/source.js +265 -14
  239. package/src/config/sources.js +67 -1
  240. package/src/merge/content-patch.js +84 -0
  241. package/templates/merge-config.json +1 -8
  242. package/bundled/upstream/ecc/skills/strategic-compact/suggest-compact.sh +0 -54
@@ -0,0 +1,265 @@
1
+ ---
2
+ description: Enforce TDD workflow for React. Write React Testing Library tests first (behavior-focused, accessibility-first), then implement components. Detects Vitest or Jest and verifies coverage targets.
3
+ ---
4
+
5
+ # React TDD Command
6
+
7
+ This command enforces test-driven development for React using React Testing Library plus Vitest or Jest, detected at runtime.
8
+
9
+ ## What This Command Does
10
+
11
+ 1. **Define Component Signature**: Scaffold the component, prop type, and exports
12
+ 2. **Write Behavior Tests First**: RTL queries (role-first), `userEvent`, MSW for network — RED
13
+ 3. **Run Tests**: Verify they fail for the right reason
14
+ 4. **Implement Minimal Code**: Just enough to pass — GREEN
15
+ 5. **Refactor**: Improve while keeping tests green
16
+ 6. **Check Coverage**: Hit the targets in [rules/react/testing.md](../rules/react/testing.md)
17
+
18
+ ## When to Use
19
+
20
+ Use `/react-test` when:
21
+
22
+ - Implementing a new React component or custom hook
23
+ - Adding test coverage to an untested component
24
+ - Fixing a bug (write failing test first that reproduces it)
25
+ - Building forms, state machines, or accessibility-critical UI
26
+ - Onboarding to RTL + Vitest/Jest workflow
27
+
28
+ ## TDD Cycle
29
+
30
+ ```
31
+ RED -> Write failing test for the next behavior
32
+ GREEN -> Implement minimal component code to pass
33
+ REFACTOR -> Improve component, tests stay green
34
+ REPEAT -> Next behavior
35
+ ```
36
+
37
+ ## Runner Detection
38
+
39
+ ```bash
40
+ test -f vitest.config.ts -o -f vitest.config.js -o -f vite.config.ts # Vitest
41
+ grep -l '"jest"' package.json # Jest
42
+ ```
43
+
44
+ Prefer Vitest for new Vite-based projects; respect Jest for existing setups.
45
+
46
+ ## Example Session
47
+
48
+ ````text
49
+ User: /react-test I need a SearchInput component with debounced search
50
+
51
+ Agent:
52
+ # TDD Session: SearchInput
53
+
54
+ ## Step 1: Define Signature
55
+
56
+ ```tsx
57
+ // src/components/SearchInput.tsx
58
+ type Props = {
59
+ onSearch: (query: string) => void;
60
+ placeholder?: string;
61
+ debounceMs?: number;
62
+ };
63
+
64
+ export function SearchInput({ onSearch, placeholder, debounceMs }: Props) {
65
+ throw new Error("not implemented");
66
+ }
67
+ ```
68
+
69
+ ## Step 2: Write Behavior Tests (RED)
70
+
71
+ ```tsx
72
+ // src/components/SearchInput.test.tsx
73
+ import { describe, expect, test, vi } from "vitest";
74
+ import { render, screen } from "@testing-library/react";
75
+ import userEvent from "@testing-library/user-event";
76
+ import { SearchInput } from "./SearchInput";
77
+
78
+ describe("SearchInput", () => {
79
+ test("renders with placeholder", () => {
80
+ render(<SearchInput onSearch={() => {}} placeholder="Search users" />);
81
+ expect(screen.getByPlaceholderText("Search users")).toBeInTheDocument();
82
+ });
83
+
84
+ test("calls onSearch after typing", async () => {
85
+ vi.useFakeTimers();
86
+ const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
87
+ const onSearch = vi.fn();
88
+ render(<SearchInput onSearch={onSearch} debounceMs={300} />);
89
+
90
+ await user.type(screen.getByRole("textbox"), "alice");
91
+
92
+ expect(onSearch).not.toHaveBeenCalled(); // before debounce
93
+ vi.advanceTimersByTime(300);
94
+ expect(onSearch).toHaveBeenCalledWith("alice"); // after debounce
95
+
96
+ vi.useRealTimers();
97
+ });
98
+
99
+ test("does not call onSearch when typing pauses then continues", async () => {
100
+ vi.useFakeTimers();
101
+ const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
102
+ const onSearch = vi.fn();
103
+ render(<SearchInput onSearch={onSearch} debounceMs={300} />);
104
+
105
+ await user.type(screen.getByRole("textbox"), "ali");
106
+ vi.advanceTimersByTime(200); // mid-debounce
107
+ await user.type(screen.getByRole("textbox"), "ce");
108
+ vi.advanceTimersByTime(300);
109
+
110
+ expect(onSearch).toHaveBeenCalledTimes(1);
111
+ expect(onSearch).toHaveBeenCalledWith("alice");
112
+
113
+ vi.useRealTimers();
114
+ });
115
+
116
+ test("is keyboard reachable and accessible", () => {
117
+ render(<SearchInput onSearch={() => {}} />);
118
+ const input = screen.getByRole("textbox");
119
+ input.focus();
120
+ expect(input).toHaveFocus();
121
+ });
122
+ });
123
+ ```
124
+
125
+ ## Step 3: Run Tests — Verify FAIL
126
+
127
+ ```bash
128
+ $ vitest run src/components/SearchInput.test.tsx
129
+
130
+ × src/components/SearchInput.test.tsx (4 tests) ✘ Error: not implemented
131
+ ```
132
+
133
+ ✓ Tests fail as expected.
134
+
135
+ ## Step 4: Implement Minimal Code (GREEN)
136
+
137
+ ```tsx
138
+ import { useEffect, useState } from "react";
139
+
140
+ export function SearchInput({ onSearch, placeholder, debounceMs = 300 }: Props) {
141
+ const [query, setQuery] = useState("");
142
+
143
+ useEffect(() => {
144
+ const id = setTimeout(() => onSearch(query), debounceMs);
145
+ return () => clearTimeout(id);
146
+ }, [query, onSearch, debounceMs]);
147
+
148
+ return (
149
+ <input
150
+ type="text"
151
+ value={query}
152
+ placeholder={placeholder}
153
+ onChange={(e) => setQuery(e.target.value)}
154
+ />
155
+ );
156
+ }
157
+ ```
158
+
159
+ ## Step 5: Run Tests — Verify PASS
160
+
161
+ ```bash
162
+ $ vitest run src/components/SearchInput.test.tsx
163
+
164
+ ✓ src/components/SearchInput.test.tsx (4 tests) 47ms
165
+ ```
166
+
167
+ ## Step 6: Coverage
168
+
169
+ ```bash
170
+ $ vitest run --coverage src/components/SearchInput.test.tsx
171
+
172
+ % Stmts: 100 % Branch: 100 % Funcs: 100 % Lines: 100
173
+ ```
174
+
175
+ ## TDD Complete!
176
+ ````
177
+
178
+ ## Test Patterns
179
+
180
+ ### Behavior, not implementation
181
+
182
+ Use `getByRole`, `getByLabelText`, `getByText`. Avoid `container.querySelector` and asserting on component state.
183
+
184
+ ### `userEvent.setup()` per test
185
+
186
+ ```tsx
187
+ const user = userEvent.setup();
188
+ await user.click(screen.getByRole("button", { name: /save/i }));
189
+ ```
190
+
191
+ ### MSW for network
192
+
193
+ ```tsx
194
+ beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
195
+ afterEach(() => server.resetHandlers());
196
+ afterAll(() => server.close());
197
+
198
+ server.use(http.post("/api/users", () => HttpResponse.json({ id: "1" }, { status: 201 })));
199
+ ```
200
+
201
+ ### Custom hooks
202
+
203
+ ```tsx
204
+ const { result } = renderHook(() => useCounter(0));
205
+ act(() => result.current.increment());
206
+ expect(result.current.count).toBe(1);
207
+ ```
208
+
209
+ ### Accessibility
210
+
211
+ ```tsx
212
+ import { axe } from "vitest-axe";
213
+ expect(await axe(container)).toHaveNoViolations();
214
+ ```
215
+
216
+ ## Coverage Targets
217
+
218
+ | Layer | Target |
219
+ |---|---|
220
+ | Pure utilities | >=90% |
221
+ | Custom hooks | >=85% |
222
+ | Presentational components | >=80% |
223
+ | Container components | >=70% |
224
+ | Pages | E2E covered separately |
225
+
226
+ Configure in `vitest.config.ts` / `jest.config.js` to enforce thresholds in CI.
227
+
228
+ ## Anti-Patterns to Avoid
229
+
230
+ - `container.querySelector(...)` — bypasses accessibility queries
231
+ - Asserting on render count
232
+ - Mocking `react` itself (`jest.mock("react", ...)`)
233
+ - Mocking child components by default (mock only when child has heavy side effects)
234
+ - Ignoring `act()` warnings — they signal real bugs
235
+ - Snapshot tests of rendered components (brittle, rubber-stamped) — use Playwright/Cypress visual diff instead
236
+
237
+ ## Test Commands
238
+
239
+ ```bash
240
+ # Vitest
241
+ vitest # watch
242
+ vitest run # one-shot
243
+ vitest run --coverage # with coverage
244
+ vitest run path/to/file.test.tsx # single file
245
+
246
+ # Jest
247
+ jest --watch
248
+ jest --coverage
249
+ jest path/to/file.test.tsx
250
+
251
+ # CI mode
252
+ CI=true vitest run --coverage
253
+ ```
254
+
255
+ ## Related Commands
256
+
257
+ - `/react-build` — fix build errors before running tests
258
+ - `/react-review` — review after implementation
259
+ - `verification-loop` skill — full verification loop
260
+
261
+ ## Related
262
+
263
+ - Skills: `skills/react-testing/`, `skills/tdd-workflow/`, `skills/accessibility/`, `skills/e2e-testing/`
264
+ - Rules: `rules/react/testing.md`
265
+ - Agents: `react-reviewer` (reviews test quality), `tdd-guide` (enforces TDD process)
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: benchmark-optimization-loop
3
+ description: Use when the user asks to make something faster, try many variants, run recursive optimization, benchmark latency/throughput/cost, or choose the best implementation by repeated measured tests.
4
+ origin: ECC
5
+ tools: Read, Write, Edit, Bash, Grep, Glob
6
+ ---
7
+
8
+ # Benchmark Optimization Loop
9
+
10
+ Use this skill to convert "make it 20x faster" or "try 50 recursive
11
+ optimizations" into a bounded measured loop that can actually improve a system.
12
+
13
+ ## Required Baseline
14
+
15
+ Do not optimize until these exist:
16
+
17
+ - the operation being optimized;
18
+ - the correctness gate that must stay green;
19
+ - the metric: wall time, p95 latency, rows/sec, cost/run, memory, error rate;
20
+ - the current baseline;
21
+ - the search budget: max variants, max time, max spend, max data impact.
22
+
23
+ If the user asks for an unrealistic target, keep the ambition but make the loop
24
+ bounded and measurable.
25
+
26
+ ## Loop
27
+
28
+ 1. Measure the baseline.
29
+ 2. Identify bottlenecks from evidence.
30
+ 3. Generate variants that test one hypothesis each.
31
+ 4. Run variants with the same input shape.
32
+ 5. Reject variants that fail correctness, safety, or reproducibility.
33
+ 6. Promote the fastest safe variant.
34
+ 7. Codify the winning path in a script, command, test, config, or doc.
35
+ 8. Rerun the baseline and winner to confirm the delta.
36
+
37
+ ## Variant Table
38
+
39
+ Track variants like this:
40
+
41
+ ```text
42
+ Variant | Hypothesis | Command | Time | Correct? | Notes
43
+ baseline | current path | npm run job | 120s | yes | stable
44
+ batch-500 | fewer round trips | npm run job -- --batch 500 | 42s | yes | winner
45
+ parallel-8 | more workers | npm run job -- --workers 8 | 31s | no | rate limited
46
+ ```
47
+
48
+ ## Recursive Search
49
+
50
+ For recursive or hyperparameter work:
51
+
52
+ - persist every run to a ledger;
53
+ - compare against the prior accepted winner, not only the previous run;
54
+ - keep a holdout or replay check;
55
+ - stop when improvement is within noise, correctness fails, cost exceeds the
56
+ budget, or the search starts changing more variables than it can explain.
57
+
58
+ Use phrases like "best measured safe variant" instead of "global optimum" unless
59
+ the search space was actually exhaustive.
60
+
61
+ ## Promotion Gate
62
+
63
+ A variant cannot become the new default until:
64
+
65
+ - correctness tests pass;
66
+ - the performance delta is repeated or explained;
67
+ - rollback is obvious;
68
+ - the change is encoded in source control or a durable runbook;
69
+ - the final summary includes exact commands and measurements.
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: blender-motion-state-inspection
3
+ description: Use this skill when inspecting Blender characters, rigs, poses, animation retargeting, ground contact, facing direction, or model-vs-motion alignment where screenshots alone are not enough.
4
+ origin: ECC
5
+ tools: Read, Write, Edit, Bash, Grep, Glob
6
+ ---
7
+
8
+ # Blender Motion State Inspection
9
+
10
+ ## When to Use
11
+
12
+ - A Blender character looks twisted, mirrored, flattened, offset, or foot-sliding in an animation.
13
+ - A user asks whether an imported avatar, armature, or retargeted motion matches an expected pose.
14
+ - You need to compare rendered evidence with structured facts such as bones, bounding boxes, contacts, and facing vectors.
15
+ - A workflow depends on deciding whether a model is a character, prop, proxy mesh, control rig, or broken import.
16
+
17
+ ## Core Principle
18
+
19
+ Do not judge animated 3D assets only from screenshots. Screenshots are review evidence, but they hide axis conventions, bone names, object scale, local transforms, parented meshes, material slots, and frame-by-frame contact state.
20
+
21
+ First extract structured Blender state, then use viewport screenshots or renders to confirm what the facts imply.
22
+
23
+ ## How It Works
24
+
25
+ 1. Establish the clean scene and asset baseline before judging motion.
26
+ 2. Extract structured facts from Blender using an exporter or Blender Python run inside Blender's own interpreter.
27
+ 3. Sample the frames most likely to expose contact, orientation, scale, and retargeting errors.
28
+ 4. Compare the measured facts against the user's expected pose, direction, ground plane, and render goal.
29
+ 5. Return a concise report that separates confirmed facts, likely causes, and required fixes.
30
+
31
+ ## Inspection Workflow
32
+
33
+ 1. Inventory the scene.
34
+ - List meshes, armatures, empties, cameras, lights, modifiers, parent relationships, and hidden objects.
35
+ - Separate character meshes from helper/proxy geometry before judging the avatar.
36
+ - Record object-space and world-space bounding boxes.
37
+
38
+ 2. Identify the skeleton.
39
+ - Capture armature names, pose bones, bone heads/tails, roll, parent chains, constraints, and rest-pose axes.
40
+ - Map semantic bones such as hips, spine, neck, head, shoulders, elbows, hands, thighs, knees, ankles, and feet.
41
+ - Flag missing left/right pairs and unusual naming schemes.
42
+
43
+ 3. Determine forward, up, and side axes.
44
+ - Use the pelvis, spine, shoulders, hips, head, and feet together; do not rely on a single mesh normal.
45
+ - Compare local armature axes with world axes and imported file conventions such as glTF Y-up vs Blender Z-up.
46
+ - Mark likely mirrored or backwards imports when face/head/feet direction conflicts with root motion.
47
+
48
+ 4. Sample animation frames.
49
+ - Inspect first, middle, contact, airborne, and extreme frames.
50
+ - Record root location, root heading, pelvis height, torso lean, limb directions, foot clearance, and mesh bounds.
51
+ - For long or fast motion, sample more densely around flips, landings, turns, collisions, and floor contacts.
52
+
53
+ 5. Check model integrity before retargeting blame.
54
+ - Confirm the clean baseline shape before applying animation.
55
+ - Preserve original mesh, materials, armature, and skinning unless the user explicitly asks for repair.
56
+ - Treat unexplained sphere-like blobs, giant proxy meshes, or crushed bodies as import/selection issues until proven otherwise.
57
+
58
+ 6. Diagnose contact and motion issues.
59
+ - Ground penetration: compare lowest foot or shoe vertices with floor height per frame.
60
+ - Foot sliding: compare foot world positions across planted frames.
61
+ - Leg crossover: compare left/right thigh, knee, ankle, and foot side ordering.
62
+ - Twist damage: compare bone swing direction separately from roll/twist around the limb axis.
63
+ - Scale drift: compare animated mesh bounds against the clean baseline bounds.
64
+
65
+ 7. Report facts before opinions.
66
+ - Include frame numbers, object names, bone names, world coordinates, and thresholds.
67
+ - Separate confirmed failures from visual suspicions.
68
+ - Attach screenshots only after the structured state explains what to look for.
69
+
70
+ ## Recommended Report Shape
71
+
72
+ ```markdown
73
+ ## Blender Motion Inspection
74
+
75
+ ### Scene Inventory
76
+ - Character candidates:
77
+ - Armatures:
78
+ - Helper/proxy objects:
79
+ - Cameras/lights:
80
+
81
+ ### Orientation
82
+ - World up:
83
+ - Character forward:
84
+ - Root heading:
85
+ - Mirrored/backwards risk:
86
+
87
+ ### Baseline Integrity
88
+ - Clean mesh bounds:
89
+ - Animated mesh bounds:
90
+ - Materials/skin preserved:
91
+ - Suspicious non-character meshes:
92
+
93
+ ### Frame Findings
94
+ | Frame | Finding | Evidence |
95
+ | --- | --- | --- |
96
+ | 1 | Clean baseline pose | hips/spine/feet aligned |
97
+ | 96 | Foot penetrates floor | left_foot min_z = -0.04 |
98
+
99
+ ### Verdict
100
+ - Pass/fail:
101
+ - Required fix:
102
+ - Render readiness:
103
+ ```
104
+
105
+ ## Examples
106
+
107
+ ### Walk Cycle With Foot Sliding
108
+
109
+ Scenario: a retargeted character appears to skate during a walk cycle, but the front camera angle makes the foot contact hard to judge.
110
+
111
+ Apply the workflow:
112
+ - Inventory the scene: character mesh `HeroBody`, armature `HeroRig`, ground plane `Floor`, no hidden proxy meshes.
113
+ - Identify the skeleton: semantic feet are `foot.L` and `foot.R`; hips are `pelvis`; root bone is `root`.
114
+ - Sample animation frames: inspect frames 1, 18, 24, 30, 42, and 48 around planted-foot moments.
115
+ - Diagnose contact and motion issues: compare world-space foot locations during planted frames.
116
+
117
+ Extracted facts:
118
+
119
+ | Frame | Fact | Evidence |
120
+ | --- | --- | --- |
121
+ | 18 | Left foot is planted | `foot.L min_z = 0.004`, toe and heel both near floor |
122
+ | 24 | Left foot slides while planted | `foot.L x = 0.21 -> 0.28` over six frames |
123
+ | 30 | Pelvis keeps moving forward | `pelvis y = 1.14 -> 1.31` |
124
+
125
+ Verdict: fail for render readiness. The motion needs foot-lock cleanup or retargeting constraint review; the body mesh does not need proportion changes.
126
+
127
+ ### Backwards Imported Character
128
+
129
+ Scenario: a character looks correct in a still frame, but the animation moves opposite the expected travel direction.
130
+
131
+ Apply the workflow:
132
+ - Determine forward, up, and side axes: compare head, chest, feet, and root motion.
133
+ - Sample animation frames: inspect frame 1 and the midpoint of the travel path.
134
+ - Report facts before opinions: include the root heading and model-facing direction separately.
135
+
136
+ Extracted facts:
137
+
138
+ | Frame | Fact | Evidence |
139
+ | --- | --- | --- |
140
+ | 1 | Character face points toward world `-Y` | head/chest vector from `neck` to `head` resolves to `-Y` |
141
+ | 72 | Root motion travels toward world `+Y` | `root y = 0.0 -> 2.8` |
142
+ | 72 | Feet remain visually forward-facing opposite travel | toe bones point `-Y` while displacement is `+Y` |
143
+
144
+ Verdict: likely backwards import or retargeting forward-axis mismatch. Fix the import/retarget axis mapping before editing animation curves.
145
+
146
+ ## Practical Thresholds
147
+
148
+ - Assume Blender's default meter-scale units unless the scene unit scale says otherwise.
149
+ - Treat ground penetration above 1-2 cm as visible unless the floor is soft or intentionally stylized.
150
+ - Treat a sudden scale change above 5% as a likely rig, constraint, or transform inheritance problem.
151
+ - Treat left/right ankle side-order flips during airborne inverted motion as leg crossover risk even if it recovers later.
152
+ - Treat root heading jumps above 30 degrees per frame as suspicious unless the source motion includes a snap turn.
153
+
154
+ ## Anti-Patterns
155
+
156
+ - Do not modify body proportions to force pose matching unless the task is explicitly mesh repair.
157
+ - Do not bake away the clean baseline before recording it.
158
+ - Do not use one rendered camera angle as proof that a pose is correct.
159
+ - Do not delete helper objects until you have recorded why they are not part of the character.
160
+ - Do not assume an avatar faces +Y, -Y, +X, or -X without checking head, feet, torso, and root motion together.
161
+
162
+ ## Tooling Notes
163
+
164
+ If a Blender state exporter is available, prefer JSON that includes meshes, armatures, pose bones, materials, contacts, bounding boxes, and sampled animation frames. If no exporter exists, run a small Blender Python script through Blender itself, for example `blender --background scene.blend --python collect_motion_state.py`, because `bpy` is not available in a normal system Python interpreter.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: canary-watch
3
- description: Use this skill to monitor a deployed URL for regressions after deploys, merges, or dependency upgrades.
3
+ description: Use this skill to monitor and verify a deployed URL after releases — checks HTTP endpoints, SSE streams, static assets, console errors, and performance regressions after deploys, merges, or dependency upgrades. Smoke / canary / post-deploy verification.
4
4
  origin: ECC
5
5
  ---
6
6
 
@@ -27,6 +27,8 @@ Monitors a deployed URL for regressions. Runs in a loop until stopped or until t
27
27
  4. Performance — LCP/CLS/INP regression vs baseline?
28
28
  5. Content — did key elements disappear? (h1, nav, footer, CTA)
29
29
  6. API Health — are critical endpoints responding within SLA?
30
+ 7. Static Assets — are JS, CSS, image, and font requests returning 2xx/3xx with expected content types?
31
+ 8. SSE Streams — do event-stream endpoints connect and receive an initial event or heartbeat?
30
32
  ```
31
33
 
32
34
  ### Watch Modes
@@ -54,12 +56,16 @@ critical: # immediate alert
54
56
  - Console error count > 5 (new errors only)
55
57
  - LCP > 4s
56
58
  - API endpoint returns 5xx
59
+ - Static asset returns 4xx/5xx
60
+ - SSE endpoint cannot connect or drops before first heartbeat
57
61
 
58
62
  warning: # flag in report
59
63
  - LCP increased > 500ms from baseline
60
64
  - CLS > 0.1
61
65
  - New console warnings
62
66
  - Response time > 2x baseline
67
+ - Static asset content type changed unexpectedly
68
+ - SSE heartbeat latency > 2x baseline
63
69
 
64
70
  info: # log only
65
71
  - Minor performance variance
@@ -87,6 +93,8 @@ When a critical threshold is crossed:
87
93
  | LCP | 1.8s ✓ | 1.6s | +200ms |
88
94
  | CLS | 0.01 ✓ | 0.01 | — |
89
95
  | API /health | 145ms ✓ | 120ms | +25ms |
96
+ | Static assets | 42/42 ✓ | 42/42 | — |
97
+ | SSE /events | connected ✓ | connected | +80ms heartbeat |
90
98
 
91
99
  ### No regressions detected. Deploy is clean.
92
100
  ```
@@ -116,7 +116,13 @@ except(KeyError, TypeError, ValueError):
116
116
  # If cwd was provided in stdin, use it for project detection
117
117
  if [ -n "$STDIN_CWD" ] && [ -d "$STDIN_CWD" ]; then
118
118
  _GIT_ROOT=$(git -C "$STDIN_CWD" rev-parse --show-toplevel 2>/dev/null || true)
119
- export CLAUDE_PROJECT_DIR="${_GIT_ROOT:-$STDIN_CWD}"
119
+ if [ -n "$_GIT_ROOT" ]; then
120
+ export CLAUDE_PROJECT_DIR="$_GIT_ROOT"
121
+ unset CLV2_NO_PROJECT
122
+ else
123
+ unset CLAUDE_PROJECT_DIR
124
+ export CLV2_NO_PROJECT=1
125
+ fi
120
126
  fi
121
127
 
122
128
  # ─────────────────────────────────────────────
@@ -333,6 +339,19 @@ print(json.dumps(observation))
333
339
  # Use flock for atomic check-then-act to prevent race conditions
334
340
  # Fallback for macOS (no flock): use lockfile or skip
335
341
  LAZY_START_LOCK="${PROJECT_DIR}/.observer-start.lock"
342
+ _REMOVE_FILE_IF_PRESENT() {
343
+ local target="$1"
344
+ if [ -n "$target" ] && [ -e "$target" ]; then
345
+ rm -- "$target" 2>/dev/null || true
346
+ fi
347
+ }
348
+
349
+ _START_OBSERVER_LOGGED() {
350
+ local bootstrap_log="${PROJECT_DIR}/observer-start.log"
351
+ mkdir -p "$PROJECT_DIR"
352
+ "${SKILL_ROOT}/agents/start-observer.sh" start >> "$bootstrap_log" 2>&1 || true
353
+ }
354
+
336
355
  _CHECK_OBSERVER_RUNNING() {
337
356
  local pid_file="$1"
338
357
  if [ -f "$pid_file" ]; then
@@ -341,7 +360,7 @@ _CHECK_OBSERVER_RUNNING() {
341
360
  # Validate PID is a positive integer (>1) to prevent signaling invalid targets
342
361
  case "$pid" in
343
362
  ''|*[!0-9]*|0|1)
344
- rm -f "$pid_file" 2>/dev/null || true
363
+ _REMOVE_FILE_IF_PRESENT "$pid_file"
345
364
  return 1
346
365
  ;;
347
366
  esac
@@ -349,7 +368,7 @@ _CHECK_OBSERVER_RUNNING() {
349
368
  return 0 # Process is alive
350
369
  fi
351
370
  # Stale PID file - remove it
352
- rm -f "$pid_file" 2>/dev/null || true
371
+ _REMOVE_FILE_IF_PRESENT "$pid_file"
353
372
  fi
354
373
  return 1 # No PID file or process dead
355
374
  }
@@ -396,7 +415,7 @@ if [ "$OBSERVER_ENABLED" = "true" ]; then
396
415
  _CHECK_OBSERVER_RUNNING "${PROJECT_DIR}/.observer.pid" || true
397
416
  _CHECK_OBSERVER_RUNNING "${CONFIG_DIR}/.observer.pid" || true
398
417
  if [ ! -f "${PROJECT_DIR}/.observer.pid" ] && [ ! -f "${CONFIG_DIR}/.observer.pid" ]; then
399
- nohup "${SKILL_ROOT}/agents/start-observer.sh" start >/dev/null 2>&1 &
418
+ _START_OBSERVER_LOGGED
400
419
  fi
401
420
  ) 9>"$LAZY_START_LOCK"
402
421
  else
@@ -404,14 +423,14 @@ if [ "$OBSERVER_ENABLED" = "true" ]; then
404
423
  if command -v lockfile >/dev/null 2>&1; then
405
424
  # Use subshell to isolate exit and add trap for cleanup
406
425
  (
407
- trap 'rm -f "$LAZY_START_LOCK" 2>/dev/null || true' EXIT
426
+ trap '_REMOVE_FILE_IF_PRESENT "$LAZY_START_LOCK"' EXIT
408
427
  lockfile -r 1 -l 30 "$LAZY_START_LOCK" 2>/dev/null || exit 0
409
428
  _CHECK_OBSERVER_RUNNING "${PROJECT_DIR}/.observer.pid" || true
410
429
  _CHECK_OBSERVER_RUNNING "${CONFIG_DIR}/.observer.pid" || true
411
430
  if [ ! -f "${PROJECT_DIR}/.observer.pid" ] && [ ! -f "${CONFIG_DIR}/.observer.pid" ]; then
412
- nohup "${SKILL_ROOT}/agents/start-observer.sh" start >/dev/null 2>&1 &
431
+ _START_OBSERVER_LOGGED
413
432
  fi
414
- rm -f "$LAZY_START_LOCK" 2>/dev/null || true
433
+ _REMOVE_FILE_IF_PRESENT "$LAZY_START_LOCK"
415
434
  )
416
435
  else
417
436
  # POSIX fallback: mkdir is atomic -- fails if dir already exists
@@ -421,7 +440,7 @@ if [ "$OBSERVER_ENABLED" = "true" ]; then
421
440
  _CHECK_OBSERVER_RUNNING "${PROJECT_DIR}/.observer.pid" || true
422
441
  _CHECK_OBSERVER_RUNNING "${CONFIG_DIR}/.observer.pid" || true
423
442
  if [ ! -f "${PROJECT_DIR}/.observer.pid" ] && [ ! -f "${CONFIG_DIR}/.observer.pid" ]; then
424
- nohup "${SKILL_ROOT}/agents/start-observer.sh" start >/dev/null 2>&1 &
443
+ _START_OBSERVER_LOGGED
425
444
  fi
426
445
  )
427
446
  fi
@@ -459,7 +478,10 @@ if [ "$should_signal" -eq 1 ]; then
459
478
  observer_pid=$(cat "$pid_file" 2>/dev/null || true)
460
479
  # Validate PID is a positive integer (>1)
461
480
  case "$observer_pid" in
462
- ''|*[!0-9]*|0|1) rm -f "$pid_file" 2>/dev/null || true; continue ;;
481
+ ''|*[!0-9]*|0|1)
482
+ _REMOVE_FILE_IF_PRESENT "$pid_file"
483
+ continue
484
+ ;;
463
485
  esac
464
486
  # Deduplicate: skip if already signaled this pass
465
487
  case "$signaled_pids" in