@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.
- package/README.md +90 -0
- package/dist/cli.js +442 -0
- package/dist/cli.js.map +1 -0
- package/package.json +39 -0
- package/templates/agents/ask/ask.md +126 -0
- package/templates/agents/assist/research/code-research.md +116 -0
- package/templates/agents/assist/research/web-research.md +105 -0
- package/templates/agents/build/dev.md +131 -0
- package/templates/agents/planning/plan.md +103 -0
- package/templates/agents/planning/project.md +122 -0
- package/templates/agents/review/reviewer.md +121 -0
- package/templates/agents/test/tester.md +170 -0
- package/templates/skills/coder/csharp/coder-csharp-aspnetcore-api/SKILL.md +352 -0
- package/templates/skills/coder/csharp/coder-csharp-async-concurrency/SKILL.md +63 -0
- package/templates/skills/coder/csharp/coder-csharp-conventions/SKILL.md +405 -0
- package/templates/skills/coder/csharp/coder-csharp-efcore-config/SKILL.md +384 -0
- package/templates/skills/coder/csharp/coder-csharp-efcore-queries/SKILL.md +434 -0
- package/templates/skills/coder/csharp/coder-csharp-error-handling/SKILL.md +354 -0
- package/templates/skills/coder/csharp/coder-csharp-logging/SKILL.md +362 -0
- package/templates/skills/coder/csharp/coder-csharp-performance/SKILL.md +71 -0
- package/templates/skills/coder/csharp/coder-csharp-security/SKILL.md +57 -0
- package/templates/skills/coder/csharp/coder-csharp-testing/SKILL.md +398 -0
- package/templates/skills/coder/rust/coder-rust-async-concurrency/SKILL.md +63 -0
- package/templates/skills/coder/rust/coder-rust-axum-api/SKILL.md +104 -0
- package/templates/skills/coder/rust/coder-rust-conventions/SKILL.md +57 -0
- package/templates/skills/coder/rust/coder-rust-error-handling/SKILL.md +56 -0
- package/templates/skills/coder/rust/coder-rust-logging/SKILL.md +69 -0
- package/templates/skills/coder/rust/coder-rust-performance/SKILL.md +51 -0
- package/templates/skills/coder/rust/coder-rust-security/SKILL.md +49 -0
- package/templates/skills/coder/rust/coder-rust-serde/SKILL.md +61 -0
- package/templates/skills/coder/rust/coder-rust-sqlx-config/SKILL.md +54 -0
- package/templates/skills/coder/rust/coder-rust-sqlx-queries/SKILL.md +66 -0
- package/templates/skills/coder/rust/coder-rust-testing/SKILL.md +52 -0
- package/templates/skills/coder/rust/coder-rust-tokio/SKILL.md +69 -0
- package/templates/skills/coder/rust/coder-rust-tower-http/SKILL.md +56 -0
- package/templates/skills/coder/typescript/coder-typescript-async-concurrency/SKILL.md +73 -0
- package/templates/skills/coder/typescript/coder-typescript-conventions/SKILL.md +156 -0
- package/templates/skills/coder/typescript/coder-typescript-error-handling/SKILL.md +126 -0
- package/templates/skills/coder/typescript/coder-typescript-logging/SKILL.md +107 -0
- package/templates/skills/coder/typescript/coder-typescript-performance/SKILL.md +83 -0
- package/templates/skills/coder/typescript/coder-typescript-security/SKILL.md +78 -0
- package/templates/skills/coder/typescript/coder-typescript-testing/SKILL.md +111 -0
- package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-composables/SKILL.md +57 -0
- package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-core/SKILL.md +65 -0
- package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-performance/SKILL.md +48 -0
- package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-primevue/SKILL.md +140 -0
- package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-primevue/scripts/primevue-docs.js +502 -0
- package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-reactivity/SKILL.md +61 -0
- package/templates/skills/coder/typescript/coder-typescript-vuejs/coder-typescript-vuejs-testing/SKILL.md +63 -0
- package/templates/skills/planning/code/planning-code-feature/SKILL.md +148 -0
- package/templates/skills/planning/code/planning-code-fix/SKILL.md +207 -0
- package/templates/skills/planning/project/fast/planning-project-fast-delivery-deploy/SKILL.md +33 -0
- package/templates/skills/planning/project/fast/planning-project-fast-intake-questions/SKILL.md +82 -0
- package/templates/skills/planning/project/fast/planning-project-fast-mvp-slicing/SKILL.md +36 -0
- package/templates/skills/planning/project/fast/planning-project-fast-output-template/SKILL.md +79 -0
- package/templates/skills/planning/project/fast/planning-project-fast-session-plan/SKILL.md +30 -0
- package/templates/skills/planning/project/shared/planning-project-acceptance-criteria/SKILL.md +46 -0
- package/templates/skills/planning/project/shared/planning-project-artifact-storage/SKILL.md +68 -0
- package/templates/skills/planning/project/shared/planning-project-checkpoints-approval/SKILL.md +24 -0
- package/templates/skills/planning/project/shared/planning-project-save-revision/SKILL.md +33 -0
- package/templates/skills/planning/project/shared/planning-project-scope-control/SKILL.md +30 -0
- package/templates/skills/planning/project/shared/planning-project-success-metric-scope/SKILL.md +41 -0
- package/templates/skills/planning/project/shared/planning-project-task-decomposition/SKILL.md +47 -0
- package/templates/skills/planning/project/shared/planning-project-testing-validation/SKILL.md +31 -0
- package/templates/skills/planning/project/standard/planning-project-standard-architecture-adr-lite/SKILL.md +68 -0
- package/templates/skills/planning/project/standard/planning-project-standard-epics-stories/SKILL.md +41 -0
- package/templates/skills/planning/project/standard/planning-project-standard-implementation-readiness-lite/SKILL.md +32 -0
- package/templates/skills/planning/project/standard/planning-project-standard-prd-fr-nfr/SKILL.md +60 -0
- package/templates/skills/planning/project/standard/planning-project-standard-product-brief/SKILL.md +46 -0
- package/templates/skills/planning/project/standard/planning-project-standard-story-to-tasks/SKILL.md +52 -0
- package/templates/skills/research-strategy/research-strategy-code/SKILL.md +80 -0
- package/templates/skills/research-strategy/research-strategy-web/SKILL.md +63 -0
- package/templates/skills/review/review-checklists/SKILL.md +57 -0
- package/templates/skills/review/review-requirements/SKILL.md +42 -0
- package/templates/skills/review/review-strategy/SKILL.md +120 -0
- package/templates/skills/testing/testing-api-manual/SKILL.md +535 -0
- package/templates/skills/testing/testing-automation-web/SKILL.md +81 -0
- package/templates/skills/testing/testing-browser-manual/SKILL.md +528 -0
- package/templates/skills/testing/testing-checklists/SKILL.md +434 -0
- package/templates/skills/testing/testing-strategy/SKILL.md +471 -0
- package/templates/skills/testing/testing-test-cases/SKILL.md +362 -0
- 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>
|