@3lineas/grooveskills 1.1.2 → 1.3.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 +112 -84
- package/dist/{chunk-5Q6O3BRA.js → chunk-M7ZPBGQE.js} +279 -90
- package/dist/chunk-M7ZPBGQE.js.map +1 -0
- package/dist/cli.js +4 -3
- package/dist/cli.js.map +1 -1
- package/dist/main.d.ts +3 -0
- package/dist/main.js +1 -1
- package/package.json +1 -1
- package/skills/clean-architecture-ddd/SKILL.md +103 -0
- package/skills/error-handling-logging/SKILL.md +105 -0
- package/skills/error-handling-logging/templates/app-error.template.md +44 -0
- package/skills/error-handling-logging/templates/logger.template.md +41 -0
- package/skills/groove-harness/SKILL.md +14 -14
- package/skills/odd-ai/SKILL.md +64 -0
- package/skills/odd-ai/references/odd-protocol-examples.md +57 -0
- package/skills/python-clean/SKILL.md +113 -0
- package/skills/python-clean/references/python-tooling-and-types.md +78 -0
- package/skills/rust-clean/SKILL.md +119 -0
- package/skills/rust-clean/references/rust-error-and-clippy.md +92 -0
- package/skills/testing-vitest/SKILL.md +109 -0
- package/skills/typescript-clean/SKILL.md +111 -0
- package/skills/typescript-clean/references/js-ts-antipatterns.md +91 -0
- package/skills/ux-writing/SKILL.md +103 -0
- package/skills/ux-writing/references/copy-patterns-es-en.md +54 -0
- package/skills/valibot-validation/SKILL.md +102 -0
- package/dist/chunk-5Q6O3BRA.js.map +0 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: typescript-clean
|
|
3
|
+
description: Advanced TypeScript 5.5+ standards, strict tsconfig rules, discriminated unions, satisfies operator, const type parameters, unknown over any, custom type guards, and elimination of unsafe type assertions (as / any). TRIGGER when writing or modifying TypeScript files (.ts, .tsx), type definitions, tsconfig.json, or when handling complex polymorphic domain models.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TypeScript Clean Code Standards (TS 5.5+)
|
|
7
|
+
|
|
8
|
+
Guidelines for writing safe, expressive, and strictly typed TypeScript with zero unsafe casts, exhaustive pattern matching, and modern language features.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Golden Rules (Non-negotiable)
|
|
13
|
+
|
|
14
|
+
1. **Zero `any` and Zero Non-null Assertions (`!`)**:
|
|
15
|
+
- `any` disables the compiler and hides runtime bugs. Use `unknown` with narrowers or generics.
|
|
16
|
+
- Non-null assertion operator `!` assumes runtime state without proof. Use optional chaining `?.` or explicit guard clauses.
|
|
17
|
+
|
|
18
|
+
2. **Discriminated Unions for Domain States**:
|
|
19
|
+
- Represent valid combinations of state using tagged unions (`type = "idle" | "loading" | "success" | "error"`).
|
|
20
|
+
- Never use "optional soup" where every field is `x?: string`.
|
|
21
|
+
|
|
22
|
+
3. **Exhaustive Type Checking with `never`**:
|
|
23
|
+
- Every `switch` or conditional on a union must have an `assertNever(value)` exhaustive check in default branch.
|
|
24
|
+
|
|
25
|
+
4. **Favor `satisfies` Over Type Annotations on Literals**:
|
|
26
|
+
- `satisfies` checks that a value adheres to a contract without widening or discarding specific literal types.
|
|
27
|
+
|
|
28
|
+
5. **`const` Type Parameters (TS 5.0+)**:
|
|
29
|
+
- Use `<const T>` in generic helper functions to preserve literal types without requiring `as const` at call site.
|
|
30
|
+
|
|
31
|
+
6. **Custom Type Guards & Inferred Type Predicates (TS 5.5+)**:
|
|
32
|
+
- Use type predicates (`x is TargetType`) or rely on TS 5.5 automatic type narrowing for array filters.
|
|
33
|
+
|
|
34
|
+
7. **Avoid Unsafe `as` Type Assertions**:
|
|
35
|
+
- Never use `value as SomeType` to bypass the type checker. Validate with Valibot schema or custom type guard first.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. Key Patterns
|
|
40
|
+
|
|
41
|
+
### A. Discriminated Unions & Exhaustiveness
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
export type RequestState<T> =
|
|
45
|
+
| { status: "idle" }
|
|
46
|
+
| { status: "loading" }
|
|
47
|
+
| { status: "success"; data: T }
|
|
48
|
+
| { status: "error"; error: Error };
|
|
49
|
+
|
|
50
|
+
export function assertNever(x: never): never {
|
|
51
|
+
throw new Error(`Unexpected value: ${JSON.stringify(x)}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function renderStatus<T>(state: RequestState<T>): string {
|
|
55
|
+
switch (state.status) {
|
|
56
|
+
case "idle":
|
|
57
|
+
return "Ready to start.";
|
|
58
|
+
case "loading":
|
|
59
|
+
return "Loading data...";
|
|
60
|
+
case "success":
|
|
61
|
+
return "Data loaded successfully.";
|
|
62
|
+
case "error":
|
|
63
|
+
return state.error.message;
|
|
64
|
+
default:
|
|
65
|
+
return assertNever(state);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### B. `satisfies` vs Widening Annotations
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
type RouteConfig = Record<string, { path: string; isProtected: boolean }>;
|
|
74
|
+
|
|
75
|
+
// ✅ Preserves exact key literals and structure
|
|
76
|
+
export const APP_ROUTES = {
|
|
77
|
+
HOME: { path: "/", isProtected: false },
|
|
78
|
+
DASHBOARD: { path: "/dashboard", isProtected: true },
|
|
79
|
+
} satisfies RouteConfig;
|
|
80
|
+
|
|
81
|
+
// APP_ROUTES.HOME.path is typed as "/" not string!
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### C. Const Generic Parameters
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
export function createEnumSet<const T extends readonly string[]>(values: T): ReadonlySet<T[number]> {
|
|
88
|
+
return new Set(values);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Inferred as ReadonlySet<"admin" | "editor" | "viewer">
|
|
92
|
+
export const ROLES = createEnumSet(["admin", "editor", "viewer"]);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 3. Strict TSConfig Expectations
|
|
98
|
+
|
|
99
|
+
Always enable:
|
|
100
|
+
- `"strict": true`
|
|
101
|
+
- `"noUncheckedIndexedAccess": true`
|
|
102
|
+
- `"noImplicitOverride": true`
|
|
103
|
+
- `"exactOptionalPropertyTypes": true` (where library ecosystem allows)
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 4. Sibling Skills
|
|
108
|
+
|
|
109
|
+
- **`best-practices`**: Universal clean code rules and 200-line limit.
|
|
110
|
+
- **`valibot-validation`**: Runtime validation inferred to static TS types.
|
|
111
|
+
- Reference guide: `references/js-ts-antipatterns.md`.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# TypeScript & JavaScript Antipatterns Reference
|
|
2
|
+
|
|
3
|
+
Common antipatterns in modern TypeScript codebases and how to refactor them.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Antipattern: The `any` Escape Hatch
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// ❌ WRONG: disables compiler checks
|
|
11
|
+
function parsePayload(raw: any) {
|
|
12
|
+
return raw.user.id;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ✅ CORRECT: unknown with schema validation or guard
|
|
16
|
+
import * as v from "valibot";
|
|
17
|
+
|
|
18
|
+
const UserPayloadSchema = v.object({
|
|
19
|
+
user: v.object({ id: v.string() }),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function parsePayload(raw: unknown): string {
|
|
23
|
+
const parsed = v.parse(UserPayloadSchema, raw);
|
|
24
|
+
return parsed.user.id;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 2. Antipattern: Non-null Assertion (`!`)
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
// ❌ WRONG: crashes if element is missing
|
|
34
|
+
const element = document.getElementById("submit-btn")!;
|
|
35
|
+
element.addEventListener("click", () => {});
|
|
36
|
+
|
|
37
|
+
// ✅ CORRECT: early guard clause
|
|
38
|
+
const element = document.getElementById("submit-btn");
|
|
39
|
+
if (!element) {
|
|
40
|
+
throw new Error("Submit button element not found in DOM.");
|
|
41
|
+
}
|
|
42
|
+
element.addEventListener("click", () => {});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. Antipattern: Type Assertion (`as Type`) Bypass
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// ❌ WRONG: compiler lies to itself; runtime crash later
|
|
51
|
+
const user = JSON.parse(response) as User;
|
|
52
|
+
|
|
53
|
+
// ✅ CORRECT: parse with Valibot schema
|
|
54
|
+
const user = v.parse(UserSchema, JSON.parse(response));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 4. Antipattern: Optional Soup (Unrepresentable States)
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
// ❌ WRONG: allows impossible state { isLoading: true, error: "fail", data: [...] }
|
|
63
|
+
interface State {
|
|
64
|
+
isLoading?: boolean;
|
|
65
|
+
data?: string[];
|
|
66
|
+
error?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ✅ CORRECT: Discriminated Union
|
|
70
|
+
type State =
|
|
71
|
+
| { status: "idle" }
|
|
72
|
+
| { status: "loading" }
|
|
73
|
+
| { status: "success"; data: string[] }
|
|
74
|
+
| { status: "error"; error: string };
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 5. Antipattern: Magic Enums in TypeScript
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// ❌ WRONG: numeric TS enums emit runtime objects and loose typing
|
|
83
|
+
enum UserRole {
|
|
84
|
+
Admin,
|
|
85
|
+
Editor,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ✅ CORRECT: const objects or union literals
|
|
89
|
+
export const USER_ROLES = ["admin", "editor"] as const;
|
|
90
|
+
export type UserRole = (typeof USER_ROLES)[number];
|
|
91
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ux-writing
|
|
3
|
+
description: Opinionated user-facing microcopy standards (error messages, form validation, button CTAs, empty states, toasts, notifications, and tooltips). Bilingual adaptive (Spanish priority, English fallback), empathetic, solution-oriented, persuasive, and professional. TRIGGER when authoring or reviewing user-visible messages, form field errors, confirmation dialogs, toasts, or landing/CTA copy.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UX Writing & Microcopy Standards
|
|
7
|
+
|
|
8
|
+
Guidelines for crafting persuasive, polite, empathetic, and solution-oriented microcopy for web and mobile interfaces.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Golden Rules (Non-negotiable)
|
|
13
|
+
|
|
14
|
+
1. **Solution-Oriented Feedback (Never Dead-End the User)**:
|
|
15
|
+
- Never say just "Error" or "Invalid format". State clearly what happened and provide the exact next step to resolve it.
|
|
16
|
+
- ❌ *"Error 500: Failed request"*
|
|
17
|
+
- ✅ *"No pudimos guardar tus cambios. Por favor, revisa tu conexión e inténtalo de nuevo."*
|
|
18
|
+
|
|
19
|
+
2. **Adaptive Bilingual First (Spanish Priority, Fluent English)**:
|
|
20
|
+
- Support Spanish (neutral Latin American / modern Spanish) and English natively.
|
|
21
|
+
- When default locale is Spanish: use warm, respectful tone (tuteo profesional: "tu cuenta", "introduce tu contraseña").
|
|
22
|
+
- When default locale is English: crisp, engaging, modern SaaS voice.
|
|
23
|
+
- Keep terminology consistent across locales. See `references/copy-patterns-es-en.md`.
|
|
24
|
+
|
|
25
|
+
3. **Active, Benefit-Driven CTAs (Call To Action)**:
|
|
26
|
+
- Button labels must start with an action verb reflecting the outcome, not the mechanism.
|
|
27
|
+
- ❌ *"Enviar"* / *"Submit"*
|
|
28
|
+
- ✅ *"Crear mi cuenta gratis"* / *"Create free account"*, *"Guardar cambios"* / *"Save changes"*
|
|
29
|
+
|
|
30
|
+
4. **Persuasive and Empathetic Tone**:
|
|
31
|
+
- Acknowledge effort and eliminate friction.
|
|
32
|
+
- Celebrate milestones and progress (e.g. *"¡Todo listo! Tu perfil ya está actualizado"*).
|
|
33
|
+
- Never blame the user (avoid *"Cometiste un error"* or *"You did not provide"*).
|
|
34
|
+
|
|
35
|
+
5. **Clarity Over Cleverness**:
|
|
36
|
+
- Avoid technical jargon, system stack traces, HTTP codes, or database column names in user-facing UI.
|
|
37
|
+
- Keep messages under 2 short sentences whenever possible.
|
|
38
|
+
|
|
39
|
+
6. **Predictable Placement & Semantics**:
|
|
40
|
+
- Inline form errors: specific to the input field, positioned right under it.
|
|
41
|
+
- Toast notifications: brief confirmations or non-blocking warnings.
|
|
42
|
+
- Dialogs / Modals: critical actions requiring explicit confirmation with clear consequences.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 2. Microcopy Decision Matrix
|
|
47
|
+
|
|
48
|
+
| Context | Tone | ❌ Avoid | ✅ Recommended (ES / EN) |
|
|
49
|
+
| :--- | :--- | :--- | :--- |
|
|
50
|
+
| **Required Field** | Direct, polite | *"Campo obligatorio"* | *"Ingresa tu correo para continuar"* / *"Enter your email to continue"* |
|
|
51
|
+
| **Invalid Format** | Instructive | *"Email incorrecto"* | *"Usa un formato como nombre@ejemplo.com"* / *"Use a format like name@example.com"* |
|
|
52
|
+
| **Password Weak** | Actionable guide | *"Clave insegura"* | *"Usa al menos 8 caracteres con números y letras"* / *"Use at least 8 characters with letters and numbers"* |
|
|
53
|
+
| **Server Timeout** | Empathetic retry | *"Error de red 504"* | *"El servidor tardó en responder. Reintenta en unos segundos."* / *"Server took too long. Please retry in a few seconds."* |
|
|
54
|
+
| **Delete Confirm** | Clear impact | *"¿Seguro?"* | *"¿Eliminar este proyecto? Esta acción no se puede deshacer."* / *"Delete this project? This action cannot be undone."* |
|
|
55
|
+
| **Empty State** | Inspiring action | *"No hay datos"* | *"Aún no tienes tareas creadas. ¡Comienza agregando la primera!"* / *"No tasks created yet. Start by adding your first one!"* |
|
|
56
|
+
| **Success Toast** | Encouraging | *"Operación exitosa"* | *"¡Cambios guardados con éxito!"* / *"Changes saved successfully!"* |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 3. Form Validation Copy Pattern (Valibot Integration)
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import * as v from "valibot";
|
|
64
|
+
|
|
65
|
+
export const signupSchema = v.object({
|
|
66
|
+
fullName: v.pipe(
|
|
67
|
+
v.string("Ingresa tu nombre completo."),
|
|
68
|
+
v.minLength(2, "Tu nombre debe tener al menos 2 caracteres.")
|
|
69
|
+
),
|
|
70
|
+
email: v.pipe(
|
|
71
|
+
v.string("Ingresa tu correo electrónico."),
|
|
72
|
+
v.email("Por favor, ingresa un correo válido (ejemplo: tú@empresa.com).")
|
|
73
|
+
),
|
|
74
|
+
password: v.pipe(
|
|
75
|
+
v.string("Crea una contraseña segura."),
|
|
76
|
+
v.minLength(8, "Tu contraseña debe tener al menos 8 caracteres.")
|
|
77
|
+
),
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 4. Toast Notification Pattern (Sonner & Actions)
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { toast } from "sonner";
|
|
87
|
+
|
|
88
|
+
toast.promise(saveUserData(payload), {
|
|
89
|
+
loading: "Guardando tu información...",
|
|
90
|
+
success: "¡Listo! Tu información ha sido actualizada.",
|
|
91
|
+
error: (err: unknown) =>
|
|
92
|
+
err instanceof Error ? err.message : "No pudimos guardar los cambios. Inténtalo de nuevo.",
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 5. Sibling Skills
|
|
99
|
+
|
|
100
|
+
- **`best-practices`**: Universal clean code standards and strict typing.
|
|
101
|
+
- **`valibot-validation`**: Schema-level validation and error messages.
|
|
102
|
+
- **`error-handling-logging`**: Backend error mapping to user-safe error responses.
|
|
103
|
+
- Reference guide: `references/copy-patterns-es-en.md`.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Guía Rápida de Patrones de Copy (ES / EN)
|
|
2
|
+
|
|
3
|
+
Diccionario y patrones de microcopy persuasivo, empático y profesional para interfaces modernas.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Acciones y Botones (CTAs)
|
|
8
|
+
|
|
9
|
+
| Acción | ❌ Genérico / Frío | ✅ Español Persuasivo | ✅ English Benefit-Driven |
|
|
10
|
+
| :--- | :--- | :--- | :--- |
|
|
11
|
+
| Enviar formulario | Submit / Enviar | Continuar / Comenzar ahora | Continue / Get started now |
|
|
12
|
+
| Guardar cambios | Guardar / Save | Guardar cambios | Save changes |
|
|
13
|
+
| Crear recurso | Crear / Create | Crear nuevo proyecto | Create new project |
|
|
14
|
+
| Registrarse | Registrar / Register | Crear mi cuenta gratis | Create free account |
|
|
15
|
+
| Iniciar sesión | Login | Entrar a mi cuenta | Sign in to my account |
|
|
16
|
+
| Cancelar proceso | Cancelar | Descartar cambios | Discard changes |
|
|
17
|
+
| Eliminar permanente | Eliminar / Delete | Sí, eliminar permanentemente | Yes, delete permanently |
|
|
18
|
+
| Actualizar plan | Upgrade | Mejorar mi plan | Upgrade my plan |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. Mensajes de Validación de Formularios
|
|
23
|
+
|
|
24
|
+
| Regla | ❌ Evitar | ✅ Español Amable | ✅ English Clear |
|
|
25
|
+
| :--- | :--- | :--- | :--- |
|
|
26
|
+
| Campo requerido | Requerido | Este campo es necesario para continuar. | This field is required to continue. |
|
|
27
|
+
| Email inválido | Formato inválido | Ingresa un correo válido (ej: hola@tuweb.com). | Enter a valid email (e.g. name@company.com). |
|
|
28
|
+
| Teléfono inválido | Número erróneo | Ingresa un número de 9 a 12 dígitos sin espacios. | Enter a 10-digit phone number. |
|
|
29
|
+
| Contraseña corta | Muy corta | Usa al menos 8 caracteres para mayor seguridad. | Use at least 8 characters for stronger security. |
|
|
30
|
+
| Confirmar clave | No coincide | Las contraseñas deben ser idénticas. | Passwords do not match. Please verify. |
|
|
31
|
+
| Archivo pesado | Archivo muy grande | El archivo supera el límite de 10 MB. Elige uno más liviano. | File exceeds 10 MB limit. Please select a smaller one. |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 3. Estados Vacíos (Empty States)
|
|
36
|
+
|
|
37
|
+
| Vista | ❌ Aburrido | ✅ Español Motivador | ✅ English Engaging |
|
|
38
|
+
| :--- | :--- | :--- | :--- |
|
|
39
|
+
| Sin proyectos | No hay proyectos. | Aún no tienes proyectos creados. ¡Crea el primero y organiza tu trabajo! | You have no projects yet. Create your first one and stay organized! |
|
|
40
|
+
| Sin notificaciones | Bandeja vacía. | Estás al día. Te avisaremos cuando haya novedades importantes. | You're all caught up. We'll notify you when something new arrives. |
|
|
41
|
+
| Búsqueda sin resultados | 0 resultados. | No encontramos coincidencias para esa búsqueda. Intenta con otros términos. | We couldn't find matching results. Try refining your search terms. |
|
|
42
|
+
| Carrito vacío | Carrito vacío. | Tu carrito está esperando por tus productos favoritos. | Your cart is waiting for your favorite items. |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 4. Estados de Carga y Asincronía (Toasts & Progress)
|
|
47
|
+
|
|
48
|
+
| Estado | Español | English |
|
|
49
|
+
| :--- | :--- | :--- |
|
|
50
|
+
| **Cargando** | Guardando tus preferencias... | Saving your preferences... |
|
|
51
|
+
| **Éxito** | ¡Todo listo! Tu información se guardó correctamente. | All set! Your details were saved successfully. |
|
|
52
|
+
| **Error de red** | No pudimos conectar con el servidor. Revisa tu conexión. | Couldn't connect to server. Check your connection and retry. |
|
|
53
|
+
| **Sesión vencida** | Tu sesión expiró por seguridad. Ingresa nuevamente. | Your session expired for security. Please sign in again. |
|
|
54
|
+
| **Permiso denegado** | No tienes permisos para realizar esta acción. | You do not have permission to perform this action. |
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: valibot-validation
|
|
3
|
+
description: Schema validation at system boundaries with Valibot (* as v from "valibot"). Strict type inference (InferInput, InferOutput), input sanitization, pipeline transformations, and courteous user-facing error messages. TRIGGER when defining API request/response schemas, validating forms, parsing external payloads, env configs, or when the project imports 'valibot'.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Valibot Schema Validation Standards
|
|
7
|
+
|
|
8
|
+
Guidelines for high-performance, modular schema validation at system boundaries using **Valibot** (`* as v from "valibot"`).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Golden Rules (Non-negotiable)
|
|
13
|
+
|
|
14
|
+
1. **Namespace Import `* as v from "valibot"`**:
|
|
15
|
+
- Always import Valibot as namespace `import * as v from "valibot";` to prevent naming collisions and keep schemas consistent.
|
|
16
|
+
|
|
17
|
+
2. **Validate Every Boundary (Zero Unchecked Inputs)**:
|
|
18
|
+
- Validate every HTTP body, query string, route param, environment variable, and database response crossing boundary lines.
|
|
19
|
+
|
|
20
|
+
3. **Pipelines with Polite Error Messages (`v.pipe`)**:
|
|
21
|
+
- Chain schema constraints using `v.pipe(...)`.
|
|
22
|
+
- Provide clear, user-facing error messages on every validation step following the `ux-writing` skill guidelines.
|
|
23
|
+
|
|
24
|
+
4. **Explicit Type Inference (`v.InferInput` & `v.InferOutput`)**:
|
|
25
|
+
- Export inferred types for transformations.
|
|
26
|
+
- Use `v.InferOutput<typeof schema>` for validated downstream data, and `v.InferInput<typeof schema>` for raw form inputs.
|
|
27
|
+
|
|
28
|
+
5. **`v.safeParse` vs `v.parse` Discipline**:
|
|
29
|
+
- Use `v.safeParse` when building user-friendly forms or API endpoints to format issues into polite error responses without throwing.
|
|
30
|
+
- Use `v.parse` for critical startup configurations (like environment variables) where throwing stops catastrophic initialization.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. Standard Schema Example
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import * as v from "valibot";
|
|
38
|
+
|
|
39
|
+
export const CreateUserSchema = v.object({
|
|
40
|
+
fullName: v.pipe(
|
|
41
|
+
v.string("El nombre completo es requerido."),
|
|
42
|
+
v.trim(),
|
|
43
|
+
v.minLength(2, "El nombre debe tener al menos 2 caracteres.")
|
|
44
|
+
),
|
|
45
|
+
email: v.pipe(
|
|
46
|
+
v.string("El correo electrónico es requerido."),
|
|
47
|
+
v.trim(),
|
|
48
|
+
v.email("Por favor ingresa un correo electrónico válido.")
|
|
49
|
+
),
|
|
50
|
+
age: v.pipe(
|
|
51
|
+
v.number("La edad debe ser un número."),
|
|
52
|
+
v.integer("La edad debe ser un número entero."),
|
|
53
|
+
v.minValue(18, "Debes ser mayor de 18 años para registrarte.")
|
|
54
|
+
),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export type CreateUserInput = v.InferInput<typeof CreateUserSchema>;
|
|
58
|
+
export type CreateUserOutput = v.InferOutput<typeof CreateUserSchema>;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 3. Safe Parsing Helper Pattern
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import * as v from "valibot";
|
|
67
|
+
|
|
68
|
+
export interface ValidationResult<T> {
|
|
69
|
+
success: boolean;
|
|
70
|
+
data?: T;
|
|
71
|
+
errors?: Record<string, string>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function validateSchema<TSchema extends v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>>(
|
|
75
|
+
schema: TSchema,
|
|
76
|
+
input: unknown
|
|
77
|
+
): ValidationResult<v.InferOutput<TSchema>> {
|
|
78
|
+
const result = v.safeParse(schema, input);
|
|
79
|
+
|
|
80
|
+
if (result.success) {
|
|
81
|
+
return { success: true, data: result.output };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const errors: Record<string, string> = {};
|
|
85
|
+
for (const issue of result.issues) {
|
|
86
|
+
const path = issue.path?.map((p) => p.key).join(".") || "root";
|
|
87
|
+
if (!errors[path]) {
|
|
88
|
+
errors[path] = issue.message;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { success: false, errors };
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 4. Sibling Skills
|
|
99
|
+
|
|
100
|
+
- **`best-practices`**: Universal clean code and `<200` line limits.
|
|
101
|
+
- **`ux-writing`**: Form validation copy and tone standards.
|
|
102
|
+
- **`hono`**: Hono API route integration with `@hono/valibot-validator` and `sValidator`.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/domains/detector/project-detector.ts","../src/domains/detector/detect-agents.ts","../src/domains/detector/detect-dependencies.ts","../src/domains/registry/skill-catalog.ts","../src/domains/ui/ui-orchestrator.ts","../src/domains/ui/banners.ts","../src/domains/ui/prompt-skills.ts","../src/domains/ui/prompt-agents.ts","../src/domains/ui/prompt-harness.ts","../src/domains/ui/prompt-confirm-overwrite.ts","../src/domains/installer/verify-skill-exists.ts","../src/domains/installer/install-orchestrator.ts","../src/domains/adapters/antigravity.adapter.ts","../src/domains/project-store/project-paths.ts","../src/domains/adapters/link-helper.ts","../src/domains/adapters/claude.adapter.ts","../src/domains/adapters/cursor.adapter.ts","../src/domains/adapters/gemini.adapter.ts","../src/domains/project-store/sync-project-store.ts","../src/domains/installer/resolve-skills-source.ts","../src/domains/harness/install-harness.ts","../src/domains/harness/harness-templates.ts","../src/domains/harness/upsert-agent-instructions.ts","../src/domains/harness/write-project-config.ts","../src/main.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { detectAgents } from \"@/domains/detector/detect-agents\";\nimport { detectDependencies } from \"@/domains/detector/detect-dependencies\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { ProjectContext } from \"@/types/context.types\";\n\nexport function detectProjectContext(targetPath: string): ProjectContext {\n const detectedAgents = detectAgents(targetPath);\n const { dependencies, exists } = detectDependencies(targetPath);\n\n const suggestedSkillIds: string[] = [\"best-practices\"];\n\n for (const skill of SKILL_CATALOG) {\n if (skill.dependencies.length === 0) {\n continue;\n }\n const hasMatch = skill.dependencies.some((dep) => dependencies.includes(dep));\n if (hasMatch && !suggestedSkillIds.includes(skill.id)) {\n suggestedSkillIds.push(skill.id);\n }\n }\n\n const harnessExists = existsSync(join(targetPath, \".grooveskills\", \"memory\", \"context.md\"));\n\n return {\n targetPath,\n detectedDependencies: dependencies,\n suggestedSkillIds,\n detectedAgents,\n packageJsonExists: exists,\n harnessExists,\n };\n}\n","import { readdirSync } from \"node:fs\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport function detectAgents(targetPath: string): AgentId[] {\n const detected: AgentId[] = [];\n\n try {\n const entries = new Set(readdirSync(targetPath));\n\n if (entries.has(\".agents\")) {\n detected.push(\"antigravity\");\n }\n if (entries.has(\".claude\")) {\n detected.push(\"claude\");\n }\n if (entries.has(\".cursor\")) {\n detected.push(\"cursor\");\n }\n if (entries.has(\".gemini\")) {\n detected.push(\"gemini\");\n }\n } catch {\n // If directory cannot be read, return empty list gracefully\n }\n\n return detected;\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface PackageJsonDetection {\n dependencies: string[];\n exists: boolean;\n}\n\nexport function detectDependencies(targetPath: string): PackageJsonDetection {\n const packageJsonPath = join(targetPath, \"package.json\");\n\n if (!existsSync(packageJsonPath)) {\n return { dependencies: [], exists: false };\n }\n\n try {\n const raw = readFileSync(packageJsonPath, \"utf-8\");\n const parsed = JSON.parse(raw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const direct = Object.keys(parsed.dependencies ?? {});\n const dev = Object.keys(parsed.devDependencies ?? {});\n const all = Array.from(new Set([...direct, ...dev]));\n\n return { dependencies: all, exists: true };\n } catch {\n return { dependencies: [], exists: true };\n }\n}\n","import type { SkillMetadata } from \"@/types/skill.types\";\n\nexport const SKILL_CATALOG: SkillMetadata[] = [\n {\n id: \"groove-harness\",\n name: \"GrooveSkills Harness\",\n description: \"Lightweight project harness, context memory, and 3-lane task execution (Answer, Task, Spec) for AI coding agents\",\n dependencies: [],\n directoryName: \"groove-harness\",\n },\n {\n id: \"best-practices\",\n name: \"Universal Best Practices\",\n description: \"Multi-language clean code standards, early returns, no barrel files, strict typing, <200 lines\",\n dependencies: [],\n directoryName: \"best-practices\",\n },\n {\n id: \"hono\",\n name: \"Hono Architecture (Valibot)\",\n description: \"Enterprise Hono API standard with Valibot validation, isolated Actions layer, and RPC bindings\",\n dependencies: [\"hono\", \"@hono/valibot-validator\", \"@hono/standard-validator\"],\n directoryName: \"hono\",\n },\n {\n id: \"react-core\",\n name: \"React Core Fundamentals\",\n description: \"Opinionated React fundamentals: function components, JSX, immutable state, core hooks, lists, and controlled inputs\",\n dependencies: [\"react\", \"react-dom\"],\n directoryName: \"react-core\",\n },\n {\n id: \"react-advanced\",\n name: \"React 19 Advanced & Compiler Architecture\",\n description: \"Modern React 19 platform features: React Compiler auto-memoization, concurrent rendering, use(), Actions, virtualization, and RSC boundaries\",\n dependencies: [\"react\", \"react-dom\"],\n directoryName: \"react-advanced\",\n },\n {\n id: \"react-create-page\",\n name: \"React Page & View Architecture\",\n description: \"Clean architecture for React pages: declarative page coordinators, domain hooks, isolated API actions, Valibot + Formisch forms, and atomic co-location\",\n dependencies: [\"react\", \"react-dom\"],\n directoryName: \"react-create-page\",\n },\n];\n","import * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { renderBanner } from \"@/domains/ui/banners\";\nimport { promptSkills } from \"@/domains/ui/prompt-skills\";\nimport { promptAgents } from \"@/domains/ui/prompt-agents\";\nimport { promptHarness } from \"@/domains/ui/prompt-harness\";\nimport { promptConfirmOverwrite } from \"@/domains/ui/prompt-confirm-overwrite\";\nimport { verifySkillExists } from \"@/domains/installer/verify-skill-exists\";\nimport { installSkills } from \"@/domains/installer/install-orchestrator\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { ProjectContext } from \"@/types/context.types\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport async function runInteractiveUi(context: ProjectContext): Promise<void> {\n console.log(renderBanner());\n p.intro(pc.magenta(\"Welcome to GrooveSkills! Let's tailor your AI agents with clean architectural standards.\"));\n\n if (context.detectedDependencies.length > 0) {\n p.note(\n `Detected dependencies: ${context.detectedDependencies.map((d) => pc.bold(d)).join(\", \")}\\n` +\n `Active AI folders: ${context.detectedAgents.map((a) => pc.green(a)).join(\", \") || \"None (will be created)\"}`,\n \"Project Environment\"\n );\n }\n\n const selectedSkills = await promptSkills(context.suggestedSkillIds);\n if (p.isCancel(selectedSkills)) {\n p.cancel(\"Installation cancelled. Have a wonderful day!\");\n process.exit(0);\n }\n\n const selectedAgents = await promptAgents(context.detectedAgents);\n if (p.isCancel(selectedAgents)) {\n p.cancel(\"Installation cancelled. Have a wonderful day!\");\n process.exit(0);\n }\n\n const harnessChoice = await promptHarness(context.harnessExists);\n if (p.isCancel(harnessChoice)) {\n p.cancel(\"Installation cancelled. Have a wonderful day!\");\n process.exit(0);\n }\n\n let forceOverwrite = true;\n const anyExists = (selectedSkills as string[]).some((skillId) => {\n const meta = SKILL_CATALOG.find((s) => s.id === skillId);\n return meta ? verifySkillExists(context.targetPath, meta.directoryName, selectedAgents as AgentId[]) : false;\n });\n\n if (anyExists) {\n const confirm = await promptConfirmOverwrite();\n if (p.isCancel(confirm) || !confirm) {\n p.cancel(\"Installation stopped to protect existing skills.\");\n process.exit(0);\n }\n forceOverwrite = Boolean(confirm);\n }\n\n const s = p.spinner();\n s.start(\"Installing and adapting skills across your configured AI agents...\");\n\n const result = await installSkills({\n targetPath: context.targetPath,\n selectedSkillIds: selectedSkills as string[],\n selectedAgents: selectedAgents as AgentId[],\n forceOverwrite,\n enableHarness: Boolean(harnessChoice),\n detectedDependencies: context.detectedDependencies,\n });\n\n s.stop(pc.green(\"All skills and harness have been successfully configured!\"));\n\n const harnessStatus = result.harnessInitialized\n ? pc.green(\"Initialized in .grooveskills/\")\n : pc.dim(\"Skipped\");\n\n p.note(\n `Configured skills: ${result.installedSkills.map((s) => pc.bold(s)).join(\", \")}\\n` +\n `Target agents: ${result.configuredAgents.map((a) => pc.cyan(a)).join(\", \")}\\n` +\n `GrooveSkills Harness: ${harnessStatus}`,\n \"Installation Summary\"\n );\n\n p.outro(pc.green(\"Your AI programming pair is now empowered with your team's architectural habits! 🚀\"));\n}\n","import pc from \"picocolors\";\n\nexport function renderBanner(): string {\n const title = pc.bold(pc.white(\" GROOVE SKILLS \"));\n const badge = pc.bgMagenta(pc.black(title));\n const subtitle = pc.dim(\"Multi-Agent AI Skills & Architectural Standards\");\n\n return `${badge} ${subtitle}\\n`;\n}\n","import * as p from \"@clack/prompts\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\n\nexport async function promptSkills(suggestedSkillIds: string[]): Promise<string[] | symbol> {\n const options = SKILL_CATALOG.map((skill) => {\n const isSuggested = suggestedSkillIds.includes(skill.id);\n return {\n value: skill.id,\n label: skill.name,\n hint: isSuggested ? \"Suggested based on your project stack\" : skill.description,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Which skills would you like to install in this project?\",\n options,\n initialValues: suggestedSkillIds,\n required: true,\n });\n\n return selected;\n}\n","import * as p from \"@clack/prompts\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport async function promptAgents(detectedAgents: AgentId[]): Promise<AgentId[] | symbol> {\n const options: Array<{ value: AgentId; label: string; hint: string }> = [\n { value: \"antigravity\", label: \"Antigravity\", hint: \".agents/skills (Google Agentic IDE)\" },\n { value: \"claude\", label: \"Claude Code\", hint: \".claude/skills (Anthropic Claude Code)\" },\n { value: \"cursor\", label: \"Cursor\", hint: \".cursor/rules/*.mdc (Cursor IDE Rules)\" },\n { value: \"gemini\", label: \"Gemini Code Assist\", hint: \".gemini/skills (Google Gemini)\" },\n ];\n\n const initialValues: AgentId[] = detectedAgents.length > 0 ? detectedAgents : [\"antigravity\"];\n\n const selected = await p.multiselect({\n message: \"Which AI agents should be configured?\",\n options,\n initialValues,\n required: true,\n });\n\n return selected as AgentId[] | symbol;\n}\n","import * as p from \"@clack/prompts\";\n\nexport async function promptHarness(harnessExists: boolean): Promise<boolean | symbol> {\n const message = harnessExists\n ? \"GrooveSkills Harness is already initialized. Would you like to update agent rules and memory templates?\"\n : \"Would you like to initialize the GrooveSkills Harness in .grooveskills/ (project memory, ADR, and 3-lane task execution)?\";\n\n const confirm = await p.confirm({\n message,\n initialValue: true,\n });\n\n return confirm;\n}\n","import * as p from \"@clack/prompts\";\n\nexport async function promptConfirmOverwrite(): Promise<boolean | symbol> {\n return await p.confirm({\n message: \"Some skills already exist in this project. Would you like to overwrite them with the latest version?\",\n initialValue: true,\n });\n}\n","import { lstatSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nconst AGENT_DESTINATION_MAP: Record<AgentId, (dir: string) => string> = {\n antigravity: (dir) => join(\".agents\", \"skills\", dir),\n claude: (dir) => join(\".claude\", \"skills\", dir),\n cursor: (dir) => join(\".cursor\", \"rules\", `${dir}.mdc`),\n gemini: (dir) => join(\".gemini\", \"skills\", dir),\n};\n\nexport function verifySkillExists(\n targetPath: string,\n skillDirectoryName: string,\n agents: AgentId[]\n): boolean {\n for (const agent of agents) {\n const relativePathResolver = AGENT_DESTINATION_MAP[agent];\n const destination = join(targetPath, relativePathResolver(skillDirectoryName));\n\n try {\n lstatSync(destination);\n return true;\n } catch {\n // Path does not exist\n }\n }\n\n return false;\n}\n","import { join } from \"node:path\";\nimport { AntigravityAdapter } from \"@/domains/adapters/antigravity.adapter\";\nimport { ClaudeAdapter } from \"@/domains/adapters/claude.adapter\";\nimport { CursorAdapter } from \"@/domains/adapters/cursor.adapter\";\nimport { GeminiAdapter } from \"@/domains/adapters/gemini.adapter\";\nimport { syncProjectStore } from \"@/domains/project-store/sync-project-store\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { installHarness } from \"@/domains/harness/install-harness\";\nimport { writeProjectConfig } from \"@/domains/harness/write-project-config\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { InstallOptions, InstallResult } from \"@/types/installer.types\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nconst ADAPTER_REGISTRY: Record<AgentId, AgentAdapter> = {\n antigravity: new AntigravityAdapter(),\n claude: new ClaudeAdapter(),\n cursor: new CursorAdapter(),\n gemini: new GeminiAdapter(),\n};\n\nexport async function installSkills(options: InstallOptions): Promise<InstallResult> {\n const skillsToInstall = [...options.selectedSkillIds];\n\n if (options.enableHarness && !skillsToInstall.includes(\"groove-harness\")) {\n skillsToInstall.push(\"groove-harness\");\n }\n\n syncProjectStore(options.targetPath, skillsToInstall, options.selectedAgents);\n\n const projectSkillsDir = getProjectSkillsDir(options.targetPath);\n const createdFiles: string[] = [];\n\n for (const skillId of skillsToInstall) {\n const skill = SKILL_CATALOG.find((item) => item.id === skillId);\n if (!skill) {\n continue;\n }\n\n const skillSourceDir = join(projectSkillsDir, skill.directoryName);\n\n for (const agentId of options.selectedAgents) {\n const adapter = ADAPTER_REGISTRY[agentId];\n if (!adapter) {\n continue;\n }\n\n const files = await adapter.installSkill(options.targetPath, skill, skillSourceDir);\n createdFiles.push(...files);\n }\n }\n\n let harnessInitialized = false;\n if (options.enableHarness) {\n const harnessFiles = installHarness({\n targetPath: options.targetPath,\n selectedAgents: options.selectedAgents,\n selectedSkillIds: skillsToInstall,\n detectedDependencies: options.detectedDependencies || [],\n });\n createdFiles.push(...harnessFiles);\n harnessInitialized = true;\n }\n\n const configPath = writeProjectConfig(\n options.targetPath,\n skillsToInstall,\n options.selectedAgents,\n Boolean(options.enableHarness)\n );\n createdFiles.push(configPath);\n\n return {\n installedSkills: skillsToInstall,\n configuredAgents: options.selectedAgents,\n createdFiles,\n harnessInitialized,\n };\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class AntigravityAdapter implements AgentAdapter {\n readonly id = \"antigravity\" as const;\n readonly name = \"Antigravity\";\n readonly targetRelativeDir = \".agents/skills\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const parentDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true });\n }\n\n const destination = join(parentDir, skill.directoryName);\n const projectSkillDir = join(getProjectSkillsDir(targetPath), skill.directoryName);\n\n createOrReplaceSymlink(projectSkillDir, destination, \"dir\");\n\n return [destination];\n }\n}\n","import { join } from \"node:path\";\n\nexport function getProjectStoreDir(targetPath: string): string {\n return join(targetPath, \".grooveskills\");\n}\n\nexport function getProjectSkillsDir(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"skills\");\n}\n\nexport function getProjectCursorRulesDir(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"cursor-rules\");\n}\n\nexport function getProjectMemoryDir(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"memory\");\n}\n\nexport function getProjectTasksDir(targetPath: string): string {\n return join(getProjectMemoryDir(targetPath), \"tasks\");\n}\n\nexport function getProjectConfigPath(targetPath: string): string {\n return join(getProjectStoreDir(targetPath), \"config.json\");\n}\n","import { lstatSync, unlinkSync, rmSync, symlinkSync } from \"node:fs\";\nimport { dirname, relative } from \"node:path\";\n\nfunction removeExistingLinkPath(path: string): void {\n try {\n const lstat = lstatSync(path);\n\n if (lstat.isDirectory() && !lstat.isSymbolicLink()) {\n rmSync(path, { recursive: true, force: true });\n return;\n }\n\n unlinkSync(path);\n } catch {\n // If path does not exist, exit early\n }\n}\n\nexport function createOrReplaceSymlink(\n target: string,\n linkPath: string,\n type: \"dir\" | \"file\"\n): void {\n removeExistingLinkPath(linkPath);\n\n const linkDir = dirname(linkPath);\n const relativeTarget = relative(linkDir, target);\n\n symlinkSync(relativeTarget, linkPath, type);\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class ClaudeAdapter implements AgentAdapter {\n readonly id = \"claude\" as const;\n readonly name = \"Claude Code\";\n readonly targetRelativeDir = \".claude/skills\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const parentDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true });\n }\n\n const destination = join(parentDir, skill.directoryName);\n const projectSkillDir = join(getProjectSkillsDir(targetPath), skill.directoryName);\n\n createOrReplaceSymlink(projectSkillDir, destination, \"dir\");\n\n return [destination];\n }\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectCursorRulesDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class CursorAdapter implements AgentAdapter {\n readonly id = \"cursor\" as const;\n readonly name = \"Cursor\";\n readonly targetRelativeDir = \".cursor/rules\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const rulesDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(rulesDir)) {\n mkdirSync(rulesDir, { recursive: true });\n }\n\n const filename = `${skill.id}.mdc`;\n const destination = join(rulesDir, filename);\n const projectRuleFile = join(getProjectCursorRulesDir(targetPath), filename);\n\n createOrReplaceSymlink(projectRuleFile, destination, \"file\");\n\n return [destination];\n }\n}\n","import { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getProjectSkillsDir } from \"@/domains/project-store/project-paths\";\nimport { createOrReplaceSymlink } from \"@/domains/adapters/link-helper\";\nimport type { AgentAdapter } from \"@/domains/adapters/adapter.interface\";\nimport type { SkillMetadata } from \"@/types/skill.types\";\n\nexport class GeminiAdapter implements AgentAdapter {\n readonly id = \"gemini\" as const;\n readonly name = \"Gemini Code Assist\";\n readonly targetRelativeDir = \".gemini/skills\";\n\n async installSkill(\n targetPath: string,\n skill: SkillMetadata,\n _skillSourceDir: string\n ): Promise<string[]> {\n const parentDir = join(targetPath, this.targetRelativeDir);\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true });\n }\n\n const destination = join(parentDir, skill.directoryName);\n const projectSkillDir = join(getProjectSkillsDir(targetPath), skill.directoryName);\n\n createOrReplaceSymlink(projectSkillDir, destination, \"dir\");\n\n return [destination];\n }\n}\n","import { cpSync, mkdirSync, existsSync, writeFileSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n getProjectSkillsDir,\n getProjectCursorRulesDir,\n} from \"@/domains/project-store/project-paths\";\nimport { resolveSkillsSourceRoot } from \"@/domains/installer/resolve-skills-source\";\nimport { SKILL_CATALOG } from \"@/domains/registry/skill-catalog\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport function syncProjectStore(\n targetPath: string,\n selectedSkillIds: string[],\n selectedAgents: AgentId[]\n): void {\n const bundledSkillsDir = resolveSkillsSourceRoot();\n const projectSkillsDir = getProjectSkillsDir(targetPath);\n const projectCursorRulesDir = getProjectCursorRulesDir(targetPath);\n\n if (!existsSync(projectSkillsDir)) {\n mkdirSync(projectSkillsDir, { recursive: true });\n }\n\n const needsCursorRules = selectedAgents.includes(\"cursor\");\n if (needsCursorRules && !existsSync(projectCursorRulesDir)) {\n mkdirSync(projectCursorRulesDir, { recursive: true });\n }\n\n for (const skillId of selectedSkillIds) {\n const skill = SKILL_CATALOG.find((item) => item.id === skillId);\n if (!skill) {\n continue;\n }\n\n const sourceSkillDir = join(bundledSkillsDir, skill.directoryName);\n const destSkillDir = join(projectSkillsDir, skill.directoryName);\n\n if (existsSync(sourceSkillDir)) {\n cpSync(sourceSkillDir, destSkillDir, { recursive: true });\n }\n\n if (!needsCursorRules) {\n continue;\n }\n\n const skillMdPath = join(destSkillDir, \"SKILL.md\");\n if (!existsSync(skillMdPath)) {\n continue;\n }\n\n const content = readFileSync(skillMdPath, \"utf-8\");\n const mdcHeader = `---\ndescription: ${skill.description}\nglobs: [\"**/*\"]\nalwaysApply: false\n---\n\n`;\n const cleanedBody = content.replace(/^---[\\s\\S]*?---\\s*/, \"\");\n const targetMdc = join(projectCursorRulesDir, `${skill.id}.mdc`);\n writeFileSync(targetMdc, `${mdcHeader}${cleanedBody}`, \"utf-8\");\n }\n}\n","import { fileURLToPath } from \"node:url\";\nimport { dirname, resolve, join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\n\nexport function resolveSkillsSourceRoot(): string {\n const currentFilePath = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFilePath);\n\n // 1. From dist/ in published npm package or local build: dist/../skills\n const candidateFromDist = resolve(currentDir, \"../skills\");\n if (existsSync(candidateFromDist)) {\n return candidateFromDist;\n }\n\n // 2. From src/domains/installer/ during development: ../../../skills\n const candidateFromSrc = resolve(currentDir, \"../../../skills\");\n if (existsSync(candidateFromSrc)) {\n return candidateFromSrc;\n }\n\n // 3. Search upward for the package root containing a skills directory\n let searchDir = currentDir;\n for (let i = 0; i < 5; i++) {\n const candidate = join(searchDir, \"skills\");\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(searchDir);\n if (parent === searchDir) {\n break;\n }\n searchDir = parent;\n }\n\n throw new Error(\n `GrooveSkills internal error: Unable to locate bundled skills directory from ${currentDir}`\n );\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n getProjectMemoryDir,\n getProjectTasksDir,\n} from \"@/domains/project-store/project-paths\";\nimport {\n buildContextTemplate,\n buildDecisionsTemplate,\n buildTaskTemplate,\n} from \"@/domains/harness/harness-templates\";\nimport { upsertAgentInstructions } from \"@/domains/harness/upsert-agent-instructions\";\nimport type { HarnessInstallOptions } from \"@/types/harness.types\";\n\nexport function installHarness(options: HarnessInstallOptions): string[] {\n const memoryDir = getProjectMemoryDir(options.targetPath);\n const tasksDir = getProjectTasksDir(options.targetPath);\n\n if (!existsSync(tasksDir)) {\n mkdirSync(tasksDir, { recursive: true });\n }\n\n const createdFiles: string[] = [];\n\n const contextPath = join(memoryDir, \"context.md\");\n if (!existsSync(contextPath)) {\n writeFileSync(contextPath, buildContextTemplate(options.detectedDependencies), \"utf-8\");\n createdFiles.push(contextPath);\n }\n\n const decisionsPath = join(memoryDir, \"decisions.md\");\n if (!existsSync(decisionsPath)) {\n writeFileSync(decisionsPath, buildDecisionsTemplate(), \"utf-8\");\n createdFiles.push(decisionsPath);\n }\n\n const templateTaskPath = join(tasksDir, \"_template.md\");\n if (!existsSync(templateTaskPath)) {\n writeFileSync(templateTaskPath, buildTaskTemplate(), \"utf-8\");\n createdFiles.push(templateTaskPath);\n }\n\n const instructions = upsertAgentInstructions(options.targetPath, options.selectedAgents);\n createdFiles.push(...instructions);\n\n return createdFiles;\n}\n","export function buildContextTemplate(detectedDependencies: string[]): string {\n const depsFormatted = detectedDependencies.length > 0\n ? detectedDependencies.map((d) => `- \\`${d}\\``).join(\"\\n\")\n : \"- (No external dependencies detected)\";\n\n return `# Project Context & Architecture\n\nThis file provides AI agents with instant architectural orientation for this project.\n\n## 1. Stack & Dependencies\n${depsFormatted}\n\n## 2. Directory Structure Conventions\n- Follow single-responsibility per file (<200 lines).\n- Maintain direct imports with path aliases; avoid barrel files.\n- Keep domain boundaries explicit and clean.\n\n## 3. Essential Commands\n- Build: Refer to \\`package.json\\` scripts.\n- Typecheck: Refer to TypeScript configuration.\n- Tests: Refer to test runner configuration.\n`;\n}\n\nexport function buildDecisionsTemplate(): string {\n const now = new Date().toISOString().split(\"T\")[0];\n return `# Architecture Decision Records (ADR)\n\nAn append-only log of significant technical and architectural choices.\n\n| Date | Title | Decision | Reason & Consequences |\n| :--- | :--- | :--- | :--- |\n| ${now} | Adopt GrooveSkills Harness | Initialized \\`.grooveskills/\\` control plane | Clean, encapsulated agent memory and 3-lane execution flow |\n`;\n}\n\nexport function buildTaskTemplate(): string {\n return `---\nstatus: in-progress\ncreatedAt: \\${CURRENT_DATE}\n---\n\n# Feature / Task Title\n\n## Intent\nDescribe what changes are being made and why they are necessary.\n\n## Scope\n- In scope:\n- Out of scope:\n\n## Checklist\n- [ ] Task 1: (Define expected observed proof)\n- [ ] Task 2: (Define expected observed proof)\n\n## Evidence\n- Observed test/typecheck/build commands or runtime outputs proving completion.\n\n## Next\n- Next concrete step if interrupted.\n`;\n}\n\nexport function buildAgentHarnessBlock(): string {\n return `<!-- grooveskills:harness:start -->\n# GrooveSkills Harness — Agent Rules & Memory\n\nThis project uses the **GrooveSkills Harness** located in \\`.grooveskills/\\`.\n\n## 1. Three-Lane Rule\n- **Answer**: Explanations, audits, or questions. Read-only; write zero code.\n- **Task**: Direct implementation. Record intent, scope, and checklist in \\`.grooveskills/memory/tasks/<slug>.md\\`. Only check off tasks with observed evidence under \\`Evidence\\`.\n- **Spec**: Ambiguous or high-impact architecture. Clarify and validate the spec in \\`.grooveskills/memory/tasks/<slug>.md\\` before writing code.\n\n## 2. Memory Locations\n- Architecture context: \\`.grooveskills/memory/context.md\\`\n- Technical decisions (ADR): \\`.grooveskills/memory/decisions.md\\`\n- Active tasks & evidence: \\`.grooveskills/memory/tasks/\\`\n<!-- grooveskills:harness:end -->`;\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { buildAgentHarnessBlock } from \"@/domains/harness/harness-templates\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nconst START_MARKER = \"<!-- grooveskills:harness:start -->\";\nconst END_MARKER = \"<!-- grooveskills:harness:end -->\";\n\nfunction applyHarnessBlock(filePath: string): void {\n const block = buildAgentHarnessBlock();\n\n if (!existsSync(filePath)) {\n writeFileSync(filePath, `${block}\\n`, \"utf-8\");\n return;\n }\n\n const existingContent = readFileSync(filePath, \"utf-8\");\n\n if (existingContent.includes(START_MARKER) && existingContent.includes(END_MARKER)) {\n const regex = new RegExp(`${START_MARKER}[\\\\s\\\\S]*?${END_MARKER}`, \"g\");\n const updated = existingContent.replace(regex, block);\n writeFileSync(filePath, updated, \"utf-8\");\n return;\n }\n\n const separator = existingContent.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n writeFileSync(filePath, `${existingContent}${separator}${block}\\n`, \"utf-8\");\n}\n\nexport function upsertAgentInstructions(targetPath: string, selectedAgents: AgentId[]): string[] {\n const updatedFiles: string[] = [];\n\n const agentsMdPath = join(targetPath, \"AGENTS.md\");\n applyHarnessBlock(agentsMdPath);\n updatedFiles.push(agentsMdPath);\n\n if (selectedAgents.includes(\"claude\")) {\n const claudeMdPath = join(targetPath, \"CLAUDE.md\");\n applyHarnessBlock(claudeMdPath);\n updatedFiles.push(claudeMdPath);\n }\n\n return updatedFiles;\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { getProjectConfigPath } from \"@/domains/project-store/project-paths\";\nimport type { GrooveSkillsConfig } from \"@/types/harness.types\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport function writeProjectConfig(\n targetPath: string,\n newSkills: string[],\n newAgents: AgentId[],\n harnessEnabled: boolean\n): string {\n const configPath = getProjectConfigPath(targetPath);\n\n let existingSkills: string[] = [];\n let existingAgents: AgentId[] = [];\n let existingHarness = false;\n\n if (existsSync(configPath)) {\n try {\n const parsed = JSON.parse(readFileSync(configPath, \"utf-8\")) as Partial<GrooveSkillsConfig>;\n if (Array.isArray(parsed.skills)) {\n existingSkills = parsed.skills;\n }\n if (Array.isArray(parsed.agents)) {\n existingAgents = parsed.agents;\n }\n if (typeof parsed.harness === \"boolean\") {\n existingHarness = parsed.harness;\n }\n } catch {\n // If parsing fails, fall back to initial state\n }\n }\n\n const mergedSkills = Array.from(new Set([...existingSkills, ...newSkills]));\n const mergedAgents = Array.from(new Set([...existingAgents, ...newAgents]));\n\n const config: GrooveSkillsConfig = {\n version: 1,\n harness: existingHarness || harnessEnabled,\n agents: mergedAgents,\n skills: mergedSkills,\n updatedAt: new Date().toISOString(),\n };\n\n writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\n return configPath;\n}\n","import { detectProjectContext } from \"@/domains/detector/project-detector\";\nimport { runInteractiveUi } from \"@/domains/ui/ui-orchestrator\";\nimport { installSkills } from \"@/domains/installer/install-orchestrator\";\nimport type { AgentId } from \"@/types/agent.types\";\n\nexport interface CliOptions {\n skills?: string[];\n agents?: AgentId[];\n yes?: boolean;\n harness?: boolean;\n}\n\nexport async function runGrooveSkills(options: CliOptions = {}): Promise<void> {\n const targetPath = process.cwd();\n const context = detectProjectContext(targetPath);\n\n const hasSkills = options.skills && options.skills.length > 0;\n const hasAgents = options.agents && options.agents.length > 0;\n const isDirectHarness = Boolean(options.harness) && hasAgents;\n\n if ((hasSkills && hasAgents) || isDirectHarness) {\n await installSkills({\n targetPath,\n selectedSkillIds: options.skills || [],\n selectedAgents: options.agents || [],\n forceOverwrite: Boolean(options.yes),\n enableHarness: options.harness,\n detectedDependencies: context.detectedDependencies,\n });\n return;\n }\n\n await runInteractiveUi(context);\n}\n"],"mappings":"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","names":["existsSync","join","existsSync","join","p","pc","p","p","confirm","p","join","join","existsSync","join","join","lstatSync","join","existsSync","mkdirSync","existsSync","join","join","existsSync","mkdirSync","mkdirSync","existsSync","join","join","existsSync","mkdirSync","mkdirSync","existsSync","join","join","existsSync","mkdirSync","mkdirSync","existsSync","readFileSync","join","dirname","join","existsSync","existsSync","mkdirSync","join","readFileSync","existsSync","mkdirSync","writeFileSync","join","existsSync","readFileSync","writeFileSync","join","existsSync","writeFileSync","readFileSync","join","existsSync","mkdirSync","join","writeFileSync","existsSync","readFileSync","writeFileSync","existsSync","readFileSync","writeFileSync","join","pc","s","confirm"]}
|