@ozerohax/assistagents 0.1.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 (82) hide show
  1. package/README.md +90 -0
  2. package/dist/cli.js +442 -0
  3. package/dist/cli.js.map +1 -0
  4. package/package.json +39 -0
  5. package/templates/agents/ask/ask.md +126 -0
  6. package/templates/agents/assist/research/code-research.md +116 -0
  7. package/templates/agents/assist/research/web-research.md +105 -0
  8. package/templates/agents/build/dev.md +131 -0
  9. package/templates/agents/planning/plan.md +103 -0
  10. package/templates/agents/planning/project.md +122 -0
  11. package/templates/agents/review/reviewer.md +121 -0
  12. package/templates/agents/test/tester.md +170 -0
  13. package/templates/skills/coder/csharp/coder-csharp-aspnetcore-api/SKILL.md +352 -0
  14. package/templates/skills/coder/csharp/coder-csharp-async-concurrency/SKILL.md +63 -0
  15. package/templates/skills/coder/csharp/coder-csharp-conventions/SKILL.md +405 -0
  16. package/templates/skills/coder/csharp/coder-csharp-efcore-config/SKILL.md +384 -0
  17. package/templates/skills/coder/csharp/coder-csharp-efcore-queries/SKILL.md +434 -0
  18. package/templates/skills/coder/csharp/coder-csharp-error-handling/SKILL.md +354 -0
  19. package/templates/skills/coder/csharp/coder-csharp-logging/SKILL.md +362 -0
  20. package/templates/skills/coder/csharp/coder-csharp-performance/SKILL.md +71 -0
  21. package/templates/skills/coder/csharp/coder-csharp-security/SKILL.md +57 -0
  22. package/templates/skills/coder/csharp/coder-csharp-testing/SKILL.md +398 -0
  23. package/templates/skills/coder/rust/coder-rust-async-concurrency/SKILL.md +63 -0
  24. package/templates/skills/coder/rust/coder-rust-axum-api/SKILL.md +104 -0
  25. package/templates/skills/coder/rust/coder-rust-conventions/SKILL.md +57 -0
  26. package/templates/skills/coder/rust/coder-rust-error-handling/SKILL.md +56 -0
  27. package/templates/skills/coder/rust/coder-rust-logging/SKILL.md +69 -0
  28. package/templates/skills/coder/rust/coder-rust-performance/SKILL.md +51 -0
  29. package/templates/skills/coder/rust/coder-rust-security/SKILL.md +49 -0
  30. package/templates/skills/coder/rust/coder-rust-serde/SKILL.md +61 -0
  31. package/templates/skills/coder/rust/coder-rust-sqlx-config/SKILL.md +54 -0
  32. package/templates/skills/coder/rust/coder-rust-sqlx-queries/SKILL.md +66 -0
  33. package/templates/skills/coder/rust/coder-rust-testing/SKILL.md +52 -0
  34. package/templates/skills/coder/rust/coder-rust-tokio/SKILL.md +69 -0
  35. package/templates/skills/coder/rust/coder-rust-tower-http/SKILL.md +56 -0
  36. package/templates/skills/coder/typescript/coder-typescript-async-concurrency/SKILL.md +73 -0
  37. package/templates/skills/coder/typescript/coder-typescript-conventions/SKILL.md +156 -0
  38. package/templates/skills/coder/typescript/coder-typescript-error-handling/SKILL.md +126 -0
  39. package/templates/skills/coder/typescript/coder-typescript-logging/SKILL.md +107 -0
  40. package/templates/skills/coder/typescript/coder-typescript-performance/SKILL.md +83 -0
  41. package/templates/skills/coder/typescript/coder-typescript-security/SKILL.md +78 -0
  42. package/templates/skills/coder/typescript/coder-typescript-testing/SKILL.md +111 -0
  43. package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-composables/SKILL.md +57 -0
  44. package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-core/SKILL.md +65 -0
  45. package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-performance/SKILL.md +48 -0
  46. package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-primevue/SKILL.md +140 -0
  47. package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-primevue/scripts/primevue-docs.js +502 -0
  48. package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-reactivity/SKILL.md +61 -0
  49. package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-testing/SKILL.md +63 -0
  50. package/templates/skills/planning/code/planning-code-feature/SKILL.md +148 -0
  51. package/templates/skills/planning/code/planning-code-fix/SKILL.md +207 -0
  52. package/templates/skills/planning/project/fast/planning-project-fast-delivery-deploy/SKILL.md +33 -0
  53. package/templates/skills/planning/project/fast/planning-project-fast-intake-questions/SKILL.md +82 -0
  54. package/templates/skills/planning/project/fast/planning-project-fast-mvp-slicing/SKILL.md +36 -0
  55. package/templates/skills/planning/project/fast/planning-project-fast-output-template/SKILL.md +79 -0
  56. package/templates/skills/planning/project/fast/planning-project-fast-session-plan/SKILL.md +30 -0
  57. package/templates/skills/planning/project/shared/planning-project-acceptance-criteria/SKILL.md +46 -0
  58. package/templates/skills/planning/project/shared/planning-project-artifact-storage/SKILL.md +68 -0
  59. package/templates/skills/planning/project/shared/planning-project-checkpoints-approval/SKILL.md +24 -0
  60. package/templates/skills/planning/project/shared/planning-project-save-revision/SKILL.md +33 -0
  61. package/templates/skills/planning/project/shared/planning-project-scope-control/SKILL.md +30 -0
  62. package/templates/skills/planning/project/shared/planning-project-success-metric-scope/SKILL.md +41 -0
  63. package/templates/skills/planning/project/shared/planning-project-task-decomposition/SKILL.md +47 -0
  64. package/templates/skills/planning/project/shared/planning-project-testing-validation/SKILL.md +31 -0
  65. package/templates/skills/planning/project/standard/planning-project-standard-architecture-adr-lite/SKILL.md +68 -0
  66. package/templates/skills/planning/project/standard/planning-project-standard-epics-stories/SKILL.md +41 -0
  67. package/templates/skills/planning/project/standard/planning-project-standard-implementation-readiness-lite/SKILL.md +32 -0
  68. package/templates/skills/planning/project/standard/planning-project-standard-prd-fr-nfr/SKILL.md +60 -0
  69. package/templates/skills/planning/project/standard/planning-project-standard-product-brief/SKILL.md +46 -0
  70. package/templates/skills/planning/project/standard/planning-project-standard-story-to-tasks/SKILL.md +52 -0
  71. package/templates/skills/research-strategy/research-strategy-code/SKILL.md +80 -0
  72. package/templates/skills/research-strategy/research-strategy-web/SKILL.md +63 -0
  73. package/templates/skills/review/review-checklists/SKILL.md +57 -0
  74. package/templates/skills/review/review-requirements/SKILL.md +42 -0
  75. package/templates/skills/review/review-strategy/SKILL.md +120 -0
  76. package/templates/skills/testing/testing-api-manual/SKILL.md +535 -0
  77. package/templates/skills/testing/testing-automation-web/SKILL.md +81 -0
  78. package/templates/skills/testing/testing-browser-manual/SKILL.md +528 -0
  79. package/templates/skills/testing/testing-checklists/SKILL.md +434 -0
  80. package/templates/skills/testing/testing-strategy/SKILL.md +471 -0
  81. package/templates/skills/testing/testing-test-cases/SKILL.md +362 -0
  82. package/templates/skills/testing/testing-triage-bugs/SKILL.md +457 -0
