Skip to content

Commit f9f555d

Browse files
committed
chore(copilot): update skills
1 parent 14b2d6b commit f9f555d

5 files changed

Lines changed: 86 additions & 18 deletions

File tree

.github/skills/common-workflows.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,25 +125,38 @@ export const vueltipPlugin = {
125125
**directive.ts:** Handles lifecycle + event listener setup/teardown
126126

127127
```typescript
128+
const LISTENERS: [
129+
event: string,
130+
handler: EventListener,
131+
][] = [
132+
['eventA', onEnter],
133+
['eventB', onLeave],
134+
]
135+
128136
export const vueltipDirective = {
129137
created: (el, binding) => {
130138
const key = generateKey()
139+
setContent(key, toContent(binding.value))
131140
el.setAttribute(getOption('keyAttribute'), key)
132-
setContent(key, toContent(binding.value)) // Module-level state
133-
el.addEventListener('mouseenter', onMouseover) // Stored reference
134-
el.addEventListener('mouseleave', onMouseout)
141+
for (const [event, handler] of LISTENERS) {
142+
el.addEventListener(event, handler)
143+
}
135144
},
136145
updated: (el, binding) => {
137-
// Re-sync content/placement on binding change
146+
// Re-sync state/attributes on binding change
138147
},
139148
beforeUnmount: (el) => {
140-
deleteContent(el.getAttribute(getOption('keyAttribute')))
141-
el.removeEventListener('mouseenter', onMouseover) // Must match
142-
el.removeEventListener('mouseleave', onMouseout)
149+
ensureKey(el, (key) => deleteContent(key))
150+
for (const [event, handler] of LISTENERS) {
151+
el.removeEventListener(event, handler)
152+
}
143153
},
144154
}
145155
```
146156

157+
**Durability note:** Keep this as a lifecycle template.
158+
Event names and attribute defaults can evolve.
159+
147160
### Composable Structure
148161

149162
**composables.ts:** Exposes floating UI + state binding for template
@@ -329,6 +342,7 @@ Enforces:
329342
- [ ] `pnpm test` passes
330343
- [ ] `pnpm lint` passes
331344
- [ ] `pnpm format` run
345+
- [ ] `pnpm typecheck` passes
332346
- [ ] Tests added for new code
333347
- [ ] `pnpm changeset` created
334348
- [ ] Demo updated (if user-facing)

.github/skills/instruction-validation.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
| Instructions match codebase | Read source files, compare patterns | Update instructions with real code examples |
88
| Examples are current | Check file links still exist | Update links or remove outdated examples |
99
| Patterns are cohesive | Cross-reference skills for consistency | Consolidate or clarify conflicting advice |
10+
| Instructions overfit internals | Scan for exact literals and private names | Replace with stable pattern + one concrete reference |
1011
| Anti-patterns are clear | Scan all ❌ marked items | Ensure each has explanation and correct approach |
1112
| Decision trees are accurate | Follow trees on real tasks | Add missing branches, remove irrelevant ones |
1213
| Completeness coverage | Map all file types and workflows | Add missing patterns, remove duplicates |
@@ -81,6 +82,7 @@ cat .github/skills/state-management.md | grep -A 10 "Event Handler Wrapper"
8182
| Same pattern explained differently | Search both skills for same keyword | Pick clearer explanation, remove duplicate |
8283
| Contradictory advice | Search for opposing ❌ markings | Determine which is correct, remove error |
8384
| Different terminology | Search for synonyms across skills | Standardize term usage everywhere |
85+
| Over-specific literals | Search defaults/attribute names in docs | Keep literals only when part of public API |
8486
| Missing links | Grep for file references | Verify all links exist, update if moved |
8587
| Outdated examples | Check line counts match | Update example code to match current file |
8688

@@ -105,6 +107,7 @@ wc -l packages/vueltip/src/state.ts # Should match any line ranges in examples
105107
2. Are line numbers accurate if provided?
106108
3. Would copying the code work as-is?
107109
4. Are imports complete and correct?
110+
5. Is this showing a durable pattern, not an unstable literal?
108111

109112
**Example check:**
110113

@@ -194,6 +197,7 @@ Before committing changes to any skill:
194197
- [ ] **Clarity**: Language is direct and unambiguous
195198
- [ ] **Consistency**: Terms match other skills
196199
- [ ] **Linkage**: All file links still valid
200+
- [ ] **Durability**: Guidance survives field/default renames
197201
- [ ] **Anti-patterns**: Each ❌ has ✅ fix shown
198202
- [ ] **Decision trees**: All branches covered
199203
- [ ] **Practicality**: Real-world applicability verified
@@ -259,6 +263,16 @@ done
259263

260264
## Red Flags: Patterns to Catch
261265

266+
**Red Flag 0: Docs mirror private internals too closely**
267+
```
268+
Instruction includes exact defaults and private key names
269+
270+
Small refactor causes many skill edits
271+
272+
Fix by documenting invariant behavior and linking to source
273+
for current literals
274+
```
275+
262276
**Red Flag 1: Example code doesn't compile**
263277
```typescript
264278
// ❌ Instruction shows:

.github/skills/package-structure.md

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ export type { PluginOptions } from './types'
5555
export { vueltipPlugin } from './plugin'
5656
export { vueltipDirective } from './directive'
5757
export { useVueltip } from './composables'
58-
export type { Placement, Content, Options } from './types'
58+
export type {
59+
PublicPayload,
60+
PublicValue,
61+
} from './types'
5962

6063
// ❌ Do NOT export:
6164
// export { hoveredElement, setContent } from './state' // Internal
@@ -98,7 +101,7 @@ packages/*/
98101
| File Type | Pattern | Export? | Example |
99102
|-----------|---------|---------|---------|
100103
| `index.ts` | Public API | Yes, only public | Composables, plugins, directives, types |
101-
| `types.ts` | All type definitions | Re-export public types from index.ts | `Content`, `Binding`, `Options` |
104+
| `types.ts` | All type definitions | Re-export public types from index.ts | Public content/value/options types |
102105
| `[feature].ts` | Feature logic | Only if public API | `debug.ts`, `directive.ts`, `plugin.ts` |
103106
| `listeners.ts` | Event handlers | No, internal | `onMouseover`, `onMouseout` |
104107
| `utils.ts` | Helper functions | No, internal | `isTruncated`, `isHtmlElement`, `elementContainsText` |
@@ -116,7 +119,14 @@ packages/*/
116119
```typescript
117120
// src/types.ts
118121
export type Placement = 'top' | 'bottom' | 'left' | 'right'
119-
export interface Content { text?: string }
122+
export interface PublicPayload {
123+
text: string | null | undefined
124+
}
125+
export type PublicValue =
126+
| string
127+
| null
128+
| undefined
129+
| (PublicPayload & { placement?: Placement })
120130
export interface Options { showDelay: number }
121131

122132
// Keep internal types here too - they stay private unless re-exported
@@ -133,10 +143,18 @@ declare module 'vue' {
133143

134144
```typescript
135145
// src/index.ts
136-
export type { Placement, Content, Options } from './types'
146+
export type {
147+
PublicPayload,
148+
PublicValue,
149+
Options,
150+
} from './types'
137151
// Don't re-export internal types
138152
```
139153

154+
> Prefer describing type *roles* (content/value/options,
155+
> public vs internal) rather than locking docs to exact
156+
> field names that may change during refactors.
157+
140158
---
141159

142160
## Dependencies

.github/skills/state-management.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
| Type-safe event handlers | Wrapper functions | None (stored ref) | `ensureEventTarget()` |
1313
| App configuration | Getter functions | None | `getOption()`, `setOptions()` |
1414

15+
> Durability rule: prefer stable patterns over exact
16+
> literals. Treat concrete default values and exact
17+
> attribute names as examples unless they are part of
18+
> documented public API.
19+
1520
---
1621

1722
## Decision Tree
@@ -166,13 +171,13 @@ scope.run(() => {
166171

167172
```typescript
168173
export const vueltipDirective = {
169-
created: (el, binding) => {
170-
el.addEventListener('mouseenter', onMouseover)
171-
el.addEventListener('focus', onMouseover)
174+
created: (el) => {
175+
el.addEventListener('eventA', handlerA)
176+
el.addEventListener('eventB', handlerB)
172177
},
173178
beforeUnmount: (el) => {
174-
el.removeEventListener('mouseenter', onMouseover)
175-
el.removeEventListener('focus', onMouseover)
179+
el.removeEventListener('eventA', handlerA)
180+
el.removeEventListener('eventB', handlerB)
176181
},
177182
}
178183
```
@@ -270,8 +275,9 @@ export const onMouseover = ensureEventTarget((target) => {
270275
import type { Options } from './types'
271276

272277
let options: Options = {
273-
placementAttribute: 'vueltip-placement',
274-
keyAttribute: 'vueltip-key',
278+
placementAttribute: DEFAULT_PLACEMENT_ATTRIBUTE,
279+
keyAttribute: DEFAULT_KEY_ATTRIBUTE,
280+
truncateAttribute: DEFAULT_TRUNCATE_ATTRIBUTE,
275281
showDelay: 0,
276282
hideDelay: 200,
277283
}
@@ -288,6 +294,8 @@ export const getOption = <T extends keyof Options>(
288294
**Critical:**
289295
- Provide typed getter: `getOption('showDelay')` returns `number`
290296
- Merge partial options: `{ ...defaults, ...provided }`
297+
- Keep defaults centralized in one module; avoid
298+
hardcoding the same literal in multiple files/docs
291299
- Keep internal: don't export `options` directly
292300
- Use in composables/directives to access config
293301

.github/skills/type-patterns.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,20 @@ declare module 'vue' {
143143
- Extend component props
144144
- Add module augmentation
145145

146+
**Vueltip custom data augmentation:**
147+
148+
```typescript
149+
declare module '@vingy/vueltip' {
150+
interface CustomVueltipData {
151+
userId?: number
152+
severity?: 'info' | 'warning' | 'error'
153+
}
154+
}
155+
156+
// Now content.custom is strongly typed:
157+
// v-tooltip="{ text: 'Profile', custom: { userId: 1 } }"
158+
```
159+
146160
**Anti-patterns:**
147161
- ❌ Ambient declarations for private types
148162
- ❌ Multiple ambient declarations in different files (consolidate in types.ts)

0 commit comments

Comments
 (0)