From d4c5797a652789aca5f075d14337d6cfa767d1c6 Mon Sep 17 00:00:00 2001 From: "jason.woltje" Date: Fri, 3 Apr 2026 02:34:43 +0000 Subject: [PATCH] fix: installer copies default framework files (AGENTS.md) to mosaicHome (#363) --- packages/cli/package.json | 2 +- packages/mosaic/package.json | 2 +- packages/mosaic/src/config/file-adapter.ts | 19 ++++++++++++++++++- packages/mosaic/src/index.ts | 12 ++++++++++-- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 15bd207..f7e45e2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@mosaic/cli", - "version": "0.0.8", + "version": "0.0.9", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/mosaic/package.json b/packages/mosaic/package.json index fb6724d..b09d1f5 100644 --- a/packages/mosaic/package.json +++ b/packages/mosaic/package.json @@ -1,6 +1,6 @@ { "name": "@mosaic/mosaic", - "version": "0.0.8", + "version": "0.0.9", "description": "Mosaic agent framework — installation wizard and meta package", "type": "module", "main": "dist/index.js", diff --git a/packages/mosaic/src/config/file-adapter.ts b/packages/mosaic/src/config/file-adapter.ts index 46d8364..f10cf40 100644 --- a/packages/mosaic/src/config/file-adapter.ts +++ b/packages/mosaic/src/config/file-adapter.ts @@ -1,4 +1,4 @@ -import { readFileSync, existsSync } from 'node:fs'; +import { readFileSync, existsSync, readdirSync, statSync, copyFileSync } from 'node:fs'; import { join } from 'node:path'; import type { ConfigService } from './config-service.js'; import type { SoulConfig, UserConfig, ToolsConfig, InstallAction } from '../types.js'; @@ -140,6 +140,23 @@ export class FileConfigAdapter implements ConfigService { preserve: preservePaths, excludeGit: true, }); + + // Copy default root-level .md files (AGENTS.md, STANDARDS.md, etc.) + // from framework/defaults/ into mosaicHome root if they don't exist yet. + // These are framework contracts — only written on first install, never + // overwritten (user may have customized them). + const defaultsDir = join(this.sourceDir, 'defaults'); + if (existsSync(defaultsDir)) { + for (const entry of readdirSync(defaultsDir)) { + const dest = join(this.mosaicHome, entry); + if (!existsSync(dest)) { + const src = join(defaultsDir, entry); + if (statSync(src).isFile()) { + copyFileSync(src, dest); + } + } + } + } } /** diff --git a/packages/mosaic/src/index.ts b/packages/mosaic/src/index.ts index f228583..3e284f2 100644 --- a/packages/mosaic/src/index.ts +++ b/packages/mosaic/src/index.ts @@ -1,5 +1,6 @@ #!/usr/bin/env node -import { resolve } from 'node:path'; +import { existsSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { Command } from 'commander'; @@ -49,7 +50,14 @@ program .action(async (opts: Record) => { try { const mosaicHome = (opts['mosaicHome'] as string) ?? DEFAULT_MOSAIC_HOME; - const sourceDir = (opts['sourceDir'] as string | undefined) ?? mosaicHome; + // Default source to the framework/ dir bundled in this npm package. + // This ensures syncFramework copies AGENTS.md, STANDARDS.md, guides/, etc. + // Falls back to mosaicHome if the bundled dir doesn't exist (shouldn't happen). + const pkgRoot = dirname(fileURLToPath(import.meta.url)); + const bundledFramework = resolve(pkgRoot, '..', 'framework'); + const sourceDir = + (opts['sourceDir'] as string | undefined) ?? + (existsSync(bundledFramework) ? bundledFramework : mosaicHome); const prompter = opts['nonInteractive'] ? new HeadlessPrompter() : new ClackPrompter();