@silverassist/agents-toolkit 2.0.0

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 (51) hide show
  1. package/LICENSE +135 -0
  2. package/README.md +388 -0
  3. package/bin/cli.js +940 -0
  4. package/package.json +52 -0
  5. package/src/index.js +58 -0
  6. package/templates/agents/AGENTS.codex.md +195 -0
  7. package/templates/agents/AGENTS.md +195 -0
  8. package/templates/agents/CLAUDE.md +213 -0
  9. package/templates/agents/copilot-instructions.md +83 -0
  10. package/templates/shared/instructions/css-styling.instructions.md +142 -0
  11. package/templates/shared/instructions/documentation-language.instructions.md +216 -0
  12. package/templates/shared/instructions/github-workflow.instructions.md +245 -0
  13. package/templates/shared/instructions/php-standards.instructions.md +293 -0
  14. package/templates/shared/instructions/react-components.instructions.md +196 -0
  15. package/templates/shared/instructions/server-actions.instructions.md +429 -0
  16. package/templates/shared/instructions/testing-standards.instructions.md +264 -0
  17. package/templates/shared/instructions/tests.instructions.md +103 -0
  18. package/templates/shared/instructions/typescript.instructions.md +106 -0
  19. package/templates/shared/instructions/wordpress-plugin-architecture.instructions.md +238 -0
  20. package/templates/shared/prompts/README.md +129 -0
  21. package/templates/shared/prompts/_partials/README.md +57 -0
  22. package/templates/shared/prompts/_partials/documentation.md +203 -0
  23. package/templates/shared/prompts/_partials/git-operations.md +171 -0
  24. package/templates/shared/prompts/_partials/github-integration.md +100 -0
  25. package/templates/shared/prompts/_partials/jira-integration.md +155 -0
  26. package/templates/shared/prompts/_partials/pr-template.md +216 -0
  27. package/templates/shared/prompts/_partials/validations.md +87 -0
  28. package/templates/shared/prompts/add-tests.prompt.md +151 -0
  29. package/templates/shared/prompts/analyze-github-issue.prompt.md +73 -0
  30. package/templates/shared/prompts/analyze-ticket.prompt.md +63 -0
  31. package/templates/shared/prompts/create-plan.prompt.md +118 -0
  32. package/templates/shared/prompts/create-pr.prompt.md +139 -0
  33. package/templates/shared/prompts/finalize-pr.prompt.md +150 -0
  34. package/templates/shared/prompts/fix-issues.prompt.md +92 -0
  35. package/templates/shared/prompts/new-wp-component.prompt.md +51 -0
  36. package/templates/shared/prompts/new-wp-plugin.prompt.md +46 -0
  37. package/templates/shared/prompts/prepare-pr.prompt.md +123 -0
  38. package/templates/shared/prompts/prepare-release.prompt.md +74 -0
  39. package/templates/shared/prompts/quality-check.prompt.md +45 -0
  40. package/templates/shared/prompts/review-code.prompt.md +81 -0
  41. package/templates/shared/prompts/work-github-issue.prompt.md +96 -0
  42. package/templates/shared/prompts/work-ticket.prompt.md +98 -0
  43. package/templates/shared/skills/README.md +53 -0
  44. package/templates/shared/skills/component-architecture/SKILL.md +321 -0
  45. package/templates/shared/skills/create-component/SKILL.md +714 -0
  46. package/templates/shared/skills/domain-driven-design/SKILL.md +277 -0
  47. package/templates/shared/skills/plugin-creation/SKILL.md +1094 -0
  48. package/templates/shared/skills/quality-checks/SKILL.md +493 -0
  49. package/templates/shared/skills/release-management/SKILL.md +649 -0
  50. package/templates/shared/skills/testing/SKILL.md +682 -0
  51. package/templates/shared/skills/testing-patterns/SKILL.md +243 -0
