@cristiancorreau/forge 2.16.0 → 2.17.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 CHANGED
@@ -7,6 +7,13 @@ Versioning: [Semantic Versioning](https://semver.org/lang/es/)
7
7
 
8
8
  ---
9
9
 
10
+ ## [2.17.0] — 2026-06-04
11
+
12
+ ### Agregado
13
+ - **`forge adopt [path]` — onboarding de forge en un repo existente (brownfield).** Lee y analiza un codebase ya existente (sin LLM), genera el `project.yaml` desde lo que detecta (stack vía `detect.ts` con lenguaje por lado, `project.type`, ORM, testing, monorepo, docker), instala la config de forge reusando los installers de `forge init` (agentes por modo, hooks, slash commands, CLAUDE.md, settings.json, architecture.rules, manifest `.forge`) sin pisar archivos existentes salvo `--force`, y **auto-genera el wiki del proyecto** con HECHOS determinísticos: `concepts/arquitectura.md` y `concepts/stack.md` (del mapa de directorios + stack), `entities/` (proyecto + cada framework/herramienta detectada), `sources/` (resumen de README + manifest), `synthesis/overview.md` (resumen factual + nota "Pendiente: compilación semántica con /wiki-ingest") y `raw/` con copias inmutables del README + manifest. El wiki generado pasa `forge wiki lint` (sin links rotos ni huérfanos). La capa SEMÁNTICA (lógica de negocio, decisiones) sigue siendo trabajo del skill `/wiki-ingest`, que `adopt` apunta como próximo paso. Flags: `--yes` (no-interactivo por defecto), `--no-wiki`, `--runtime`, `--mode`, `--force`, `--dry-run`. Módulos puros y testeados: `lib/project-analysis.ts` y `lib/wiki-autogen.ts` (SPEC-038).
14
+
15
+ ---
16
+
10
17
  ## [2.16.0] — 2026-06-04
11
18
 
12
19
  ### Agregado
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge",
3
- "version": "2.16.0",
3
+ "version": "2.17.0",
4
4
  "description": "Agentic development framework for Claude Code, OpenCode, Codex and Kiro",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/cristiancorreau/forge",
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { init } from './commands/init.js';
3
+ import { adopt } from './commands/adopt.js';
3
4
  import { audit } from './commands/audit.js';
4
5
  import { generate } from './commands/generate.js';
5
6
  import { validate } from './commands/validate.js';
@@ -21,6 +22,7 @@ Usage: forge <command> [options]
21
22
  Setup
22
23
  panel Open the interactive panel (config, monitor, skills, hooks, templates)
23
24
  init Initialize forge in a project (wizard + post-install dashboard)
25
+ adopt Onboard forge into an EXISTING codebase (analyze + auto-wiki)
24
26
  generate Generate runtime config files from project.yaml
25
27
  migrate Migrate project.yaml from the v1 schema to v2 (--dry-run, --backup)
26
28
  scaffold Scaffold a new agent: Tier 2 profile, or Tier 3 domain agent (--tier 3)
@@ -48,6 +50,7 @@ Run forge <command> --help for command-specific options.
48
50
 
49
51
  Examples:
50
52
  npx @cristiancorreau/forge init
53
+ npx @cristiancorreau/forge adopt ./my-existing-repo --yes
51
54
  npx @cristiancorreau/forge panel
52
55
  npx @cristiancorreau/forge skills
53
56
  npx @cristiancorreau/forge migrate --dry-run
@@ -60,6 +63,9 @@ switch (cmd) {
60
63
  case 'init':
61
64
  exitCode = await init(rest);
62
65
  break;
66
+ case 'adopt':
67
+ exitCode = await adopt(rest);
68
+ break;
63
69
  case 'audit':
64
70
  exitCode = await audit(rest);
65
71
  break;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function adopt(args: string[]): Promise<number>;
2
+ //# sourceMappingURL=adopt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.d.ts","sourceRoot":"","sources":["../../src/commands/adopt.ts"],"names":[],"mappings":"AAwLA,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA+G3D"}
@@ -0,0 +1,259 @@
1
+ /**
2
+ * `forge adopt [path]` — onboard forge into an EXISTING codebase (brownfield).
3
+ *
4
+ * Unlike `forge init` (greenfield wizard), adopt READS the target project, infers
5
+ * its configuration by static analysis, and materializes everything non-
6
+ * interactively: project.yaml + the forge config (.claude/, CLAUDE.md, settings,
7
+ * architecture.rules, manifest) + an auto-generated FACTUAL wiki.
8
+ *
9
+ * The wiki it seeds is deterministic facts only (stack, structure, dependencies,
10
+ * scripts, README summary). The deep SEMANTIC compilation stays the job of the
11
+ * /wiki-ingest skill, which adopt points to as the explicit next step.
12
+ *
13
+ * It reuses init's exported installers so the installed config is identical to
14
+ * `forge init`, and never clobbers existing files unless --force.
15
+ */
16
+ import { existsSync, mkdirSync, writeFileSync, statSync } from 'fs';
17
+ import { join, resolve } from 'path';
18
+ import { resolveForgeRoot } from '../lib/paths.js';
19
+ import { generateClaudeMd } from '../lib/generators/claude-code.js';
20
+ import { generateAgentsMd } from '../lib/generators/opencode.js';
21
+ import { generateCodexAgentsMd } from '../lib/generators/codex.js';
22
+ import { scaffoldWikiStructure } from './wiki.js';
23
+ import { analyzeProject, slugify } from '../lib/project-analysis.js';
24
+ import { generateWiki } from '../lib/wiki-autogen.js';
25
+ import { languageLabel, deriveProjectLanguage, hasBackend, hasFrontend } from '../lib/wizard-flow.js';
26
+ import { VERSION } from '../version.js';
27
+ import { defaultAgentsForMode, installCoreAgents, installHooks, installCommands, writeSettingsJson, installSpecScaffold, saveInstallManifest, write, buildProjectYaml, } from './init.js';
28
+ import { bold, dim, green, cyan, gray, yellow, icons } from '../ui/colors.js';
29
+ import { box } from '../ui/box.js';
30
+ const HELP = `Usage: forge adopt [path] [options]
31
+
32
+ Onboard forge into an EXISTING codebase. Analyzes the project, generates
33
+ project.yaml from what it detects, installs the forge config, and seeds the
34
+ project wiki with FACTUAL knowledge (stack, structure, dependencies, scripts,
35
+ README). Non-interactive by default.
36
+
37
+ Arguments:
38
+ path Target project directory (default: current directory)
39
+
40
+ Options:
41
+ --yes Non-interactive (default — no prompts)
42
+ --no-wiki Skip the auto-generated wiki
43
+ --runtime <name> Runtime: claude-code (default), opencode, codex
44
+ --mode <mode> Mode: startup, standard (default), enterprise
45
+ --force Overwrite existing files instead of preserving them
46
+ --dry-run Analyze + print the plan; write nothing
47
+ -h, --help Show this help
48
+
49
+ The wiki adopt seeds is deterministic FACTS. The deep semantic compilation
50
+ (business logic, decisions) is the job of /wiki-ingest — adopt prints it as the
51
+ next step.
52
+ `;
53
+ function flagValue(args, flag) {
54
+ const i = args.indexOf(flag);
55
+ return i !== -1 ? (args[i + 1] ?? null) : null;
56
+ }
57
+ function parseOptions(args) {
58
+ // First non-flag arg (not a flag value) is the target path.
59
+ const flagsWithValue = new Set(['--runtime', '--mode']);
60
+ let target = process.cwd();
61
+ for (let i = 0; i < args.length; i++) {
62
+ const arg = args[i];
63
+ if (arg.startsWith('-')) {
64
+ if (flagsWithValue.has(arg))
65
+ i++; // skip its value
66
+ continue;
67
+ }
68
+ target = resolve(arg);
69
+ break;
70
+ }
71
+ const modeRaw = flagValue(args, '--mode');
72
+ const mode = modeRaw === 'startup' || modeRaw === 'enterprise' ? modeRaw : 'standard';
73
+ return {
74
+ target,
75
+ runtime: flagValue(args, '--runtime') ?? 'claude-code',
76
+ mode,
77
+ wiki: !args.includes('--no-wiki'),
78
+ force: args.includes('--force'),
79
+ dryRun: args.includes('--dry-run'),
80
+ };
81
+ }
82
+ /** Map a ProjectAnalysis to a WizardResult so buildProjectYaml can render YAML. */
83
+ function analysisToWizardResult(a, opts) {
84
+ const s = a.stack;
85
+ // Per-side language falls back to the base detected language when no framework
86
+ // was matched on that side (e.g. a Python backend whose framework isn't in
87
+ // detect.ts still has a Python backend language, not the TS default).
88
+ const backendLanguage = s.backendLanguage
89
+ ?? (hasBackend(a.type) ? (s.language ?? undefined) : undefined)
90
+ ?? undefined;
91
+ const frontendLanguage = s.frontendLanguage
92
+ ?? (hasFrontend(a.type) ? 'typescript' : undefined)
93
+ ?? undefined;
94
+ const language = deriveProjectLanguage({ type: a.type, backendLanguage, frontendLanguage });
95
+ // Auto-detect profiles from the detected frameworks (mirrors the wizard).
96
+ const PROFILE_MAP = {
97
+ hono: 'hono-drizzle', nextjs: 'nextjs-admin', astro: 'astro',
98
+ fastapi: 'fastapi', rails: 'rails', laravel: 'laravel',
99
+ };
100
+ const profiles = [];
101
+ for (const key of [s.backend, s.frontend]) {
102
+ if (key && PROFILE_MAP[key])
103
+ profiles.push(PROFILE_MAP[key]);
104
+ }
105
+ return {
106
+ name: a.name,
107
+ slug: slugify(a.name),
108
+ description: a.description || '',
109
+ language,
110
+ type: a.type,
111
+ backendLanguage,
112
+ frontendLanguage,
113
+ mode: opts.mode,
114
+ backend: s.backend ?? undefined,
115
+ frontend: s.frontend ?? undefined,
116
+ database: s.database ?? undefined,
117
+ orm: s.orm ?? undefined,
118
+ packageManager: s.packageManager ?? undefined,
119
+ testing: s.testing,
120
+ profiles: [...new Set(profiles)],
121
+ skills: ['wiki-ingest', 'wiki-query', 'wiki-lint'],
122
+ runtime: opts.runtime,
123
+ detected: true,
124
+ };
125
+ }
126
+ /** Build the in-memory ProjectYaml config (matches init's config shape). */
127
+ function buildConfig(result) {
128
+ return {
129
+ project: {
130
+ name: result.name, slug: result.slug, description: result.description,
131
+ language: result.language, type: result.type, mode: result.mode, status: 'active',
132
+ },
133
+ stack: {
134
+ backend: result.backend, backend_language: result.backendLanguage,
135
+ frontend: result.frontend, frontend_language: result.frontendLanguage,
136
+ database: result.database, orm: result.orm,
137
+ package_manager: result.packageManager, testing: result.testing,
138
+ },
139
+ agents: { active: defaultAgentsForMode(result.mode), compliance: [], specialized: [], profiles: result.profiles },
140
+ runtimes: { active: [result.runtime] },
141
+ skills: result.skills,
142
+ };
143
+ }
144
+ function printDetectedSummary(a) {
145
+ const s = a.stack;
146
+ const lines = [];
147
+ lines.push(`${bold('Proyecto')}: ${a.name}${a.description ? gray(` — ${a.description}`) : ''}`);
148
+ lines.push(`${bold('Tipo')}: ${a.type} ${bold('Lenguaje')}: ${a.stack.language ? languageLabel(a.stack.language) : '—'} ${bold('Ecosistema')}: ${a.ecosystem}`);
149
+ if (s.backend)
150
+ lines.push(`${bold('Backend')}: ${s.backend}${s.backendLanguage ? ` (${s.backendLanguage})` : ''}`);
151
+ if (s.frontend)
152
+ lines.push(`${bold('Frontend')}: ${s.frontend}${s.frontendLanguage ? ` (${s.frontendLanguage})` : ''}`);
153
+ if (s.database || s.orm)
154
+ lines.push(`${bold('Datos')}: ${[s.database, s.orm].filter(Boolean).join(' + ') || '—'}`);
155
+ if (s.testing.length)
156
+ lines.push(`${bold('Testing')}: ${s.testing.join(', ')}`);
157
+ if (s.packageManager)
158
+ lines.push(`${bold('Package manager')}: ${s.packageManager}`);
159
+ lines.push(`${bold('Directorios')}: ${a.directories.slice(0, 6).map(d => `${d.name}/ (${d.fileCount})`).join(' ') || '—'}`);
160
+ if (a.entrypoints.length)
161
+ lines.push(`${bold('Entrypoints')}: ${a.entrypoints.slice(0, 4).join(', ')}`);
162
+ if (a.git.remote)
163
+ lines.push(`${bold('Git')}: ${a.git.remote}${a.git.branch ? ` @ ${a.git.branch}` : ''}`);
164
+ console.log('\n' + box(cyan('Proyecto detectado'), lines));
165
+ }
166
+ export async function adopt(args) {
167
+ if (args.includes('-h') || args.includes('--help')) {
168
+ process.stdout.write(HELP);
169
+ return 0;
170
+ }
171
+ const opts = parseOptions(args);
172
+ console.log(cyan(bold('forge adopt')) + dim(` ${opts.target}`) + '\n');
173
+ if (!existsSync(opts.target) || !statSync(opts.target).isDirectory()) {
174
+ console.error(` ${icons.error} El target no existe o no es un directorio: ${opts.target}\n`);
175
+ return 1;
176
+ }
177
+ // 1. Analyze the existing project (never throws).
178
+ const analysis = analyzeProject(opts.target);
179
+ printDetectedSummary(analysis);
180
+ const result = analysisToWizardResult(analysis, opts);
181
+ const config = buildConfig(result);
182
+ // --- dry-run: print the plan, write nothing ---
183
+ if (opts.dryRun) {
184
+ const plan = [
185
+ `project.yaml ${gray('(generado del análisis)')}`,
186
+ ...(opts.runtime === 'claude-code' ? [
187
+ `.claude/agents/ ${gray(`${config.agents?.active?.length ?? 0} agents (${opts.mode})`)}`,
188
+ '.claude/hooks/ ' + gray('guardrails'),
189
+ '.claude/commands/ ' + gray('slash commands'),
190
+ 'CLAUDE.md ' + gray('generado'),
191
+ '.claude/settings.json ' + gray('permisos + hooks'),
192
+ '.claude/architecture.rules + docs/specs/',
193
+ '.forge/manifest.json',
194
+ ] : [`${opts.runtime}: AGENTS.md ${gray('generado')}`]),
195
+ ...(opts.wiki ? [`wiki/ ${gray('poblado (hechos) — semántica vía /wiki-ingest')}`] : []),
196
+ ];
197
+ console.log('\n' + box(yellow('Plan (--dry-run, no escribe nada)'), plan));
198
+ console.log(dim('\n Ejecutá sin --dry-run para aplicar.\n'));
199
+ return 0;
200
+ }
201
+ // 2. Write project.yaml (preserve existing unless --force).
202
+ const projectYamlPath = join(opts.target, 'project.yaml');
203
+ const created = [];
204
+ if (!existsSync(projectYamlPath) || opts.force) {
205
+ writeFileSync(projectYamlPath, buildProjectYaml(result, []), 'utf-8');
206
+ created.push('project.yaml');
207
+ }
208
+ else {
209
+ console.log(dim(' project.yaml ya existe — se conserva (usá --force para sobrescribir).'));
210
+ }
211
+ // 3. Install the forge config, reusing init's exported installers.
212
+ const forgeRoot = resolveForgeRoot();
213
+ if (opts.runtime === 'claude-code') {
214
+ const claudeDir = join(opts.target, '.claude');
215
+ mkdirSync(claudeDir, { recursive: true });
216
+ const activeAgents = config.agents?.active ?? [];
217
+ const profiles = config.agents?.profiles ?? [];
218
+ installCoreAgents(forgeRoot, join(claudeDir, 'agents'), activeAgents, profiles, opts.force);
219
+ installHooks(forgeRoot, join(claudeDir, 'hooks'), opts.mode, opts.force);
220
+ installCommands(forgeRoot, join(claudeDir, 'commands'), opts.force);
221
+ write(join(opts.target, 'CLAUDE.md'), generateClaudeMd(config), opts.force);
222
+ writeSettingsJson(join(claudeDir, 'settings.json'), config.project.language ?? 'typescript', opts.mode, opts.force);
223
+ installSpecScaffold(forgeRoot, opts.target, claudeDir, config);
224
+ saveInstallManifest(opts.target, claudeDir, opts.runtime, activeAgents, [], VERSION);
225
+ created.push('.claude/ (agents, hooks, commands, settings.json, architecture.rules)', 'CLAUDE.md', 'docs/specs/', '.forge/manifest.json');
226
+ }
227
+ else if (opts.runtime === 'opencode') {
228
+ mkdirSync(join(opts.target, '.opencode'), { recursive: true });
229
+ write(join(opts.target, 'AGENTS.md'), generateAgentsMd(config), opts.force);
230
+ created.push('AGENTS.md');
231
+ }
232
+ else if (opts.runtime === 'codex') {
233
+ write(join(opts.target, 'AGENTS.md'), generateCodexAgentsMd(config), opts.force);
234
+ created.push('AGENTS.md');
235
+ }
236
+ // 4. Auto-generate the wiki (factual) unless --no-wiki.
237
+ let wikiResult = null;
238
+ if (opts.wiki) {
239
+ scaffoldWikiStructure(opts.target, false);
240
+ wikiResult = generateWiki(analysis);
241
+ created.push(`wiki/ (${wikiResult.pages.length} páginas, ${wikiResult.rawSources.length} fuentes en raw/)`);
242
+ }
243
+ // 5. Summary + next steps.
244
+ console.log('\n' + box(green(`forge adoptado — ${opts.runtime}`), created.map(c => `${icons.ok} ${c}`)));
245
+ const rawList = wikiResult?.rawSources.length
246
+ ? wikiResult.rawSources.map(r => `wiki/raw/${r}`)
247
+ : [];
248
+ const nextSteps = [];
249
+ if (opts.wiki) {
250
+ nextSteps.push(`${cyan('/wiki-ingest')} ${dim('— compilá la capa semántica desde las fuentes:')}`, ...rawList.map(r => ` ${dim(r)}`));
251
+ }
252
+ nextSteps.push(`${cyan('forge audit')} ${dim('— verificá el proyecto contra el estándar forge')}`, `${cyan('forge panel')} ${dim('— panel interactivo (config, monitor, skills)')}`);
253
+ console.log('\n' + bold(' Próximos pasos:'));
254
+ for (const step of nextSteps)
255
+ console.log(` ${step}`);
256
+ console.log('');
257
+ return 0;
258
+ }
259
+ //# sourceMappingURL=adopt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopt.js","sourceRoot":"","sources":["../../src/commands/adopt.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,43 @@
1
1
  import { runWizard } from '../lib/wizard.js';
2
- export declare function buildProjectYaml(result: Awaited<ReturnType<typeof runWizard>>, specialized?: string[]): string;
2
+ import type { ProjectYaml } from '../lib/yaml.js';
3
+ export declare function write(path: string, content: string, force: boolean): void;
4
+ /**
5
+ * Auto-detecta agentes Tier 3 existentes: escanea .claude/agents/*.md en `root`
6
+ * y devuelve los nombres cuyo frontmatter declara `tier: 3`. Sirve para poblar
7
+ * agents.specialized en project.yaml durante `forge init`.
8
+ */
9
+ export declare function detectTier3Agents(root: string): string[];
10
+ /**
11
+ * Lista los archivos instalados en `<claudeDir>/<subdir>` (p. ej. hooks/ o
12
+ * commands/) como rutas RELATIVAS a `projectRoot`, usando separadores `/` para
13
+ * que el manifest sea estable entre plataformas. Devuelve [] si el dir no existe.
14
+ * Recorre subdirectorios (los slash commands pueden estar anidados).
15
+ */
16
+ export declare function listInstalledRelativeFiles(claudeDir: string, subdir: string, projectRoot: string): string[];
17
+ export declare function buildProjectYaml(result: Awaited<ReturnType<typeof runWizard>> | null, specialized?: string[]): string;
18
+ export declare function defaultAgentsForMode(mode: string): string[];
19
+ export declare function installCoreAgents(forgeRoot: string, destDir: string, activeAgents: string[], profiles: string[], force: boolean): void;
20
+ export declare function installHooks(forgeRoot: string, destDir: string, mode: string, force: boolean): void;
21
+ /**
22
+ * Escribe `.claude/settings.json`. Si el archivo ya existe (y es JSON válido),
23
+ * mezcla preservando keys externas (`env`, etc.) y permisos previos. Si no
24
+ * existe o no se puede parsear, escribe los settings generados tal cual.
25
+ * Respeta `force`: con `force=false` no toca un archivo existente.
26
+ */
27
+ export declare function writeSettingsJson(path: string, language: string, mode: string, force: boolean): void;
28
+ export declare function installCommands(forgeRoot: string, destDir: string, force: boolean): void;
29
+ /**
30
+ * Scaffolds docs/specs/ (+ _template.md), docs/daily-notes/ and the
31
+ * .claude/architecture.rules file. Idempotent: never overwrites the spec
32
+ * template or architecture.rules once they exist. Shared by `forge init` and
33
+ * `forge adopt` so both lay down the same SDD scaffold.
34
+ */
35
+ export declare function installSpecScaffold(forgeRoot: string, projectRoot: string, claudeDir: string, config: ProjectYaml): void;
36
+ /**
37
+ * Builds and saves the .forge/manifest.json for a claude-code install: tracks
38
+ * CLAUDE.md, settings.json, architecture.rules, all agents (active + compliance
39
+ * + specialized) and the installed hooks/commands. Shared by init and adopt.
40
+ */
41
+ export declare function saveInstallManifest(projectRoot: string, claudeDir: string, runtime: string, allAgents: string[], specializedAgents: string[], forgeVersion: string): void;
3
42
  export declare function init(args: string[]): Promise<number>;
4
43
  //# sourceMappingURL=init.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA0I7C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,WAAW,GAAE,MAAM,EAAO,GAAG,MAAM,CAwDlH;AAiLD,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmP1D"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA2C7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AA4BlD,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGzE;AAiBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBxD;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAa3G;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE,WAAW,GAAE,MAAM,EAAO,GAAG,MAAM,CAwDzH;AAYD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAI3D;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAsBtI;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAqBnG;AAiED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAiBpG;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAKxF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAaxH;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EACvD,SAAS,EAAE,MAAM,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,GACrE,IAAI,CAYN;AAmBD,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwN1D"}
@@ -61,7 +61,7 @@ Options:
61
61
  // ---------------------------------------------------------------------------
62
62
  // Helpers
63
63
  // ---------------------------------------------------------------------------
64
- function write(path, content, force) {
64
+ export function write(path, content, force) {
65
65
  if (existsSync(path) && !force)
66
66
  return;
67
67
  writeFileSync(path, content, 'utf-8');
@@ -88,7 +88,7 @@ function copyDir(src, dest, force) {
88
88
  * y devuelve los nombres cuyo frontmatter declara `tier: 3`. Sirve para poblar
89
89
  * agents.specialized en project.yaml durante `forge init`.
90
90
  */
91
- function detectTier3Agents(root) {
91
+ export function detectTier3Agents(root) {
92
92
  const agentsDir = join(root, '.claude', 'agents');
93
93
  if (!existsSync(agentsDir))
94
94
  return [];
@@ -118,7 +118,7 @@ function detectTier3Agents(root) {
118
118
  * que el manifest sea estable entre plataformas. Devuelve [] si el dir no existe.
119
119
  * Recorre subdirectorios (los slash commands pueden estar anidados).
120
120
  */
121
- function listInstalledRelativeFiles(claudeDir, subdir, projectRoot) {
121
+ export function listInstalledRelativeFiles(claudeDir, subdir, projectRoot) {
122
122
  const baseDir = join(claudeDir, subdir);
123
123
  if (!existsSync(baseDir))
124
124
  return [];
@@ -204,14 +204,14 @@ function getAgentTech(agent) {
204
204
  };
205
205
  return map[agent] ?? 'specialized';
206
206
  }
207
- function defaultAgentsForMode(mode) {
207
+ export function defaultAgentsForMode(mode) {
208
208
  if (mode === 'startup')
209
209
  return ['orchestrator', 'backend-engineer', 'frontend-engineer'];
210
210
  if (mode === 'enterprise')
211
211
  return ['orchestrator', 'backend-engineer', 'frontend-engineer', 'test-engineer', 'docs-writer', 'compliance-reviewer', 'security-auditor'];
212
212
  return ['orchestrator', 'backend-engineer', 'frontend-engineer', 'test-engineer', 'docs-writer'];
213
213
  }
214
- function installCoreAgents(forgeRoot, destDir, activeAgents, profiles, force) {
214
+ export function installCoreAgents(forgeRoot, destDir, activeAgents, profiles, force) {
215
215
  mkdirSync(destDir, { recursive: true });
216
216
  // Tier 2: profile agents first
217
217
  for (const profile of profiles) {
@@ -232,7 +232,7 @@ function installCoreAgents(forgeRoot, destDir, activeAgents, profiles, force) {
232
232
  }
233
233
  }
234
234
  }
235
- function installHooks(forgeRoot, destDir, mode, force) {
235
+ export function installHooks(forgeRoot, destDir, mode, force) {
236
236
  mkdirSync(destDir, { recursive: true });
237
237
  const hooksDir = join(forgeRoot, 'core', 'hooks');
238
238
  if (!existsSync(hooksDir))
@@ -318,7 +318,7 @@ function mergeSettings(generated, existing) {
318
318
  * existe o no se puede parsear, escribe los settings generados tal cual.
319
319
  * Respeta `force`: con `force=false` no toca un archivo existente.
320
320
  */
321
- function writeSettingsJson(path, language, mode, force) {
321
+ export function writeSettingsJson(path, language, mode, force) {
322
322
  const generated = buildSettings(language, mode);
323
323
  if (existsSync(path)) {
324
324
  if (!force)
@@ -338,13 +338,51 @@ function writeSettingsJson(path, language, mode, force) {
338
338
  }
339
339
  writeFileSync(path, JSON.stringify(generated, null, 2), 'utf-8');
340
340
  }
341
- function installCommands(forgeRoot, destDir, force) {
341
+ export function installCommands(forgeRoot, destDir, force) {
342
342
  mkdirSync(destDir, { recursive: true });
343
343
  const commandsDir = join(forgeRoot, 'adapters', 'claude-code', 'commands');
344
344
  if (!existsSync(commandsDir))
345
345
  return;
346
346
  copyDir(commandsDir, destDir, force);
347
347
  }
348
+ /**
349
+ * Scaffolds docs/specs/ (+ _template.md), docs/daily-notes/ and the
350
+ * .claude/architecture.rules file. Idempotent: never overwrites the spec
351
+ * template or architecture.rules once they exist. Shared by `forge init` and
352
+ * `forge adopt` so both lay down the same SDD scaffold.
353
+ */
354
+ export function installSpecScaffold(forgeRoot, projectRoot, claudeDir, config) {
355
+ mkdirSync(join(projectRoot, 'docs', 'specs'), { recursive: true });
356
+ mkdirSync(join(projectRoot, 'docs', 'daily-notes'), { recursive: true });
357
+ const specTemplateSrc = join(forgeRoot, 'core', 'templates', 'spec-template.md');
358
+ if (existsSync(specTemplateSrc)) {
359
+ copyFile(specTemplateSrc, join(projectRoot, 'docs', 'specs', '_template.md'), false);
360
+ }
361
+ const archRulesTemplate = join(forgeRoot, 'core', 'templates', 'claude-md', 'architecture.rules');
362
+ const archRulesDest = join(claudeDir, 'architecture.rules');
363
+ if (existsSync(archRulesTemplate) && !existsSync(archRulesDest)) {
364
+ const content = readFileSync(archRulesTemplate, 'utf-8').replace('<NOMBRE_PROYECTO>', config.project.name ?? 'Mi Proyecto');
365
+ writeFileSync(archRulesDest, content, 'utf-8');
366
+ }
367
+ }
368
+ /**
369
+ * Builds and saves the .forge/manifest.json for a claude-code install: tracks
370
+ * CLAUDE.md, settings.json, architecture.rules, all agents (active + compliance
371
+ * + specialized) and the installed hooks/commands. Shared by init and adopt.
372
+ */
373
+ export function saveInstallManifest(projectRoot, claudeDir, runtime, allAgents, specializedAgents, forgeVersion) {
374
+ const installedFiles = [
375
+ 'CLAUDE.md', '.claude/settings.json', '.claude/architecture.rules',
376
+ ...allAgents.map(a => `.claude/agents/${a}.md`),
377
+ ...specializedAgents.map(a => `.claude/agents/${a}.md`),
378
+ ...listInstalledRelativeFiles(claudeDir, 'hooks', projectRoot),
379
+ ...listInstalledRelativeFiles(claudeDir, 'commands', projectRoot),
380
+ ];
381
+ const seen = new Set();
382
+ const uniqueFiles = installedFiles.filter(f => (seen.has(f) ? false : seen.add(f)));
383
+ const ts = new Date().toISOString();
384
+ saveManifest(projectRoot, buildManifest(runtime, uniqueFiles, projectRoot, forgeVersion, ts));
385
+ }
348
386
  function installKiro(forgeRoot, projectRoot, config, force) {
349
387
  const kiroDir = join(projectRoot, '.kiro', 'steering');
350
388
  const hooksDir = join(projectRoot, '.kiro', 'hooks');
@@ -503,20 +541,7 @@ export async function init(args) {
503
541
  {
504
542
  title: 'docs/specs/ + architecture.rules',
505
543
  tech: 'scaffold',
506
- task: () => {
507
- mkdirSync(join(projectRoot, 'docs', 'specs'), { recursive: true });
508
- mkdirSync(join(projectRoot, 'docs', 'daily-notes'), { recursive: true });
509
- const specTemplateSrc = join(forgeRoot, 'core', 'templates', 'spec-template.md');
510
- if (existsSync(specTemplateSrc)) {
511
- copyFile(specTemplateSrc, join(projectRoot, 'docs', 'specs', '_template.md'), false);
512
- }
513
- const archRulesTemplate = join(forgeRoot, 'core', 'templates', 'claude-md', 'architecture.rules');
514
- const archRulesDest = join(claudeDir, 'architecture.rules');
515
- if (existsSync(archRulesTemplate) && !existsSync(archRulesDest)) {
516
- const content = readFileSync(archRulesTemplate, 'utf-8').replace('<NOMBRE_PROYECTO>', config.project.name ?? 'Mi Proyecto');
517
- writeFileSync(archRulesDest, content, 'utf-8');
518
- }
519
- },
544
+ task: () => installSpecScaffold(forgeRoot, projectRoot, claudeDir, config),
520
545
  },
521
546
  // Knowledge base — only for projects that activate a wiki-* skill. Other
522
547
  // projects don't get a wiki/ dir forced on them.
@@ -528,24 +553,7 @@ export async function init(args) {
528
553
  {
529
554
  title: '.forge/manifest.json',
530
555
  tech: 'sha256 tracking',
531
- task: () => {
532
- const specializedAgents = config.agents?.specialized ?? [];
533
- const installedFiles = [
534
- 'CLAUDE.md', '.claude/settings.json', '.claude/architecture.rules',
535
- // Tier 1 (active) + compliance agents.
536
- ...allAgents.map(a => `.claude/agents/${a}.md`),
537
- // Tier 3 (specialized) agents — must not be dropped from the manifest.
538
- ...specializedAgents.map(a => `.claude/agents/${a}.md`),
539
- // Installed guardrail hooks and slash commands (if present on disk).
540
- ...listInstalledRelativeFiles(claudeDir, 'hooks', projectRoot),
541
- ...listInstalledRelativeFiles(claudeDir, 'commands', projectRoot),
542
- ];
543
- // De-dup while preserving order (an agent could appear in both lists).
544
- const seen = new Set();
545
- const uniqueFiles = installedFiles.filter(f => (seen.has(f) ? false : seen.add(f)));
546
- const ts = new Date().toISOString();
547
- saveManifest(projectRoot, buildManifest(runtime, uniqueFiles, projectRoot, VERSION, ts));
548
- },
556
+ task: () => saveInstallManifest(projectRoot, claudeDir, runtime, allAgents, config.agents?.specialized ?? [], VERSION),
549
557
  },
550
558
  ]);
551
559
  }