@damenor/agent-docs 0.1.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/README.md +115 -0
- package/dist/index.js +568 -0
- package/package.json +53 -0
- package/templates/base/AGENTS.md +177 -0
- package/templates/base/CHANGELOG.md +86 -0
- package/templates/base/README.md +110 -0
- package/templates/base/docs/CONTEXT.md +111 -0
- package/templates/base/docs/README.md +131 -0
- package/templates/base/docs/adr/TEMPLATE.md +83 -0
- package/templates/modules/agents/.agents/agents/doc-designer.md +56 -0
- package/templates/modules/agents/.agents/agents/doc-maintainer.md +54 -0
- package/templates/modules/agents/.agents/agents/doc-reviewer.md +80 -0
- package/templates/modules/agents/.agents/agents/doc-writer.md +66 -0
- package/templates/modules/agents/.agents/agents/reviewer.md +138 -0
- package/templates/modules/agents/.agents/skills/doc-design/SKILL.md +359 -0
- package/templates/modules/agents/.agents/skills/doc-design/references/design-system-format.md +550 -0
- package/templates/modules/agents/.agents/skills/doc-maintain/SKILL.md +345 -0
- package/templates/modules/agents/.agents/skills/doc-maintain/references/triggers.md +311 -0
- package/templates/modules/agents/.agents/skills/doc-review/SKILL.md +324 -0
- package/templates/modules/agents/.agents/skills/doc-review/references/health-checklist.md +290 -0
- package/templates/modules/agents/.agents/skills/doc-scaffold/SKILL.md +277 -0
- package/templates/modules/agents/.agents/skills/doc-scaffold/references/diataxis-quick-ref.md +149 -0
- package/templates/modules/agents/.agents/skills/doc-write/SKILL.md +414 -0
- package/templates/modules/agents/.agents/skills/doc-write/references/adr-format.md +194 -0
- package/templates/modules/agents/.agents/skills/doc-write/references/diataxis-patterns.md +351 -0
- package/templates/modules/ci/.github/workflows/docs-check.yml +94 -0
- package/templates/modules/design/docs/DESIGN.md +253 -0
- package/templates/modules/explanation/docs/explanation/agent-flow.md +15 -0
- package/templates/modules/explanation/docs/explanation/architecture.md +138 -0
- package/templates/modules/guides/docs/guides/deployment.md +189 -0
- package/templates/modules/guides/docs/guides/runbooks/TEMPLATE.md +86 -0
- package/templates/modules/guides/docs/guides/troubleshooting.md +65 -0
- package/templates/modules/operations/docs/operations/README.md +115 -0
- package/templates/modules/product/docs/product/overview.md +90 -0
- package/templates/modules/product/docs/roadmap.md +80 -0
- package/templates/modules/reference/docs/reference/api.md +131 -0
- package/templates/modules/reference/docs/reference/code-style.md +275 -0
- package/templates/modules/reference/docs/reference/configuration.md +117 -0
- package/templates/modules/reference/docs/reference/infrastructure.md +191 -0
- package/templates/modules/tutorials/docs/tutorials/environment-setup.md +212 -0
- package/templates/modules/tutorials/docs/tutorials/first-task.md +246 -0
- package/templates/modules/tutorials/docs/tutorials/quick-start.md +146 -0
- package/templates/shared/.editorconfig +20 -0
- package/templates/shared/.markdownlint.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<img src="https://img.shields.io/badge/agents-docs-blueviolet?style=for-the-badge" alt="agent-docs">
|
|
3
|
+
<br>
|
|
4
|
+
@damenor/agent-docs
|
|
5
|
+
</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Documentación profesional para proyectos con agentes AI</strong>
|
|
9
|
+
<br>
|
|
10
|
+
<sub>CLI interactivo que genera estructura Diátaxis + ADR + AGENTS.md en segundos</sub>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<img src="https://img.shields.io/npm/v/@damenor/agent-docs?style=flat-square" alt="npm version">
|
|
15
|
+
<img src="https://img.shields.io/npm/dt/@damenor/agent-docs?style=flat-square" alt="downloads">
|
|
16
|
+
<img src="https://img.shields.io/github/license/damenordev/doc-projects?style=flat-square" alt="license">
|
|
17
|
+
<img src="https://img.shields.io/node/v/@damenor/agent-docs?style=flat-square" alt="node version">
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @damenor/agent-docs
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
That's it. The wizard guides you through 7 steps and generates a complete documentation structure.
|
|
29
|
+
|
|
30
|
+
## What it does
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
npx @damenor/agent-docs
|
|
34
|
+
│
|
|
35
|
+
├── 1. Project name
|
|
36
|
+
├── 2. Target directory
|
|
37
|
+
├── 3. Stack detection (auto/manual/skip)
|
|
38
|
+
│ package.json · pyproject.toml · go.mod · Cargo.toml · pom.xml
|
|
39
|
+
├── 4. Language (ES/EN)
|
|
40
|
+
├── 5. Module selection
|
|
41
|
+
├── 6. Git init
|
|
42
|
+
└── 7. Generate → docs/ ready to customize
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 9 selectable modules
|
|
46
|
+
|
|
47
|
+
| Module | Generates |
|
|
48
|
+
|--------|-----------|
|
|
49
|
+
| Tutorials | quick-start, environment-setup, first-task |
|
|
50
|
+
| Guides | deployment, troubleshooting, runbooks |
|
|
51
|
+
| Reference | API, configuration, infrastructure, code-style |
|
|
52
|
+
| Explanation | architecture.md |
|
|
53
|
+
| Product | overview, roadmap |
|
|
54
|
+
| Operations | monitoring, incidents, SLAs |
|
|
55
|
+
| Design System | DESIGN.md with tokens |
|
|
56
|
+
| AI Agent Skills | `.agents/` with 5 skills + 5 agents |
|
|
57
|
+
| CI/CD | GitHub Actions docs-check workflow |
|
|
58
|
+
|
|
59
|
+
**Plus**, every run includes the base layer: `AGENTS.md`, `CONTEXT.md`, `README.md`, ADR template, and shared config files.
|
|
60
|
+
|
|
61
|
+
## Stack detection
|
|
62
|
+
|
|
63
|
+
Automatically detects your tech stack from project files:
|
|
64
|
+
|
|
65
|
+
| File detected | Stack |
|
|
66
|
+
|---------------|-------|
|
|
67
|
+
| `package.json` | Node.js (npm/pnpm/yarn/bun) |
|
|
68
|
+
| `pyproject.toml` / `requirements.txt` | Python (pip/poetry) |
|
|
69
|
+
| `go.mod` | Go |
|
|
70
|
+
| `Cargo.toml` | Rust |
|
|
71
|
+
| `pom.xml` / `build.gradle` | Java/Kotlin |
|
|
72
|
+
|
|
73
|
+
Detected commands (`dev`, `build`, `test`, `lint`) are injected into templates automatically.
|
|
74
|
+
|
|
75
|
+
## Output example
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
my-project/
|
|
79
|
+
├── AGENTS.md ← AI agent protocol
|
|
80
|
+
├── docs/
|
|
81
|
+
│ ├── CONTEXT.md ← Domain language & glossary
|
|
82
|
+
│ ├── README.md ← Documentation index
|
|
83
|
+
│ ├── tutorials/ ← Step-by-step learning
|
|
84
|
+
│ ├── guides/ ← How-to guides
|
|
85
|
+
│ ├── reference/ ← Technical reference
|
|
86
|
+
│ ├── explanation/ ← Architecture & ADRs
|
|
87
|
+
│ ├── product/ ← Overview & roadmap
|
|
88
|
+
│ ├── operations/ ← Runbooks & monitoring
|
|
89
|
+
│ ├── DESIGN.md ← Design system tokens
|
|
90
|
+
│ └── adr/ ← Architecture Decision Records
|
|
91
|
+
├── .agents/ ← Skills & agent configs
|
|
92
|
+
├── .github/workflows/ ← CI/CD for docs
|
|
93
|
+
├── .editorconfig
|
|
94
|
+
└── .markdownlint.json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Why this exists
|
|
98
|
+
|
|
99
|
+
Most projects have **no documentation structure**. When you add AI agents to the mix, they need a shared vocabulary (`CONTEXT.md`), operating rules (`AGENTS.md`), and a consistent organization system (Diátaxis).
|
|
100
|
+
|
|
101
|
+
This CLI scaffolds all of that in one command, so your team and your AI agents speak the same language from day one.
|
|
102
|
+
|
|
103
|
+
## Built for
|
|
104
|
+
|
|
105
|
+
- **Developers** who want professional docs without starting from zero
|
|
106
|
+
- **AI agents** that need structured context to work effectively
|
|
107
|
+
- **Teams** that follow Diátaxis (Tutorials / How-to / Reference / Explanation)
|
|
108
|
+
|
|
109
|
+
## Requirements
|
|
110
|
+
|
|
111
|
+
- Node.js >= 18
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT — [github.com/damenordev/doc-projects](https://github.com/damenordev/doc-projects)
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import * as p from "@clack/prompts";
|
|
5
|
+
import pc2 from "picocolors";
|
|
6
|
+
import path4 from "path";
|
|
7
|
+
|
|
8
|
+
// src/utils/colors.ts
|
|
9
|
+
import pc from "picocolors";
|
|
10
|
+
var brand = {
|
|
11
|
+
name: "@damenor/agent-docs",
|
|
12
|
+
version: "0.1.0",
|
|
13
|
+
/** Título con estilo */
|
|
14
|
+
title: (text2) => pc.bold(pc.cyan(text2)),
|
|
15
|
+
/** Texto de éxito */
|
|
16
|
+
success: (text2) => pc.bold(pc.green(text2)),
|
|
17
|
+
/** Texto de advertencia */
|
|
18
|
+
warn: (text2) => pc.bold(pc.yellow(text2)),
|
|
19
|
+
/** Texto de error */
|
|
20
|
+
error: (text2) => pc.bold(pc.red(text2)),
|
|
21
|
+
/** Texto sutil */
|
|
22
|
+
dim: (text2) => pc.dim(text2),
|
|
23
|
+
/** Texto de enlace/path */
|
|
24
|
+
path: (text2) => pc.underline(pc.cyan(text2)),
|
|
25
|
+
/** Texto destacado */
|
|
26
|
+
highlight: (text2) => pc.bold(pc.magenta(text2)),
|
|
27
|
+
/** Label de sección */
|
|
28
|
+
label: (text2) => pc.bold(pc.white(text2))
|
|
29
|
+
};
|
|
30
|
+
var icons = {
|
|
31
|
+
docs: "\u{1F4DA}",
|
|
32
|
+
check: "\u2705",
|
|
33
|
+
folder: "\u{1F4C1}",
|
|
34
|
+
file: "\u{1F4C4}",
|
|
35
|
+
rocket: "\u{1F680}",
|
|
36
|
+
gear: "\u2699\uFE0F",
|
|
37
|
+
search: "\u{1F50D}",
|
|
38
|
+
sparkle: "\u2728",
|
|
39
|
+
warning: "\u26A0\uFE0F",
|
|
40
|
+
bolt: "\u26A1",
|
|
41
|
+
shield: "\u{1F6E1}\uFE0F",
|
|
42
|
+
palette: "\u{1F3A8}",
|
|
43
|
+
robot: "\u{1F916}",
|
|
44
|
+
chart: "\u{1F4CA}",
|
|
45
|
+
wrench: "\u{1F527}",
|
|
46
|
+
package: "\u{1F4E6}"
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/constants.ts
|
|
50
|
+
var DOC_MODULES = [
|
|
51
|
+
{
|
|
52
|
+
value: "tutorials",
|
|
53
|
+
label: "Tutoriales",
|
|
54
|
+
hint: "quick-start, environment, first-task",
|
|
55
|
+
templateDir: "tutorials",
|
|
56
|
+
files: [
|
|
57
|
+
"docs/tutorials/quick-start.md",
|
|
58
|
+
"docs/tutorials/environment-setup.md",
|
|
59
|
+
"docs/tutorials/first-task.md"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
value: "guides",
|
|
64
|
+
label: "Gu\xEDas",
|
|
65
|
+
hint: "deployment, troubleshooting, runbooks",
|
|
66
|
+
templateDir: "guides",
|
|
67
|
+
files: [
|
|
68
|
+
"docs/guides/deployment.md",
|
|
69
|
+
"docs/guides/troubleshooting.md",
|
|
70
|
+
"docs/guides/runbooks/TEMPLATE.md"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
value: "reference",
|
|
75
|
+
label: "Referencia",
|
|
76
|
+
hint: "API, config, infra, code-style",
|
|
77
|
+
templateDir: "reference",
|
|
78
|
+
files: [
|
|
79
|
+
"docs/reference/api.md",
|
|
80
|
+
"docs/reference/configuration.md",
|
|
81
|
+
"docs/reference/infrastructure.md",
|
|
82
|
+
"docs/reference/code-style.md"
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
value: "explanation",
|
|
87
|
+
label: "Explicaci\xF3n",
|
|
88
|
+
hint: "architecture",
|
|
89
|
+
templateDir: "explanation",
|
|
90
|
+
files: ["docs/explanation/architecture.md"]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
value: "product",
|
|
94
|
+
label: "Producto",
|
|
95
|
+
hint: "overview, roadmap",
|
|
96
|
+
templateDir: "product",
|
|
97
|
+
files: ["docs/product/overview.md", "docs/roadmap.md"]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
value: "operations",
|
|
101
|
+
label: "Operaciones",
|
|
102
|
+
hint: "monitoring, incidents, SLAs",
|
|
103
|
+
templateDir: "operations",
|
|
104
|
+
files: ["docs/operations/README.md"]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
value: "design",
|
|
108
|
+
label: "Design System",
|
|
109
|
+
hint: "DESIGN.md con tokens",
|
|
110
|
+
templateDir: "design",
|
|
111
|
+
files: ["docs/DESIGN.md"]
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
value: "agents",
|
|
115
|
+
label: "Skills para agentes AI",
|
|
116
|
+
hint: ".agents/ con 5 skills + 5 agents",
|
|
117
|
+
templateDir: "agents",
|
|
118
|
+
files: [".agents/"]
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
value: "ci",
|
|
122
|
+
label: "CI/CD",
|
|
123
|
+
hint: "GitHub Actions docs check",
|
|
124
|
+
templateDir: "ci",
|
|
125
|
+
files: [".github/workflows/docs-check.yml"]
|
|
126
|
+
}
|
|
127
|
+
];
|
|
128
|
+
var LANGUAGES = [
|
|
129
|
+
{ value: "es", label: "Espa\xF1ol", hint: "recomendado" },
|
|
130
|
+
{ value: "en", label: "English" }
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
// src/detector.ts
|
|
134
|
+
import fs from "fs";
|
|
135
|
+
import path from "path";
|
|
136
|
+
function detectStack(targetDir) {
|
|
137
|
+
const checks = [
|
|
138
|
+
{
|
|
139
|
+
file: "package.json",
|
|
140
|
+
detect: (content, dir) => detectNodeStack(content, dir)
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
file: "requirements.txt",
|
|
144
|
+
detect: () => ({
|
|
145
|
+
language: "Python",
|
|
146
|
+
packageManager: "pip",
|
|
147
|
+
devCommand: "python manage.py runserver",
|
|
148
|
+
testCommand: "pytest",
|
|
149
|
+
lintCommand: "ruff check ."
|
|
150
|
+
})
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
file: "pyproject.toml",
|
|
154
|
+
detect: (content) => ({
|
|
155
|
+
language: "Python",
|
|
156
|
+
framework: content.includes("django") ? "Django" : content.includes("fastapi") ? "FastAPI" : content.includes("flask") ? "Flask" : void 0,
|
|
157
|
+
packageManager: content.includes("[tool.poetry]") ? "poetry" : "pip",
|
|
158
|
+
devCommand: content.includes("django") ? "python manage.py runserver" : "uvicorn main:app --reload",
|
|
159
|
+
testCommand: "pytest",
|
|
160
|
+
lintCommand: "ruff check ."
|
|
161
|
+
})
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
file: "go.mod",
|
|
165
|
+
detect: () => ({
|
|
166
|
+
language: "Go",
|
|
167
|
+
packageManager: "go modules",
|
|
168
|
+
devCommand: "go run .",
|
|
169
|
+
testCommand: "go test ./...",
|
|
170
|
+
lintCommand: "golangci-lint run"
|
|
171
|
+
})
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
file: "Cargo.toml",
|
|
175
|
+
detect: () => ({
|
|
176
|
+
language: "Rust",
|
|
177
|
+
packageManager: "cargo",
|
|
178
|
+
devCommand: "cargo run",
|
|
179
|
+
buildCommand: "cargo build --release",
|
|
180
|
+
testCommand: "cargo test",
|
|
181
|
+
lintCommand: "cargo clippy"
|
|
182
|
+
})
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
file: "pom.xml",
|
|
186
|
+
detect: () => ({
|
|
187
|
+
language: "Java",
|
|
188
|
+
framework: "Spring Boot",
|
|
189
|
+
packageManager: "maven",
|
|
190
|
+
devCommand: "mvn spring-boot:run",
|
|
191
|
+
buildCommand: "mvn package",
|
|
192
|
+
testCommand: "mvn test",
|
|
193
|
+
lintCommand: "mvn checkstyle:check"
|
|
194
|
+
})
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
file: "build.gradle",
|
|
198
|
+
detect: () => ({
|
|
199
|
+
language: "Java/Kotlin",
|
|
200
|
+
framework: "Spring Boot",
|
|
201
|
+
packageManager: "gradle",
|
|
202
|
+
devCommand: "gradle bootRun",
|
|
203
|
+
buildCommand: "gradle build",
|
|
204
|
+
testCommand: "gradle test"
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
];
|
|
208
|
+
for (const check of checks) {
|
|
209
|
+
const filePath = path.join(targetDir, check.file);
|
|
210
|
+
if (fs.existsSync(filePath)) {
|
|
211
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
212
|
+
return check.detect(content, targetDir);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
function detectNodeStack(packageJsonContent, dir) {
|
|
218
|
+
const pkg = JSON.parse(packageJsonContent);
|
|
219
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
220
|
+
let framework;
|
|
221
|
+
if (deps["next"]) framework = `Next.js ${deps["next"].replace("^", "").replace("~", "")}`;
|
|
222
|
+
else if (deps["nuxt"]) framework = `Nuxt ${deps["nuxt"].replace("^", "").replace("~", "")}`;
|
|
223
|
+
else if (deps["astro"]) framework = `Astro ${deps["astro"].replace("^", "").replace("~", "")}`;
|
|
224
|
+
else if (deps["svelte"] || deps["@sveltejs/kit"]) framework = "SvelteKit";
|
|
225
|
+
else if (deps["react"]) framework = `React ${deps["react"].replace("^", "").replace("~", "")}`;
|
|
226
|
+
else if (deps["vue"]) framework = `Vue ${deps["vue"].replace("^", "").replace("~", "")}`;
|
|
227
|
+
else if (deps["express"]) framework = "Express";
|
|
228
|
+
else if (deps["fastify"]) framework = "Fastify";
|
|
229
|
+
else if (deps["hono"]) framework = "Hono";
|
|
230
|
+
else if (deps["@nestjs/core"]) framework = "NestJS";
|
|
231
|
+
let packageManager = "npm";
|
|
232
|
+
if (fs.existsSync(path.join(dir, "pnpm-lock.yaml"))) packageManager = "pnpm";
|
|
233
|
+
else if (fs.existsSync(path.join(dir, "yarn.lock"))) packageManager = "yarn";
|
|
234
|
+
else if (fs.existsSync(path.join(dir, "bun.lockb"))) packageManager = "bun";
|
|
235
|
+
const scripts = pkg.scripts || {};
|
|
236
|
+
const run = packageManager === "npm" ? "npm run" : packageManager;
|
|
237
|
+
const hasTypeScript = deps["typescript"] || fs.existsSync(path.join(dir, "tsconfig.json"));
|
|
238
|
+
return {
|
|
239
|
+
language: hasTypeScript ? "TypeScript" : "JavaScript",
|
|
240
|
+
framework,
|
|
241
|
+
packageManager,
|
|
242
|
+
devCommand: scripts.dev ? `${run} dev` : void 0,
|
|
243
|
+
buildCommand: scripts.build ? `${run} build` : void 0,
|
|
244
|
+
testCommand: scripts.test ? `${run} test` : void 0,
|
|
245
|
+
lintCommand: scripts.lint ? `${run} lint` : void 0
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function formatStack(stack) {
|
|
249
|
+
const parts = [stack.language];
|
|
250
|
+
if (stack.framework) parts.push(stack.framework);
|
|
251
|
+
if (stack.packageManager) parts.push(`(${stack.packageManager})`);
|
|
252
|
+
return parts.join(" + ");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/generator.ts
|
|
256
|
+
import path3 from "path";
|
|
257
|
+
import { fileURLToPath } from "url";
|
|
258
|
+
|
|
259
|
+
// src/utils/fs.ts
|
|
260
|
+
import fs2 from "fs";
|
|
261
|
+
import path2 from "path";
|
|
262
|
+
function ensureDir(dirPath) {
|
|
263
|
+
if (!fs2.existsSync(dirPath)) {
|
|
264
|
+
fs2.mkdirSync(dirPath, { recursive: true });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function writeFile(filePath, content) {
|
|
268
|
+
ensureDir(path2.dirname(filePath));
|
|
269
|
+
fs2.writeFileSync(filePath, content, "utf-8");
|
|
270
|
+
}
|
|
271
|
+
function isDirEmpty(dirPath) {
|
|
272
|
+
if (!fs2.existsSync(dirPath)) return true;
|
|
273
|
+
const files = fs2.readdirSync(dirPath);
|
|
274
|
+
return files.length === 0 || files.length === 1 && files[0] === ".git";
|
|
275
|
+
}
|
|
276
|
+
function copyTemplateDir(src, dest, replacements) {
|
|
277
|
+
ensureDir(dest);
|
|
278
|
+
const entries = fs2.readdirSync(src, { withFileTypes: true });
|
|
279
|
+
for (const entry of entries) {
|
|
280
|
+
const srcPath = path2.join(src, entry.name);
|
|
281
|
+
const destPath = path2.join(dest, entry.name);
|
|
282
|
+
if (entry.isDirectory()) {
|
|
283
|
+
copyTemplateDir(srcPath, destPath, replacements);
|
|
284
|
+
} else {
|
|
285
|
+
let content = fs2.readFileSync(srcPath, "utf-8");
|
|
286
|
+
if (isTextFile(entry.name)) {
|
|
287
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
288
|
+
content = content.replaceAll(placeholder, value);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
writeFile(destPath, content);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function isTextFile(filename) {
|
|
296
|
+
const textExtensions = [".md", ".yml", ".yaml", ".json", ".txt", ".editorconfig"];
|
|
297
|
+
return textExtensions.some((ext) => filename.endsWith(ext)) || filename.startsWith(".");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/generator.ts
|
|
301
|
+
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
302
|
+
async function generate(options) {
|
|
303
|
+
const { projectName, targetDir, stack, modules, language } = options;
|
|
304
|
+
const createdFiles = [];
|
|
305
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
306
|
+
const replacements = {
|
|
307
|
+
"{{PROJECT_NAME}}": projectName,
|
|
308
|
+
"{{TECH_STACK}}": stack ? formatStackForTemplate(stack) : "[TECNOLOG\xCDA PRINCIPAL]",
|
|
309
|
+
"{{DEV_COMMAND}}": stack?.devCommand || "[comando de dev]",
|
|
310
|
+
"{{BUILD_COMMAND}}": stack?.buildCommand || "[comando de build]",
|
|
311
|
+
"{{TEST_COMMAND}}": stack?.testCommand || "[comando de test]",
|
|
312
|
+
"{{LINT_COMMAND}}": stack?.lintCommand || "[comando de lint]",
|
|
313
|
+
"{{LANGUAGE}}": stack?.language || "[lenguaje]",
|
|
314
|
+
"{{FRAMEWORK}}": stack?.framework || "[framework]",
|
|
315
|
+
"{{PACKAGE_MANAGER}}": stack?.packageManager || "[package manager]",
|
|
316
|
+
"{{DATE}}": today,
|
|
317
|
+
// Mantener los placeholders originales para compatibilidad
|
|
318
|
+
"[NOMBRE DEL PROYECTO]": projectName
|
|
319
|
+
};
|
|
320
|
+
const templatesDir = await resolveTemplatesDir();
|
|
321
|
+
const baseDir = path3.join(templatesDir, "base");
|
|
322
|
+
copyTemplateDir(baseDir, targetDir, replacements);
|
|
323
|
+
createdFiles.push(...await listGeneratedFiles(baseDir, targetDir));
|
|
324
|
+
for (const moduleName of modules) {
|
|
325
|
+
const moduleDir = path3.join(templatesDir, "modules", moduleName);
|
|
326
|
+
copyTemplateDir(moduleDir, targetDir, replacements);
|
|
327
|
+
createdFiles.push(...await listGeneratedFiles(moduleDir, targetDir));
|
|
328
|
+
}
|
|
329
|
+
const sharedDir = path3.join(templatesDir, "shared");
|
|
330
|
+
copyTemplateDir(sharedDir, targetDir, replacements);
|
|
331
|
+
createdFiles.push(...await listGeneratedFiles(sharedDir, targetDir));
|
|
332
|
+
if (options.initGit) {
|
|
333
|
+
await initGit(targetDir);
|
|
334
|
+
}
|
|
335
|
+
return createdFiles;
|
|
336
|
+
}
|
|
337
|
+
async function resolveTemplatesDir() {
|
|
338
|
+
const prodPath = path3.resolve(__dirname, "..", "templates");
|
|
339
|
+
const devPath = path3.resolve(__dirname, "..", "..", "templates");
|
|
340
|
+
const { existsSync } = await import("fs");
|
|
341
|
+
if (existsSync(prodPath)) return prodPath;
|
|
342
|
+
if (existsSync(devPath)) return devPath;
|
|
343
|
+
throw new Error("No se encontr\xF3 el directorio de templates. \xBFSe instal\xF3 correctamente el paquete?");
|
|
344
|
+
}
|
|
345
|
+
async function listGeneratedFiles(templateDir, targetDir) {
|
|
346
|
+
const { readdirSync } = await import("fs");
|
|
347
|
+
const files = [];
|
|
348
|
+
function walk(dir, base) {
|
|
349
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
350
|
+
const rel = path3.join(base, entry.name);
|
|
351
|
+
if (entry.isDirectory()) {
|
|
352
|
+
walk(path3.join(dir, entry.name), rel);
|
|
353
|
+
} else {
|
|
354
|
+
files.push(rel);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
walk(templateDir, "");
|
|
359
|
+
return files;
|
|
360
|
+
}
|
|
361
|
+
async function initGit(dir) {
|
|
362
|
+
const { execSync } = await import("child_process");
|
|
363
|
+
try {
|
|
364
|
+
execSync("git init", { cwd: dir, stdio: "ignore" });
|
|
365
|
+
execSync("git add -A", { cwd: dir, stdio: "ignore" });
|
|
366
|
+
execSync('git commit -m "docs: inicializaci\xF3n de documentaci\xF3n con @damenor/agent-docs"', {
|
|
367
|
+
cwd: dir,
|
|
368
|
+
stdio: "ignore"
|
|
369
|
+
});
|
|
370
|
+
} catch {
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function formatStackForTemplate(stack) {
|
|
374
|
+
const parts = [stack.language];
|
|
375
|
+
if (stack.framework) parts.push(stack.framework);
|
|
376
|
+
return parts.join(" + ");
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/cli.ts
|
|
380
|
+
async function cli() {
|
|
381
|
+
console.clear();
|
|
382
|
+
p.intro(
|
|
383
|
+
`${icons.docs} ${brand.title("@damenor/agent-docs")} ${pc2.dim("v0.1.0")}
|
|
384
|
+
${pc2.dim("Documentaci\xF3n profesional para proyectos con agentes AI")}`
|
|
385
|
+
);
|
|
386
|
+
const projectName = await p.text({
|
|
387
|
+
message: `${icons.sparkle} Nombre del proyecto`,
|
|
388
|
+
placeholder: "mi-proyecto",
|
|
389
|
+
validate: (value) => {
|
|
390
|
+
if (!value.trim()) return "El nombre del proyecto es obligatorio.";
|
|
391
|
+
if (!/^[a-zA-Z0-9_-][a-zA-Z0-9_.\- ]*$/.test(value.trim())) {
|
|
392
|
+
return "Usa letras, n\xFAmeros, guiones o espacios.";
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
if (p.isCancel(projectName)) {
|
|
397
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
398
|
+
process.exit(0);
|
|
399
|
+
}
|
|
400
|
+
const targetDir = await p.text({
|
|
401
|
+
message: `${icons.folder} Directorio de destino`,
|
|
402
|
+
placeholder: "./",
|
|
403
|
+
initialValue: "./",
|
|
404
|
+
validate: (value) => {
|
|
405
|
+
if (!value.trim()) return "El directorio es obligatorio.";
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
if (p.isCancel(targetDir)) {
|
|
409
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
410
|
+
process.exit(0);
|
|
411
|
+
}
|
|
412
|
+
const resolvedDir = path4.resolve(targetDir.trim());
|
|
413
|
+
if (!isDirEmpty(resolvedDir)) {
|
|
414
|
+
const overwrite = await p.confirm({
|
|
415
|
+
message: `${icons.warning} El directorio no est\xE1 vac\xEDo. \xBFContinuar? (puede sobrescribir archivos)`,
|
|
416
|
+
initialValue: false
|
|
417
|
+
});
|
|
418
|
+
if (p.isCancel(overwrite) || !overwrite) {
|
|
419
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
420
|
+
process.exit(0);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const stackOption = await p.select({
|
|
424
|
+
message: `${icons.search} Stack tecnol\xF3gico`,
|
|
425
|
+
options: [
|
|
426
|
+
{ value: "auto", label: "Auto-detectar", hint: "recomendado \u2014 analiza el proyecto" },
|
|
427
|
+
{ value: "manual", label: "Configurar manualmente" },
|
|
428
|
+
{ value: "skip", label: "Omitir", hint: "rellenar despu\xE9s" }
|
|
429
|
+
]
|
|
430
|
+
});
|
|
431
|
+
if (p.isCancel(stackOption)) {
|
|
432
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
433
|
+
process.exit(0);
|
|
434
|
+
}
|
|
435
|
+
let stack = null;
|
|
436
|
+
if (stackOption === "auto") {
|
|
437
|
+
const s2 = p.spinner();
|
|
438
|
+
s2.start("Analizando proyecto...");
|
|
439
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
440
|
+
stack = detectStack(resolvedDir);
|
|
441
|
+
if (stack) {
|
|
442
|
+
s2.stop(`${icons.check} Detectado: ${brand.highlight(formatStack(stack))}`);
|
|
443
|
+
} else {
|
|
444
|
+
s2.stop(`${icons.warning} No se detect\xF3 stack \u2014 los placeholders se rellenar\xE1n despu\xE9s`);
|
|
445
|
+
}
|
|
446
|
+
} else if (stackOption === "manual") {
|
|
447
|
+
const manualStack = await p.group(
|
|
448
|
+
{
|
|
449
|
+
language: () => p.select({
|
|
450
|
+
message: "Lenguaje principal",
|
|
451
|
+
options: [
|
|
452
|
+
{ value: "TypeScript", label: "TypeScript" },
|
|
453
|
+
{ value: "JavaScript", label: "JavaScript" },
|
|
454
|
+
{ value: "Python", label: "Python" },
|
|
455
|
+
{ value: "Go", label: "Go" },
|
|
456
|
+
{ value: "Rust", label: "Rust" },
|
|
457
|
+
{ value: "Java", label: "Java" },
|
|
458
|
+
{ value: "Other", label: "Otro" }
|
|
459
|
+
]
|
|
460
|
+
}),
|
|
461
|
+
framework: () => p.text({
|
|
462
|
+
message: "Framework (opcional)",
|
|
463
|
+
placeholder: "Next.js 14, Django 5, etc."
|
|
464
|
+
})
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
onCancel: () => {
|
|
468
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
469
|
+
process.exit(0);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
stack = {
|
|
474
|
+
language: manualStack.language,
|
|
475
|
+
framework: manualStack.framework?.trim() || void 0
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
const language = await p.select({
|
|
479
|
+
message: `${icons.docs} Idioma de la documentaci\xF3n`,
|
|
480
|
+
options: LANGUAGES.map((lang) => ({
|
|
481
|
+
value: lang.value,
|
|
482
|
+
label: lang.label,
|
|
483
|
+
hint: lang.hint
|
|
484
|
+
}))
|
|
485
|
+
});
|
|
486
|
+
if (p.isCancel(language)) {
|
|
487
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
488
|
+
process.exit(0);
|
|
489
|
+
}
|
|
490
|
+
const selectedModules = await p.multiselect({
|
|
491
|
+
message: `${icons.package} M\xF3dulos a incluir ${pc2.dim("(espacio para seleccionar)")}`,
|
|
492
|
+
options: DOC_MODULES.map((mod) => ({
|
|
493
|
+
value: mod.value,
|
|
494
|
+
label: mod.label,
|
|
495
|
+
hint: mod.hint
|
|
496
|
+
})),
|
|
497
|
+
required: false
|
|
498
|
+
});
|
|
499
|
+
if (p.isCancel(selectedModules)) {
|
|
500
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
501
|
+
process.exit(0);
|
|
502
|
+
}
|
|
503
|
+
const initGit2 = await p.confirm({
|
|
504
|
+
message: `${icons.gear} \xBFInicializar repositorio git?`,
|
|
505
|
+
initialValue: true
|
|
506
|
+
});
|
|
507
|
+
if (p.isCancel(initGit2)) {
|
|
508
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
509
|
+
process.exit(0);
|
|
510
|
+
}
|
|
511
|
+
const modulesLabel = selectedModules.length > 0 ? selectedModules.join(", ") : pc2.dim("ninguno (solo archivos base)");
|
|
512
|
+
p.note(
|
|
513
|
+
[
|
|
514
|
+
`${brand.label("Proyecto")}: ${projectName}`,
|
|
515
|
+
`${brand.label("Directorio")}: ${brand.path(resolvedDir)}`,
|
|
516
|
+
`${brand.label("Stack")}: ${stack ? formatStack(stack) : pc2.dim("no detectado")}`,
|
|
517
|
+
`${brand.label("Idioma")}: ${language === "es" ? "Espa\xF1ol" : "English"}`,
|
|
518
|
+
`${brand.label("M\xF3dulos")}: ${modulesLabel}`,
|
|
519
|
+
`${brand.label("Git")}: ${initGit2 ? "S\xED" : "No"}`
|
|
520
|
+
].join("\n"),
|
|
521
|
+
`${icons.chart} Resumen`
|
|
522
|
+
);
|
|
523
|
+
const confirmed = await p.confirm({
|
|
524
|
+
message: "\xBFGenerar documentaci\xF3n?",
|
|
525
|
+
initialValue: true
|
|
526
|
+
});
|
|
527
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
528
|
+
p.cancel("Operaci\xF3n cancelada.");
|
|
529
|
+
process.exit(0);
|
|
530
|
+
}
|
|
531
|
+
const s = p.spinner();
|
|
532
|
+
s.start("Creando estructura de documentaci\xF3n...");
|
|
533
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
534
|
+
s.message("Generando archivos base (AGENTS.md, CONTEXT.md, ADR...)");
|
|
535
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
536
|
+
if (selectedModules.length > 0) {
|
|
537
|
+
s.message(`A\xF1adiendo m\xF3dulos: ${selectedModules.join(", ")}`);
|
|
538
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
539
|
+
}
|
|
540
|
+
const createdFiles = await generate({
|
|
541
|
+
projectName: projectName.trim(),
|
|
542
|
+
targetDir: resolvedDir,
|
|
543
|
+
stack,
|
|
544
|
+
modules: selectedModules,
|
|
545
|
+
language,
|
|
546
|
+
initGit: initGit2
|
|
547
|
+
});
|
|
548
|
+
if (initGit2) {
|
|
549
|
+
s.message("Inicializando repositorio git...");
|
|
550
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
551
|
+
}
|
|
552
|
+
s.stop(`${icons.check} ${brand.success(`${createdFiles.length} archivos generados`)}`);
|
|
553
|
+
const nextSteps = [
|
|
554
|
+
`${pc2.bold("1.")} Rellenar ${brand.path("docs/CONTEXT.md")} con los t\xE9rminos del dominio`,
|
|
555
|
+
`${pc2.bold("2.")} Revisar ${brand.path("AGENTS.md")} y ajustar stack/comandos`,
|
|
556
|
+
`${pc2.bold("3.")} Ejecutar ${pc2.cyan("npx @damenor/agent-docs --help")} para m\xE1s opciones`
|
|
557
|
+
];
|
|
558
|
+
p.note(nextSteps.join("\n"), `${icons.rocket} Pr\xF3ximos pasos`);
|
|
559
|
+
p.outro(
|
|
560
|
+
`${icons.sparkle} ${brand.title("\xA1Documentaci\xF3n lista!")} ${pc2.dim("\u2014 github.com/damenordev/doc-projects")}`
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// src/index.ts
|
|
565
|
+
cli().catch((error) => {
|
|
566
|
+
console.error(error);
|
|
567
|
+
process.exit(1);
|
|
568
|
+
});
|