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.
- package/.local/skills/THIRD_PARTY_LICENSES/AvdLee-SwiftUI-Agent-Skill.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/Dimillian-Skills.LICENSE +21 -0
- package/.local/skills/THIRD_PARTY_LICENSES/README.md +36 -0
- package/.local/skills/THIRD_PARTY_LICENSES/twostraws-swiftui-agent-skill.LICENSE +21 -0
- package/.local/skills/ios-debugger-agent/SKILL.md +51 -0
- package/.local/skills/ios-debugger-agent/agents/openai.yaml +4 -0
- package/.local/skills/prompt-optimizer/SKILL.md +262 -19
- package/.local/skills/swift-concurrency-expert/SKILL.md +105 -0
- package/.local/skills/swift-concurrency-expert/agents/openai.yaml +4 -0
- package/.local/skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
- package/.local/skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
- package/.local/skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
- package/.local/skills/swiftui-expert-skill/SKILL.md +162 -0
- package/.local/skills/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
- package/.local/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
- package/.local/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
- package/.local/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
- package/.local/skills/swiftui-expert-skill/references/charts.md +602 -0
- package/.local/skills/swiftui-expert-skill/references/focus-patterns.md +299 -0
- package/.local/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
- package/.local/skills/swiftui-expert-skill/references/latest-apis.md +488 -0
- package/.local/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
- package/.local/skills/swiftui-expert-skill/references/liquid-glass.md +423 -0
- package/.local/skills/swiftui-expert-skill/references/list-patterns.md +446 -0
- package/.local/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
- package/.local/skills/swiftui-expert-skill/references/macos-views.md +357 -0
- package/.local/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
- package/.local/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
- package/.local/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
- package/.local/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
- package/.local/skills/swiftui-expert-skill/references/state-management.md +388 -0
- package/.local/skills/swiftui-expert-skill/references/text-patterns.md +32 -0
- package/.local/skills/swiftui-expert-skill/references/trace-analysis.md +295 -0
- package/.local/skills/swiftui-expert-skill/references/trace-recording.md +134 -0
- package/.local/skills/swiftui-expert-skill/references/view-structure.md +780 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/analyze_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/__pycache__/record_trace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/analyze_trace.py +301 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__init__.py +1 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/__init__.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/causes.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/correlate.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/events.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hangs.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hitches.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/summary.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/swiftui.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/time_profiler.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xctrace.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xml_utils.cpython-313.pyc +0 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/causes.py +187 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/correlate.py +179 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/events.py +291 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hangs.py +108 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hitches.py +145 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/summary.py +243 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/swiftui.py +195 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/time_profiler.py +135 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +117 -0
- package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +224 -0
- package/.local/skills/swiftui-expert-skill/scripts/record_trace.py +252 -0
- package/.local/skills/swiftui-liquid-glass/SKILL.md +90 -0
- package/.local/skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
- package/.local/skills/swiftui-performance-audit/SKILL.md +106 -0
- package/.local/skills/swiftui-performance-audit/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-performance-audit/references/code-smells.md +150 -0
- package/.local/skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/.local/skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/.local/skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/.local/skills/swiftui-performance-audit/references/report-template.md +47 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/.local/skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/.local/skills/swiftui-pro/SKILL.md +108 -0
- package/.local/skills/swiftui-pro/agents/openai.yaml +10 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
- package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
- package/.local/skills/swiftui-pro/references/accessibility.md +13 -0
- package/.local/skills/swiftui-pro/references/api.md +39 -0
- package/.local/skills/swiftui-pro/references/data.md +43 -0
- package/.local/skills/swiftui-pro/references/design.md +32 -0
- package/.local/skills/swiftui-pro/references/hygiene.md +9 -0
- package/.local/skills/swiftui-pro/references/navigation.md +14 -0
- package/.local/skills/swiftui-pro/references/performance.md +46 -0
- package/.local/skills/swiftui-pro/references/swift.md +56 -0
- package/.local/skills/swiftui-pro/references/views.md +36 -0
- package/.local/skills/swiftui-ui-patterns/SKILL.md +95 -0
- package/.local/skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/.local/skills/swiftui-ui-patterns/references/async-state.md +96 -0
- package/.local/skills/swiftui-ui-patterns/references/components-index.md +50 -0
- package/.local/skills/swiftui-ui-patterns/references/controls.md +57 -0
- package/.local/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/.local/skills/swiftui-ui-patterns/references/focus.md +90 -0
- package/.local/skills/swiftui-ui-patterns/references/form.md +97 -0
- package/.local/skills/swiftui-ui-patterns/references/grids.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/haptics.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/.local/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/list.md +86 -0
- package/.local/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/.local/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/.local/skills/swiftui-ui-patterns/references/media.md +73 -0
- package/.local/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/.local/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/.local/skills/swiftui-ui-patterns/references/overlay.md +45 -0
- package/.local/skills/swiftui-ui-patterns/references/performance.md +62 -0
- package/.local/skills/swiftui-ui-patterns/references/previews.md +48 -0
- package/.local/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/.local/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/.local/skills/swiftui-ui-patterns/references/searchable.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/sheets.md +155 -0
- package/.local/skills/swiftui-ui-patterns/references/split-views.md +72 -0
- package/.local/skills/swiftui-ui-patterns/references/tabview.md +114 -0
- package/.local/skills/swiftui-ui-patterns/references/theming.md +71 -0
- package/.local/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/.local/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/.local/skills/swiftui-view-refactor/SKILL.md +202 -0
- package/.local/skills/swiftui-view-refactor/agents/openai.yaml +4 -0
- package/.local/skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/.omc-curation/ecc-selection.json +80 -0
- package/.omc-curation/governance.json +113 -0
- package/.omc-curation/sources.lock.json +25 -0
- package/README.md +69 -4
- package/bundled/manifest.json +5 -5
- package/bundled/upstream/anthropic-skills/.omc-source/bundle.json +18 -0
- package/bundled/upstream/anthropic-skills/.omc-source/provenance.json +399 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/SKILL.md +18 -17
- package/bundled/upstream/anthropic-skills/skills/claude-api/curl/examples.md +9 -9
- package/bundled/upstream/anthropic-skills/skills/claude-api/curl/managed-agents.md +4 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/go/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/java/claude-api.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/java/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/php/claude-api.md +10 -10
- package/bundled/upstream/anthropic-skills/skills/claude-api/php/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/README.md +16 -16
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/batches.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/files-api.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/streaming.md +7 -7
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/tool-use.md +19 -19
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/managed-agents/README.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/claude-api.md +4 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/managed-agents/README.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/error-codes.md +5 -5
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/live-sources.md +3 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-api-reference.md +10 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-core.md +19 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-environments.md +6 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-multiagent.md +1 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-onboarding.md +3 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-overview.md +3 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +173 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-tools.md +10 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/model-migration.md +113 -13
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/models.md +14 -11
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/prompt-caching.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/tool-use-concepts.md +4 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/README.md +15 -15
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/batches.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/files-api.md +1 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/streaming.md +5 -5
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/tool-use.md +15 -15
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/managed-agents/README.md +3 -3
- package/bundled/upstream/ecc/.omc-source/bundle.json +2 -1
- package/bundled/upstream/ecc/.omc-source/last-plan-apply.json +108 -24
- package/bundled/upstream/ecc/.omc-source/manifests/.claude-plugin/marketplace.json +3 -3
- package/bundled/upstream/ecc/.omc-source/provenance.json +563 -0
- package/bundled/upstream/ecc/agents/marketing-agent.md +159 -0
- package/bundled/upstream/ecc/agents/react-build-resolver.md +215 -0
- package/bundled/upstream/ecc/agents/react-reviewer.md +167 -0
- package/bundled/upstream/ecc/agents/typescript-reviewer.md +3 -0
- package/bundled/upstream/ecc/commands/harness-audit.md +17 -10
- package/bundled/upstream/ecc/commands/marketing-campaign.md +129 -0
- package/bundled/upstream/ecc/commands/react-build.md +187 -0
- package/bundled/upstream/ecc/commands/react-review.md +170 -0
- package/bundled/upstream/ecc/commands/react-test.md +265 -0
- package/bundled/upstream/ecc/skills/benchmark-optimization-loop/SKILL.md +69 -0
- package/bundled/upstream/ecc/skills/blender-motion-state-inspection/SKILL.md +164 -0
- package/bundled/upstream/ecc/skills/canary-watch/SKILL.md +9 -1
- package/bundled/upstream/ecc/skills/continuous-learning-v2/hooks/observe.sh +31 -9
- package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/detect-project.sh +38 -4
- package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/instinct-cli.py +319 -12
- package/bundled/upstream/ecc/skills/data-throughput-accelerator/SKILL.md +72 -0
- package/bundled/upstream/ecc/skills/dynamic-workflow-mode/SKILL.md +123 -0
- package/bundled/upstream/ecc/skills/frontend-a11y/SKILL.md +446 -0
- package/bundled/upstream/ecc/skills/ito-basket-compare/SKILL.md +63 -0
- package/bundled/upstream/ecc/skills/ito-data-atlas-agent/SKILL.md +63 -0
- package/bundled/upstream/ecc/skills/ito-market-intelligence/SKILL.md +60 -0
- package/bundled/upstream/ecc/skills/ito-trade-planner/SKILL.md +67 -0
- package/bundled/upstream/ecc/skills/latency-critical-systems/SKILL.md +73 -0
- package/bundled/upstream/ecc/skills/marketing-campaign/SKILL.md +113 -0
- package/bundled/upstream/ecc/skills/nextjs-turbopack/SKILL.md +13 -0
- package/bundled/upstream/ecc/skills/parallel-execution-optimizer/SKILL.md +72 -0
- package/bundled/upstream/ecc/skills/prediction-market-oracle-research/SKILL.md +63 -0
- package/bundled/upstream/ecc/skills/prediction-market-risk-review/SKILL.md +60 -0
- package/bundled/upstream/ecc/skills/react-patterns/SKILL.md +341 -0
- package/bundled/upstream/ecc/skills/react-performance/SKILL.md +574 -0
- package/bundled/upstream/ecc/skills/react-testing/SKILL.md +423 -0
- package/bundled/upstream/ecc/skills/recsys-pipeline-architect/SKILL.md +114 -0
- package/bundled/upstream/ecc/skills/recursive-decision-ledger/SKILL.md +79 -0
- package/bundled/upstream/ecc/skills/social-publisher/SKILL.md +115 -0
- package/bundled/upstream/ecc/skills/team-agent-orchestration/SKILL.md +110 -0
- package/bundled/upstream/ecc/skills/uncloud/SKILL.md +343 -0
- package/bundled/upstream/ecc/skills/windows-desktop-e2e/SKILL.md +99 -0
- package/bundled/upstream/oh-my-claudecode/.omc-source/bundle.json +2 -1
- package/bundled/upstream/oh-my-claudecode/.omc-source/provenance.json +116 -0
- package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +7 -0
- package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/deep-interview/SKILL.md +39 -5
- package/bundled/upstream/oh-my-claudecode/skills/hud/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/local-build-reminder/SKILL.md +78 -0
- package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/SKILL.md +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/SKILL.md +26 -10
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/01-install-claude-md.md +3 -3
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +6 -4
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +2 -2
- package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +6 -6
- package/bundled/upstream/oh-my-claudecode/skills/plan/SKILL.md +44 -32
- package/bundled/upstream/oh-my-claudecode/skills/ralph/SKILL.md +45 -21
- package/bundled/upstream/oh-my-claudecode/skills/ralplan/SKILL.md +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/SKILL.md +7 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/resolve-paths.mjs +39 -15
- package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +132 -90
- package/bundled/upstream/oh-my-claudecode/skills/ultragoal/SKILL.md +93 -0
- package/bundled/upstream/oh-my-claudecode/skills/ultraqa/SKILL.md +28 -13
- package/bundled/upstream/oh-my-claudecode/skills/ultrawork/SKILL.md +7 -0
- package/bundled/upstream/superpowers/.omc-source/bundle.json +2 -1
- package/bundled/upstream/superpowers/.omc-source/provenance.json +63 -0
- package/package.json +2 -1
- package/src/catalog/source-catalog.js +10 -4
- package/src/cli/index.js +4 -0
- package/src/cli/plan.js +14 -2
- package/src/cli/setup.js +52 -13
- package/src/cli/skill.js +1 -1
- package/src/cli/source.js +265 -14
- package/src/config/sources.js +67 -1
- package/src/merge/content-patch.js +84 -0
- package/templates/merge-config.json +1 -8
- 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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 '
|
|
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
|
-
|
|
431
|
+
_START_OBSERVER_LOGGED
|
|
413
432
|
fi
|
|
414
|
-
|
|
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
|
-
|
|
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)
|
|
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
|