navori 0.2.0 → 0.2.2
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/LICENSE +21 -0
- package/README.md +77 -17
- package/dist/assets/core/core-assets/agents/commit-pr-pilot.md +15 -9
- package/dist/assets/core/core-assets/lib-skills/formik.md +57 -0
- package/dist/assets/core/core-assets/lib-skills/joi-validation.md +73 -0
- package/dist/assets/core/core-assets/{presets/express-mongoose/skills → lib-skills}/mongoose.md +3 -2
- package/dist/assets/core/core-assets/lib-skills/redux-toolkit.md +59 -0
- package/dist/assets/core/core-assets/lib-skills/socketio.md +56 -0
- package/dist/assets/core/core-assets/lib-skills/tanstack-query.md +58 -0
- package/dist/assets/core/core-assets/managed/cierre-sesion.md +1 -1
- package/dist/assets/core/core-assets/managed/idioma-rol.md +1 -1
- package/dist/assets/core/core-assets/managed/operaciones-seguras.md +1 -0
- package/dist/assets/core/core-assets/presets/background-worker/managed/stack.md +18 -0
- package/dist/assets/core/core-assets/presets/background-worker/skills/job-scheduling.md +54 -0
- package/dist/assets/core/core-assets/presets/background-worker/skills/queue-consumers.md +55 -0
- package/dist/assets/core/core-assets/presets/background-worker/skills/worker-lifecycle.md +57 -0
- package/dist/assets/core/core-assets/presets/background-worker.json +39 -0
- package/dist/assets/core/core-assets/presets/express-mongoose/managed/stack.md +2 -2
- package/dist/assets/core/core-assets/presets/express-mongoose/skills/pr-create.md +18 -18
- package/dist/assets/core/core-assets/presets/express-mongoose.json +0 -12
- package/dist/assets/core/core-assets/settings/settings-base.json +22 -1
- package/dist/index.js +797 -346
- package/package.json +5 -4
- /package/dist/assets/core/core-assets/{presets/express-mongoose/skills → lib-skills}/zod-validation.md +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: job-scheduling
|
|
3
|
+
description: Definir y agendar jobs en un worker (agenda / bullmq) — idempotencia, reintentos con backoff, concurrencia. Aplica al crear o tocar un job programado o recurrente.
|
|
4
|
+
type: reference
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# job-scheduling — jobs idempotentes y reintentables
|
|
8
|
+
|
|
9
|
+
Un job define **qué** hacer; el scheduler decide **cuándo** y **cuántas veces**. Como un job puede correr más de una vez (reintento, doble disparo), el handler debe ser idempotente.
|
|
10
|
+
|
|
11
|
+
## Cuándo usar este skill
|
|
12
|
+
|
|
13
|
+
Al definir un job nuevo, agendar uno recurrente, o ajustar reintentos/concurrencia.
|
|
14
|
+
|
|
15
|
+
## El patrón (agenda)
|
|
16
|
+
|
|
17
|
+
Un archivo por job (`<name>.job.ts`) que registra el handler; el scheduling vive aparte del handler.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
export function defineSyncJob(agenda: Agenda) {
|
|
21
|
+
agenda.define('sync-user', { concurrency: 5, lockLifetime: 60_000 }, async (job) => {
|
|
22
|
+
const { userId } = job.attrs.data as { userId: string };
|
|
23
|
+
// idempotente: chequea estado antes de actuar
|
|
24
|
+
if (await alreadySynced(userId, job.attrs.lastRunAt)) return;
|
|
25
|
+
await syncUser(userId);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// scheduling, separado del handler:
|
|
30
|
+
await agenda.every('0 * * * *', 'sync-user', { userId }); // recurrente
|
|
31
|
+
await agenda.schedule('in 5 minutes', 'sync-user', { userId }); // one-off
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
bullmq es equivalente: `new Worker(name, handler, { concurrency })` + `queue.add(name, data, { repeat, attempts, backoff })`.
|
|
35
|
+
|
|
36
|
+
## Gotchas que muerden
|
|
37
|
+
|
|
38
|
+
- **Doble disparo**: dos instancias del worker pueden tomar el mismo job. agenda usa `lockLifetime`; bullmq usa locks por job. Aun así, **el handler debe ser idempotente** — no confíes solo en el lock.
|
|
39
|
+
- **Reintentos sin backoff** martillan un servicio caído. Configura `attempts` + `backoff` exponencial.
|
|
40
|
+
- **`lockLifetime` corto** + job largo → el lock expira y otro worker lo retoma en paralelo. Ajústalo por encima de la duración real del job.
|
|
41
|
+
|
|
42
|
+
## Reglas duras
|
|
43
|
+
|
|
44
|
+
1. Un job por archivo `<name>.job.ts`; handler separado del scheduling.
|
|
45
|
+
2. Handler **idempotente**: chequea estado antes de mutar; usa upserts/claves de dedup.
|
|
46
|
+
3. Reintentos con backoff exponencial y un tope (`attempts`); sin reintento infinito.
|
|
47
|
+
4. `concurrency` y `lockLifetime` explícitos y coherentes con la duración del job.
|
|
48
|
+
5. Nada de trabajo no idempotente que dependa de "correr exactamente una vez".
|
|
49
|
+
|
|
50
|
+
## Antes de declarar listo
|
|
51
|
+
|
|
52
|
+
- El handler es seguro de re-ejecutar (probado corriéndolo dos veces).
|
|
53
|
+
- Reintentos con backoff y tope configurados.
|
|
54
|
+
- `{{qualityGate.fast}}` en verde.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: queue-consumers
|
|
3
|
+
description: Consumir mensajes de una cola en un worker (amqplib / bullmq) — ack/nack, dead-letter, prefetch/backpressure, idempotencia. Aplica al crear o tocar un consumidor de cola.
|
|
4
|
+
type: reference
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# queue-consumers — consumir sin perder ni duplicar
|
|
8
|
+
|
|
9
|
+
Un consumer reacciona a mensajes. La regla central: **un mensaje no se confirma (`ack`) hasta que se procesó con éxito**; si falla, se re-encola o va a dead-letter — nunca se pierde en silencio.
|
|
10
|
+
|
|
11
|
+
## Cuándo usar este skill
|
|
12
|
+
|
|
13
|
+
Al crear un consumer, manejar fallos de procesamiento, o ajustar prefetch / dead-letter.
|
|
14
|
+
|
|
15
|
+
## El patrón (amqplib)
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
await channel.prefetch(10); // backpressure: máx 10 sin ack a la vez
|
|
19
|
+
await channel.consume(queue, async (msg) => {
|
|
20
|
+
if (!msg) return;
|
|
21
|
+
try {
|
|
22
|
+
const payload = JSON.parse(msg.content.toString());
|
|
23
|
+
if (await alreadyProcessed(payload.id)) { channel.ack(msg); return; } // idempotente
|
|
24
|
+
await handle(payload);
|
|
25
|
+
channel.ack(msg);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
logger.error({ err }, 'consume failed');
|
|
28
|
+
// requeue una vez; si ya fue redelivered, mándalo a la DLQ (no requeue infinito)
|
|
29
|
+
channel.nack(msg, false, !msg.fields.redelivered);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
bullmq: lanzar dentro del `Worker` handler re-encola según `attempts`/`backoff`; al agotarse, el job queda `failed` (tu DLQ lógica).
|
|
35
|
+
|
|
36
|
+
## Gotchas que muerden
|
|
37
|
+
|
|
38
|
+
- **`nack` con `requeue: true` siempre** → loop infinito si el mensaje es venenoso. Requeue una vez (chequea `redelivered`), luego dead-letter.
|
|
39
|
+
- **Sin `prefetch`** el consumer traga toda la cola en memoria. Fija un prefetch acorde a la duración del handler.
|
|
40
|
+
- **`ack` antes de procesar** = pérdida de mensajes si el handler crashea. Confirma **después** del éxito.
|
|
41
|
+
- **Mensajes duplicados** son normales (redelivery). El handler debe ser idempotente.
|
|
42
|
+
|
|
43
|
+
## Reglas duras
|
|
44
|
+
|
|
45
|
+
1. `ack` solo tras éxito; en fallo, `nack`/requeue acotado o dead-letter.
|
|
46
|
+
2. Nunca requeue infinito de un mensaje venenoso — DLQ tras el primer redelivery.
|
|
47
|
+
3. `prefetch` explícito para backpressure.
|
|
48
|
+
4. Handler **idempotente**: chequea dedup antes de actuar.
|
|
49
|
+
5. Errores logueados (estructurado), nunca tragados en silencio.
|
|
50
|
+
|
|
51
|
+
## Antes de declarar listo
|
|
52
|
+
|
|
53
|
+
- Un mensaje que falla no se pierde ni hace loop infinito (va a DLQ).
|
|
54
|
+
- `prefetch` configurado; el handler es idempotente.
|
|
55
|
+
- `{{qualityGate.fast}}` en verde.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: worker-lifecycle
|
|
3
|
+
description: Ciclo de vida de un worker de fondo en Node/TS — bootstrap, graceful shutdown, healthcheck mínimo, sin servir HTTP de negocio. Aplica al tocar el arranque/apagado del proceso o la conexión a DB/broker.
|
|
4
|
+
type: reference
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# worker-lifecycle — arrancar y apagar limpio
|
|
8
|
+
|
|
9
|
+
Un worker no es un HTTP server: arranca conexiones, registra schedulers/consumers, y debe **apagar limpio** sin matar trabajo en vuelo. Su `main` orquesta el bootstrap y un único shutdown idempotente.
|
|
10
|
+
|
|
11
|
+
## Cuándo usar este skill
|
|
12
|
+
|
|
13
|
+
Al tocar `index.ts`/`main.ts`, el arranque del scheduler/consumer, la conexión a Mongo/broker, o el manejo de señales.
|
|
14
|
+
|
|
15
|
+
## El patrón
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
async function main() {
|
|
19
|
+
const db = await connectMongo(config.mongoUri);
|
|
20
|
+
const broker = await connectBroker(config.amqpUrl);
|
|
21
|
+
const scheduler = startScheduler({ db }); // job-scheduling
|
|
22
|
+
const consumer = startConsumer({ broker }); // queue-consumers
|
|
23
|
+
|
|
24
|
+
const shutdown = once(async (signal: string) => {
|
|
25
|
+
logger.info({ signal }, 'shutting down');
|
|
26
|
+
await consumer.stop(); // deja de tomar mensajes nuevos
|
|
27
|
+
await scheduler.stop(); // deja de disparar jobs
|
|
28
|
+
await drainInflight(15_000); // espera lo en vuelo, con timeout
|
|
29
|
+
await broker.close();
|
|
30
|
+
await db.close();
|
|
31
|
+
process.exit(0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
for (const sig of ['SIGTERM', 'SIGINT'] as const) process.on(sig, () => shutdown(sig));
|
|
35
|
+
}
|
|
36
|
+
main().catch((err) => { logger.error({ err }, 'fatal on boot'); process.exit(1); });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`once` garantiza que dos señales seguidas no disparen dos shutdowns. El orden importa: **primero dejas de aceptar trabajo**, luego drenas lo en vuelo, luego cierras conexiones.
|
|
40
|
+
|
|
41
|
+
## Healthcheck (si el orquestador lo exige)
|
|
42
|
+
|
|
43
|
+
Un solo endpoint `/health` con un `http.createServer` mínimo está bien — **no es** una API. Devuelve `200` si las conexiones (DB, broker) están vivas. Nada de rutas de negocio aquí.
|
|
44
|
+
|
|
45
|
+
## Reglas duras
|
|
46
|
+
|
|
47
|
+
1. Un único punto de shutdown, idempotente (`once`), escuchando `SIGTERM` y `SIGINT`.
|
|
48
|
+
2. Dejar de aceptar trabajo **antes** de drenar; drenar con timeout; cerrar conexiones al final.
|
|
49
|
+
3. Nunca `process.exit` a mitad de un job sin re-encolarlo o dejarlo `nack`-eado.
|
|
50
|
+
4. Sin rutas HTTP de negocio. `/health` es el único endpoint permitido.
|
|
51
|
+
5. Errores de arranque → log estructurado + `exit(1)`; no arranques a medias.
|
|
52
|
+
|
|
53
|
+
## Antes de declarar listo
|
|
54
|
+
|
|
55
|
+
- `SIGTERM` apaga limpio: sin jobs muertos a la mitad, conexiones cerradas.
|
|
56
|
+
- El proceso no expone endpoints de negocio.
|
|
57
|
+
- `{{qualityGate.fast}}` en verde.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://navori.dev/schema/navori.preset.v1.json",
|
|
3
|
+
"id": "background-worker",
|
|
4
|
+
"displayName": "Background worker (jobs + queues)",
|
|
5
|
+
"extends": "core",
|
|
6
|
+
"extras": {
|
|
7
|
+
"managed": [
|
|
8
|
+
{
|
|
9
|
+
"id": "stack-background-worker",
|
|
10
|
+
"relPath": "presets/background-worker/managed/stack.md"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"agents": [],
|
|
14
|
+
"skills": [
|
|
15
|
+
{
|
|
16
|
+
"id": "worker-lifecycle",
|
|
17
|
+
"relPath": "presets/background-worker/skills/worker-lifecycle.md",
|
|
18
|
+
"destRelPath": ".claude/skills/worker-lifecycle.md"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "job-scheduling",
|
|
22
|
+
"relPath": "presets/background-worker/skills/job-scheduling.md",
|
|
23
|
+
"destRelPath": ".claude/skills/job-scheduling.md"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "queue-consumers",
|
|
27
|
+
"relPath": "presets/background-worker/skills/queue-consumers.md",
|
|
28
|
+
"destRelPath": ".claude/skills/queue-consumers.md"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"hooks": []
|
|
32
|
+
},
|
|
33
|
+
"invariants": [
|
|
34
|
+
"worker-lifecycle",
|
|
35
|
+
"job-scheduling",
|
|
36
|
+
"queue-consumers",
|
|
37
|
+
"graceful shutdown"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
## Stack — Express + Mongoose
|
|
2
2
|
|
|
3
|
-
Backend HTTP sobre Express + Mongoose/MongoDB en TypeScript. Las peticiones fluyen en capas: `route → validate(
|
|
3
|
+
Backend HTTP sobre Express + Mongoose/MongoDB en TypeScript. Las peticiones fluyen en capas: `route → validate(schema) → asyncHandler → controller → Model (Mongoose) → ApiResponse`. Los controllers tocan los Models directo (sin repository wrappers); los errores se propagan vía `ApiError` y las respuestas se envuelven en `ApiResponse`. El logging va por el `Logger` de winston, nunca `console.log`.
|
|
4
4
|
|
|
5
|
-
Regla de oro: nada de `res.json` / `res.status(500)` crudos; nada de `console.log`; nada de `process.env` fuera del módulo de config. La validación SIEMPRE ocurre en el boundary con Zod, y todo `ObjectId` se construye con `new Types.ObjectId(...)`. Aplica las skills `express-routes`, `
|
|
5
|
+
Regla de oro: nada de `res.json` / `res.status(500)` crudos; nada de `console.log`; nada de `process.env` fuera del módulo de config. La validación SIEMPRE ocurre en el boundary (con el validador del repo — Zod o Joi), y todo `ObjectId` se construye con `new Types.ObjectId(...)`. Aplica las skills `express-routes`, `mongo-aggregations` y `winston-logging` del preset según la capa que toques. Las skills de `mongoose` y de validación (`zod-validation` o `joi-validation`) se inyectan según las dependencias que detecte navori en el repo — si están en `.claude/skills/`, aplícalas.
|
|
6
6
|
|
|
7
7
|
El trabajo de un ticket sigue el pipeline documentado en la skill `ticket-intake` (la orquestadora). No es un generador de specs: es un protocolo que el `leader` ejecuta invocando agentes y skills en orden, con gates objetivos y artefactos en `.claude/progress/`. Mapeo de fases a la infraestructura de navori:
|
|
8
8
|
|
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pr-create
|
|
3
|
-
description: Crea un PR en GitHub contra la rama
|
|
3
|
+
description: Crea un PR en GitHub contra la rama target del repo, delegando title/body a un modelo y validando el output. Antes de crear cualquier PR al cerrar el ciclo de un ticket (Fase 8 de ticket-intake).
|
|
4
4
|
type: reference
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- candidate: workflow-backend -->
|
|
8
8
|
|
|
9
|
-
# pr-create — crear PR contra `{{
|
|
9
|
+
# pr-create — crear PR contra `{{prTarget}}`
|
|
10
10
|
|
|
11
11
|
## Cuándo usar este skill
|
|
12
12
|
|
|
13
|
-
Al cierre del ciclo, tras el `APPROVED` del reviewer
|
|
13
|
+
Al cierre del ciclo, tras el `APPROVED` del reviewer (Fase 8 de `ticket-intake`). El pre-flight es bloqueante: ningún PR sale con el gate en rojo o sin aprobación (harness activo).
|
|
14
|
+
|
|
15
|
+
`{{branchBase}}` es el punto de fork; `{{prTarget}}` es la rama destino del PR. Cuando difieren, el PR y su diff van contra `{{prTarget}}`.
|
|
14
16
|
|
|
15
17
|
## Pre-flight (bloqueante — cualquier check falla → ABORT con mensaje claro)
|
|
16
18
|
|
|
17
19
|
1. **Working tree limpio** o solo cambios del feature: `git status --porcelain`. Si hay cambios uncommitted que NO son del feature, párate y pregunta.
|
|
18
|
-
2. **No estás en rama
|
|
20
|
+
2. **No estás en una rama protegida**: aborta si la rama actual es `main|master|{{branchBase}}|{{prTarget}}`.
|
|
19
21
|
3. **`gh` autenticado**: `gh auth status`.
|
|
20
22
|
4. **Gate verde en este turno**: `{{qualityGate.fast}}`. Falla → manda al implementer.
|
|
21
23
|
5. **Review APPROVED** (si el harness está activo): `grep -q APPROVED .claude/progress/review_*.md`. Falla → manda al reviewer.
|
|
22
|
-
6. **Hay commits
|
|
23
|
-
7. **Branch sincronizada**: `git
|
|
24
|
+
6. **Hay commits para el PR**: `git fetch origin {{prTarget}} --quiet` y `git log origin/{{prTarget}}..HEAD --oneline`. Vacío → nada que PR-ear.
|
|
25
|
+
7. **Branch sincronizada**: `git log HEAD..origin/{{prTarget}} --oneline`. Si origin va adelante, rebase y pregunta.
|
|
26
|
+
8. **Arrastre de commits** (solo si `{{branchBase}}` ≠ `{{prTarget}}`): `git rev-list --count origin/{{prTarget}}..origin/{{branchBase}}`. Si es > 0, `{{branchBase}}` va adelantado de `{{prTarget}}` y el PR arrastra esos commits ajenos: avisa y sugiere `git rebase origin/{{prTarget}}` antes de abrir.
|
|
24
27
|
|
|
25
28
|
## Push y redacción
|
|
26
29
|
|
|
@@ -28,32 +31,29 @@ Si la branch no está pusheada: `git push -u origin "$current_branch"`. Si el up
|
|
|
28
31
|
|
|
29
32
|
Delega title + body a un `Agent` (modelo rápido). Reglas que le impones:
|
|
30
33
|
- **Title**: Conventional Commit con scope de tu dominio, ≤70 chars, español MX, sin emojis ni puntuación final.
|
|
31
|
-
- **Body**:
|
|
32
|
-
- **Contexto al redactor**: branch, base `{{
|
|
34
|
+
- **Body**: secciones fijas `## Resumen`, `## Cambios`, `## Test plan`, `## Notas` (opcional). Tono directo, sin "Generated by Claude".
|
|
35
|
+
- **Contexto al redactor**: branch, base `{{prTarget}}`, ticket, `impl_<feature>.md`, `review_<feature>.md`, y el diff REAL del PR — `git log origin/{{prTarget}}..HEAD --oneline` + `git diff origin/{{prTarget}}...HEAD --stat`.
|
|
33
36
|
- **Output**: JSON exacto `{"title": "...", "body": "..."}` sin fences.
|
|
34
37
|
|
|
35
|
-
Valida
|
|
38
|
+
Valida: `title` ≤70 y Conventional Commit; `body` con Resumen, Cambios y Test plan. Si falla, reintenta (máx. 2).
|
|
36
39
|
|
|
37
40
|
## Crear el PR
|
|
38
41
|
|
|
39
42
|
```bash
|
|
40
|
-
gh pr create --base {{
|
|
43
|
+
gh pr create --base {{prTarget}} --title "$title" --body "$body"
|
|
41
44
|
```
|
|
42
45
|
|
|
43
46
|
Captura la URL del output y muéstrasela al usuario.
|
|
44
47
|
|
|
45
48
|
## Reglas duras
|
|
46
49
|
|
|
47
|
-
- **NUNCA `git push --force`** sin que lo pida el usuario.
|
|
48
|
-
- **
|
|
49
|
-
- **NUNCA `--no-verify`** en commits previos.
|
|
50
|
+
- **NUNCA `git push --force`** ni `--no-verify` sin que lo pida el usuario.
|
|
51
|
+
- **Siempre `--base {{prTarget}}`.** No lo cambies a mano; si el target del repo cambió, ajústalo con `navori configure pr-target`.
|
|
50
52
|
- **Cambios uncommitted ajenos al feature** → párate y pregunta, no los arrastres al PR.
|
|
51
|
-
- **No agregues** "Generated with Claude" ni emojis al body.
|
|
52
53
|
- **Reviewers/labels**: no los agregues automático salvo que el usuario lo pida.
|
|
53
54
|
|
|
54
55
|
## Antes de declarar listo
|
|
55
56
|
|
|
56
|
-
- El pre-flight pasó completo
|
|
57
|
-
- El
|
|
58
|
-
-
|
|
59
|
-
- Post-PR: `mem_save` de cualquier decisión no obvia, entrada en `history.md`, `current.md` a `state: idle`, y `mem_session_summary`.
|
|
57
|
+
- El pre-flight pasó completo y el title/body validaron.
|
|
58
|
+
- El PR se creó contra `{{prTarget}}` y su URL quedó mostrada al usuario.
|
|
59
|
+
- Post-PR: `mem_save` de decisiones no obvias, entrada en `history.md`, `current.md` a `state: idle`, y `mem_session_summary`.
|
|
@@ -17,16 +17,6 @@
|
|
|
17
17
|
"relPath": "presets/express-mongoose/skills/express-routes.md",
|
|
18
18
|
"destRelPath": ".claude/skills/express-routes.md"
|
|
19
19
|
},
|
|
20
|
-
{
|
|
21
|
-
"id": "mongoose",
|
|
22
|
-
"relPath": "presets/express-mongoose/skills/mongoose.md",
|
|
23
|
-
"destRelPath": ".claude/skills/mongoose.md"
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"id": "zod-validation",
|
|
27
|
-
"relPath": "presets/express-mongoose/skills/zod-validation.md",
|
|
28
|
-
"destRelPath": ".claude/skills/zod-validation.md"
|
|
29
|
-
},
|
|
30
20
|
{
|
|
31
21
|
"id": "mongo-aggregations",
|
|
32
22
|
"relPath": "presets/express-mongoose/skills/mongo-aggregations.md",
|
|
@@ -66,8 +56,6 @@
|
|
|
66
56
|
"ApiResponse",
|
|
67
57
|
"mongoose",
|
|
68
58
|
"Types.ObjectId",
|
|
69
|
-
"zod-validation",
|
|
70
|
-
"z.coerce",
|
|
71
59
|
"ticket-intake",
|
|
72
60
|
"new-resource"
|
|
73
61
|
]
|
|
@@ -14,6 +14,18 @@
|
|
|
14
14
|
"Bash(git branch*)",
|
|
15
15
|
"Bash(git fetch*)",
|
|
16
16
|
"Bash(git stash*)",
|
|
17
|
+
"Bash(git blame*)",
|
|
18
|
+
"Bash(git describe*)",
|
|
19
|
+
"Bash(git rev-parse*)",
|
|
20
|
+
"Bash(git ls-files*)",
|
|
21
|
+
"Bash(git cat-file*)",
|
|
22
|
+
"Bash(git shortlog*)",
|
|
23
|
+
"Bash(git tag -l*)",
|
|
24
|
+
"Bash(git tag --list*)",
|
|
25
|
+
"Bash(git config --get*)",
|
|
26
|
+
"Bash(git config --list*)",
|
|
27
|
+
"Bash(git remote -v*)",
|
|
28
|
+
"Bash(git remote get-url*)",
|
|
17
29
|
"Read",
|
|
18
30
|
"Glob",
|
|
19
31
|
"Grep",
|
|
@@ -26,7 +38,16 @@
|
|
|
26
38
|
"Bash(which:*)",
|
|
27
39
|
"Bash(file:*)",
|
|
28
40
|
"Bash(stat:*)",
|
|
29
|
-
"Bash(tree:*)"
|
|
41
|
+
"Bash(tree:*)",
|
|
42
|
+
"Bash(grep:*)",
|
|
43
|
+
"Bash(jq:*)",
|
|
44
|
+
"Bash(diff:*)",
|
|
45
|
+
"Bash(cut:*)",
|
|
46
|
+
"Bash(du:*)",
|
|
47
|
+
"Bash(df:*)",
|
|
48
|
+
"Bash(realpath:*)",
|
|
49
|
+
"Bash(dirname:*)",
|
|
50
|
+
"Bash(basename:*)"
|
|
30
51
|
],
|
|
31
52
|
"ask": [
|
|
32
53
|
"Bash(rm -rf *)",
|