feat: add Vue ecosystem review support

This commit is contained in:
Bujidao 2026-06-12 19:14:31 +08:00
parent 6865316ab3
commit 86e2a2061a
17 changed files with 89 additions and 59 deletions

View File

@ -11,7 +11,7 @@
{ {
"name": "ecc", "name": "ecc",
"source": "./", "source": "./",
"description": "Harness-native ECC operator layer - 64 agents, 262 skills, 84 legacy command shims, reusable hooks, rules, selective install profiles, and production-ready workflows for Claude Code, Codex, OpenCode, Cursor, and related agent harnesses", "description": "Harness-native ECC operator layer - 65 agents, 263 skills, 85 legacy command shims, reusable hooks, rules, selective install profiles, and production-ready workflows for Claude Code, Codex, OpenCode, Cursor, and related agent harnesses",
"version": "2.0.0", "version": "2.0.0",
"author": { "author": {
"name": "Affaan Mustafa", "name": "Affaan Mustafa",

View File

@ -1,7 +1,7 @@
{ {
"name": "ecc", "name": "ecc",
"version": "2.0.0", "version": "2.0.0",
"description": "Harness-native ECC plugin for engineering teams - 64 agents, 262 skills, 84 legacy command shims, reusable hooks, rules, MCP conventions, and operator workflows for Claude Code plus adjacent agent harnesses", "description": "Harness-native ECC plugin for engineering teams - 65 agents, 263 skills, 85 legacy command shims, reusable hooks, rules, MCP conventions, and operator workflows for Claude Code plus adjacent agent harnesses",
"author": { "author": {
"name": "Affaan Mustafa", "name": "Affaan Mustafa",
"url": "https://x.com/affaanmustafa" "url": "https://x.com/affaanmustafa"

View File

@ -1,6 +1,6 @@
# Everything Claude Code (ECC) — Agent Instructions # Everything Claude Code (ECC) — Agent Instructions
This is a **production-ready AI coding plugin** providing 64 specialized agents, 262 skills, 84 commands, and automated hook workflows for software development. This is a **production-ready AI coding plugin** providing 65 specialized agents, 263 skills, 85 commands, and automated hook workflows for software development.
**Version:** 2.0.0 **Version:** 2.0.0
@ -149,9 +149,9 @@ Troubleshoot failures: check test isolation → verify mocks → fix implementat
## Project Structure ## Project Structure
``` ```
agents/ — 64 specialized subagents agents/ — 65 specialized subagents
skills/ — 262 workflow skills and domain knowledge skills/ — 263 workflow skills and domain knowledge
commands/ — 84 slash commands commands/ — 85 slash commands
hooks/ — Trigger-based automations hooks/ — Trigger-based automations
rules/ — Always-follow guidelines (common + per-language) rules/ — Always-follow guidelines (common + per-language)
scripts/ — Cross-platform Node.js utilities scripts/ — Cross-platform Node.js utilities

View File

@ -154,7 +154,7 @@ Stable graduation of the 2.0 line: 261 skills, the control-pane substrate (sessi
### v2.0.0-rc.1 — Surface Refresh, Operator Workflows, and ECC 2.0 Alpha (Apr 2026) ### v2.0.0-rc.1 — Surface Refresh, Operator Workflows, and ECC 2.0 Alpha (Apr 2026)
- **Dashboard GUI** — New Tkinter-based desktop application (`ecc_dashboard.py` or `npm run dashboard`) with dark/light theme toggle, font customization, and project logo in header and taskbar. - **Dashboard GUI** — New Tkinter-based desktop application (`ecc_dashboard.py` or `npm run dashboard`) with dark/light theme toggle, font customization, and project logo in header and taskbar.
- **Public surface synced to the live repo** — metadata, catalog counts, plugin manifests, and install-facing docs now match the actual OSS surface: 64 agents, 262 skills, and 84 legacy command shims. - **Public surface synced to the live repo** — metadata, catalog counts, plugin manifests, and install-facing docs now match the actual OSS surface: 65 agents, 263 skills, and 85 legacy command shims.
- **Operator and outbound workflow expansion**`brand-voice`, `social-graph-ranker`, `connections-optimizer`, `customer-billing-ops`, `ecc-tools-cost-audit`, `google-workspace-ops`, `project-flow-ops`, and `workspace-surface-audit` round out the operator lane. - **Operator and outbound workflow expansion**`brand-voice`, `social-graph-ranker`, `connections-optimizer`, `customer-billing-ops`, `ecc-tools-cost-audit`, `google-workspace-ops`, `project-flow-ops`, and `workspace-surface-audit` round out the operator lane.
- **Media and launch tooling**`manim-video`, `remotion-video-creation`, and upgraded social publishing surfaces make technical explainers and launch content part of the same system. - **Media and launch tooling**`manim-video`, `remotion-video-creation`, and upgraded social publishing surfaces make technical explainers and launch content part of the same system.
- **Framework and product surface growth**`nestjs-patterns`, richer Codex/OpenCode install surfaces, and expanded cross-harness packaging keep the repo usable beyond Claude Code alone. - **Framework and product surface growth**`nestjs-patterns`, richer Codex/OpenCode install surfaces, and expanded cross-harness packaging keep the repo usable beyond Claude Code alone.
@ -425,7 +425,7 @@ If you stacked methods, clean up in this order:
/plugin list ecc@ecc /plugin list ecc@ecc
``` ```
**That's it!** You now have access to 64 agents, 262 skills, and 84 legacy command shims. **That's it!** You now have access to 65 agents, 263 skills, and 85 legacy command shims.
### Dashboard GUI ### Dashboard GUI
@ -555,7 +555,7 @@ ECC/
| |-- plugin.json # Plugin metadata and component paths | |-- plugin.json # Plugin metadata and component paths
| |-- marketplace.json # Marketplace catalog for /plugin marketplace add | |-- marketplace.json # Marketplace catalog for /plugin marketplace add
| |
|-- agents/ # 64 specialized subagents for delegation |-- agents/ # 65 specialized subagents for delegation
| |-- planner.md # Feature implementation planning | |-- planner.md # Feature implementation planning
| |-- architect.md # System design decisions | |-- architect.md # System design decisions
| |-- tdd-guide.md # Test-driven development | |-- tdd-guide.md # Test-driven development
@ -1507,9 +1507,9 @@ The configuration is automatically detected from `.opencode/opencode.json`.
| Feature | Claude Code | OpenCode | Status | | Feature | Claude Code | OpenCode | Status |
|---------|---------------------|----------|--------| |---------|---------------------|----------|--------|
| Agents | PASS: 64 agents | PASS: 12 agents | **Claude Code leads** | | Agents | PASS: 65 agents | PASS: 12 agents | **Claude Code leads** |
| Commands | PASS: 84 commands | PASS: 35 commands | **Claude Code leads** | | Commands | PASS: 85 commands | PASS: 35 commands | **Claude Code leads** |
| Skills | PASS: 262 skills | PASS: 37 skills | **Claude Code leads** | | Skills | PASS: 263 skills | PASS: 37 skills | **Claude Code leads** |
| Hooks | PASS: 8 event types | PASS: 11 events | **OpenCode has more!** | | Hooks | PASS: 8 event types | PASS: 11 events | **OpenCode has more!** |
| Rules | PASS: 29 rules | PASS: 13 instructions | **Claude Code leads** | | Rules | PASS: 29 rules | PASS: 13 instructions | **Claude Code leads** |
| MCP Servers | PASS: 14 servers | PASS: Full | **Full parity** | | MCP Servers | PASS: 14 servers | PASS: Full | **Full parity** |
@ -1668,9 +1668,9 @@ ECC is the **first plugin to maximize every major AI coding tool**. Here's how e
| Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode | GitHub Copilot | | Feature | Claude Code | Cursor IDE | Codex CLI | OpenCode | GitHub Copilot |
|---------|-----------------------|------------|-----------|----------|----------------| |---------|-----------------------|------------|-----------|----------|----------------|
| **Agents** | 64 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 | N/A | | **Agents** | 65 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 | N/A |
| **Commands** | 84 | Shared | Instruction-based | 35 | 5 prompts | | **Commands** | 85 | Shared | Instruction-based | 35 | 5 prompts |
| **Skills** | 262 | Shared | 10 (native format) | 37 | Via instructions | | **Skills** | 263 | Shared | 10 (native format) | 37 | Via instructions |
| **Hook Events** | 8 types | 15 types | None yet | 11 types | None | | **Hook Events** | 8 types | 15 types | None yet | 11 types | None |
| **Hook Scripts** | 20+ scripts | 16 scripts (DRY adapter) | N/A | Plugin hooks | N/A | | **Hook Scripts** | 20+ scripts | 16 scripts (DRY adapter) | N/A | Plugin hooks | N/A |
| **Rules** | 34 (common + lang) | 34 (YAML frontmatter) | Instruction-based | 13 instructions | 1 always-on file | | **Rules** | 34 (common + lang) | 34 (YAML frontmatter) | Instruction-based | 13 instructions | 1 always-on file |

View File

@ -164,7 +164,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
/plugin list ecc@ecc /plugin list ecc@ecc
``` ```
**完成!** 你现在可以使用 64 个代理、262 个技能和 84 个命令。 **完成!** 你现在可以使用 65 个代理、263 个技能和 85 个命令。
### multi-* 命令需要额外配置 ### multi-* 命令需要额外配置

View File

@ -103,7 +103,7 @@ You DO NOT refactor or rewrite code — you report findings only.
### HIGH — State Management (Pinia) ### HIGH — State Management (Pinia)
- **Direct store property mutation without `$patch` or action**: Mutations outside actions lose devtools tracking and make state flow non-obvious. - **Scattered complex store mutations outside actions or `$patch()`**: Pinia allows direct state writes, but multi-field business mutations should live in actions or grouped `$patch()` calls so devtools history and state flow stay understandable.
- **Storing non-serializable data in Pinia state**: Saved state (SSR hydration, devtools, local persistence) won't survive round-trip. - **Storing non-serializable data in Pinia state**: Saved state (SSR hydration, devtools, local persistence) won't survive round-trip.
- **`mapState` / `mapActions` in Options API without proper typing**: Type inference breaks — prefer Composition API or declare full types. - **`mapState` / `mapActions` in Options API without proper typing**: Type inference breaks — prefer Composition API or declare full types.
- **Store action without error boundary**: Async store actions should handle failures and not leave state inconsistent. - **Store action without error boundary**: Async store actions should handle failures and not leave state inconsistent.

View File

@ -165,7 +165,6 @@ Recommendation: FAIL: Block merge until CRITICAL issue is fixed
- Run tests to ensure component tests pass - Run tests to ensure component tests pass
- Run `/vue-review` before merging Vue code - Run `/vue-review` before merging Vue code
- Use `/code-review` for non-Vue-specific concerns on the same PR - Use `/code-review` for non-Vue-specific concerns on the same PR
- Use `/vue-test` (if created) for Vue-specific test generation
## Related ## Related

View File

@ -1,6 +1,6 @@
{ {
"schemaVersion": 1, "schemaVersion": 1,
"totalCommands": 84, "totalCommands": 85,
"commands": [ "commands": [
{ {
"command": "aside", "command": "aside",
@ -919,6 +919,23 @@
"allAgents": [], "allAgents": [],
"skills": [], "skills": [],
"path": "commands/update-docs.md" "path": "commands/update-docs.md"
},
{
"command": "vue-review",
"description": "Comprehensive Vue.js code review for Composition API correctness, reactivity, composable patterns, template security, accessibility, and Vue-specific performance. Invokes the vue-reviewer agent (and typescript-reviewer alongside on .vue/.ts changes).",
"type": "testing",
"primaryAgents": [
"typescript-reviewer",
"vue-reviewer"
],
"allAgents": [
"typescript-reviewer",
"vue-reviewer"
],
"skills": [
"vue-patterns"
],
"path": "commands/vue-review.md"
} }
], ],
"statistics": { "statistics": {
@ -929,7 +946,7 @@
"planning": 2, "planning": 2,
"refactoring": 1, "refactoring": 1,
"review": 9, "review": 9,
"testing": 52 "testing": 53
}, },
"topAgents": [ "topAgents": [
{ {
@ -940,6 +957,10 @@
"agent": "flutter-reviewer", "agent": "flutter-reviewer",
"count": 2 "count": 2
}, },
{
"agent": "typescript-reviewer",
"count": 2
},
{ {
"agent": "cpp-build-resolver", "agent": "cpp-build-resolver",
"count": 1 "count": 1
@ -967,10 +988,6 @@
{ {
"agent": "planner", "agent": "planner",
"count": 1 "count": 1
},
{
"agent": "python-reviewer",
"count": 1
} }
], ],
"topSkills": [ "topSkills": [

View File

@ -1,6 +1,6 @@
# Everything Claude Code (ECC) — 智能体指令 # Everything Claude Code (ECC) — 智能体指令
这是一个**生产就绪的 AI 编码插件**,提供 64 个专业代理、262 项技能、84 条命令以及自动化钩子工作流,用于软件开发。 这是一个**生产就绪的 AI 编码插件**,提供 65 个专业代理、263 项技能、85 条命令以及自动化钩子工作流,用于软件开发。
**版本:** 2.0.0 **版本:** 2.0.0
@ -146,9 +146,9 @@
## 项目结构 ## 项目结构
``` ```
agents/ — 64 个专业子代理 agents/ — 65 个专业子代理
skills/ — 262 个工作流技能和领域知识 skills/ — 263 个工作流技能和领域知识
commands/ — 84 个斜杠命令 commands/ — 85 个斜杠命令
hooks/ — 基于触发的自动化 hooks/ — 基于触发的自动化
rules/ — 始终遵循的指导方针(通用 + 每种语言) rules/ — 始终遵循的指导方针(通用 + 每种语言)
scripts/ — 跨平台 Node.js 实用工具 scripts/ — 跨平台 Node.js 实用工具

View File

@ -228,7 +228,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
/plugin list ecc@ecc /plugin list ecc@ecc
``` ```
**搞定!** 你现在可以使用 64 个智能体、262 项技能和 84 个命令了。 **搞定!** 你现在可以使用 65 个智能体、263 项技能和 85 个命令了。
*** ***
@ -1140,9 +1140,9 @@ opencode
| 功能特性 | Claude Code | OpenCode | 状态 | | 功能特性 | Claude Code | OpenCode | 状态 |
|---------|---------------|----------|--------| |---------|---------------|----------|--------|
| 智能体 | PASS: 64 个 | PASS: 12 个 | **Claude Code 领先** | | 智能体 | PASS: 65 个 | PASS: 12 个 | **Claude Code 领先** |
| 命令 | PASS: 84 个 | PASS: 35 个 | **Claude Code 领先** | | 命令 | PASS: 85 个 | PASS: 35 个 | **Claude Code 领先** |
| 技能 | PASS: 262 项 | PASS: 37 项 | **Claude Code 领先** | | 技能 | PASS: 263 项 | PASS: 37 项 | **Claude Code 领先** |
| 钩子 | PASS: 8 种事件类型 | PASS: 11 种事件 | **OpenCode 更多!** | | 钩子 | PASS: 8 种事件类型 | PASS: 11 种事件 | **OpenCode 更多!** |
| 规则 | PASS: 29 条 | PASS: 13 条指令 | **Claude Code 领先** | | 规则 | PASS: 29 条 | PASS: 13 条指令 | **Claude Code 领先** |
| MCP 服务器 | PASS: 14 个 | PASS: 完整 | **完全对等** | | MCP 服务器 | PASS: 14 个 | PASS: 完整 | **完全对等** |
@ -1248,9 +1248,9 @@ ECC 是**第一个最大化利用每个主要 AI 编码工具的插件**。以
| 功能特性 | Claude Code | Cursor IDE | Codex CLI | OpenCode | | 功能特性 | Claude Code | Cursor IDE | Codex CLI | OpenCode |
|---------|-----------------------|------------|-----------|----------| |---------|-----------------------|------------|-----------|----------|
| **智能体** | 64 | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 | | **智能体** | 65 | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 |
| **命令** | 84 | 共享 | 基于指令 | 35 | | **命令** | 85 | 共享 | 基于指令 | 35 |
| **技能** | 262 | 共享 | 10 (原生格式) | 37 | | **技能** | 263 | 共享 | 10 (原生格式) | 37 |
| **钩子事件** | 8 种类型 | 15 种类型 | 暂无 | 11 种类型 | | **钩子事件** | 8 种类型 | 15 种类型 | 暂无 | 11 种类型 |
| **钩子脚本** | 20+ 个脚本 | 16 个脚本 (DRY 适配器) | N/A | 插件钩子 | | **钩子脚本** | 20+ 个脚本 | 16 个脚本 (DRY 适配器) | N/A | 插件钩子 |
| **规则** | 34 (通用 + 语言) | 34 (YAML 前页) | 基于指令 | 13 条指令 | | **规则** | 34 (通用 + 语言) | 34 (YAML 前页) | 基于指令 | 13 条指令 |

View File

@ -97,6 +97,14 @@
"framework-language" "framework-language"
] ]
}, },
{
"id": "framework:vue",
"family": "framework",
"description": "Vue.js, Nuxt, Pinia, and Vue Router engineering guidance. Currently resolves through the shared framework-language module.",
"modules": [
"framework-language"
]
},
{ {
"id": "framework:nextjs", "id": "framework:nextjs",
"family": "framework", "family": "framework",
@ -510,6 +518,14 @@
"framework-language" "framework-language"
] ]
}, },
{
"id": "skill:vue-patterns",
"family": "skill",
"description": "Vue.js 3 Composition API, reactivity, Pinia, Vue Router, and Nuxt SSR patterns.",
"modules": [
"framework-language"
]
},
{ {
"id": "skill:backend-patterns", "id": "skill:backend-patterns",
"family": "skill", "family": "skill",

View File

@ -183,7 +183,8 @@
"skills/springboot-patterns", "skills/springboot-patterns",
"skills/springboot-tdd", "skills/springboot-tdd",
"skills/springboot-verification", "skills/springboot-verification",
"skills/ui-to-vue" "skills/ui-to-vue",
"skills/vue-patterns"
], ],
"targets": [ "targets": [
"claude", "claude",

View File

@ -307,6 +307,7 @@
"skills/video-editing/", "skills/video-editing/",
"skills/videodb/", "skills/videodb/",
"skills/visa-doc-translate/", "skills/visa-doc-translate/",
"skills/vue-patterns/",
"skills/windows-desktop-e2e/", "skills/windows-desktop-e2e/",
"skills/workspace-surface-audit/", "skills/workspace-surface-audit/",
"skills/x-api/", "skills/x-api/",

View File

@ -75,7 +75,7 @@ watch(() => count, (newVal) => { ... });
When passing a destructured prop to a composable that needs reactivity, wrap in a getter and use `toValue()` inside the composable: When passing a destructured prop to a composable that needs reactivity, wrap in a getter and use `toValue()` inside the composable:
```ts ```ts
useDynamicCount(() => count); // preserves reactivity useDynamicCount(() => count); // preserves reactivity
``` ```
### Replacing reactive() Objects ### Replacing reactive() Objects
@ -132,7 +132,7 @@ const fullName = computed({
// WRONG: side effect in computed // WRONG: side effect in computed
const displayName = computed(() => { const displayName = computed(() => {
analytics.track("name-computed"); // side effect analytics.track("name-computed"); // side effect
return user.value.name; return user.value.name;
}); });
``` ```
@ -164,23 +164,19 @@ watchEffect(() => {
## Watcher Source Pitfalls ## Watcher Source Pitfalls
```ts ```ts
// WRONG: watching a ref object (never changes) // CORRECT: watching a ref tracks its value
const u = ref({ name: "Alice" }); const u = ref({ name: "Alice" });
watch(u, (val) => {}); // ❌ watches the ref wrapper, not the value watch(u, (val) => {});
// CORRECT: getter returning .value // ALSO CORRECT: getter returning .value
watch(() => u.value, (val) => {}); watch(() => u.value, (val) => {});
// ALSO WRONG: reactive getter that doesn't track
watch(() => state.name, (val) => {}); // ❌ val is snapshot at setup
// CORRECT: getter that accesses property on reactive object // CORRECT: getter that accesses property on reactive object
watch(() => state.name, (val) => {}); // ✅ .name access inside getter is tracked watch(() => state.name, (val) => {}); // .name access inside getter is tracked
// Wait — careful: `() => state.name` DOES track correctly because the getter // The getter is re-evaluated because it accesses `.name` on the reactive proxy.
// accesses `.name` on the reactive proxy. The getter is re-evaluated by Vue.
// ACTUALLY WRONG case: direct reactive property // WRONG: direct reactive property
watch(state.name, ...); // state.name evaluates to a primitive, not trackable watch(state.name, ...); // state.name evaluates to a primitive, not trackable
// CORRECT: getter returning reactive property // CORRECT: getter returning reactive property
watch(() => state.name, (newName) => { ... }); watch(() => state.name, (newName) => { ... });
@ -190,7 +186,7 @@ watch(() => state.name, (newName) => { ... });
Every watcher that creates subscriptions, intervals, or fetch requests must clean up. Every watcher that creates subscriptions, intervals, or fetch requests must clean up.
**Vue 3.5+**: Use `onWatcherCleanup()` (globally importable from `vue`) for watcher-side-effect cleanup: **Vue 3.5+**: Use `onWatcherCleanup()` (globally importable from `vue`) for watcher-side-effect cleanup. It must be called synchronously inside the watcher callback:
```ts ```ts
import { watch, onWatcherCleanup } from "vue"; import { watch, onWatcherCleanup } from "vue";
@ -319,7 +315,7 @@ Never initialize state, start timers, or subscribe to external systems in the mo
```ts ```ts
// WRONG: module scope side effect // WRONG: module scope side effect
const globalCount = ref(0); // shared across all components const globalCount = ref(0); // FAIL shared across all components
setInterval(() => globalCount.value++, 1000); setInterval(() => globalCount.value++, 1000);
export function useGlobalCount() { export function useGlobalCount() {
@ -342,7 +338,7 @@ Use `shallowRef()` for large immutable data structures that are replaced as a wh
```ts ```ts
const items = shallowRef<Item[]>([]); const items = shallowRef<Item[]>([]);
// items.value = await fetchItems(); // replacement works // items.value = await fetchItems(); // replacement works
// items.value[0].name = "new"; // inner mutations are NOT reactive // items.value[0].name = "new"; // FAIL inner mutations are NOT reactive
``` ```
Use `shallowReactive()` when only top-level properties should be reactive. Use `shallowReactive()` when only top-level properties should be reactive.

View File

@ -317,7 +317,7 @@ Use `<Teleport>` for modals, tooltips, notifications — content that must escap
```vue ```vue
<!-- defer: target can appear after the Teleport in the DOM --> <!-- defer: target can appear after the Teleport in the DOM -->
<Teleport defer target="#container"> <Teleport defer to="#container">
<p>Teleported content</p> <p>Teleported content</p>
</Teleport> </Teleport>
<div id="container"></div> <div id="container"></div>

View File

@ -83,7 +83,7 @@ app.directive("render-html", (el, binding) => {
```ts ```ts
// CRITICAL: secret leaked to client bundle (Vite) // CRITICAL: secret leaked to client bundle (Vite)
const apiKey = import.meta.env.VITE_STRIPE_SECRET; // VITE_ prefix = public const apiKey = import.meta.env.VITE_STRIPE_SECRET; // FAIL VITE_ prefix = public
// CORRECT: server-side only // CORRECT: server-side only
// vite.config.ts — never pass VITE_ prefixed secrets // vite.config.ts — never pass VITE_ prefixed secrets
@ -158,7 +158,7 @@ export default defineEventHandler(async (event) => {
```ts ```ts
// CRITICAL: session tokens in localStorage // CRITICAL: session tokens in localStorage
localStorage.setItem("token", jwt); // any XSS can read this localStorage.setItem("token", jwt); // FAIL any XSS can read this
// CORRECT: httpOnly cookie set by server // CORRECT: httpOnly cookie set by server
// Client never touches the token directly. // Client never touches the token directly.

View File

@ -201,7 +201,7 @@ export const useCartStore = defineStore("cart", () => {
``` ```
- Use Setup Store syntax (not Options Store). - Use Setup Store syntax (not Options Store).
- Actions: only place to mutate state. - Prefer actions for business-level mutations and `$patch()` for grouped updates.
- Every async action: handle loading + success + error. - Every async action: handle loading + success + error.
--- ---
@ -385,7 +385,7 @@ const { count = 0, msg = "hello" } = defineProps<{
}>(); }>();
// Limitation: cannot watch destructured prop directly // Limitation: cannot watch destructured prop directly
watch(() => count, (newVal) => { ... }); // getter required watch(() => count, (newVal) => { ... }); // PASS getter required
``` ```
### `useTemplateRef()` ### `useTemplateRef()`
@ -402,7 +402,7 @@ Supports dynamic ref IDs: `useTemplateRef(dynamicRefId)`.
### `onWatcherCleanup()` ### `onWatcherCleanup()`
Globally importable watcher cleanup API (Vue 3.5+): Globally importable watcher cleanup API (Vue 3.5+). It must be called synchronously inside the watcher callback:
```ts ```ts
import { watch, onWatcherCleanup } from "vue"; import { watch, onWatcherCleanup } from "vue";
@ -428,7 +428,7 @@ const id = useId();
`<Teleport defer>` allows teleporting to targets rendered in the same cycle: `<Teleport defer>` allows teleporting to targets rendered in the same cycle:
```vue ```vue
<Teleport defer target="#container">Content</Teleport> <Teleport defer to="#container">Content</Teleport>
<div id="container"></div> <div id="container"></div>
``` ```