@@ -0,0 +1,196 @@
1
+ ---
2
+ applyTo: "**/components/**/*.tsx"
3
+ ---
4
+ # React Component Standards
5
+
6
+ ## Component Structure
7
+
8
+ **✅ ALWAYS use folder structure** with `index.tsx`:
9
+
10
+ ```
11
+ components/
12
+ └── domain/ # Domain folder (auth, checkout, etc.)
13
+ ├── index.ts # Barrel export for domain
14
+ └── component-name/ # kebab-case folder
15
+ ├── index.tsx # Main component (export default)
16
+ ├── types.ts # Component-specific types (if needed)
17
+ └── __tests__/ # Tests folder
18
+ └── component-name.test.tsx
19
+ ```
20
+
21
+ ## Export Pattern
22
+
23
+ ### Components: Default Export
24
+
25
+ Per Next.js recommendation, components use `export default` for better tree-shaking:
26
+
27
+ ```tsx
28
+ // ✅ CORRECT: Default export for components
29
+ interface ButtonProps {
30
+ onClick: () => void;
31
+ children: React.ReactNode;
32
+ }
33
+
34
+ export default function Button({ onClick, children }: ButtonProps) {
35
+ return <button onClick={onClick}>{children}</button>;
36
+ }
37
+
38
+ // ❌ INCORRECT: Named export for components (worse tree-shaking)
39
+ export function Button({ onClick, children }: ButtonProps) {
40
+ return <button onClick={onClick}>{children}</button>;
41
+ }
42
+
43
+ // ❌ INCORRECT: Arrow function (loses name in stack traces)
44
+ export default const Button = ({ onClick, children }: ButtonProps) => {
45
+ return <button onClick={onClick}>{children}</button>;
46
+ };
47
+ ```
48
+
49
+ ### Barrel Exports for Domains
50
+
51
+ Re-export components from domain `index.ts`:
52
+
53
+ ```typescript
54
+ // src/components/auth/index.ts
55
+ export { default as LoginForm } from "./login-form";
56
+ export { default as RegisterForm } from "./register-form";
57
+
58
+ // Usage - clean imports
59
+ import { LoginForm, RegisterForm } from "@/components/auth";
60
+ ```
61
+
62
+ ### Non-Components: Named Exports
63
+
64
+ Helpers, types, hooks use named exports:
65
+
66
+ ```typescript
67
+ // types.ts
68
+ export interface User { }
69
+ export type Status = "active" | "inactive";
70
+
71
+ // helpers.ts
72
+ export function formatUserName(user: User): string { }
73
+ ```
74
+
75
+ ## Server vs Client Components
76
+
77
+ ### Server Component (Default)
78
+
79
+ ```tsx
80
+ // src/components/dashboard/stats-card/index.tsx
81
+ import { getStats } from "@/data/stats";
82
+
83
+ interface StatsCardProps {
84
+ title: string;
85
+ }
86
+
87
+ export default async function StatsCard({ title }: StatsCardProps) {
88
+ const stats = await getStats(); // Direct data fetching
89
+
90
+ return (
91
+ <div>
92
+ <h3>{title}</h3>
93
+ <p>{stats.value}</p>
94
+ </div>
95
+ );
96
+ }
97
+ ```
98
+
99
+ ### Client Component (Interactive)
100
+
101
+ ```tsx
102
+ // src/components/checkout/add-to-cart/index.tsx
103
+ "use client";
104
+
105
+ import { useState } from "react";
106
+
107
+ interface AddToCartProps {
108
+ productId: string;
109
+ }
110
+
111
+ export default function AddToCart({ productId }: AddToCartProps) {
112
+ const [quantity, setQuantity] = useState(1);
113
+
114
+ return (
115
+ <button onClick={() => setQuantity(q => q + 1)}>
116
+ Add ({quantity})
117
+ </button>
118
+ );
119
+ }
120
+ ```
121
+
122
+ ## Props Interface
123
+
124
+ **✅ ALWAYS define props interface inside the component file**:
125
+
126
+ ```tsx
127
+ // ✅ CORRECT: Interface defined in component file
128
+ interface UserCardProps {
129
+ user: User;
130
+ onSelect?: (user: User) => void;
131
+ className?: string;
132
+ }
133
+
134
+ export default function UserCard({ user, onSelect, className }: UserCardProps) {
135
+ return (
136
+ <div className={className}>
137
+ <h2>{user.name}</h2>
138
+ </div>
139
+ );
140
+ }
141
+ ```
142
+
143
+ ## Hook Placement (CRITICAL)
144
+
145
+ **✅ ALL hooks MUST come BEFORE any conditional returns**:
146
+
147
+ ```tsx
148
+ // ✅ CORRECT: Hooks first, then early returns
149
+ export default function UserList({ users }: UserListProps) {
150
+ const [filter, setFilter] = useState("");
151
+ const filteredUsers = useMemo(() =>
152
+ users.filter(u => u.name.includes(filter)),
153
+ [users, filter]
154
+ );
155
+
156
+ // Early returns AFTER all hooks
157
+ if (!users?.length) {
158
+ return <p>No users found</p>;
159
+ }
160
+
161
+ return <ul>{/* ... */}</ul>;
162
+ }
163
+
164
+ // ❌ INCORRECT: Hook after conditional
165
+ export default function UserList({ users }: UserListProps) {
166
+ if (!users?.length) return null; // ❌ Early return before hooks
167
+
168
+ const [filter, setFilter] = useState(""); // ❌ Error!
169
+ return <ul>{/* ... */}</ul>;
170
+ }
171
+ ```
172
+
173
+ ## Event Handlers
174
+
175
+ **✅ Use `handle` prefix** for event handlers:
176
+
177
+ ```tsx
178
+ import type { ChangeEvent, SyntheticEvent } from "react";
179
+
180
+ export default function Form() {
181
+ const handleSubmit = (e: SyntheticEvent<HTMLFormElement>) => {
182
+ e.preventDefault();
183
+ // ...
184
+ };
185
+
186
+ const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
187
+ // ...
188
+ };
189
+
190
+ return (
191
+ <form onSubmit={handleSubmit}>
192
+ <input onChange={handleInputChange} />
193
+ </form>
194
+ );
195
+ }
196
+ ```
@@ -0,0 +1,429 @@
1
+ ---
2
+ applyTo: "**/actions/**/*.ts"
3
+ ---
4
+ # Server Actions Standards
5
+
6
+ > **Security First**: Server Actions create public HTTP endpoints. Treat them with the same
7
+ > security assumptions as any public API endpoint.
8
+
9
+ ## File Structure
10
+
11
+ Organize actions by domain (consistent with DDD principles):
12
+
13
+ ```
14
+ actions/
15
+ ├── auth/
16
+ │ ├── login.ts
17
+ │ └── register.ts
18
+ ├── user/
19
+ │ └── update-profile.ts
20
+ └── contact/
21
+ └── submit-form.ts
22
+ data/ # Data Access Layer (DAL)
23
+ ├── user-dto.ts
24
+ ├── auth.ts
25
+ └── db.ts
26
+ ```
27
+
28
+ For smaller projects, flat structure is acceptable:
29
+
30
+ ```
31
+ actions/
32
+ ├── auth-actions.ts
33
+ ├── user-actions.ts
34
+ └── contact-actions.ts
35
+ data/
36
+ ├── dal.ts # Centralized Data Access Layer
37
+ └── dto.ts # Data Transfer Objects
38
+ ```
39
+
40
+ ## Security Architecture
41
+
42
+ ### Data Access Layer (DAL)
43
+
44
+ **CRITICAL**: Create a dedicated Data Access Layer for all data operations. Never access
45
+ databases or sensitive data directly in Server Actions.
46
+
47
+ ```typescript
48
+ // data/dal.ts
49
+ import "server-only";
50
+ import { cache } from "react";
51
+ import { cookies } from "next/headers";
52
+
53
+ /**
54
+ * Cached user retrieval - safe to call multiple times
55
+ * Uses React cache to deduplicate requests within a render
56
+ */
57
+ export const getCurrentUser = cache(async () => {
58
+ const cookieStore = await cookies();
59
+ const token = cookieStore.get("AUTH_TOKEN");
60
+ const decodedToken = await decryptAndValidate(token);
61
+
62
+ // Return minimal, safe user object - NOT the full database record
63
+ return new User(decodedToken.id);
64
+ });
65
+
66
+ /**
67
+ * Get user profile with authorization checks
68
+ * Returns only safe, filtered data (DTO pattern)
69
+ */
70
+ export async function getUserProfileDTO(userId: string) {
71
+ const currentUser = await getCurrentUser();
72
+ const userData = await db.user.findUnique({ where: { id: userId } });
73
+
74
+ // Return only authorized fields
75
+ return {
76
+ username: canSeeUsername(currentUser) ? userData.username : null,
77
+ email: canSeeEmail(currentUser, userData) ? userData.email : null,
78
+ // Never expose: password, tokens, internal IDs, etc.
79
+ };
80
+ }
81
+ ```
82
+
83
+ ### Server-Only Marker
84
+
85
+ **CRITICAL**: Always mark DAL files with `server-only` to prevent client-side imports:
86
+
87
+ ```typescript
88
+ // data/dal.ts
89
+ import "server-only";
90
+
91
+ // This file will cause a build error if imported in client code
92
+ ```
93
+
94
+ Install the package: `npm install server-only`
95
+
96
+ ## Action Pattern
97
+
98
+ ```typescript
99
+ "use server";
100
+
101
+ import { revalidatePath } from "next/cache";
102
+ import { getCurrentUser } from "@/data/dal";
103
+ import { createUserInDB } from "@/data/user-dto";
104
+
105
+ /**
106
+ * State returned from server actions
107
+ */
108
+ interface ActionState {
109
+ success: boolean;
110
+ message: string;
111
+ data?: unknown;
112
+ errors?: Record<string, string>;
113
+ }
114
+
115
+ /**
116
+ * Creates a new user
117
+ * @param prevState - Previous form state
118
+ * @param formData - Form data from submission
119
+ * @returns Action result state
120
+ */
121
+ export async function createUser(
122
+ prevState: ActionState,
123
+ formData: FormData
124
+ ): Promise<ActionState> {
125
+ try {
126
+ // 1. ALWAYS verify authentication first
127
+ const user = await getCurrentUser();
128
+ if (!user) {
129
+ return {
130
+ success: false,
131
+ message: "You must be signed in to perform this action",
132
+ };
133
+ }
134
+
135
+ // 2. ALWAYS verify authorization
136
+ if (!user.canCreateUsers) {
137
+ return {
138
+ success: false,
139
+ message: "You do not have permission to create users",
140
+ };
141
+ }
142
+
143
+ // 3. ALWAYS validate ALL inputs (never trust client data)
144
+ const name = formData.get("name") as string;
145
+ const email = formData.get("email") as string;
146
+
147
+ if (!name || !email) {
148
+ return {
149
+ success: false,
150
+ message: "Missing required fields",
151
+ errors: {
152
+ name: !name ? "Name is required" : "",
153
+ email: !email ? "Email is required" : "",
154
+ },
155
+ };
156
+ }
157
+
158
+ // 4. Use DAL for data operations (never direct DB access)
159
+ const result = await createUserInDB({ name, email });
160
+
161
+ // 5. Revalidate cache after mutations
162
+ revalidatePath("/users");
163
+
164
+ return {
165
+ success: true,
166
+ message: "User created successfully",
167
+ data: result, // Return only safe DTO, not raw DB result
168
+ };
169
+ } catch (error) {
170
+ return {
171
+ success: false,
172
+ message: error instanceof Error ? error.message : "Unknown error",
173
+ };
174
+ }
175
+ }
176
+ ```
177
+
178
+ ## Security Rules (CRITICAL)
179
+
180
+ ### 1. Always use "use server" directive
181
+ ```typescript
182
+ "use server";
183
+ ```
184
+
185
+ ### 2. ALWAYS authenticate and authorize
186
+ ```typescript
187
+ // ❌ INCORRECT: No auth check
188
+ export async function deleteUser(userId: string) {
189
+ await db.user.delete({ where: { id: userId } });
190
+ }
191
+
192
+ // ✅ CORRECT: Auth + authz before any operation
193
+ export async function deleteUser(userId: string) {
194
+ const currentUser = await getCurrentUser();
195
+ if (!currentUser) {
196
+ throw new Error("You must be signed in");
197
+ }
198
+ if (!currentUser.isAdmin && currentUser.id !== userId) {
199
+ throw new Error("Not authorized");
200
+ }
201
+ await deleteUserFromDB(userId); // Use DAL
202
+ }
203
+ ```
204
+
205
+ ### 3. NEVER trust client input
206
+ ```typescript
207
+ // ❌ INCORRECT: Trusting client data
208
+ export async function updateRole(formData: FormData) {
209
+ const isAdmin = formData.get("isAdmin") === "true";
210
+ await db.user.update({ data: { isAdmin } }); // Vulnerable!
211
+ }
212
+
213
+ // ✅ CORRECT: Re-verify permissions server-side
214
+ export async function updateRole(formData: FormData) {
215
+ const currentUser = await getCurrentUser();
216
+ if (!currentUser?.isSuperAdmin) {
217
+ return { success: false, message: "Not authorized" };
218
+ }
219
+ // Now safe to proceed...
220
+ }
221
+ ```
222
+
223
+ ### 4. Return state, don't redirect
224
+ ```typescript
225
+ // ❌ INCORRECT: Don't call redirect in actions
226
+ redirect("/success");
227
+
228
+ // ✅ CORRECT: Return state and handle redirect in client
229
+ return { success: true, redirectTo: "/success" };
230
+ ```
231
+
232
+ ### 5. Validate all inputs with schema validation
233
+ ```typescript
234
+ import { z } from "zod";
235
+
236
+ const CreateUserSchema = z.object({
237
+ name: z.string().min(2).max(100),
238
+ email: z.string().email(),
239
+ });
240
+
241
+ export async function createUser(prevState: ActionState, formData: FormData) {
242
+ const validatedFields = CreateUserSchema.safeParse({
243
+ name: formData.get("name"),
244
+ email: formData.get("email"),
245
+ });
246
+
247
+ if (!validatedFields.success) {
248
+ return {
249
+ success: false,
250
+ message: "Invalid fields",
251
+ errors: validatedFields.error.flatten().fieldErrors,
252
+ };
253
+ }
254
+
255
+ // Use validatedFields.data (sanitized)
256
+ }
257
+ ```
258
+
259
+ ### 6. Handle errors gracefully (don't leak internals)
260
+ ```typescript
261
+ try {
262
+ // action logic
263
+ } catch (error) {
264
+ // Log full error server-side
265
+ console.error("Action error:", error);
266
+
267
+ // Return generic message to client (don't expose internals)
268
+ return {
269
+ success: false,
270
+ message: "An error occurred. Please try again.",
271
+ };
272
+ }
273
+ ```
274
+
275
+ ### 7. Revalidate after mutations
276
+ ```typescript
277
+ revalidatePath("/affected-path");
278
+ // or
279
+ revalidateTag("users");
280
+ ```
281
+
282
+ ### 8. Avoid mutations during rendering
283
+ ```typescript
284
+ // ❌ INCORRECT: Side effect during render
285
+ export default async function Page({ searchParams }) {
286
+ if (searchParams.get("logout")) {
287
+ cookies().delete("AUTH_TOKEN"); // Bad!
288
+ }
289
+ return <div>...</div>;
290
+ }
291
+
292
+ // ✅ CORRECT: Use Server Action
293
+ export default function Page() {
294
+ return (
295
+ <form action={logout}>
296
+ <button type="submit">Logout</button>
297
+ </form>
298
+ );
299
+ }
300
+ ```
301
+
302
+ ## Closures Security
303
+
304
+ When defining Server Actions inside components, be aware that closed-over variables
305
+ are sent to the client (encrypted). Never close over sensitive data:
306
+
307
+ ```typescript
308
+ // ⚠️ Sensitive data in closure (encrypted but still transmitted)
309
+ export default async function Page() {
310
+ const secretKey = process.env.SECRET_KEY; // Don't do this!
311
+
312
+ async function submit() {
313
+ "use server";
314
+ // secretKey is captured and sent to client (encrypted)
315
+ }
316
+
317
+ return <form action={submit}>...</form>;
318
+ }
319
+
320
+ // ✅ CORRECT: Read secrets inside the action
321
+ export default function Page() {
322
+ async function submit() {
323
+ "use server";
324
+ const secretKey = process.env.SECRET_KEY; // Safe - read server-side
325
+ }
326
+
327
+ return <form action={submit}>...</form>;
328
+ }
329
+ ```
330
+
331
+ ## Using with useActionState
332
+
333
+ ```tsx
334
+ "use client";
335
+
336
+ import { useActionState } from "react";
337
+ import { createUser } from "@/actions/user-actions";
338
+
339
+ const initialState = { success: false, message: "" };
340
+
341
+ export function UserForm() {
342
+ const [state, formAction, isPending] = useActionState(
343
+ createUser,
344
+ initialState
345
+ );
346
+
347
+ return (
348
+ <form action={formAction}>
349
+ <input name="name" required />
350
+ <input name="email" type="email" required />
351
+ <button type="submit" disabled={isPending}>
352
+ {isPending ? "Saving..." : "Save"}
353
+ </button>
354
+ {state.message && (
355
+ <p role="alert" className={state.success ? "text-green-600" : "text-red-600"}>
356
+ {state.message}
357
+ </p>
358
+ )}
359
+ </form>
360
+ );
361
+ }
362
+ ```
363
+
364
+ ## Troubleshooting
365
+
366
+ ### Error: "Failed to find Server Action"
367
+
368
+ **Cause**: Next.js creates encrypted, non-deterministic IDs for Server Actions. These IDs
369
+ are recalculated between builds. In multi-server environments (self-hosted), each instance
370
+ may have different encryption keys.
371
+
372
+ **Solutions**:
373
+
374
+ 1. **Self-hosting with multiple servers**: Configure a consistent encryption key:
375
+ ```bash
376
+ # .env
377
+ NEXT_SERVER_ACTIONS_ENCRYPTION_KEY="your-aes-gcm-encrypted-key"
378
+ ```
379
+ The key must be AES-GCM encrypted and consistent across all servers.
380
+
381
+ 2. **Vercel**: Use [Skew Protection](https://vercel.com/docs/deployments/skew-protection) to
382
+ keep assets and functions from previous versions available after a deploy.
383
+
384
+ 3. **Local development**: If it occurs in development, restart the dev server (`npm run dev`).
385
+
386
+ 4. **Corrupted cache**: Clear the Next.js cache:
387
+ ```bash
388
+ rm -rf .next
389
+ npm run build
390
+ ```
391
+
392
+ ### Error: Action doesn't execute / Does nothing
393
+
394
+ Verify that:
395
+ - The function has `"use server"` at the top of the file OR inside the function
396
+ - The form uses `action={formAction}` (not `onSubmit`)
397
+ - There are no JavaScript errors in the browser console
398
+
399
+ ### Error: "Functions cannot be passed directly to Client Components"
400
+
401
+ ```typescript
402
+ // ❌ INCORRECT: Passing function directly
403
+ <ClientComponent onSubmit={serverAction} />
404
+
405
+ // ✅ CORRECT: Use in form action or useActionState
406
+ <form action={serverAction}>...</form>
407
+
408
+ // ✅ CORRECT: Wrap in client component
409
+ "use client";
410
+ export function FormWrapper({ action }) {
411
+ const [state, formAction] = useActionState(action, initialState);
412
+ return <form action={formAction}>...</form>;
413
+ }
414
+ ```
415
+
416
+ ## Security Checklist
417
+
418
+ Before deploying any Server Action, verify:
419
+
420
+ - [ ] `"use server"` directive is present
421
+ - [ ] User is authenticated (if required)
422
+ - [ ] User is authorized for the specific action
423
+ - [ ] All inputs are validated (use Zod or similar)
424
+ - [ ] Data access goes through DAL (not direct DB queries)
425
+ - [ ] No sensitive data in closures
426
+ - [ ] Error messages don't leak internal details
427
+ - [ ] Cache is revalidated after mutations
428
+ - [ ] DAL files are marked with `server-only`
429
+ - [ ] `NEXT_SERVER_ACTIONS_ENCRYPTION_KEY` configured (if multi-server self-hosting)