@dforce2055/dai 0.1.1 → 0.2.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.
- package/CHANGELOG.md +24 -0
- package/CODE_OF_CONDUCT.md +1 -1
- package/README.md +20 -11
- package/VERSION +1 -1
- package/cli/dai.mjs +99 -26
- package/cli/lib/args.mjs +17 -0
- package/cli/lib/bootstrap.mjs +27 -0
- package/docs/adr/0008-estrategia-de-i18n.md +73 -0
- package/docs/adr/0009-adaptador-cursor.md +63 -0
- package/docs/adr/README.md +2 -0
- package/index.html +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
3
3
|
Formato basado en [Keep a Changelog](https://keepachangelog.com/). Versionado semver
|
|
4
4
|
(ver `VERSION`).
|
|
5
5
|
|
|
6
|
+
## [0.2.0] — 2026-07-08
|
|
7
|
+
|
|
8
|
+
Soporte para **Cursor** como asistente y un `--for` combinable. Incluye la **primera
|
|
9
|
+
contribución de la comunidad** 🎉 (@sermati).
|
|
10
|
+
|
|
11
|
+
### Agregado
|
|
12
|
+
- **Adaptador de Cursor** ([ADR-0009](docs/adr/0009-adaptador-cursor.md), aporte de la
|
|
13
|
+
comunidad): `dai init` / `install` / `doctor` soportan Cursor — generan
|
|
14
|
+
`.cursor/skills/*/SKILL.md` y `.cursor/rules/dai-constitution.mdc` (regla always-on) desde
|
|
15
|
+
la misma fuente `skills/*/SKILL.md`.
|
|
16
|
+
- **`--for` combinable**: acepta subconjuntos de asistentes (`--for claude,cursor`,
|
|
17
|
+
`--for copilot`), además de `both` (Claude+Copilot) y `all` (los tres). Nuevo
|
|
18
|
+
`parseAssistants()` en `args.mjs`.
|
|
19
|
+
|
|
20
|
+
### Cambiado
|
|
21
|
+
- **Default de `dai init` = `all`** (Claude + Copilot + Cursor) — deja el repo listo para
|
|
22
|
+
cualquier asistente.
|
|
23
|
+
- El mensaje de "próximos pasos" de `dai init` apunta a la **URL online** de la guía
|
|
24
|
+
`PROBAR.md` (antes una ruta local que el usuario instalado no encontraba).
|
|
25
|
+
|
|
26
|
+
### Interno
|
|
27
|
+
- **93 tests** (+6 desde 0.1.1: `skillToCursor`, `constitutionCursorRule`, `parseAssistants`).
|
|
28
|
+
|
|
6
29
|
## [0.1.1] — 2026-07-06
|
|
7
30
|
|
|
8
31
|
Solo documentación y metadata — **el CLI no cambia** (mismo `ac_hash`, mismo protocolo).
|
|
@@ -52,5 +75,6 @@ ClickUp y Jira Cloud.
|
|
|
52
75
|
- Tests de las rutas de red (jira/clickup/forge) con `fetch` mockeado. Sin links rotos;
|
|
53
76
|
`files` de npm sin tests ni secretos.
|
|
54
77
|
|
|
78
|
+
[0.2.0]: https://github.com/dforce2055/dai/releases/tag/v0.2.0
|
|
55
79
|
[0.1.1]: https://github.com/dforce2055/dai/releases/tag/v0.1.1
|
|
56
80
|
[0.1.0]: https://github.com/dforce2055/dai/releases/tag/v0.1.0
|
package/CODE_OF_CONDUCT.md
CHANGED
|
@@ -11,7 +11,7 @@ apariencia, religión u orientación.
|
|
|
11
11
|
|
|
12
12
|
Comportamientos que esperamos:
|
|
13
13
|
|
|
14
|
-
- Lenguaje
|
|
14
|
+
- Lenguaje respetuoso y considerado.
|
|
15
15
|
- Respeto por puntos de vista y experiencias distintas.
|
|
16
16
|
- Aceptar la crítica constructiva con gracia.
|
|
17
17
|
- Enfocarse en lo mejor para la comunidad.
|
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ escribió, aparece el **vibe coding**, y el *qué* (negocio) se mezcla con el *c
|
|
|
28
28
|
|
|
29
29
|
Juntas hacen que la IA potencie tu desarrollo **sin perder el control**: todo lo que se
|
|
30
30
|
construye queda linkeado a por qué se construyó, y **la máquina te avisa sola** cuando algo
|
|
31
|
-
se desincroniza. Del solo developer a un equipo entero de desarrollo — el mismo método, con Claude o
|
|
31
|
+
se desincroniza. Del solo developer a un equipo entero de desarrollo — el mismo método, con Claude, Copilot o Cursor.
|
|
32
32
|
|
|
33
33
|
## Cómo funciona (3 ideas)
|
|
34
34
|
|
|
@@ -49,7 +49,7 @@ deja las skills disponibles:
|
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
51
|
npm i -g @dforce2055/dai # el CLI
|
|
52
|
-
dai install # skills de IA →
|
|
52
|
+
dai install # skills de IA → Claude y Cursor (global por defecto)
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Y después, en el chat del asistente, según lo que tengas:
|
|
@@ -128,7 +128,7 @@ flowchart TD
|
|
|
128
128
|
| # | Fase | Cómo | Quién |
|
|
129
129
|
|---|---|---|---|
|
|
130
130
|
| 1 | **Instalar el CLI** | `npm i -g @dforce2055/dai` (o `npm link` en dev) · `dai --version` | dev |
|
|
131
|
-
| 2 | **Bootstrap del repo** | `dai init` → `.dai` + Claude/Copilot + config + PR template | dev/lead |
|
|
131
|
+
| 2 | **Bootstrap del repo** | `dai init` → `.dai` + Claude/Copilot/Cursor + config + PR template | dev/lead |
|
|
132
132
|
| 3a | **Definir el QUÉ** | `/grill-user-story` (una US) · `/grill-epic` (algo grande) · `/doc-to-backlog` (un doc) — te interrogan hasta una US testeable | PO / analista |
|
|
133
133
|
| 3b | **Publicar la US** | la skill la sube al tracker vía **MCP**, o con **`dai publish <us.md>`** (crea el issue vía token, sin MCP) → devuelve el key | PO / IA |
|
|
134
134
|
| 4 | **Linkear la US** | `dai link-us <ID>` → branch + `openspec/changes/<id>/implements.yaml` | dev |
|
|
@@ -156,8 +156,8 @@ flowchart TD
|
|
|
156
156
|
|
|
157
157
|
| Comando | Qué hace |
|
|
158
158
|
|---|---|
|
|
159
|
-
| `dai init [<repo>]` | scaffolder interactivo del repo. Flags: `--for claude\|copilot\|both` (asistente,
|
|
160
|
-
| `dai install [--global \| --local <repo>] [--force] [--dry-run]` | instala/actualiza
|
|
159
|
+
| `dai init [<repo>]` | scaffolder interactivo del repo. Flags: `--for claude\|copilot\|both\|cursor\|all` (asistente, default `all`) · `--pm md\|jira\|clickup` (tracker) · `--openspec` |
|
|
160
|
+
| `dai install [--global \| --local <repo>] [--force] [--dry-run] [--for claude\|cursor\|all]` | instala/actualiza skills de IA en Claude y/o Cursor (`--for all` por defecto). `--force` re-copia aunque ya existan. Ej: `dai install --local . --for cursor --force` · `dai install --global --for all --force` |
|
|
161
161
|
| `dai publish <us.md>` | crea la US en el tracker (Jira/ClickUp/md) desde un `.md` y devuelve el key. Es el fallback del MCP para publicar sin el asistente |
|
|
162
162
|
| `dai link-us <ID> [--us <md>]` | crea branch + `implements.yaml`; sin `--us` trae la US del tracker |
|
|
163
163
|
| `dai link-us <ID> --resync` | re-estampa el `ac_hash` contra la US viva (tras un ⚠️ de check) |
|
|
@@ -183,18 +183,23 @@ ver [`.env.example`](.env.example). Auth (SSH + tokens): [ADR-0007](docs/adr/000
|
|
|
183
183
|
|---|---|---|
|
|
184
184
|
| `--for claude` | `.claude/skills/` + `CLAUDE.md` | tu equipo usa **Claude** (Code / Desktop) |
|
|
185
185
|
| `--for copilot` | `.github/prompts/*.prompt.md` + `.github/copilot-instructions.md` | tu equipo usa **GitHub Copilot** (en VS Code / JetBrains) |
|
|
186
|
-
| `--for
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
| `--for cursor` | `.cursor/skills/` + `.cursor/rules/dai-constitution.mdc` | tu equipo usa **Cursor Agent** |
|
|
187
|
+
| `--for both` | Claude + Copilot | equipo mixto sin Cursor |
|
|
188
|
+
| `--for all` *(default)* | Claude + Copilot + Cursor | quieres dejar el repo listo para cualquier asistente |
|
|
189
|
+
|
|
190
|
+
- **Combinables:** pasá un subconjunto separado por coma — `--for claude,cursor` o
|
|
191
|
+
`--for copilot`. `all` = los tres · `both` = Claude+Copilot. (Igual en `dai install`,
|
|
192
|
+
aunque ahí Copilot no aplica: no tiene skills instalables.)
|
|
193
|
+
- Es **aditivo, no destructivo**: los conjuntos conviven sin pisarse (viven en
|
|
189
194
|
carpetas distintas). La **misma** skill se transforma al formato de cada asistente.
|
|
190
195
|
- Si ejecutas `dai init` sin flag, te lo pregunta de forma interactiva.
|
|
191
196
|
- **No afecta el CLI:** `dai link-us` / `check` / `stamp` funcionan igual con cualquier
|
|
192
197
|
`--for` (o ninguno) — el flag solo prepara la **invocación de skills** en el asistente.
|
|
193
|
-
- Ante la duda, `--for
|
|
198
|
+
- Ante la duda, `--for all`: cubre a todo el equipo y no cuesta nada.
|
|
194
199
|
|
|
195
200
|
## Lo que obtienes en tu repo
|
|
196
201
|
|
|
197
|
-
Después de `dai init` (con `--for
|
|
202
|
+
Después de `dai init` (con `--for all`):
|
|
198
203
|
|
|
199
204
|
```
|
|
200
205
|
mi-repo/
|
|
@@ -206,6 +211,9 @@ mi-repo/
|
|
|
206
211
|
│ ├── copilot-instructions.md · La constitución, auto-inyectada en cada chat de Copilot
|
|
207
212
|
│ ├── prompts/*.prompt.md · Las mismas skills, generadas en formato Copilot
|
|
208
213
|
│ └── pull_request_template.md · Molde de PR/MR atado al link
|
|
214
|
+
├── .cursor/
|
|
215
|
+
│ ├── skills/ · Las mismas skills, en formato Cursor
|
|
216
|
+
│ └── rules/dai-constitution.mdc · Constitución always-on de Cursor
|
|
209
217
|
└── .dai/
|
|
210
218
|
├── templates/ · formato-us · epica · DoR · DoD · adr · pull-request
|
|
211
219
|
└── governance/ · branch-naming · ci-rules · commit-convention
|
|
@@ -225,6 +233,7 @@ Las skills se invocan en el asistente — **no en todas sus superficies** (lími
|
|
|
225
233
|
|---|---|---|
|
|
226
234
|
| **Claude Desktop** | ✅ | `~/.claude/skills/` (global) — sin IDE ni consola |
|
|
227
235
|
| **Claude Code** | ✅ | `~/.claude/skills/` + `.claude/skills/` del repo |
|
|
236
|
+
| **Cursor Agent (IDE)** | ✅ | `.cursor/skills/*/SKILL.md` + `.cursor/rules/*.mdc` |
|
|
228
237
|
| **Copilot en VS Code / JetBrains** | ✅ | los `.github/prompts/*.prompt.md` |
|
|
229
238
|
| **Copilot CLI** | ✅ | custom agents |
|
|
230
239
|
| **Copilot app standalone / github.com chat** | ❌ | los prompt files son solo-IDE |
|
|
@@ -256,7 +265,7 @@ Además: [`docs/glosario.md`](docs/glosario.md) · guías por rol ([`po`](docs/g
|
|
|
256
265
|
dai/
|
|
257
266
|
├── cli/ 🖥️ el binario `dai` (Node, cero dependencias) + su suite de tests
|
|
258
267
|
├── docs/ 📖 la metodología: MANIFIESTO · METODOLOGIA · SCRUM-CON-IA · EJEMPLO ·
|
|
259
|
-
│ glosario · guias/ · detalle/ (10 pasos) · adr/ (0001–
|
|
268
|
+
│ glosario · guias/ · detalle/ (10 pasos) · adr/ (0001–0009)
|
|
260
269
|
├── templates/ 🧩 los moldes (formato-us · epica · DoR · DoD · adr · pull-request)
|
|
261
270
|
├── skills/ 🤖 doc-to-backlog · grill-intent · grill-epic · grill-user-story · link-us · tdd · dai-review
|
|
262
271
|
├── governance/ 🛡️ branch-naming · ci-rules · commit-convention
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.0
|
package/cli/dai.mjs
CHANGED
|
@@ -27,8 +27,8 @@ import { branchUrl, commitUrl, parseRemote, detectForge } from "./lib/forge-url.
|
|
|
27
27
|
import { parsePrRef, getPR, postComment } from "./lib/forge-api.mjs";
|
|
28
28
|
import { composePrBody, prTitle, forgeTool } from "./lib/pr.mjs";
|
|
29
29
|
import { dirsEqual } from "./lib/fsutil.mjs";
|
|
30
|
-
import { parseFlags } from "./lib/args.mjs";
|
|
31
|
-
import { skillToPrompt, constitution, envFor } from "./lib/bootstrap.mjs";
|
|
30
|
+
import { parseFlags, parseAssistants } from "./lib/args.mjs";
|
|
31
|
+
import { skillToPrompt, skillToCursor, constitution, constitutionCursorRule, envFor } from "./lib/bootstrap.mjs";
|
|
32
32
|
|
|
33
33
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
34
34
|
|
|
@@ -40,7 +40,8 @@ const ok = (m) => process.stdout.write(`✓ ${m}\n`);
|
|
|
40
40
|
const info = (m) => process.stdout.write(`› ${m}\n`);
|
|
41
41
|
const warn = (m) => process.stdout.write(`⚠ ${m}\n`);
|
|
42
42
|
const ROOT = join(HERE, ".."); // raíz del paquete dai (cli/ está adentro)
|
|
43
|
-
const
|
|
43
|
+
const CLAUDE_SKILLS_DIR = process.env.CLAUDE_SKILLS_DIR || join(homedir(), ".claude", "skills");
|
|
44
|
+
const CURSOR_SKILLS_DIR = process.env.CURSOR_SKILLS_DIR || join(homedir(), ".cursor", "skills");
|
|
44
45
|
function git(args, opts = {}) {
|
|
45
46
|
// stderr en 'pipe' (no 'inherit') para no filtrar errores de git a la salida;
|
|
46
47
|
// quedan en e.stderr para quien quiera inspeccionarlos.
|
|
@@ -412,6 +413,15 @@ async function cmdPr(opts) {
|
|
|
412
413
|
async function cmdInstall(opts) {
|
|
413
414
|
const skillsSrc = join(ROOT, "skills");
|
|
414
415
|
const skills = readdirSync(skillsSrc).filter((n) => statSync(join(skillsSrc, n)).isDirectory());
|
|
416
|
+
let want;
|
|
417
|
+
try { want = parseAssistants(typeof opts.for === "string" ? opts.for : "all"); }
|
|
418
|
+
catch (e) { fail(`--for ${e.message}`); }
|
|
419
|
+
// Copilot no tiene skills instalables (no hay dir global ni local de skills de Copilot):
|
|
420
|
+
// sus prompts los genera `dai init` en el repo. Se ignora en `install`.
|
|
421
|
+
if (want.copilot) warn("Copilot no tiene skills instalables — se generan con `dai init` en el repo. Ignoro 'copilot'.");
|
|
422
|
+
const wantClaude = want.claude, wantCursor = want.cursor;
|
|
423
|
+
if (!wantClaude && !wantCursor) fail("nada para instalar: pasá --for claude|cursor|all.");
|
|
424
|
+
const installFor = [wantClaude && "claude", wantCursor && "cursor"].filter(Boolean).join("+");
|
|
415
425
|
const interactive = process.stdin.isTTY && !opts.global && opts.local === undefined;
|
|
416
426
|
const rl = interactive ? createInterface({ input: process.stdin, output: process.stdout }) : null;
|
|
417
427
|
|
|
@@ -422,25 +432,54 @@ async function cmdInstall(opts) {
|
|
|
422
432
|
return a === "l" ? { scope: "local", repo: process.cwd() } : a === "s" ? { scope: "skip" } : { scope: "global" };
|
|
423
433
|
};
|
|
424
434
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
const
|
|
435
|
+
const installOne = async ({ name, scope, repo, kind }) => {
|
|
436
|
+
const src = join(skillsSrc, name);
|
|
437
|
+
const targetDir = scope === "local"
|
|
438
|
+
? join(repo, kind === "cursor" ? ".cursor" : ".claude", "skills")
|
|
439
|
+
: kind === "cursor" ? CURSOR_SKILLS_DIR : CLAUDE_SKILLS_DIR;
|
|
440
|
+
const target = join(targetDir, name);
|
|
441
|
+
const label = kind === "cursor" ? `${name} (cursor)` : `${name} (claude)`;
|
|
442
|
+
|
|
443
|
+
let sameAsSource = false;
|
|
431
444
|
if (existsSync(target)) {
|
|
432
|
-
if (
|
|
445
|
+
if (kind === "claude") {
|
|
446
|
+
sameAsSource = dirsEqual(src, target);
|
|
447
|
+
} else {
|
|
448
|
+
const tempRoot = mkdtempSync(join(tmpdir(), "dai-cursor-skill-"));
|
|
449
|
+
const tempTarget = join(tempRoot, name);
|
|
450
|
+
mkdirSync(tempRoot, { recursive: true });
|
|
451
|
+
cpSync(src, tempTarget, { recursive: true });
|
|
452
|
+
const srcMd = readFileSync(join(src, "SKILL.md"), "utf8");
|
|
453
|
+
writeFileSync(join(tempTarget, "SKILL.md"), skillToCursor(srcMd));
|
|
454
|
+
sameAsSource = dirsEqual(tempTarget, target);
|
|
455
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (sameAsSource) { ok(`${label} — ya instalada e idéntica, salto`); return; }
|
|
433
459
|
if (!opts.force) {
|
|
434
|
-
if (!interactive) { warn(`${
|
|
435
|
-
const a = (await rl.question(` ${
|
|
436
|
-
if (a !== "p") { warn(`salto ${
|
|
460
|
+
if (!interactive) { warn(`${label} existe y difiere — salto (usa --force)`); return; }
|
|
461
|
+
const a = (await rl.question(` ${label} existe y DIFIERE. ¿[p]isar · [s]altar? (s) `)).trim().toLowerCase();
|
|
462
|
+
if (a !== "p") { warn(`salto ${label}`); return; }
|
|
437
463
|
}
|
|
438
464
|
}
|
|
439
|
-
|
|
465
|
+
|
|
466
|
+
if (opts.dryRun) { info(`[dry-run] ${label} → ${targetDir}`); return; }
|
|
440
467
|
rmSync(target, { recursive: true, force: true });
|
|
441
468
|
mkdirSync(targetDir, { recursive: true });
|
|
442
469
|
cpSync(src, target, { recursive: true });
|
|
443
|
-
|
|
470
|
+
if (kind === "cursor") {
|
|
471
|
+
const srcMd = readFileSync(join(src, "SKILL.md"), "utf8");
|
|
472
|
+
writeFileSync(join(target, "SKILL.md"), skillToCursor(srcMd));
|
|
473
|
+
}
|
|
474
|
+
ok(`${label} → ${targetDir}`);
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
info(`Instalando skills de dai (${installFor})`);
|
|
478
|
+
for (const name of skills) {
|
|
479
|
+
const { scope, repo } = await scopeFor(name);
|
|
480
|
+
if (scope === "skip") { warn(`salto ${name}`); continue; }
|
|
481
|
+
if (wantClaude) await installOne({ name, scope, repo, kind: "claude" });
|
|
482
|
+
if (wantCursor) await installOne({ name, scope, repo, kind: "cursor" });
|
|
444
483
|
}
|
|
445
484
|
if (rl) rl.close();
|
|
446
485
|
}
|
|
@@ -483,12 +522,15 @@ async function cmdInit(repo, opts) {
|
|
|
483
522
|
// Preguntas primero (después cerramos readline para liberar stdin a los instaladores).
|
|
484
523
|
let forOpt = typeof opts.for === "string" ? opts.for.toLowerCase() : null;
|
|
485
524
|
if (!forOpt && rl) forOpt = await askMenu(rl, "¿Para qué asistente de IA preparo el repo? (genera las skills en su formato)", [
|
|
486
|
-
{ value: "
|
|
525
|
+
{ value: "all", label: "Todos (Claude + Copilot + Cursor) — por defecto" },
|
|
526
|
+
{ value: "both", label: "Claude + Copilot — equipo mixto (sin Cursor)" },
|
|
487
527
|
{ value: "claude", label: "Solo Claude (Code / Desktop)" },
|
|
488
528
|
{ value: "copilot", label: "Solo Copilot (en VS Code / JetBrains)" },
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
529
|
+
{ value: "cursor", label: "Solo Cursor (Agent)" },
|
|
530
|
+
], "all");
|
|
531
|
+
forOpt = forOpt || "all";
|
|
532
|
+
let want;
|
|
533
|
+
try { want = parseAssistants(forOpt); } catch (e) { fail(`--for ${e.message}`); }
|
|
492
534
|
|
|
493
535
|
let pm = typeof opts.pm === "string" ? opts.pm.toLowerCase() : null;
|
|
494
536
|
if (!pm && rl) pm = await askMenu(rl, "¿Dónde van a vivir las User Stories?", [
|
|
@@ -515,8 +557,7 @@ async function cmdInit(repo, opts) {
|
|
|
515
557
|
if (rl) rl.close();
|
|
516
558
|
|
|
517
559
|
// ── Generación ───────────────────────────────────────────────────────────────
|
|
518
|
-
const wantClaude =
|
|
519
|
-
const wantCopilot = forOpt !== "claude";
|
|
560
|
+
const wantClaude = want.claude, wantCopilot = want.copilot, wantCursor = want.cursor;
|
|
520
561
|
process.stdout.write("\n Configurando…\n\n");
|
|
521
562
|
|
|
522
563
|
const dai = join(repo, ".dai");
|
|
@@ -554,6 +595,20 @@ async function cmdInit(repo, opts) {
|
|
|
554
595
|
writeFileSync(join(repo, ".github", "copilot-instructions.md"), constitution("copilot"));
|
|
555
596
|
ok(`Copilot: .github/prompts/ (${skills.length}) + copilot-instructions.md`);
|
|
556
597
|
}
|
|
598
|
+
if (wantCursor) {
|
|
599
|
+
const dir = join(repo, ".cursor", "skills");
|
|
600
|
+
mkdirSync(dir, { recursive: true });
|
|
601
|
+
for (const name of skills) {
|
|
602
|
+
const src = join(skillsSrc, name);
|
|
603
|
+
const target = join(dir, name);
|
|
604
|
+
cpSync(src, target, { recursive: true });
|
|
605
|
+
const srcMd = readFileSync(join(src, "SKILL.md"), "utf8");
|
|
606
|
+
writeFileSync(join(target, "SKILL.md"), skillToCursor(srcMd));
|
|
607
|
+
}
|
|
608
|
+
mkdirSync(join(repo, ".cursor", "rules"), { recursive: true });
|
|
609
|
+
writeFileSync(join(repo, ".cursor", "rules", "dai-constitution.mdc"), constitutionCursorRule());
|
|
610
|
+
ok(`Cursor: .cursor/skills/ (${skills.length}) + .cursor/rules/dai-constitution.mdc`);
|
|
611
|
+
}
|
|
557
612
|
|
|
558
613
|
// ── OpenSpec ───────────────────────────────────────────────────────────────
|
|
559
614
|
// OpenSpec tiene modo NO-interactivo (`openspec init --tools <lista> --force`),
|
|
@@ -561,7 +616,8 @@ async function cmdInit(repo, opts) {
|
|
|
561
616
|
// dejaba a medias porque se intentaba correr su modo interactivo anidado.)
|
|
562
617
|
process.stdout.write("\n");
|
|
563
618
|
const openspecPresent = () => { try { execFileSync(npmBin("openspec"), ["--version"], { stdio: "ignore" }); return true; } catch { return false; } };
|
|
564
|
-
const osTools =
|
|
619
|
+
const osTools = [want.claude && "claude", want.copilot && "github-copilot", want.cursor && "cursor"]
|
|
620
|
+
.filter(Boolean).join(",") || "claude,github-copilot,cursor";
|
|
565
621
|
const osHint = "para sumarlo después: npm i -g @fission-ai/openspec@latest && openspec init --tools " + osTools;
|
|
566
622
|
if (hasOpenspec) {
|
|
567
623
|
ok("OpenSpec: ya inicializado en el repo");
|
|
@@ -596,7 +652,7 @@ async function cmdInit(repo, opts) {
|
|
|
596
652
|
: ` 1. Completa el token de ${pm} en .env, y verifica con: dai doctor\n`);
|
|
597
653
|
process.stdout.write(" 2. dai link-us <ID> → crea la branch + el link a la US\n");
|
|
598
654
|
process.stdout.write(" 3. Implementa con test primero, después: dai check\n");
|
|
599
|
-
process.stdout.write(" Guía paso a paso: docs/PROBAR.md\n\n");
|
|
655
|
+
process.stdout.write(" Guía paso a paso: https://github.com/dforce2055/dai/blob/main/docs/PROBAR.md\n\n");
|
|
600
656
|
}
|
|
601
657
|
|
|
602
658
|
// ── docs: documentación conceptual → <destino> ────────────────────────────────
|
|
@@ -617,13 +673,29 @@ function cmdDoctor() {
|
|
|
617
673
|
const localDir = join(process.cwd(), ".claude", "skills");
|
|
618
674
|
info("skills (repo local / global ~/.claude/skills):");
|
|
619
675
|
for (const name of readdirSync(join(ROOT, "skills"))) {
|
|
620
|
-
const local = existsSync(join(localDir, name)), global = existsSync(join(
|
|
676
|
+
const local = existsSync(join(localDir, name)), global = existsSync(join(CLAUDE_SKILLS_DIR, name));
|
|
621
677
|
if (local && global) ok(`${name} (local + global)`);
|
|
622
678
|
else if (local) ok(`${name} (local, este repo)`);
|
|
623
679
|
else if (global) ok(`${name} (global)`);
|
|
624
680
|
else warn(`${name} — no instalada (dai init en el repo, o dai install global)`);
|
|
625
681
|
}
|
|
626
682
|
|
|
683
|
+
const cursorLocalDir = join(process.cwd(), ".cursor", "skills");
|
|
684
|
+
info("skills Cursor (repo local / global ~/.cursor/skills):");
|
|
685
|
+
for (const name of readdirSync(join(ROOT, "skills"))) {
|
|
686
|
+
const local = existsSync(join(cursorLocalDir, name)), global = existsSync(join(CURSOR_SKILLS_DIR, name));
|
|
687
|
+
if (local && global) ok(`${name} (local + global)`);
|
|
688
|
+
else if (local) ok(`${name} (local, este repo)`);
|
|
689
|
+
else if (global) ok(`${name} (global)`);
|
|
690
|
+
else warn(`${name} — no instalada en Cursor (dai init --for cursor|all, o dai install --for cursor|all)`);
|
|
691
|
+
}
|
|
692
|
+
const localRule = join(process.cwd(), ".cursor", "rules", "dai-constitution.mdc");
|
|
693
|
+
const globalRule = join(homedir(), ".cursor", "rules", "dai-constitution.mdc");
|
|
694
|
+
if (existsSync(localRule) && existsSync(globalRule)) ok("constitución Cursor (local + global)");
|
|
695
|
+
else if (existsSync(localRule)) ok("constitución Cursor (local)");
|
|
696
|
+
else if (existsSync(globalRule)) ok("constitución Cursor (global)");
|
|
697
|
+
else warn("falta constitución Cursor (dai-constitution.mdc)");
|
|
698
|
+
|
|
627
699
|
info("adaptador de PM:");
|
|
628
700
|
const pm = process.env.DAI_PM || "md";
|
|
629
701
|
ok(`DAI_PM=${pm}`);
|
|
@@ -680,9 +752,10 @@ switch (cmd) {
|
|
|
680
752
|
" pr [--assignee u] [--base b] [--draft] [--yes] crea TU PR/MR precargada (muestra + confirma)\n" +
|
|
681
753
|
" forge comment <ref> --body-file <f> · forge pr <ref> comentar/leer una PR ajena (github/gitlab)\n\n" +
|
|
682
754
|
"Instalación:\n" +
|
|
683
|
-
" install [--global | --local <repo>] [--force] [--dry-run] skills → Claude\n" +
|
|
755
|
+
" install [--global | --local <repo>] [--force] [--dry-run] [--for <asistentes>] skills → Claude/Cursor\n" +
|
|
684
756
|
" init [<repo>] scaffolder interactivo del repo (asistente, gestor, OpenSpec)\n" +
|
|
685
|
-
" --for claude|copilot|
|
|
757
|
+
" --for <asistentes> claude|copilot|cursor (combinables con coma) · o both|all (default all)\n" +
|
|
758
|
+
" ej: --for claude,cursor · --for copilot · --for all\n" +
|
|
686
759
|
" --pm md|jira|clickup · --openspec (con flags salteas las preguntas)\n" +
|
|
687
760
|
" docs <destino> documentación conceptual → <destino>\n" +
|
|
688
761
|
" doctor diagnóstico del entorno\n\n" +
|
package/cli/lib/args.mjs
CHANGED
|
@@ -5,6 +5,23 @@
|
|
|
5
5
|
|
|
6
6
|
export const camel = (s) => s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
7
7
|
|
|
8
|
+
// Parsea el valor de `--for` como una LISTA COMBINABLE de asistentes.
|
|
9
|
+
// Acepta "claude", "copilot", "cursor" (combinables con coma o espacio),
|
|
10
|
+
// "both" (= claude+copilot) y "all" (= los tres). Lanza si hay un token inválido.
|
|
11
|
+
// Ej.: "claude,cursor" → { claude:true, copilot:false, cursor:true }.
|
|
12
|
+
export function parseAssistants(str) {
|
|
13
|
+
const want = { claude: false, copilot: false, cursor: false };
|
|
14
|
+
const toks = String(str ?? "all").toLowerCase().split(/[,\s]+/).filter(Boolean);
|
|
15
|
+
if (toks.length === 0) { want.claude = want.copilot = want.cursor = true; return want; }
|
|
16
|
+
for (const t of toks) {
|
|
17
|
+
if (t === "all") { want.claude = want.copilot = want.cursor = true; }
|
|
18
|
+
else if (t === "both") { want.claude = want.copilot = true; }
|
|
19
|
+
else if (t in want) { want[t] = true; }
|
|
20
|
+
else throw new Error(`asistente inválido: '${t}' (claude|copilot|cursor, combinables con coma; o both|all)`);
|
|
21
|
+
}
|
|
22
|
+
return want;
|
|
23
|
+
}
|
|
24
|
+
|
|
8
25
|
export function parseFlags(argv) {
|
|
9
26
|
const opts = {};
|
|
10
27
|
const pos = [];
|
package/cli/lib/bootstrap.mjs
CHANGED
|
@@ -27,6 +27,20 @@ export function skillToPrompt(md) {
|
|
|
27
27
|
return `${fm}\n\n${body}\n`;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
// Transforma un SKILL.md (Claude) en un SKILL.md de Cursor.
|
|
31
|
+
// Conserva name/description/body y ajusta solo el frontmatter.
|
|
32
|
+
export function skillToCursor(md) {
|
|
33
|
+
const { name, description, body } = parseFrontmatter(md);
|
|
34
|
+
if (!name) return md.trim() + "\n";
|
|
35
|
+
const fm = [
|
|
36
|
+
"---",
|
|
37
|
+
`name: ${name}`,
|
|
38
|
+
`description: ${JSON.stringify(description || "")}`,
|
|
39
|
+
"---",
|
|
40
|
+
].join("\n");
|
|
41
|
+
return `${fm}\n\n${body}\n`;
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
// Contenido del .env según el backend de PM elegido (tokens vacíos, a completar).
|
|
31
45
|
export function envFor(pm) {
|
|
32
46
|
const head = "# Config de dai — completá lo que falte. NUNCA commitees tokens (.env está gitignored).\n";
|
|
@@ -44,6 +58,8 @@ export function envFor(pm) {
|
|
|
44
58
|
export function constitution(kind) {
|
|
45
59
|
const head = kind === "copilot"
|
|
46
60
|
? "# Instrucciones de Copilot para este repo\n\nEste repo sigue la metodología **dai**. Aplicá estas reglas en todo lo que generes.\n\n> **Superficie:** los prompts de dai (`.github/prompts/`) se invocan solo en VS Code /\n> JetBrains, o como custom agents en el Copilot CLI — no en la app standalone ni en\n> github.com. El CLI `dai` corre en cualquier terminal."
|
|
61
|
+
: kind === "cursor"
|
|
62
|
+
? "# Constitución del proyecto (dai)\n\nEste repo sigue la metodología **dai**. Estas reglas gobiernan todo el trabajo.\n\n> **Superficie:** las skills de dai (`.cursor/skills/`) se invocan con `/nombre-skill`\n> o cuando el agente las detecta por descripción. El CLI `dai` corre en cualquier terminal."
|
|
47
63
|
: "# Constitución del proyecto (dai)\n\nEste repo sigue la metodología **dai**. Estas reglas gobiernan todo el trabajo.";
|
|
48
64
|
return `${head}
|
|
49
65
|
|
|
@@ -72,3 +88,14 @@ export function constitution(kind) {
|
|
|
72
88
|
Detalle completo de la metodología: ${REPO_URL}
|
|
73
89
|
`;
|
|
74
90
|
}
|
|
91
|
+
|
|
92
|
+
// Regla de Cursor always-on con el contenido de la constitución (sin título H1).
|
|
93
|
+
export function constitutionCursorRule() {
|
|
94
|
+
const content = constitution("cursor").replace(/^# .+\n\n/, "");
|
|
95
|
+
return `---
|
|
96
|
+
description: Metodología dai — constitución del proyecto (valores, reglas, herramientas)
|
|
97
|
+
alwaysApply: true
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
${content}`;
|
|
101
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ADR-0008 — Estrategia de internacionalización (i18n)
|
|
2
|
+
|
|
3
|
+
- **Estado:** propuesto
|
|
4
|
+
- **Fecha:** 2026-07-06
|
|
5
|
+
- **Decide:** lead / arquitecto de la metodología
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
`dai` nació y se escribió **en español**. Para su difusión —el README es lo primero que
|
|
10
|
+
se ve en npm y GitHub, y el público de open source es mayoritariamente anglófono— hace
|
|
11
|
+
falta una versión en **inglés**. Pero traducir un proyecto tiene trampas: superficies muy
|
|
12
|
+
distintas (docs, landing HTML, mensajes del CLI, skills que son prompts), y el riesgo de
|
|
13
|
+
que las traducciones **se desincronicen** del original con cada cambio.
|
|
14
|
+
|
|
15
|
+
Dos cosas juegan a favor: (1) el tono ya es **español neutro internacional** (se sacó el
|
|
16
|
+
voseo y los modismos a propósito), que traduce limpio; y (2) `dai` puede **dogfood-earse**
|
|
17
|
+
—usar un agente para traducir de forma consistente— si se le fija la terminología.
|
|
18
|
+
|
|
19
|
+
La decisión es cómo estructurar el i18n para que sea **mantenible** y no genere drift.
|
|
20
|
+
|
|
21
|
+
## Decisión
|
|
22
|
+
|
|
23
|
+
Adoptamos un modelo de **fuente única + traducciones derivadas**, por superficie:
|
|
24
|
+
|
|
25
|
+
1. **Fuente de verdad: el español.** Se escribió primero y es el canónico. Cada archivo
|
|
26
|
+
traducido lleva una nota — *"Translation of the Spanish source; if they diverge, the
|
|
27
|
+
Spanish wins."* — igual que METODOLOGIA marca a los HTML como vistas derivadas.
|
|
28
|
+
|
|
29
|
+
2. **Estructura de carpetas.** `docs/es/` (fuente) y `docs/en/` (traducción). En la raíz,
|
|
30
|
+
`README.es.md` + `README.en.md`, y `README.md` con un **selector de idioma** arriba
|
|
31
|
+
(`🇪🇸 Español · 🇬🇧 English`). El landing: una versión por idioma o un toggle en la página.
|
|
32
|
+
|
|
33
|
+
3. **CLI: locale por variable, catálogo cero-dependencias.** El idioma sale de
|
|
34
|
+
`DAI_LANG` (default `es`; si no, se puede inferir de `LANG`). Los strings viven en un
|
|
35
|
+
catálogo (`cli/lib/i18n.mjs`, objeto `{ es, en }`) accedido por una función `t(key,…)`.
|
|
36
|
+
Sin librería de i18n — fiel al ethos de cero dependencias (ADR-0006).
|
|
37
|
+
|
|
38
|
+
4. **Skills: se generan en el idioma elegido.** `dai init --lang en|es` copia la variante
|
|
39
|
+
del `SKILL.md`. La IA ya es multilingüe; solo cambia el idioma de las instrucciones.
|
|
40
|
+
|
|
41
|
+
5. **Glosario de términos ES→EN fijo.** Para que la terminología no varíe entre archivos:
|
|
42
|
+
QUÉ→WHAT, CÓMO→HOW, estampar→stamp, trazabilidad→traceability, atrasado→stale, etc. Es
|
|
43
|
+
el insumo que guía la traducción (humana o asistida).
|
|
44
|
+
|
|
45
|
+
6. **Implementación por fases** (no todo de una): (1) README + landing en inglés · (2) docs
|
|
46
|
+
core (MANIFIESTO, METODOLOGIA, glosario, EJEMPLO, guías) · (3) CLI i18n + skills · (4) el
|
|
47
|
+
resto (detalle/, ADRs, templates). Se prioriza por alcance, no por completitud.
|
|
48
|
+
|
|
49
|
+
## Consecuencias
|
|
50
|
+
|
|
51
|
+
- ✅ Alcance internacional con el README/landing en inglés (fase 1) sin reescribir todo.
|
|
52
|
+
- ✅ Regla anti-drift clara: una sola fuente de verdad; las traducciones nunca "ganan".
|
|
53
|
+
- ✅ El CLI localiza sin sumar dependencias; `DAI_LANG` es opt-in (default español).
|
|
54
|
+
- ✅ La terminología queda estable entre superficies gracias al glosario ES→EN.
|
|
55
|
+
- ⚠️ Doble mantenimiento: cada cambio en un `.md` fuente obliga a re-traducir su par. Se
|
|
56
|
+
mitiga traduciendo con un agente + el glosario, y aceptando *lag* temporal en `en/`.
|
|
57
|
+
- ⚠️ El CLI necesita un refactor de strings (de literales a `t(key)`) — es mecánico pero toca
|
|
58
|
+
muchos puntos; se hace de una sola vez.
|
|
59
|
+
- ⚠️ Hay que decidir, al implementar, si el `README.md` raíz redirige (selector) o **es** una
|
|
60
|
+
de las lenguas (npm muestra el `README.md` — probablemente convenga inglés ahí).
|
|
61
|
+
|
|
62
|
+
## Alternativas consideradas
|
|
63
|
+
|
|
64
|
+
- **Un framework de docs con i18n (Docusaurus / VitePress / mkdocs)** — descartado por ahora:
|
|
65
|
+
aporta i18n y versionado, pero cambia todo el setup de docs (hoy markdown plano + un HTML
|
|
66
|
+
autocontenido) y suma tooling/dependencias pesadas para un proyecto en `0.x`. Reconsiderable
|
|
67
|
+
si la doc crece mucho.
|
|
68
|
+
- **Inglés como fuente de verdad** — descartado: el contenido se authoró en español; invertir
|
|
69
|
+
la fuente ahora duplicaría el riesgo de error justo en el material canónico (manifiesto,
|
|
70
|
+
metodología). El español queda como fuente hasta que haya razón fuerte para migrar.
|
|
71
|
+
- **Traducción automática sin glosario ni fuente fija** — descartado: garantiza drift
|
|
72
|
+
terminológico (el mismo término traducido distinto en cada archivo) y pérdida de la
|
|
73
|
+
precisión del método. La traducción se ancla a un glosario y a una fuente única.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# ADR-0009 — Adaptador nativo para Cursor
|
|
2
|
+
|
|
3
|
+
- **Estado:** propuesto
|
|
4
|
+
- **Fecha:** 2026-07-07
|
|
5
|
+
- **Decide:** lead / arquitecto de la metodología
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
ADR-0002 consolidó la estrategia agnóstica por asistente con tres capas: contenido
|
|
10
|
+
portable, CLI determinista y adaptadores delgados/generados por asistente. La
|
|
11
|
+
implementación actual cubre Claude y Copilot, pero no Cursor de forma nativa.
|
|
12
|
+
|
|
13
|
+
En la práctica, equipos que usan Cursor quedan con una experiencia incompleta: no
|
|
14
|
+
hay scaffolding en `.cursor/skills/`, no existe constitución always-on en rules, y
|
|
15
|
+
`dai doctor` / `dai install` no diagnostican ni instalan superficies de Cursor.
|
|
16
|
+
|
|
17
|
+
Cursor soporta skills (`.cursor/skills/<name>/SKILL.md`) y rules
|
|
18
|
+
(`.cursor/rules/*.mdc`) de forma nativa, y OpenSpec soporta `cursor` en `--tools`.
|
|
19
|
+
Eso permite agregar soporte sin romper el contrato existente ni duplicar lógica.
|
|
20
|
+
|
|
21
|
+
## Decisión
|
|
22
|
+
|
|
23
|
+
Incorporamos Cursor como tercer adaptador generado en la capa 3:
|
|
24
|
+
|
|
25
|
+
1. `dai init --for` acepta `cursor` y `all`, además de `claude`, `copilot`, `both`.
|
|
26
|
+
2. El default de `dai init` pasa a `all` (Claude + Copilot + Cursor).
|
|
27
|
+
3. `both` mantiene su significado histórico (Claude + Copilot), para compatibilidad
|
|
28
|
+
semántica.
|
|
29
|
+
4. Las skills de Cursor se generan en `.cursor/skills/` desde la misma fuente
|
|
30
|
+
(`skills/*/SKILL.md`) con `skillToCursor()`.
|
|
31
|
+
5. El transformador de Cursor conserva `name`, `description` y cuerpo, y no agrega
|
|
32
|
+
`disable-model-invocation` (se permite auto-invocación por descripción).
|
|
33
|
+
6. La constitución de Cursor se genera como rule `.mdc` en
|
|
34
|
+
`.cursor/rules/dai-constitution.mdc` con `alwaysApply: true`.
|
|
35
|
+
7. `dai doctor` reporta skills y constitución en rutas locales/globales de Cursor.
|
|
36
|
+
8. `dai install` soporta Cursor vía `--for claude|cursor|all` (default `all`).
|
|
37
|
+
9. OpenSpec mapea `--for all` a `claude,github-copilot,cursor`.
|
|
38
|
+
|
|
39
|
+
## Consecuencias
|
|
40
|
+
|
|
41
|
+
- ✅ La metodología mantiene su principio agnóstico también para Cursor, sin bifurcar
|
|
42
|
+
contenido de skills.
|
|
43
|
+
- ✅ Equipos mixtos pueden coexistir en un repo con Claude, Copilot y Cursor sin
|
|
44
|
+
pisarse (carpetas separadas).
|
|
45
|
+
- ✅ El runtime mecánico sigue centralizado en CLI (`dai`), sin mover lógica
|
|
46
|
+
determinista a prompts.
|
|
47
|
+
- ✅ Cursor recibe constitución always-on alineada a Claude/Copilot.
|
|
48
|
+
- ⚠️ Cambia el comportamiento por defecto de `dai init` (de `both` a `all`); requiere
|
|
49
|
+
documentación clara para evitar sorpresa.
|
|
50
|
+
- ⚠️ `dai install` ahora maneja más de un target de asistente y aumenta la superficie
|
|
51
|
+
de mantenimiento.
|
|
52
|
+
|
|
53
|
+
## Alternativas consideradas
|
|
54
|
+
|
|
55
|
+
- **Depender de `.claude/skills/` por compatibilidad de Cursor** — descartado: no da
|
|
56
|
+
soporte profesional de rules/doctor/install y contradice la idea de adaptador
|
|
57
|
+
nativo generado.
|
|
58
|
+
- **Redefinir `both` para incluir Cursor** — descartado: rompe semántica histórica del
|
|
59
|
+
valor; se prefiere agregar `all`.
|
|
60
|
+
- **Forzar `disable-model-invocation: true` en Cursor** — descartado para este repo:
|
|
61
|
+
se busca paridad de auto-invocación con Claude.
|
|
62
|
+
- **Constitución de Cursor en `AGENTS.md`** — descartado: la superficie nativa always-on
|
|
63
|
+
de Cursor son `.cursor/rules/*.mdc`.
|
package/docs/adr/README.md
CHANGED
|
@@ -13,6 +13,8 @@ decisión cambia, se escribe un ADR nuevo que supersede al viejo. Molde en
|
|
|
13
13
|
| [0005](0005-superficie-comandos-y-stamp.md) | Superficie de comandos (`ls`/`check`/`stamp`) y contenido del stamp (branch + commit-ancla) | aceptado |
|
|
14
14
|
| [0006](0006-distribucion-y-licencia.md) | Distribución (npm + fallback) y licencia (GPLv3) | aceptado |
|
|
15
15
|
| [0007](0007-modelo-de-autenticacion.md) | Modelo de auth: SSH para git, tokens scopeados para forge/tracker, sin contraseñas | aceptado |
|
|
16
|
+
| [0008](0008-estrategia-de-i18n.md) | Estrategia de i18n: fuente única (español) + traducciones derivadas, `DAI_LANG` en el CLI, por fases | propuesto |
|
|
17
|
+
| [0009](0009-adaptador-cursor.md) | Adaptador nativo para Cursor (skills + rules) con `dai init`/`install`/`doctor` | propuesto |
|
|
16
18
|
|
|
17
19
|
> Estas son las decisiones que cierran las "Decisiones abiertas" de
|
|
18
20
|
> [`METODOLOGIA.md §7`](../METODOLOGIA.md) y las enmiendas al
|
package/index.html
CHANGED
|
@@ -208,6 +208,7 @@
|
|
|
208
208
|
<div class="cta">
|
|
209
209
|
<a class="btn p" href="#empezar">Empezar ahora</a>
|
|
210
210
|
<a class="btn s" href="https://github.com/dforce2055/dai">Ver en GitHub</a>
|
|
211
|
+
<a class="btn s" href="https://www.npmjs.com/package/@dforce2055/dai">Ver en npm</a>
|
|
211
212
|
</div>
|
|
212
213
|
<div class="install">
|
|
213
214
|
<span class="m"># instala el CLI (Node ≥18, cero dependencias)</span><br>
|
|
@@ -436,6 +437,7 @@
|
|
|
436
437
|
<span><b style="color:var(--brand)">dai</b> — Desarrollo Asistido por IA</span>
|
|
437
438
|
<span class="sp"></span>
|
|
438
439
|
<a href="https://github.com/dforce2055/dai">GitHub</a>
|
|
440
|
+
<a href="https://www.npmjs.com/package/@dforce2055/dai">npm</a>
|
|
439
441
|
<a href="https://github.com/dforce2055/dai/blob/main/docs/MANIFIESTO.md">Manifiesto</a>
|
|
440
442
|
<a href="https://github.com/dforce2055/dai/blob/main/LICENSE">GPLv3</a>
|
|
441
443
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dforce2055/dai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Metodología de desarrollo asistido por IA — CLI de acciones deterministas (trazabilidad QUÉ↔CÓMO).",
|
|
5
5
|
"repository": { "type": "git", "url": "git+https://github.com/dforce2055/dai.git" },
|
|
6
6
|
"homepage": "https://dforce2055.github.io/dai/",
|