@@ -0,0 +1,502 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const BASE_URL = "https://primevue.org/llms";
5
+ const COMPONENTS_URL = `${BASE_URL}/components`;
6
+ const MAX_SEARCH_MATCHES = 50;
7
+
8
+ async function fetchText(url) {
9
+ const res = await fetch(url);
10
+ if (!res.ok) {
11
+ throw new Error(`Request failed: ${res.status} ${res.statusText} (${url})`);
12
+ }
13
+ return res.text();
14
+ }
15
+
16
+ function printUsage() {
17
+ const text = `
18
+ PrimeVue Documentation CLI Helper
19
+ =================================
20
+
21
+ Usage:
22
+ primevue-docs.js <command> [options]
23
+
24
+ Commands:
25
+ list List all available components with descriptions
26
+ list --names List component names only (one per line)
27
+ list --category <cat> Filter by category: form, data, panel, overlay, menu,
28
+ button, media, misc, directive
29
+
30
+ component <name> Get full documentation for a component
31
+ component <name> --props Show only props table
32
+ component <name> --events Show only events
33
+ component <name> --slots Show only slots
34
+ component <name> --examples Show only code examples
35
+
36
+ search <query> Search across all documentation
37
+ search <query> --context Show surrounding context (±3 lines)
38
+
39
+ guides List all available guides
40
+ guide <name> Get a specific guide (e.g., configuration, theming)
41
+
42
+ theming Get theming/styling documentation
43
+
44
+ help Show this help message
45
+
46
+ Examples:
47
+ primevue-docs.js list
48
+ primevue-docs.js list --category form
49
+ primevue-docs.js component datatable
50
+ primevue-docs.js component button --props
51
+ primevue-docs.js search "row selection"
52
+ primevue-docs.js search "virtual scroll" --context
53
+ primevue-docs.js guide configuration
54
+
55
+ Notes:
56
+ - Component names are case-insensitive
57
+ - Search is case-insensitive and matches partial words
58
+ - Data fetched from official PrimeVue LLM endpoints (primevue.org/llms/)
59
+ `.trim();
60
+ console.log(text);
61
+ }
62
+
63
+ /**
64
+ * Parse component entries from llms.txt
65
+ * Format: - [Vue Button Component](https://primevue.org/button): Description
66
+ */
67
+ function parseComponentsFromLlms(text) {
68
+ const components = [];
69
+ const lines = text.split(/\r?\n/);
70
+
71
+ // Match: - [Title](url): Description
72
+ const regex = /^-\s+\[([^\]]+)\]\(https:\/\/primevue\.org\/([^)]+)\):\s*(.*)$/;
73
+
74
+ let inComponentsSection = false;
75
+
76
+ for (const line of lines) {
77
+ // Detect components section
78
+ if (line.includes("## Components")) {
79
+ inComponentsSection = true;
80
+ continue;
81
+ }
82
+
83
+ // Stop at next section
84
+ if (inComponentsSection && line.startsWith("## ") && !line.includes("Components")) {
85
+ break;
86
+ }
87
+
88
+ if (!inComponentsSection) continue;
89
+
90
+ const match = line.match(regex);
91
+ if (match) {
92
+ const [, title, slug, description] = match;
93
+
94
+ // Skip guides and non-component entries
95
+ if (slug.includes("/") || slug === "mcp") continue;
96
+
97
+ // Determine category from title/description
98
+ let category = "misc";
99
+ const lowerTitle = title.toLowerCase();
100
+ const lowerDesc = description.toLowerCase();
101
+
102
+ if (/directive/i.test(title)) {
103
+ category = "directive";
104
+ } else if (/button|splitbutton|speeddial/i.test(slug)) {
105
+ category = "button";
106
+ } else if (/menu|menubar|megamenu|panelmenu|contextmenu|breadcrumb|dock|tabmenu|steps|tieredmenu/i.test(slug)) {
107
+ category = "menu";
108
+ } else if (/dialog|drawer|popover|confirmdialog|confirmpopup|dynamicdialog|tooltip|overlay/i.test(slug)) {
109
+ category = "overlay";
110
+ } else if (/panel|accordion|fieldset|card|divider|splitter|scrollpanel|tab|stepper|toolbar/i.test(slug)) {
111
+ category = "panel";
112
+ } else if (/datatable|dataview|tree|treetable|timeline|organizationchart|orderlist|picklist|paginator|virtualscroller/i.test(slug)) {
113
+ category = "data";
114
+ } else if (/input|select|checkbox|radio|toggle|slider|rating|knob|colorpicker|password|calendar|datepicker|autocomplete|multiselect|cascadeselect|listbox|editor|textarea|otp|mask|number|float|ifta|iconfield|fluid|form/i.test(slug)) {
115
+ category = "form";
116
+ } else if (/image|galleria|carousel|avatar|badge|chip|tag|skeleton|progressbar|progressspinner|meter|terminal/i.test(slug)) {
117
+ category = "media";
118
+ }
119
+
120
+ components.push({
121
+ name: slug,
122
+ title: title,
123
+ description: description.trim(),
124
+ category: category
125
+ });
126
+ }
127
+ }
128
+
129
+ return components;
130
+ }
131
+
132
+ /**
133
+ * Parse guides from llms.txt
134
+ */
135
+ function parseGuidesFromLlms(text) {
136
+ const guides = [];
137
+ const lines = text.split(/\r?\n/);
138
+
139
+ const regex = /^-\s+\[([^\]]+)\]\(https:\/\/primevue\.org\/([^)]+)\):\s*(.*)$/;
140
+
141
+ let inGuidesSection = false;
142
+
143
+ for (const line of lines) {
144
+ if (line.includes("## Guides")) {
145
+ inGuidesSection = true;
146
+ continue;
147
+ }
148
+
149
+ if (inGuidesSection && line.startsWith("## ")) {
150
+ break;
151
+ }
152
+
153
+ if (!inGuidesSection) continue;
154
+
155
+ const match = line.match(regex);
156
+ if (match) {
157
+ const [, title, slug, description] = match;
158
+ guides.push({
159
+ name: slug.replace(/^guides\//, ""),
160
+ title: title,
161
+ description: description.trim(),
162
+ url: `https://primevue.org/${slug}`
163
+ });
164
+ }
165
+ }
166
+
167
+ return guides;
168
+ }
169
+
170
+ async function listComponents(options = {}) {
171
+ const text = await fetchText(`${BASE_URL}/llms.txt`);
172
+ const components = parseComponentsFromLlms(text);
173
+
174
+ if (components.length === 0) {
175
+ console.log("No components found.");
176
+ return;
177
+ }
178
+
179
+ let filtered = components;
180
+
181
+ // Filter by category if specified
182
+ if (options.category) {
183
+ filtered = components.filter(c => c.category === options.category.toLowerCase());
184
+ if (filtered.length === 0) {
185
+ console.log(`No components found in category: ${options.category}`);
186
+ console.log("\nAvailable categories: form, data, panel, overlay, menu, button, media, misc, directive");
187
+ return;
188
+ }
189
+ }
190
+
191
+ // Names only mode
192
+ if (options.namesOnly) {
193
+ filtered.forEach(c => console.log(c.name));
194
+ return;
195
+ }
196
+
197
+ // Group by category
198
+ const grouped = {};
199
+ for (const comp of filtered) {
200
+ if (!grouped[comp.category]) {
201
+ grouped[comp.category] = [];
202
+ }
203
+ grouped[comp.category].push(comp);
204
+ }
205
+
206
+ const categoryOrder = ["form", "data", "panel", "overlay", "menu", "button", "media", "misc", "directive"];
207
+
208
+ for (const cat of categoryOrder) {
209
+ if (!grouped[cat]) continue;
210
+
211
+ console.log(`\n## ${cat.toUpperCase()}`);
212
+ console.log("─".repeat(60));
213
+
214
+ for (const comp of grouped[cat]) {
215
+ console.log(` ${comp.name.padEnd(20)} ${comp.description.slice(0, 60)}${comp.description.length > 60 ? "..." : ""}`);
216
+ }
217
+ }
218
+
219
+ console.log(`\nTotal: ${filtered.length} components`);
220
+ }
221
+
222
+ async function listGuides() {
223
+ const text = await fetchText(`${BASE_URL}/llms.txt`);
224
+ const guides = parseGuidesFromLlms(text);
225
+
226
+ if (guides.length === 0) {
227
+ console.log("No guides found.");
228
+ return;
229
+ }
230
+
231
+ console.log("\n## GUIDES");
232
+ console.log("─".repeat(60));
233
+
234
+ for (const guide of guides) {
235
+ console.log(` ${guide.name.padEnd(20)} ${guide.description.slice(0, 55)}${guide.description.length > 55 ? "..." : ""}`);
236
+ }
237
+
238
+ console.log(`\nTotal: ${guides.length} guides`);
239
+ }
240
+
241
+ async function getComponent(name, options = {}) {
242
+ if (!name) {
243
+ throw new Error("Missing component name. Use: primevue-docs.js component <name>");
244
+ }
245
+
246
+ const safeName = String(name).toLowerCase();
247
+ const url = `${COMPONENTS_URL}/${safeName}.md`;
248
+
249
+ let text;
250
+ try {
251
+ text = await fetchText(url);
252
+ } catch (err) {
253
+ // Try alternative names
254
+ const alternatives = {
255
+ "calendar": "datepicker",
256
+ "sidebar": "drawer",
257
+ "overlaypanel": "popover",
258
+ "inputswitch": "toggleswitch",
259
+ "chips": "chip",
260
+ "messages": "message",
261
+ "toast": "toast",
262
+ "navbar": "menubar",
263
+ "dropdown": "select"
264
+ };
265
+
266
+ if (alternatives[safeName]) {
267
+ console.log(`Note: "${safeName}" is now "${alternatives[safeName]}" in PrimeVue 4+\n`);
268
+ text = await fetchText(`${COMPONENTS_URL}/${alternatives[safeName]}.md`);
269
+ } else {
270
+ throw new Error(`Component "${name}" not found. Use "list" to see available components.`);
271
+ }
272
+ }
273
+
274
+ // Filter sections if requested
275
+ if (options.propsOnly) {
276
+ const propsSection = extractSection(text, "### Props", "###");
277
+ if (propsSection) {
278
+ console.log("## Props\n");
279
+ console.log(propsSection);
280
+ } else {
281
+ console.log("No props section found.");
282
+ }
283
+ return;
284
+ }
285
+
286
+ if (options.eventsOnly) {
287
+ const eventsSection = extractSection(text, "### Emits", "###") || extractSection(text, "### Events", "###");
288
+ if (eventsSection) {
289
+ console.log("## Events\n");
290
+ console.log(eventsSection);
291
+ } else {
292
+ console.log("No events section found.");
293
+ }
294
+ return;
295
+ }
296
+
297
+ if (options.slotsOnly) {
298
+ const slotsSection = extractSection(text, "### Slots", "###");
299
+ if (slotsSection) {
300
+ console.log("## Slots\n");
301
+ console.log(slotsSection);
302
+ } else {
303
+ console.log("No slots section found.");
304
+ }
305
+ return;
306
+ }
307
+
308
+ if (options.examplesOnly) {
309
+ const examples = extractCodeExamples(text);
310
+ if (examples.length > 0) {
311
+ console.log(`## Code Examples (${examples.length} found)\n`);
312
+ examples.forEach((ex, i) => {
313
+ console.log(`### Example ${i + 1}`);
314
+ console.log(ex);
315
+ console.log("");
316
+ });
317
+ } else {
318
+ console.log("No code examples found.");
319
+ }
320
+ return;
321
+ }
322
+
323
+ // Full documentation
324
+ console.log(text);
325
+ }
326
+
327
+ function extractSection(text, startMarker, endMarker) {
328
+ const startIdx = text.indexOf(startMarker);
329
+ if (startIdx === -1) return null;
330
+
331
+ const afterStart = text.slice(startIdx + startMarker.length);
332
+ const endIdx = afterStart.indexOf(endMarker);
333
+
334
+ if (endIdx === -1) {
335
+ return afterStart.trim();
336
+ }
337
+
338
+ return afterStart.slice(0, endIdx).trim();
339
+ }
340
+
341
+ function extractCodeExamples(text) {
342
+ const examples = [];
343
+ const regex = /```vue([\s\S]*?)```/g;
344
+
345
+ let match;
346
+ while ((match = regex.exec(text)) !== null) {
347
+ examples.push(match[1].trim());
348
+ }
349
+
350
+ return examples;
351
+ }
352
+
353
+ async function searchDocs(query, options = {}) {
354
+ if (!query) {
355
+ throw new Error("Missing search query. Use: primevue-docs.js search <query>");
356
+ }
357
+
358
+ const url = `${BASE_URL}/llms-full.txt`;
359
+ const text = await fetchText(url);
360
+ const q = String(query).toLowerCase();
361
+ const lines = text.split(/\r?\n/);
362
+
363
+ let matches = 0;
364
+ const contextLines = options.context ? 3 : 0;
365
+
366
+ for (let i = 0; i < lines.length; i++) {
367
+ const line = lines[i];
368
+ if (line.toLowerCase().includes(q)) {
369
+ matches++;
370
+
371
+ if (contextLines > 0) {
372
+ console.log(`\n--- Match ${matches} (line ${i + 1}) ---`);
373
+ const start = Math.max(0, i - contextLines);
374
+ const end = Math.min(lines.length - 1, i + contextLines);
375
+ for (let j = start; j <= end; j++) {
376
+ const prefix = j === i ? ">>>" : " ";
377
+ console.log(`${prefix} ${j + 1}: ${lines[j]}`);
378
+ }
379
+ } else {
380
+ console.log(`${i + 1}: ${line}`);
381
+ }
382
+
383
+ if (matches >= MAX_SEARCH_MATCHES) {
384
+ console.log(`\n[Stopped at ${MAX_SEARCH_MATCHES} matches]`);
385
+ return;
386
+ }
387
+ }
388
+ }
389
+
390
+ if (matches === 0) {
391
+ console.log(`No matches found for "${query}".`);
392
+ } else {
393
+ console.log(`\n[Found ${matches} matches]`);
394
+ }
395
+ }
396
+
397
+ async function getGuide(name) {
398
+ if (!name) {
399
+ throw new Error("Missing guide name. Use: primevue-docs.js guide <name>");
400
+ }
401
+
402
+ const safeName = String(name).toLowerCase();
403
+
404
+ // Try direct guide URL first
405
+ let url = `${BASE_URL}/guides/${safeName}.md`;
406
+
407
+ try {
408
+ const text = await fetchText(url);
409
+ console.log(text);
410
+ } catch {
411
+ // Try without guides/ prefix
412
+ url = `${BASE_URL}/${safeName}.md`;
413
+ try {
414
+ const text = await fetchText(url);
415
+ console.log(text);
416
+ } catch {
417
+ throw new Error(`Guide "${name}" not found. Use "guides" to list available guides.`);
418
+ }
419
+ }
420
+ }
421
+
422
+ async function getTheming() {
423
+ // Fetch styled mode documentation
424
+ const text = await fetchText(`${BASE_URL}/styled.md`);
425
+ console.log(text);
426
+ }
427
+
428
+ async function main() {
429
+ const args = process.argv.slice(2);
430
+ const command = args[0];
431
+
432
+ if (!command || command === "-h" || command === "--help" || command === "help") {
433
+ printUsage();
434
+ return;
435
+ }
436
+
437
+ // Parse flags
438
+ const hasFlag = (flag) => args.includes(flag);
439
+ const getFlagValue = (flag) => {
440
+ const idx = args.indexOf(flag);
441
+ if (idx !== -1 && args[idx + 1]) {
442
+ return args[idx + 1];
443
+ }
444
+ return null;
445
+ };
446
+
447
+ switch (command) {
448
+ case "list":
449
+ case "list-components":
450
+ await listComponents({
451
+ namesOnly: hasFlag("--names"),
452
+ category: getFlagValue("--category")
453
+ });
454
+ return;
455
+
456
+ case "guides":
457
+ case "list-guides":
458
+ await listGuides();
459
+ return;
460
+
461
+ case "guide":
462
+ await getGuide(args[1]);
463
+ return;
464
+
465
+ case "component":
466
+ case "comp":
467
+ case "c":
468
+ await getComponent(args[1], {
469
+ propsOnly: hasFlag("--props"),
470
+ eventsOnly: hasFlag("--events"),
471
+ slotsOnly: hasFlag("--slots"),
472
+ examplesOnly: hasFlag("--examples")
473
+ });
474
+ return;
475
+
476
+ case "search":
477
+ case "s":
478
+ await searchDocs(args.slice(1).filter(a => !a.startsWith("--")).join(" "), {
479
+ context: hasFlag("--context")
480
+ });
481
+ return;
482
+
483
+ case "theming":
484
+ case "theme":
485
+ case "styled":
486
+ await getTheming();
487
+ return;
488
+
489
+ default:
490
+ // Assume it's a component name if not recognized
491
+ if (!command.startsWith("-")) {
492
+ await getComponent(command);
493
+ return;
494
+ }
495
+ throw new Error(`Unknown command: ${command}`);
496
+ }
497
+ }
498
+
499
+ main().catch((err) => {
500
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
501
+ process.exit(1);
502
+ });
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: coder-typescript-vuejs-reactivity
3
+ description: Vue 3 reactivity best practices: ref/reactive, computed, watch/watchEffect, and lifecycle-safe patterns.
4
+ ---
5
+ <skill_overview>
6
+ <purpose>Use Vue reactivity correctly and efficiently with TypeScript</purpose>
7
+ <triggers>
8
+ <trigger>Managing component state with refs and reactive objects</trigger>
9
+ <trigger>Deriving state with computed</trigger>
10
+ <trigger>Responding to changes with watch or watchEffect</trigger>
11
+ </triggers>
12
+ <sources>
13
+ <source url="https://vuejs.org/guide/essentials/reactivity-fundamentals">Reactivity Fundamentals</source>
14
+ <source url="https://vuejs.org/guide/essentials/computed">Computed Properties</source>
15
+ <source url="https://vuejs.org/guide/essentials/watchers">Watchers</source>
16
+ <source url="https://vuejs.org/api/reactivity-core">Reactivity API</source>
17
+ </sources>
18
+ </skill_overview>
19
+ <ref_vs_reactive>
20
+ <rules>
21
+ <rule>Use ref for primitives; use reactive for objects</rule>
22
+ <rule>Prefer shallowRef/shallowReactive for large immutable structures</rule>
23
+ <rule>Avoid destructuring reactive objects without toRefs</rule>
24
+ </rules>
25
+ <example>
26
+ <code>
27
+ const state = reactive({ count: 0, label: "A" });
28
+ const { count } = toRefs(state);
29
+ </code>
30
+ </example>
31
+ </ref_vs_reactive>
32
+ <computed>
33
+ <rules>
34
+ <rule>Use computed for derived state that needs caching</rule>
35
+ <rule>Keep computed getters side-effect free</rule>
36
+ <rule>Prefer computed over methods for values used in templates</rule>
37
+ </rules>
38
+ <example>
39
+ <code>
40
+ const total = computed(() => items.value.reduce((sum, i) => sum + i.price, 0));
41
+ </code>
42
+ </example>
43
+ </computed>
44
+ <watchers>
45
+ <rules>
46
+ <rule>Use watch for explicit sources and async side effects</rule>
47
+ <rule>Use watchEffect for automatic dependency tracking</rule>
48
+ <rule>Clean up effects with onCleanup when needed</rule>
49
+ </rules>
50
+ </watchers>
51
+ <reactive_props>
52
+ <rules>
53
+ <rule>Prefer defineProps with types for clarity</rule>
54
+ <rule>Do not mutate props; derive local state if needed</rule>
55
+ </rules>
56
+ </reactive_props>
57
+ <anti_patterns>
58
+ <avoid name="deep_watch">Deep watch on large objects without need</avoid>
59
+ <avoid name="computed_side_effects">Side effects inside computed getters</avoid>
60
+ <avoid name="lost_reactivity">Destructuring reactive without toRefs</avoid>
61
+ </anti_patterns>
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: coder-typescript-vuejs-testing
3
+ description: Vue 3 testing best practices: unit, component, and e2e tests with recommended tooling.
4
+ ---
5
+ <skill_overview>
6
+ <purpose>Test Vue components and composables with fast, reliable patterns</purpose>
7
+ <triggers>
8
+ <trigger>Writing unit tests for logic or composables</trigger>
9
+ <trigger>Testing components and slots</trigger>
10
+ <trigger>Adding end-to-end coverage</trigger>
11
+ </triggers>
12
+ <sources>
13
+ <source url="https://vuejs.org/guide/scaling-up/testing">Testing</source>
14
+ <source url="https://test-utils.vuejs.org/guide/">Vue Test Utils</source>
15
+ </sources>
16
+ </skill_overview>
17
+ <test_types>
18
+ <unit>
19
+ <description>Test composables and pure logic in isolation</description>
20
+ </unit>
21
+ <component>
22
+ <description>Test component behavior via props, events, and slots</description>
23
+ </component>
24
+ <e2e>
25
+ <description>Test full user flows in a real browser</description>
26
+ </e2e>
27
+ </test_types>
28
+ <tooling>
29
+ <rules>
30
+ <rule>Use Vitest for unit tests in Vite projects</rule>
31
+ <rule>Use Vue Test Utils for component testing</rule>
32
+ <rule>Use Playwright or Cypress for e2e</rule>
33
+ </rules>
34
+ </tooling>
35
+ <component_testing>
36
+ <rules>
37
+ <rule>Test public behavior, not implementation details</rule>
38
+ <rule>Use async/await for updates after trigger/setValue</rule>
39
+ <rule>Prefer shallow mocks only when necessary</rule>
40
+ </rules>
41
+ <example>
42
+ <code>
43
+ import { render } from "@testing-library/vue";
44
+ import MyComponent from "./MyComponent.vue";
45
+
46
+ test("renders title", () => {
47
+ const { getByText } = render(MyComponent, { props: { title: "Hello" } });
48
+ getByText("Hello");
49
+ });
50
+ </code>
51
+ </example>
52
+ </component_testing>
53
+ <composables_testing>
54
+ <rules>
55
+ <rule>Call composables directly when they only use reactivity</rule>
56
+ <rule>Wrap composables with a host app when lifecycle is required</rule>
57
+ </rules>
58
+ </composables_testing>
59
+ <anti_patterns>
60
+ <avoid name="testing_internals">Asserting on private state or methods</avoid>
61
+ <avoid name="flaky_time">Real timers instead of fake or deterministic inputs</avoid>
62
+ <avoid name="over_mocking">Mocking Vue internals unnecessarily</avoid>
63
+ </anti_patterns>