@cristiancorreau/forge 2.7.0 → 2.8.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 +64 -5
- package/dist/cli.js +44 -10
- package/dist/cli.js.map +1 -1
- package/dist/commands/aitmpl-search.d.ts +2 -0
- package/dist/commands/aitmpl-search.d.ts.map +1 -0
- package/dist/commands/aitmpl-search.js +711 -0
- package/dist/commands/aitmpl-search.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +113 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/migrate.d.ts +2 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +261 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/scaffold.d.ts +2 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/scaffold.js +214 -0
- package/dist/commands/scaffold.js.map +1 -0
- package/dist/commands/skills.d.ts +2 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +86 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/teardown.d.ts +2 -0
- package/dist/commands/teardown.d.ts.map +1 -0
- package/dist/commands/teardown.js +186 -0
- package/dist/commands/teardown.js.map +1 -0
- package/dist/commands/wiki.d.ts +2 -0
- package/dist/commands/wiki.d.ts.map +1 -0
- package/dist/commands/wiki.js +400 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/lib/catalog.d.ts +22 -0
- package/dist/lib/catalog.d.ts.map +1 -0
- package/dist/lib/catalog.js +49 -0
- package/dist/lib/catalog.js.map +1 -0
- package/dist/lib/yaml.d.ts +4 -0
- package/dist/lib/yaml.d.ts.map +1 -1
- package/dist/lib/yaml.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { resolveForgeRoot } from '../lib/paths.js';
|
|
4
|
+
import { bold, dim, green, red, yellow, cyan, gray, icons } from '../ui/colors.js';
|
|
5
|
+
import { box } from '../ui/box.js';
|
|
6
|
+
const HELP = `Usage: forge scaffold [options]
|
|
7
|
+
|
|
8
|
+
Scaffold a new Tier 2 profile for a stack not covered by forge. Creates
|
|
9
|
+
profiles/<stack>/agents/<engineer>.md (with frontmatter and standard
|
|
10
|
+
sections) plus a basic profiles/<stack>/README.md.
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--name <stack> Profile slug (e.g. django) [required]
|
|
14
|
+
--engineer <agent> Engineer agent name (e.g. api-engineer) [required]
|
|
15
|
+
--description <text> Short description for the agent
|
|
16
|
+
--stack-details <text> Stack details (technologies, versions)
|
|
17
|
+
--force Overwrite the agent file if it already exists
|
|
18
|
+
-h, --help Show this help
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
forge scaffold --name django --engineer api-engineer
|
|
22
|
+
forge scaffold --name django --engineer api-engineer \\
|
|
23
|
+
--description "Backend Django con DRF" \\
|
|
24
|
+
--stack-details "Django 4.2 + PostgreSQL + Django REST Framework"
|
|
25
|
+
`;
|
|
26
|
+
function parseArgs(args) {
|
|
27
|
+
const result = {
|
|
28
|
+
name: '',
|
|
29
|
+
engineer: '',
|
|
30
|
+
description: '',
|
|
31
|
+
stackDetails: '',
|
|
32
|
+
force: false,
|
|
33
|
+
};
|
|
34
|
+
for (let i = 0; i < args.length; i++) {
|
|
35
|
+
const arg = args[i];
|
|
36
|
+
switch (arg) {
|
|
37
|
+
case '--name':
|
|
38
|
+
result.name = args[++i] ?? '';
|
|
39
|
+
break;
|
|
40
|
+
case '--engineer':
|
|
41
|
+
result.engineer = args[++i] ?? '';
|
|
42
|
+
break;
|
|
43
|
+
case '--description':
|
|
44
|
+
result.description = args[++i] ?? '';
|
|
45
|
+
break;
|
|
46
|
+
case '--stack-details':
|
|
47
|
+
result.stackDetails = args[++i] ?? '';
|
|
48
|
+
break;
|
|
49
|
+
case '--force':
|
|
50
|
+
result.force = true;
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
function titleCase(slug) {
|
|
59
|
+
return slug
|
|
60
|
+
.replace(/-/g, ' ')
|
|
61
|
+
.split(' ')
|
|
62
|
+
.filter(Boolean)
|
|
63
|
+
.map(w => w.charAt(0).toUpperCase() + w.slice(1))
|
|
64
|
+
.join(' ');
|
|
65
|
+
}
|
|
66
|
+
function agentMarkdown(args) {
|
|
67
|
+
const slugTitle = titleCase(args.name);
|
|
68
|
+
const engTitle = titleCase(args.engineer);
|
|
69
|
+
const descLine = args.description
|
|
70
|
+
? args.description
|
|
71
|
+
: `Implementa el backend del proyecto usando ${slugTitle}. NO trabaja fuera del directorio definido en project.yaml.`;
|
|
72
|
+
const stackBlock = args.stackDetails
|
|
73
|
+
? args.stackDetails
|
|
74
|
+
: `- **Framework:** ${slugTitle}\n- **Lenguaje:** (especificar)\n- **ORM/DB:** (especificar)\n- **Tests:** (especificar)`;
|
|
75
|
+
return `---
|
|
76
|
+
name: ${args.engineer}
|
|
77
|
+
description: ${descLine}
|
|
78
|
+
model: sonnet
|
|
79
|
+
tools: Read, Grep, Glob, Bash, Edit, Write
|
|
80
|
+
tier: 2
|
|
81
|
+
profile: ${args.name}
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
# ${engTitle} — ${slugTitle}
|
|
85
|
+
|
|
86
|
+
Implementás el backend del proyecto con ${slugTitle}. Tu scope es el directorio
|
|
87
|
+
definido en el \`CLAUDE.md\` del proyecto. Leé ese archivo antes de empezar.
|
|
88
|
+
|
|
89
|
+
## Stack
|
|
90
|
+
|
|
91
|
+
${stackBlock}
|
|
92
|
+
|
|
93
|
+
## Tu trabajo
|
|
94
|
+
|
|
95
|
+
- Implementar endpoints, modelos y migraciones según las specs en \`docs/specs/\`.
|
|
96
|
+
- Escribir tests unitarios y de integración para toda la lógica nueva.
|
|
97
|
+
- Correr el linter, typecheck y tests antes de reportar al orchestrator.
|
|
98
|
+
- Proponer un plan antes de codificar cuando la tarea afecte >3 archivos.
|
|
99
|
+
|
|
100
|
+
## Reglas
|
|
101
|
+
|
|
102
|
+
- **Logs de auditoría son append-only.** NUNCA \`UPDATE\` ni \`DELETE\` sobre tablas de eventos.
|
|
103
|
+
- **PII nunca en logs.** Solo IDs o indicadores no reversibles.
|
|
104
|
+
- **Parámetros preparados siempre:** nunca interpolar input del usuario en SQL.
|
|
105
|
+
- **Auth + authz en cada endpoint:** verificar sesión Y permisos por recurso.
|
|
106
|
+
- **Migraciones reversibles:** toda migración tiene su operación inversa documentada.
|
|
107
|
+
- Sin spec en \`docs/specs/\` → no empieces. Pedí que se cree primero.
|
|
108
|
+
|
|
109
|
+
## No hagas
|
|
110
|
+
|
|
111
|
+
- No salgas del directorio de API/backend del proyecto.
|
|
112
|
+
- No implementes lógica de UI ni de frontend.
|
|
113
|
+
- No modifiques specs ni documentación de arquitectura sin aprobación.
|
|
114
|
+
- No mergees ni crees PRs directamente.
|
|
115
|
+
- No uses queries SQL raw con interpolación de strings.
|
|
116
|
+
|
|
117
|
+
## Forge v2
|
|
118
|
+
|
|
119
|
+
- Workflow: leé el \`CLAUDE.md\` del proyecto y la spec activa antes de tocar código.
|
|
120
|
+
- Revisá el data model si la tarea toca schema; informá al compliance-reviewer si toca compliance.
|
|
121
|
+
- Implementá con tests (TDD para lógica core, integración para endpoints).
|
|
122
|
+
- Reportá al orchestrator: qué se hizo, qué archivos se tocaron, qué falta.
|
|
123
|
+
- Este es un profile Tier 2 — activalo en \`project.yaml\` (\`agents.profiles\`) y corré \`forge init\`.
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
function readmeMarkdown(args) {
|
|
127
|
+
const slugTitle = titleCase(args.name);
|
|
128
|
+
return `# Profile: ${slugTitle}
|
|
129
|
+
|
|
130
|
+
Profile Tier 2 para el stack \`${args.name}\`.
|
|
131
|
+
|
|
132
|
+
## Agentes
|
|
133
|
+
|
|
134
|
+
- \`${args.engineer}\` — ${args.description || `Engineer del stack ${slugTitle}.`}
|
|
135
|
+
|
|
136
|
+
## Activación
|
|
137
|
+
|
|
138
|
+
Agregar el profile en el \`project.yaml\` del proyecto:
|
|
139
|
+
|
|
140
|
+
\`\`\`yaml
|
|
141
|
+
agents:
|
|
142
|
+
profiles:
|
|
143
|
+
- ${args.name}
|
|
144
|
+
\`\`\`
|
|
145
|
+
|
|
146
|
+
Luego instalar los agentes con \`forge init\`.
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
export async function scaffold(args) {
|
|
150
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
151
|
+
process.stdout.write(HELP);
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
const parsed = parseArgs(args);
|
|
155
|
+
parsed.name = parsed.name.trim().toLowerCase();
|
|
156
|
+
parsed.engineer = parsed.engineer.trim().toLowerCase();
|
|
157
|
+
parsed.description = parsed.description.trim();
|
|
158
|
+
parsed.stackDetails = parsed.stackDetails.trim();
|
|
159
|
+
if (!parsed.name || !parsed.engineer) {
|
|
160
|
+
console.error(`${icons.error} ${red('--name y --engineer son obligatorios y no pueden estar vacíos.')}\n`);
|
|
161
|
+
process.stdout.write(HELP);
|
|
162
|
+
return 1;
|
|
163
|
+
}
|
|
164
|
+
let forgeRoot;
|
|
165
|
+
try {
|
|
166
|
+
forgeRoot = resolveForgeRoot();
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
console.error(`${icons.error} ${red(e instanceof Error ? e.message : String(e))}`);
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
const profileDir = join(forgeRoot, 'profiles', parsed.name);
|
|
173
|
+
const agentsDir = join(profileDir, 'agents');
|
|
174
|
+
const agentFile = join(agentsDir, `${parsed.engineer}.md`);
|
|
175
|
+
const readmeFile = join(profileDir, 'README.md');
|
|
176
|
+
if (existsSync(agentFile) && !parsed.force) {
|
|
177
|
+
console.error(`${icons.error} ${red(`${agentFile} ya existe.`)} ${dim('Usá --force para sobrescribir.')}`);
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
const created = [];
|
|
181
|
+
const skipped = [];
|
|
182
|
+
try {
|
|
183
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
184
|
+
writeFileSync(agentFile, agentMarkdown(parsed), 'utf-8');
|
|
185
|
+
created.push(agentFile);
|
|
186
|
+
if (existsSync(readmeFile)) {
|
|
187
|
+
skipped.push(readmeFile);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
writeFileSync(readmeFile, readmeMarkdown(parsed), 'utf-8');
|
|
191
|
+
created.push(readmeFile);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (e) {
|
|
195
|
+
console.error(`${icons.error} ${red(`Error al escribir archivos: ${e instanceof Error ? e.message : String(e)}`)}`);
|
|
196
|
+
return 1;
|
|
197
|
+
}
|
|
198
|
+
console.log(cyan(bold('forge scaffold')) + '\n');
|
|
199
|
+
for (const file of created) {
|
|
200
|
+
console.log(` [${icons.ok}] ${green('creado')} ${file}`);
|
|
201
|
+
}
|
|
202
|
+
for (const file of skipped) {
|
|
203
|
+
console.log(` [${icons.skip}] ${yellow('omitido')} ${dim(file)} ${gray('(ya existía)')}`);
|
|
204
|
+
}
|
|
205
|
+
const nextSteps = [
|
|
206
|
+
`1. Revisar y completar el agente: ${parsed.engineer}.md`,
|
|
207
|
+
`2. Documentar el profile en docs/agent-standard.md (tabla Tier 2)`,
|
|
208
|
+
`3. Activar en project.yaml: agents.profiles → - ${parsed.name}`,
|
|
209
|
+
`4. Instalar el agente: forge init`,
|
|
210
|
+
];
|
|
211
|
+
console.log('\n' + box(green(`Profile '${parsed.name}' listo`), nextSteps));
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/commands/scaffold.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAkCA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAiE5D"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { findProjectYaml, loadProjectYaml } from '../lib/yaml.js';
|
|
2
|
+
import { bold, dim, green, cyan, gray, icons } from '../ui/colors.js';
|
|
3
|
+
import { box } from '../ui/box.js';
|
|
4
|
+
import { SKILLS } from '../lib/catalog.js';
|
|
5
|
+
const HELP = `Usage: forge skills [options]
|
|
6
|
+
|
|
7
|
+
List the forge skills available, grouped by category. If a project.yaml is
|
|
8
|
+
found, the skills enabled in config (skills:) are marked with a ${icons.ok}.
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--active Show only the skills enabled in project.yaml
|
|
12
|
+
--json Output results as JSON
|
|
13
|
+
-h, --help Show this help
|
|
14
|
+
`;
|
|
15
|
+
/** Read the active skill ids from project.yaml (skills:), normalising slashes. */
|
|
16
|
+
function loadActiveSkills(root) {
|
|
17
|
+
const yamlPath = findProjectYaml(root);
|
|
18
|
+
if (!yamlPath)
|
|
19
|
+
return { ids: new Set(), yamlPath: null };
|
|
20
|
+
try {
|
|
21
|
+
const config = loadProjectYaml(yamlPath);
|
|
22
|
+
const raw = config.skills ?? [];
|
|
23
|
+
const ids = new Set(raw.map(s => s.replace(/^\//, '')));
|
|
24
|
+
return { ids, yamlPath };
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return { ids: new Set(), yamlPath };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function skills(args) {
|
|
31
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
32
|
+
process.stdout.write(HELP);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
const jsonMode = args.includes('--json');
|
|
36
|
+
const activeOnly = args.includes('--active');
|
|
37
|
+
const root = process.cwd();
|
|
38
|
+
const { ids: activeIds, yamlPath } = loadActiveSkills(root);
|
|
39
|
+
let rows = SKILLS.map(s => ({ ...s, active: activeIds.has(s.id) }));
|
|
40
|
+
if (activeOnly)
|
|
41
|
+
rows = rows.filter(r => r.active);
|
|
42
|
+
if (jsonMode) {
|
|
43
|
+
console.log(JSON.stringify({
|
|
44
|
+
projectYaml: yamlPath,
|
|
45
|
+
total: rows.length,
|
|
46
|
+
active: rows.filter(r => r.active).length,
|
|
47
|
+
skills: rows,
|
|
48
|
+
}, null, 2));
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
console.log(cyan(bold('forge skills')) + '\n');
|
|
52
|
+
if (rows.length === 0) {
|
|
53
|
+
console.log(dim(activeOnly
|
|
54
|
+
? ' No hay skills activas en project.yaml.'
|
|
55
|
+
: ' No hay skills en el catálogo.'));
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
// Group by category, preserving catalog order of first appearance.
|
|
59
|
+
const categories = [];
|
|
60
|
+
const byCategory = new Map();
|
|
61
|
+
for (const row of rows) {
|
|
62
|
+
if (!byCategory.has(row.category)) {
|
|
63
|
+
byCategory.set(row.category, []);
|
|
64
|
+
categories.push(row.category);
|
|
65
|
+
}
|
|
66
|
+
byCategory.get(row.category).push(row);
|
|
67
|
+
}
|
|
68
|
+
const commandWidth = Math.max(...rows.map(r => r.command.length));
|
|
69
|
+
for (const category of categories) {
|
|
70
|
+
console.log(bold(category));
|
|
71
|
+
for (const row of byCategory.get(category)) {
|
|
72
|
+
const mark = row.active ? icons.ok : gray('·');
|
|
73
|
+
const command = cyan(row.command.padEnd(commandWidth));
|
|
74
|
+
console.log(` ${mark} ${command} ${row.purpose}`);
|
|
75
|
+
console.log(` ${' '.repeat(2)}${' '.repeat(commandWidth)} ${dim(row.trigger)}`);
|
|
76
|
+
}
|
|
77
|
+
console.log('');
|
|
78
|
+
}
|
|
79
|
+
const activeCount = rows.filter(r => r.active).length;
|
|
80
|
+
const summary = yamlPath
|
|
81
|
+
? `${rows.length} skill(s) · ${green(String(activeCount) + ' activa(s)')} en ${yamlPath}`
|
|
82
|
+
: `${rows.length} skill(s) en el catálogo · ${dim('sin project.yaml — ninguna marcada como activa')}`;
|
|
83
|
+
console.log(box('Catálogo de skills', [summary]));
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teardown.d.ts","sourceRoot":"","sources":["../../src/commands/teardown.ts"],"names":[],"mappings":"AA2GA,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4G9D"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { existsSync, rmSync, readdirSync, statSync } from 'fs';
|
|
2
|
+
import { join, relative } from 'path';
|
|
3
|
+
import { createInterface } from 'readline';
|
|
4
|
+
import { findProjectYaml, projectRoot as yamlProjectRoot } from '../lib/yaml.js';
|
|
5
|
+
import { loadManifest } from '../lib/lock.js';
|
|
6
|
+
import { bold, dim, green, red, yellow, cyan, gray, icons } from '../ui/colors.js';
|
|
7
|
+
import { box } from '../ui/box.js';
|
|
8
|
+
const HELP = `Usage: forge teardown [options]
|
|
9
|
+
|
|
10
|
+
Cleanly uninstall forge from the current project. Removes the files that forge
|
|
11
|
+
installed (.claude/agents/, hooks, commands, settings.json, CLAUDE.md, .forge/,
|
|
12
|
+
architecture.rules) based on .forge/manifest.json, falling back to the standard
|
|
13
|
+
forge layout when no manifest is present.
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--dry-run List what would be removed without deleting anything
|
|
17
|
+
--keep-config Preserve project.yaml (kept by default; flag is explicit)
|
|
18
|
+
--yes, -y Skip the confirmation prompt
|
|
19
|
+
-h, --help Show this help
|
|
20
|
+
`;
|
|
21
|
+
/**
|
|
22
|
+
* Standard forge layout — used to find leftovers even when the manifest is
|
|
23
|
+
* missing or incomplete. Directories are removed recursively.
|
|
24
|
+
*/
|
|
25
|
+
const STANDARD_FILES = [
|
|
26
|
+
'.claude/settings.json',
|
|
27
|
+
'.claude/architecture.rules',
|
|
28
|
+
'CLAUDE.md',
|
|
29
|
+
];
|
|
30
|
+
const STANDARD_DIRS = [
|
|
31
|
+
'.claude/agents',
|
|
32
|
+
'.claude/hooks',
|
|
33
|
+
'.claude/commands',
|
|
34
|
+
'.forge',
|
|
35
|
+
];
|
|
36
|
+
function relPath(root, abs) {
|
|
37
|
+
const r = relative(root, abs);
|
|
38
|
+
return r === '' ? '.' : r;
|
|
39
|
+
}
|
|
40
|
+
/** Collects removal targets, de-duplicated by absolute path. */
|
|
41
|
+
function collectTargets(root, keepConfig) {
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
const targets = [];
|
|
44
|
+
const add = (abs, isDir, source) => {
|
|
45
|
+
if (seen.has(abs))
|
|
46
|
+
return;
|
|
47
|
+
if (!existsSync(abs))
|
|
48
|
+
return;
|
|
49
|
+
seen.add(abs);
|
|
50
|
+
targets.push({ path: abs, rel: relPath(root, abs), isDir, source });
|
|
51
|
+
};
|
|
52
|
+
// 1. Manifest-driven: delete exactly what forge recorded installing.
|
|
53
|
+
const manifest = loadManifest(root);
|
|
54
|
+
if (manifest) {
|
|
55
|
+
for (const file of Object.keys(manifest.files)) {
|
|
56
|
+
if (keepConfig && (file === 'project.yaml' || file.endsWith('/project.yaml')))
|
|
57
|
+
continue;
|
|
58
|
+
const abs = join(root, file);
|
|
59
|
+
const isDir = existsSync(abs) && statSync(abs).isDirectory();
|
|
60
|
+
add(abs, isDir, 'manifest');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// 2. Standard layout — catches files not tracked by the manifest.
|
|
64
|
+
for (const file of STANDARD_FILES) {
|
|
65
|
+
add(join(root, file), false, 'standard');
|
|
66
|
+
}
|
|
67
|
+
for (const dir of STANDARD_DIRS) {
|
|
68
|
+
add(join(root, dir), true, 'standard');
|
|
69
|
+
}
|
|
70
|
+
return targets;
|
|
71
|
+
}
|
|
72
|
+
/** True when the directory has no entries (so it is safe to remove). */
|
|
73
|
+
function isEmptyDir(abs) {
|
|
74
|
+
try {
|
|
75
|
+
return readdirSync(abs).length === 0;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function confirm(question) {
|
|
82
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
rl.question(question, (answer) => {
|
|
85
|
+
rl.close();
|
|
86
|
+
resolve(/^y(es)?$/i.test(answer.trim()));
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export async function teardown(args) {
|
|
91
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
92
|
+
process.stdout.write(HELP);
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
const dryRun = args.includes('--dry-run');
|
|
96
|
+
const keepConfig = args.includes('--keep-config');
|
|
97
|
+
const assumeYes = args.includes('--yes') || args.includes('-y');
|
|
98
|
+
const yamlPath = findProjectYaml(process.cwd());
|
|
99
|
+
if (!yamlPath) {
|
|
100
|
+
console.error(red('ERROR: ') + 'No se encontró project.yaml — ¿estás dentro de un proyecto forge?');
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
const root = yamlProjectRoot(yamlPath);
|
|
104
|
+
const targets = collectTargets(root, keepConfig);
|
|
105
|
+
console.log(cyan(bold('forge teardown')) + (dryRun ? dim(' (dry-run)') : '') + '\n');
|
|
106
|
+
if (targets.length === 0) {
|
|
107
|
+
console.log(' ' + gray('Nada que eliminar — el proyecto ya está limpio de forge.'));
|
|
108
|
+
console.log('\n' + box(green('Nada que hacer'), ['No se encontraron artefactos de forge.']));
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
// Preview: list every target.
|
|
112
|
+
console.log(dim('Se eliminarán los siguientes artefactos de forge:') + '\n');
|
|
113
|
+
for (const t of targets) {
|
|
114
|
+
const kind = t.isDir ? dim('DIR ') : dim('FILE');
|
|
115
|
+
const tag = t.source === 'manifest' ? gray('[manifest]') : gray('[standard]');
|
|
116
|
+
console.log(` ${red('-')} ${kind} ${bold(t.rel)} ${tag}`);
|
|
117
|
+
}
|
|
118
|
+
if (keepConfig) {
|
|
119
|
+
console.log('\n ' + cyan(icons.info) + ' ' + dim('project.yaml se conserva (--keep-config)'));
|
|
120
|
+
}
|
|
121
|
+
if (dryRun) {
|
|
122
|
+
console.log('\n' + box(yellow('Dry-run'), [
|
|
123
|
+
`${targets.length} artefacto(s) se eliminarían.`,
|
|
124
|
+
'Nada fue modificado. Quita --dry-run para ejecutar.',
|
|
125
|
+
]));
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
// Confirmation, unless --yes.
|
|
129
|
+
if (!assumeYes) {
|
|
130
|
+
console.log('');
|
|
131
|
+
const ok = await confirm(yellow('¿Eliminar estos artefactos? ') + dim('(y/N) '));
|
|
132
|
+
if (!ok) {
|
|
133
|
+
console.log('\n ' + gray('Cancelado. Nada fue eliminado.'));
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
console.log('');
|
|
138
|
+
let removed = 0;
|
|
139
|
+
let failed = 0;
|
|
140
|
+
const skipped = [];
|
|
141
|
+
for (const t of targets) {
|
|
142
|
+
// Don't delete a non-empty .claude/agents/ etc. if it holds files forge
|
|
143
|
+
// didn't install — only remove dirs that are empty after manifest deletions,
|
|
144
|
+
// or dirs that are fully owned by forge (.forge).
|
|
145
|
+
if (t.isDir && t.source === 'standard' && !isEmptyDir(t.path) && t.rel !== '.forge') {
|
|
146
|
+
const remaining = readdirSync(t.path);
|
|
147
|
+
skipped.push(`${t.rel} (retiene ${remaining.length} entrada(s) no instaladas por forge)`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
rmSync(t.path, { recursive: true, force: true });
|
|
152
|
+
const kind = t.isDir ? 'DIR ' : 'FILE';
|
|
153
|
+
console.log(` ${green(icons.ok)} ${dim('eliminado')} ${kind} ${bold(t.rel)}`);
|
|
154
|
+
removed++;
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
158
|
+
console.log(` ${red(icons.error)} ${dim('falló')} ${bold(t.rel)} ${dim(msg)}`);
|
|
159
|
+
failed++;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Clean up .claude/ if it ended up empty.
|
|
163
|
+
const claudeDir = join(root, '.claude');
|
|
164
|
+
if (existsSync(claudeDir) && isEmptyDir(claudeDir)) {
|
|
165
|
+
try {
|
|
166
|
+
rmSync(claudeDir, { recursive: true, force: true });
|
|
167
|
+
console.log(` ${green(icons.ok)} ${dim('eliminado')} DIR ${bold(relPath(root, claudeDir))} ${dim('(vacío)')}`);
|
|
168
|
+
removed++;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// best-effort
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (const s of skipped) {
|
|
175
|
+
console.log(` ${yellow(icons.skip)} ${dim('conservado')} ${s}`);
|
|
176
|
+
}
|
|
177
|
+
const summary = `${green(String(removed) + ' eliminados')} · ${yellow(String(skipped.length) + ' conservados')} · ${red(String(failed) + ' fallidos')}`;
|
|
178
|
+
const title = failed > 0 ? red('Teardown con errores') : green('Teardown completado');
|
|
179
|
+
const lines = [summary];
|
|
180
|
+
if (keepConfig)
|
|
181
|
+
lines.push(dim('project.yaml conservado.'));
|
|
182
|
+
lines.push(dim('Revisa CLAUDE.md/.git si quedaron referencias manuales a forge.'));
|
|
183
|
+
console.log('\n' + box(title, lines));
|
|
184
|
+
return failed > 0 ? 1 : 0;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=teardown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teardown.js","sourceRoot":"","sources":["../../src/commands/teardown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki.d.ts","sourceRoot":"","sources":["../../src/commands/wiki.ts"],"names":[],"mappings":"AA4bA,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyB1D"}
|