@contentrain/mcp 1.0.7 → 1.1.1
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 +13 -2
- package/dist/{apply-manager-BDtHM8z-.mjs → apply-manager-Cf5OWOJ7.mjs} +7 -7
- package/dist/{apply-manager-BDtHM8z-.mjs.map → apply-manager-Cf5OWOJ7.mjs.map} +1 -1
- package/dist/{branch-lifecycle-DB6sgeJi.mjs → branch-lifecycle-wGJg25LT.mjs} +31 -12
- package/dist/branch-lifecycle-wGJg25LT.mjs.map +1 -0
- package/dist/{config-CPlhDwsv.mjs → config-B5kc2oeV.mjs} +2 -2
- package/dist/{config-CPlhDwsv.mjs.map → config-B5kc2oeV.mjs.map} +1 -1
- package/dist/{context-CUFulSi2.mjs → context-DIDt_TxX.mjs} +4 -4
- package/dist/{context-CUFulSi2.mjs.map → context-DIDt_TxX.mjs.map} +1 -1
- package/dist/core/apply-manager.mjs +10 -5
- package/dist/core/config.mjs +3 -1
- package/dist/core/content-manager.d.mts +1 -9
- package/dist/core/content-manager.d.mts.map +1 -1
- package/dist/core/content-manager.mjs +4 -1
- package/dist/core/context.mjs +6 -2
- package/dist/core/graph-builder.mjs +4 -1
- package/dist/core/meta-manager.mjs +3 -1
- package/dist/core/model-manager.mjs +4 -1
- package/dist/core/scan-config.mjs +3 -1
- package/dist/core/scanner.mjs +4 -1
- package/dist/core/validator.d.mts.map +1 -1
- package/dist/core/validator.mjs +6 -2
- package/dist/{detect-C8XmJ4S6.mjs → detect-DinOQAmK.mjs} +2 -2
- package/dist/{detect-C8XmJ4S6.mjs.map → detect-DinOQAmK.mjs.map} +1 -1
- package/dist/{fs-BbuGnVcG.mjs → fs-BnIQ4dKj.mjs} +2 -2
- package/dist/{fs-BbuGnVcG.mjs.map → fs-BnIQ4dKj.mjs.map} +1 -1
- package/dist/git/branch-lifecycle.d.mts.map +1 -1
- package/dist/git/branch-lifecycle.mjs +4 -1
- package/dist/git/transaction.d.mts +7 -3
- package/dist/git/transaction.d.mts.map +1 -1
- package/dist/git/transaction.mjs +9 -4
- package/dist/{graph-builder-fPrDDwnu.mjs → graph-builder-tM7zj-SX.mjs} +3 -3
- package/dist/{graph-builder-fPrDDwnu.mjs.map → graph-builder-tM7zj-SX.mjs.map} +1 -1
- package/dist/{id-BdD4HvMY.mjs → id-DV_T9Ic8.mjs} +3 -5
- package/dist/id-DV_T9Ic8.mjs.map +1 -0
- package/dist/index.mjs +16 -9
- package/dist/index.mjs.map +1 -1
- package/dist/{meta-manager-CECrfsKm.mjs → meta-manager--0IwAPCl.mjs} +2 -2
- package/dist/{meta-manager-CECrfsKm.mjs.map → meta-manager--0IwAPCl.mjs.map} +1 -1
- package/dist/{model-manager-kl78AAMg.mjs → model-manager-DW_fOGRM.mjs} +16 -186
- package/dist/model-manager-DW_fOGRM.mjs.map +1 -0
- package/dist/{scan-config-AJGxCdNd.mjs → scan-config-QgnJ1-52.mjs} +2 -2
- package/dist/{scan-config-AJGxCdNd.mjs.map → scan-config-QgnJ1-52.mjs.map} +1 -1
- package/dist/{scanner-BdTiv8sw.mjs → scanner-DPrbU-oK.mjs} +3 -3
- package/dist/{scanner-BdTiv8sw.mjs.map → scanner-DPrbU-oK.mjs.map} +1 -1
- package/dist/serializer-CnHTtmc1.mjs +2 -0
- package/dist/{server-QgivXkem.mjs → server-BXguCuJb.mjs} +62 -47
- package/dist/server-BXguCuJb.mjs.map +1 -0
- package/dist/server.mjs +16 -9
- package/dist/templates/index.mjs +1 -1
- package/dist/{templates-3HWi-PTu.mjs → templates-bRPzYq4M.mjs} +1 -1
- package/dist/{templates-3HWi-PTu.mjs.map → templates-bRPzYq4M.mjs.map} +1 -1
- package/dist/transaction-B0V0_SE2.mjs +288 -0
- package/dist/transaction-B0V0_SE2.mjs.map +1 -0
- package/dist/util/detect.mjs +3 -1
- package/dist/util/fs.mjs +2 -1
- package/dist/util/id.d.mts +2 -1
- package/dist/util/id.d.mts.map +1 -1
- package/dist/util/id.mjs +1 -1
- package/dist/util/serializer.d.mts +2 -14
- package/dist/util/serializer.mjs +2 -2
- package/dist/{validator-CyckZAVr.mjs → validator-SQYUV2JP.mjs} +23 -197
- package/dist/validator-SQYUV2JP.mjs.map +1 -0
- package/package.json +3 -3
- package/dist/branch-lifecycle-DB6sgeJi.mjs.map +0 -1
- package/dist/id-BdD4HvMY.mjs.map +0 -1
- package/dist/model-manager-kl78AAMg.mjs.map +0 -1
- package/dist/serializer-Dueih-i2.mjs +0 -33
- package/dist/serializer-Dueih-i2.mjs.map +0 -1
- package/dist/server-QgivXkem.mjs.map +0 -1
- package/dist/transaction-_AiXqGuD.mjs +0 -143
- package/dist/transaction-_AiXqGuD.mjs.map +0 -1
- package/dist/util/serializer.d.mts.map +0 -1
- package/dist/validator-CyckZAVr.mjs.map +0 -1
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../serializer-CnHTtmc1.mjs";
|
|
2
|
+
import "../fs-BnIQ4dKj.mjs";
|
|
3
|
+
import { a as classifyFile, i as autoDetectSourceDirs, n as SCAN_EXTENSIONS, o as discoverFiles, r as SCAN_IGNORE_DIRS, t as MAX_SCAN_FILES } from "../scan-config-QgnJ1-52.mjs";
|
|
2
4
|
export { MAX_SCAN_FILES, SCAN_EXTENSIONS, SCAN_IGNORE_DIRS, autoDetectSourceDirs, classifyFile, discoverFiles };
|
package/dist/core/scanner.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../serializer-CnHTtmc1.mjs";
|
|
2
|
+
import "../fs-BnIQ4dKj.mjs";
|
|
3
|
+
import "../scan-config-QgnJ1-52.mjs";
|
|
4
|
+
import { n as scanCandidates, r as scanSummary, t as isNonContent } from "../scanner-DPrbU-oK.mjs";
|
|
2
5
|
import "../tsx-parser-CYVyBWjn.mjs";
|
|
3
6
|
export { isNonContent, scanCandidates, scanSummary };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.mts","names":[],"sources":["../../src/core/validator.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"validator.d.mts","names":[],"sources":["../../src/core/validator.ts"],"mappings":";;;UAYiB,eAAA;EACf,KAAA;EACA,GAAA;AAAA;AAAA,UAGe,cAAA;EACf,KAAA;EACA,OAAA;IACE,MAAA;IACA,QAAA;IACA,OAAA;IACA,cAAA;IACA,eAAA;EAAA;EAEF,MAAA,EAAQ,eAAA;EACR,KAAA;AAAA;AAAA,iBAksBoB,eAAA,CACpB,WAAA,UACA,OAAA,GAAU,eAAA,GACT,OAAA,CAAQ,cAAA"}
|
package/dist/core/validator.mjs
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import
|
|
1
|
+
import "../serializer-CnHTtmc1.mjs";
|
|
2
|
+
import "../fs-BnIQ4dKj.mjs";
|
|
3
|
+
import "../config-B5kc2oeV.mjs";
|
|
4
|
+
import "../meta-manager--0IwAPCl.mjs";
|
|
5
|
+
import "../model-manager-DW_fOGRM.mjs";
|
|
6
|
+
import { t as validateProject } from "../validator-SQYUV2JP.mjs";
|
|
3
7
|
export { validateProject };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as readJson, r as pathExists } from "./fs-
|
|
1
|
+
import { a as readJson, r as pathExists } from "./fs-BnIQ4dKj.mjs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
//#region src/util/detect.ts
|
|
4
4
|
const STACK_META = {
|
|
@@ -359,4 +359,4 @@ async function collectAllDeps(projectRoot) {
|
|
|
359
359
|
//#endregion
|
|
360
360
|
export { detectStackInfo as n, inferPlatform as r, detectStack as t };
|
|
361
361
|
|
|
362
|
-
//# sourceMappingURL=detect-
|
|
362
|
+
//# sourceMappingURL=detect-DinOQAmK.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect-C8XmJ4S6.mjs","names":[],"sources":["../src/util/detect.ts"],"sourcesContent":["import type { StackType, Platform } from '@contentrain/types'\nimport { join, dirname } from 'node:path'\nimport { readJson, pathExists } from './fs.js'\n\ninterface PackageJson {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n workspaces?: string[] | { packages: string[] }\n}\n\nexport interface StackInfo {\n stack: StackType\n platform: Platform\n name: string\n description: string\n monorepo: boolean\n monorepoTool?: string\n features: string[]\n}\n\nconst STACK_META: Record<StackType, { name: string; description: string }> = {\n // Meta-frameworks\n nuxt: { name: 'Nuxt', description: 'Vue meta-framework with SSR/SSG' },\n next: { name: 'Next.js', description: 'React framework with SSR/SSG' },\n astro: { name: 'Astro', description: 'Content-first web framework' },\n sveltekit: { name: 'SvelteKit', description: 'Svelte meta-framework' },\n remix: { name: 'Remix', description: 'Full-stack React framework' },\n analog: { name: 'Analog', description: 'Angular meta-framework' },\n // Plain frameworks\n vue: { name: 'Vue', description: 'Progressive JavaScript framework' },\n react: { name: 'React', description: 'UI library for web and native' },\n svelte: { name: 'Svelte', description: 'Compile-time UI framework' },\n solid: { name: 'Solid', description: 'Reactive UI library' },\n angular: { name: 'Angular', description: 'Platform for web applications' },\n // Mobile\n 'react-native': { name: 'React Native', description: 'Cross-platform mobile framework' },\n expo: { name: 'Expo', description: 'React Native toolchain' },\n flutter: { name: 'Flutter', description: 'Cross-platform UI toolkit (Dart)' },\n // Backend\n node: { name: 'Node.js', description: 'Server-side JavaScript runtime' },\n express: { name: 'Express', description: 'Minimal Node.js web framework' },\n fastify: { name: 'Fastify', description: 'Fast Node.js web framework' },\n nestjs: { name: 'NestJS', description: 'Progressive Node.js framework' },\n django: { name: 'Django', description: 'Python web framework' },\n rails: { name: 'Rails', description: 'Ruby web framework' },\n laravel: { name: 'Laravel', description: 'PHP web framework' },\n go: { name: 'Go', description: 'Go programming language' },\n rust: { name: 'Rust', description: 'Rust programming language' },\n dotnet: { name: '.NET', description: 'Microsoft .NET platform' },\n // Static\n hugo: { name: 'Hugo', description: 'Go-based static site generator' },\n jekyll: { name: 'Jekyll', description: 'Ruby-based static site generator' },\n eleventy: { name: 'Eleventy', description: 'JavaScript static site generator' },\n // Desktop\n electron: { name: 'Electron', description: 'Cross-platform desktop apps' },\n tauri: { name: 'Tauri', description: 'Lightweight desktop apps (Rust)' },\n // Catch-all\n other: { name: 'Other', description: 'Unknown or unsupported framework' },\n}\n\nexport function inferPlatform(stack: StackType): Platform {\n switch (stack) {\n case 'nuxt': case 'next': case 'astro': case 'sveltekit': case 'remix': case 'analog':\n case 'vue': case 'react': case 'svelte': case 'solid': case 'angular':\n return 'web'\n case 'react-native': case 'expo': case 'flutter':\n return 'mobile'\n case 'node': case 'express': case 'fastify': case 'nestjs':\n case 'django': case 'rails': case 'laravel': case 'go': case 'rust': case 'dotnet':\n return 'api'\n case 'electron': case 'tauri':\n return 'desktop'\n case 'hugo': case 'jekyll': case 'eleventy':\n return 'static'\n default:\n return 'other'\n }\n}\n\n/** Backward-compatible: returns just the StackType string */\nexport async function detectStack(projectRoot: string): Promise<StackType> {\n const info = await detectStackInfo(projectRoot)\n return info.stack\n}\n\n/** Rich detection: stack + platform + monorepo + features */\nexport async function detectStackInfo(projectRoot: string): Promise<StackInfo> {\n let stack = await detectFromDeps(projectRoot)\n\n // Walk up for monorepo root if local didn't match\n if (stack === 'other') {\n let dir = dirname(projectRoot)\n for (let i = 0; i < 5; i++) {\n const pkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (pkg?.workspaces) {\n const rootStack = await detectFromDeps(dir)\n if (rootStack !== 'other') {\n stack = rootStack\n break\n }\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n }\n\n // Non-JS detection if still 'other'\n if (stack === 'other') {\n stack = await detectNonJs(projectRoot)\n }\n\n const mono = await detectMonorepo(projectRoot)\n const features = await detectFeatures(projectRoot)\n const meta = STACK_META[stack]\n\n return {\n stack,\n platform: inferPlatform(stack),\n name: meta.name,\n description: meta.description,\n monorepo: mono.isMonorepo,\n monorepoTool: mono.tool,\n features,\n }\n}\n\nasync function detectFromDeps(dir: string): Promise<StackType> {\n const pkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (!pkg) return 'other'\n\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }\n\n // Meta-frameworks (check BEFORE plain frameworks)\n if ('nuxt' in allDeps) return 'nuxt'\n if ('next' in allDeps) return 'next'\n if ('astro' in allDeps) return 'astro'\n if ('@sveltejs/kit' in allDeps) return 'sveltekit'\n if ('@remix-run/node' in allDeps || 'remix' in allDeps) return 'remix'\n if ('@analogjs/platform' in allDeps) return 'analog'\n\n // Mobile (check before plain react)\n if ('expo' in allDeps) return 'expo'\n if ('react-native' in allDeps) return 'react-native'\n\n // Plain frameworks\n if ('vue' in allDeps) return 'vue'\n if ('svelte' in allDeps) return 'svelte'\n if ('solid-js' in allDeps) return 'solid'\n if ('@angular/core' in allDeps) return 'angular'\n if ('react' in allDeps) return 'react'\n\n // Desktop\n if ('electron' in allDeps) return 'electron'\n if ('@tauri-apps/api' in allDeps) return 'tauri'\n\n // Backend (Node.js)\n if ('@nestjs/core' in allDeps) return 'nestjs'\n if ('fastify' in allDeps) return 'fastify'\n if ('express' in allDeps) return 'express'\n\n // Static site generators\n if ('@11ty/eleventy' in allDeps) return 'eleventy'\n\n // Generic Node.js (has package.json but no framework)\n if ('node' in (pkg.dependencies ?? {})) return 'node'\n\n return 'other'\n}\n\nasync function detectNonJs(projectRoot: string): Promise<StackType> {\n // Go\n if (await pathExists(join(projectRoot, 'go.mod'))) return 'go'\n\n // Rust\n if (await pathExists(join(projectRoot, 'Cargo.toml'))) return 'rust'\n\n // Python\n for (const f of ['requirements.txt', 'pyproject.toml', 'setup.py']) {\n if (await pathExists(join(projectRoot, f))) {\n // Check for Django\n try {\n const { readText } = await import('./fs.js')\n const content = await readText(join(projectRoot, f))\n if (content?.includes('django') || content?.includes('Django')) return 'django'\n } catch { /* ignore */ }\n return 'other' // Generic Python — no specific stack type yet\n }\n }\n\n // Ruby\n if (await pathExists(join(projectRoot, 'Gemfile'))) {\n try {\n const { readText } = await import('./fs.js')\n const content = await readText(join(projectRoot, 'Gemfile'))\n if (content?.includes('rails')) return 'rails'\n } catch { /* ignore */ }\n return 'other'\n }\n\n // .NET\n const dotnetFiles = ['*.csproj', '*.sln']\n for (const pattern of dotnetFiles) {\n if (pattern === '*.csproj' && await pathExists(join(projectRoot, 'Program.cs'))) return 'dotnet'\n if (pattern === '*.sln' && await pathExists(join(projectRoot, 'Program.cs'))) return 'dotnet'\n }\n\n // PHP / Laravel\n if (await pathExists(join(projectRoot, 'composer.json'))) {\n try {\n const composer = await readJson<Record<string, unknown>>(join(projectRoot, 'composer.json'))\n const require = composer?.require as Record<string, string> | undefined\n if (require?.['laravel/framework']) return 'laravel'\n } catch { /* ignore */ }\n return 'other'\n }\n\n // Flutter (Dart)\n if (await pathExists(join(projectRoot, 'pubspec.yaml'))) return 'flutter'\n\n // Hugo\n if (await pathExists(join(projectRoot, 'hugo.toml'))) return 'hugo'\n if (await pathExists(join(projectRoot, 'config.toml'))) {\n try {\n const { readText } = await import('./fs.js')\n const content = await readText(join(projectRoot, 'config.toml'))\n if (content?.includes('baseURL') || content?.includes('hugo')) return 'hugo'\n } catch { /* ignore */ }\n }\n\n // Jekyll\n if (await pathExists(join(projectRoot, '_config.yml'))) return 'jekyll'\n\n return 'other'\n}\n\nasync function detectMonorepo(projectRoot: string): Promise<{ isMonorepo: boolean; tool?: string }> {\n if (await pathExists(join(projectRoot, 'pnpm-workspace.yaml'))) return { isMonorepo: true, tool: 'pnpm workspaces' }\n if (await pathExists(join(projectRoot, 'lerna.json'))) return { isMonorepo: true, tool: 'Lerna' }\n if (await pathExists(join(projectRoot, 'nx.json'))) return { isMonorepo: true, tool: 'Nx' }\n if (await pathExists(join(projectRoot, 'turbo.json'))) return { isMonorepo: true, tool: 'Turborepo' }\n\n const pkg = await readJson<PackageJson>(join(projectRoot, 'package.json'))\n if (pkg?.workspaces) return { isMonorepo: true, tool: 'npm/yarn workspaces' }\n\n // Walk up\n let dir = dirname(projectRoot)\n for (let i = 0; i < 5; i++) {\n if (await pathExists(join(dir, 'pnpm-workspace.yaml'))) return { isMonorepo: true, tool: 'pnpm workspaces' }\n if (await pathExists(join(dir, 'lerna.json'))) return { isMonorepo: true, tool: 'Lerna' }\n if (await pathExists(join(dir, 'nx.json'))) return { isMonorepo: true, tool: 'Nx' }\n if (await pathExists(join(dir, 'turbo.json'))) return { isMonorepo: true, tool: 'Turborepo' }\n const parentPkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (parentPkg?.workspaces) return { isMonorepo: true, tool: 'npm/yarn workspaces' }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n\n return { isMonorepo: false }\n}\n\nasync function detectFeatures(projectRoot: string): Promise<string[]> {\n const features: string[] = []\n const allDeps = await collectAllDeps(projectRoot)\n\n if ('typescript' in allDeps || await pathExists(join(projectRoot, 'tsconfig.json'))) features.push('TypeScript')\n\n const i18nLibs = ['vue-i18n', '@nuxtjs/i18n', 'next-intl', 'react-intl', 'i18next', 'react-i18next']\n for (const lib of i18nLibs) {\n if (lib in allDeps) { features.push(`i18n (${lib})`); break }\n }\n\n if ('tailwindcss' in allDeps) features.push('Tailwind CSS')\n else if ('sass' in allDeps || 'scss' in allDeps) features.push('Sass/SCSS')\n\n if ('vitest' in allDeps) features.push('Vitest')\n else if ('jest' in allDeps) features.push('Jest')\n\n if ('pinia' in allDeps) features.push('Pinia')\n else if ('zustand' in allDeps) features.push('Zustand')\n else if ('@reduxjs/toolkit' in allDeps || 'redux' in allDeps) features.push('Redux')\n\n return features\n}\n\nasync function collectAllDeps(projectRoot: string): Promise<Record<string, string>> {\n const pkg = await readJson<PackageJson>(join(projectRoot, 'package.json'))\n const allDeps: Record<string, string> = { ...pkg?.dependencies, ...pkg?.devDependencies }\n\n let dir = dirname(projectRoot)\n for (let i = 0; i < 5; i++) {\n const parentPkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (parentPkg?.workspaces) {\n Object.assign(allDeps, parentPkg.dependencies, parentPkg.devDependencies)\n break\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n\n return allDeps\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"detect-DinOQAmK.mjs","names":[],"sources":["../src/util/detect.ts"],"sourcesContent":["import type { StackType, Platform } from '@contentrain/types'\nimport { join, dirname } from 'node:path'\nimport { readJson, pathExists } from './fs.js'\n\ninterface PackageJson {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n workspaces?: string[] | { packages: string[] }\n}\n\nexport interface StackInfo {\n stack: StackType\n platform: Platform\n name: string\n description: string\n monorepo: boolean\n monorepoTool?: string\n features: string[]\n}\n\nconst STACK_META: Record<StackType, { name: string; description: string }> = {\n // Meta-frameworks\n nuxt: { name: 'Nuxt', description: 'Vue meta-framework with SSR/SSG' },\n next: { name: 'Next.js', description: 'React framework with SSR/SSG' },\n astro: { name: 'Astro', description: 'Content-first web framework' },\n sveltekit: { name: 'SvelteKit', description: 'Svelte meta-framework' },\n remix: { name: 'Remix', description: 'Full-stack React framework' },\n analog: { name: 'Analog', description: 'Angular meta-framework' },\n // Plain frameworks\n vue: { name: 'Vue', description: 'Progressive JavaScript framework' },\n react: { name: 'React', description: 'UI library for web and native' },\n svelte: { name: 'Svelte', description: 'Compile-time UI framework' },\n solid: { name: 'Solid', description: 'Reactive UI library' },\n angular: { name: 'Angular', description: 'Platform for web applications' },\n // Mobile\n 'react-native': { name: 'React Native', description: 'Cross-platform mobile framework' },\n expo: { name: 'Expo', description: 'React Native toolchain' },\n flutter: { name: 'Flutter', description: 'Cross-platform UI toolkit (Dart)' },\n // Backend\n node: { name: 'Node.js', description: 'Server-side JavaScript runtime' },\n express: { name: 'Express', description: 'Minimal Node.js web framework' },\n fastify: { name: 'Fastify', description: 'Fast Node.js web framework' },\n nestjs: { name: 'NestJS', description: 'Progressive Node.js framework' },\n django: { name: 'Django', description: 'Python web framework' },\n rails: { name: 'Rails', description: 'Ruby web framework' },\n laravel: { name: 'Laravel', description: 'PHP web framework' },\n go: { name: 'Go', description: 'Go programming language' },\n rust: { name: 'Rust', description: 'Rust programming language' },\n dotnet: { name: '.NET', description: 'Microsoft .NET platform' },\n // Static\n hugo: { name: 'Hugo', description: 'Go-based static site generator' },\n jekyll: { name: 'Jekyll', description: 'Ruby-based static site generator' },\n eleventy: { name: 'Eleventy', description: 'JavaScript static site generator' },\n // Desktop\n electron: { name: 'Electron', description: 'Cross-platform desktop apps' },\n tauri: { name: 'Tauri', description: 'Lightweight desktop apps (Rust)' },\n // Catch-all\n other: { name: 'Other', description: 'Unknown or unsupported framework' },\n}\n\nexport function inferPlatform(stack: StackType): Platform {\n switch (stack) {\n case 'nuxt': case 'next': case 'astro': case 'sveltekit': case 'remix': case 'analog':\n case 'vue': case 'react': case 'svelte': case 'solid': case 'angular':\n return 'web'\n case 'react-native': case 'expo': case 'flutter':\n return 'mobile'\n case 'node': case 'express': case 'fastify': case 'nestjs':\n case 'django': case 'rails': case 'laravel': case 'go': case 'rust': case 'dotnet':\n return 'api'\n case 'electron': case 'tauri':\n return 'desktop'\n case 'hugo': case 'jekyll': case 'eleventy':\n return 'static'\n default:\n return 'other'\n }\n}\n\n/** Backward-compatible: returns just the StackType string */\nexport async function detectStack(projectRoot: string): Promise<StackType> {\n const info = await detectStackInfo(projectRoot)\n return info.stack\n}\n\n/** Rich detection: stack + platform + monorepo + features */\nexport async function detectStackInfo(projectRoot: string): Promise<StackInfo> {\n let stack = await detectFromDeps(projectRoot)\n\n // Walk up for monorepo root if local didn't match\n if (stack === 'other') {\n let dir = dirname(projectRoot)\n for (let i = 0; i < 5; i++) {\n const pkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (pkg?.workspaces) {\n const rootStack = await detectFromDeps(dir)\n if (rootStack !== 'other') {\n stack = rootStack\n break\n }\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n }\n\n // Non-JS detection if still 'other'\n if (stack === 'other') {\n stack = await detectNonJs(projectRoot)\n }\n\n const mono = await detectMonorepo(projectRoot)\n const features = await detectFeatures(projectRoot)\n const meta = STACK_META[stack]\n\n return {\n stack,\n platform: inferPlatform(stack),\n name: meta.name,\n description: meta.description,\n monorepo: mono.isMonorepo,\n monorepoTool: mono.tool,\n features,\n }\n}\n\nasync function detectFromDeps(dir: string): Promise<StackType> {\n const pkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (!pkg) return 'other'\n\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }\n\n // Meta-frameworks (check BEFORE plain frameworks)\n if ('nuxt' in allDeps) return 'nuxt'\n if ('next' in allDeps) return 'next'\n if ('astro' in allDeps) return 'astro'\n if ('@sveltejs/kit' in allDeps) return 'sveltekit'\n if ('@remix-run/node' in allDeps || 'remix' in allDeps) return 'remix'\n if ('@analogjs/platform' in allDeps) return 'analog'\n\n // Mobile (check before plain react)\n if ('expo' in allDeps) return 'expo'\n if ('react-native' in allDeps) return 'react-native'\n\n // Plain frameworks\n if ('vue' in allDeps) return 'vue'\n if ('svelte' in allDeps) return 'svelte'\n if ('solid-js' in allDeps) return 'solid'\n if ('@angular/core' in allDeps) return 'angular'\n if ('react' in allDeps) return 'react'\n\n // Desktop\n if ('electron' in allDeps) return 'electron'\n if ('@tauri-apps/api' in allDeps) return 'tauri'\n\n // Backend (Node.js)\n if ('@nestjs/core' in allDeps) return 'nestjs'\n if ('fastify' in allDeps) return 'fastify'\n if ('express' in allDeps) return 'express'\n\n // Static site generators\n if ('@11ty/eleventy' in allDeps) return 'eleventy'\n\n // Generic Node.js (has package.json but no framework)\n if ('node' in (pkg.dependencies ?? {})) return 'node'\n\n return 'other'\n}\n\nasync function detectNonJs(projectRoot: string): Promise<StackType> {\n // Go\n if (await pathExists(join(projectRoot, 'go.mod'))) return 'go'\n\n // Rust\n if (await pathExists(join(projectRoot, 'Cargo.toml'))) return 'rust'\n\n // Python\n for (const f of ['requirements.txt', 'pyproject.toml', 'setup.py']) {\n if (await pathExists(join(projectRoot, f))) {\n // Check for Django\n try {\n const { readText } = await import('./fs.js')\n const content = await readText(join(projectRoot, f))\n if (content?.includes('django') || content?.includes('Django')) return 'django'\n } catch { /* ignore */ }\n return 'other' // Generic Python — no specific stack type yet\n }\n }\n\n // Ruby\n if (await pathExists(join(projectRoot, 'Gemfile'))) {\n try {\n const { readText } = await import('./fs.js')\n const content = await readText(join(projectRoot, 'Gemfile'))\n if (content?.includes('rails')) return 'rails'\n } catch { /* ignore */ }\n return 'other'\n }\n\n // .NET\n const dotnetFiles = ['*.csproj', '*.sln']\n for (const pattern of dotnetFiles) {\n if (pattern === '*.csproj' && await pathExists(join(projectRoot, 'Program.cs'))) return 'dotnet'\n if (pattern === '*.sln' && await pathExists(join(projectRoot, 'Program.cs'))) return 'dotnet'\n }\n\n // PHP / Laravel\n if (await pathExists(join(projectRoot, 'composer.json'))) {\n try {\n const composer = await readJson<Record<string, unknown>>(join(projectRoot, 'composer.json'))\n const require = composer?.require as Record<string, string> | undefined\n if (require?.['laravel/framework']) return 'laravel'\n } catch { /* ignore */ }\n return 'other'\n }\n\n // Flutter (Dart)\n if (await pathExists(join(projectRoot, 'pubspec.yaml'))) return 'flutter'\n\n // Hugo\n if (await pathExists(join(projectRoot, 'hugo.toml'))) return 'hugo'\n if (await pathExists(join(projectRoot, 'config.toml'))) {\n try {\n const { readText } = await import('./fs.js')\n const content = await readText(join(projectRoot, 'config.toml'))\n if (content?.includes('baseURL') || content?.includes('hugo')) return 'hugo'\n } catch { /* ignore */ }\n }\n\n // Jekyll\n if (await pathExists(join(projectRoot, '_config.yml'))) return 'jekyll'\n\n return 'other'\n}\n\nasync function detectMonorepo(projectRoot: string): Promise<{ isMonorepo: boolean; tool?: string }> {\n if (await pathExists(join(projectRoot, 'pnpm-workspace.yaml'))) return { isMonorepo: true, tool: 'pnpm workspaces' }\n if (await pathExists(join(projectRoot, 'lerna.json'))) return { isMonorepo: true, tool: 'Lerna' }\n if (await pathExists(join(projectRoot, 'nx.json'))) return { isMonorepo: true, tool: 'Nx' }\n if (await pathExists(join(projectRoot, 'turbo.json'))) return { isMonorepo: true, tool: 'Turborepo' }\n\n const pkg = await readJson<PackageJson>(join(projectRoot, 'package.json'))\n if (pkg?.workspaces) return { isMonorepo: true, tool: 'npm/yarn workspaces' }\n\n // Walk up\n let dir = dirname(projectRoot)\n for (let i = 0; i < 5; i++) {\n if (await pathExists(join(dir, 'pnpm-workspace.yaml'))) return { isMonorepo: true, tool: 'pnpm workspaces' }\n if (await pathExists(join(dir, 'lerna.json'))) return { isMonorepo: true, tool: 'Lerna' }\n if (await pathExists(join(dir, 'nx.json'))) return { isMonorepo: true, tool: 'Nx' }\n if (await pathExists(join(dir, 'turbo.json'))) return { isMonorepo: true, tool: 'Turborepo' }\n const parentPkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (parentPkg?.workspaces) return { isMonorepo: true, tool: 'npm/yarn workspaces' }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n\n return { isMonorepo: false }\n}\n\nasync function detectFeatures(projectRoot: string): Promise<string[]> {\n const features: string[] = []\n const allDeps = await collectAllDeps(projectRoot)\n\n if ('typescript' in allDeps || await pathExists(join(projectRoot, 'tsconfig.json'))) features.push('TypeScript')\n\n const i18nLibs = ['vue-i18n', '@nuxtjs/i18n', 'next-intl', 'react-intl', 'i18next', 'react-i18next']\n for (const lib of i18nLibs) {\n if (lib in allDeps) { features.push(`i18n (${lib})`); break }\n }\n\n if ('tailwindcss' in allDeps) features.push('Tailwind CSS')\n else if ('sass' in allDeps || 'scss' in allDeps) features.push('Sass/SCSS')\n\n if ('vitest' in allDeps) features.push('Vitest')\n else if ('jest' in allDeps) features.push('Jest')\n\n if ('pinia' in allDeps) features.push('Pinia')\n else if ('zustand' in allDeps) features.push('Zustand')\n else if ('@reduxjs/toolkit' in allDeps || 'redux' in allDeps) features.push('Redux')\n\n return features\n}\n\nasync function collectAllDeps(projectRoot: string): Promise<Record<string, string>> {\n const pkg = await readJson<PackageJson>(join(projectRoot, 'package.json'))\n const allDeps: Record<string, string> = { ...pkg?.dependencies, ...pkg?.devDependencies }\n\n let dir = dirname(projectRoot)\n for (let i = 0; i < 5; i++) {\n const parentPkg = await readJson<PackageJson>(join(dir, 'package.json'))\n if (parentPkg?.workspaces) {\n Object.assign(allDeps, parentPkg.dependencies, parentPkg.devDependencies)\n break\n }\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n\n return allDeps\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as canonicalStringify } from "./serializer-
|
|
1
|
+
import { t as canonicalStringify } from "./serializer-CnHTtmc1.mjs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { access, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
4
4
|
//#region src/util/fs.ts
|
|
@@ -49,4 +49,4 @@ function contentrainDir(projectRoot) {
|
|
|
49
49
|
//#endregion
|
|
50
50
|
export { readJson as a, writeText as c, readDir as i, ensureDir as n, readText as o, pathExists as r, writeJson as s, contentrainDir as t };
|
|
51
51
|
|
|
52
|
-
//# sourceMappingURL=fs-
|
|
52
|
+
//# sourceMappingURL=fs-BnIQ4dKj.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs-
|
|
1
|
+
{"version":3,"file":"fs-BnIQ4dKj.mjs","names":[],"sources":["../src/util/fs.ts"],"sourcesContent":["import { readFile, readdir, access, writeFile, mkdir } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { canonicalStringify } from './serializer.js'\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\nexport async function readJson<T>(filePath: string): Promise<T | null> {\n try {\n const raw = await readFile(filePath, 'utf-8')\n return JSON.parse(raw) as T\n } catch {\n return null\n }\n}\n\nexport async function readDir(dirPath: string): Promise<string[]> {\n try {\n return await readdir(dirPath)\n } catch {\n return []\n }\n}\n\nexport async function writeJson(filePath: string, data: unknown, fieldOrder?: string[]): Promise<void> {\n await mkdir(join(filePath, '..'), { recursive: true })\n await writeFile(filePath, canonicalStringify(data, fieldOrder), 'utf-8')\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await mkdir(dirPath, { recursive: true })\n}\n\nexport async function readText(filePath: string): Promise<string | null> {\n try {\n return await readFile(filePath, 'utf-8')\n } catch {\n return null\n }\n}\n\nexport async function writeText(filePath: string, content: string): Promise<void> {\n await mkdir(join(filePath, '..'), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\nexport function contentrainDir(projectRoot: string): string {\n return join(projectRoot, '.contentrain')\n}\n"],"mappings":";;;;AAIA,eAAsB,WAAW,UAAoC;AACnE,KAAI;AACF,QAAM,OAAO,SAAS;AACtB,SAAO;SACD;AACN,SAAO;;;AAIX,eAAsB,SAAY,UAAqC;AACrE,KAAI;EACF,MAAM,MAAM,MAAM,SAAS,UAAU,QAAQ;AAC7C,SAAO,KAAK,MAAM,IAAI;SAChB;AACN,SAAO;;;AAIX,eAAsB,QAAQ,SAAoC;AAChE,KAAI;AACF,SAAO,MAAM,QAAQ,QAAQ;SACvB;AACN,SAAO,EAAE;;;AAIb,eAAsB,UAAU,UAAkB,MAAe,YAAsC;AACrG,OAAM,MAAM,KAAK,UAAU,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AACtD,OAAM,UAAU,UAAU,mBAAmB,MAAM,WAAW,EAAE,QAAQ;;AAG1E,eAAsB,UAAU,SAAgC;AAC9D,OAAM,MAAM,SAAS,EAAE,WAAW,MAAM,CAAC;;AAG3C,eAAsB,SAAS,UAA0C;AACvE,KAAI;AACF,SAAO,MAAM,SAAS,UAAU,QAAQ;SAClC;AACN,SAAO;;;AAIX,eAAsB,UAAU,UAAkB,SAAgC;AAChF,OAAM,MAAM,KAAK,UAAU,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AACtD,OAAM,UAAU,UAAU,SAAS,QAAQ;;AAG7C,SAAgB,eAAe,aAA6B;AAC1D,QAAO,KAAK,aAAa,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-lifecycle.d.mts","names":[],"sources":["../../src/git/branch-lifecycle.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"branch-lifecycle.d.mts","names":[],"sources":["../../src/git/branch-lifecycle.ts"],"mappings":";UAIiB,aAAA;EACf,OAAA;EACA,SAAA;EACA,eAAA;AAAA;AAAA,UAGe,iBAAA;EACf,KAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA;EACA,OAAA;EACA,OAAA;AAAA;;;;;iBAOoB,qBAAA,CAAsB,WAAA,WAAsB,OAAA,CAAQ,aAAA;;;;;AAA1E;iBAqEsB,iBAAA,CAAkB,WAAA,WAAsB,OAAA,CAAQ,iBAAA"}
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../serializer-CnHTtmc1.mjs";
|
|
2
|
+
import "../fs-BnIQ4dKj.mjs";
|
|
3
|
+
import "../config-B5kc2oeV.mjs";
|
|
4
|
+
import { n as cleanupMergedBranches, t as checkBranchHealth } from "../branch-lifecycle-wGJg25LT.mjs";
|
|
2
5
|
export { checkBranchHealth, cleanupMergedBranches };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SyncResult } from "@contentrain/types";
|
|
2
|
+
|
|
1
3
|
//#region src/git/transaction.d.ts
|
|
2
4
|
interface ContextUpdate {
|
|
3
5
|
tool: string;
|
|
@@ -9,18 +11,20 @@ interface GitTransaction {
|
|
|
9
11
|
worktree: string;
|
|
10
12
|
branch: string;
|
|
11
13
|
write(callback: (worktreePath: string) => Promise<void>): Promise<void>;
|
|
12
|
-
commit(message: string): Promise<string>;
|
|
13
|
-
complete(
|
|
14
|
+
commit(message: string, contextUpdate?: ContextUpdate): Promise<string>;
|
|
15
|
+
complete(): Promise<{
|
|
14
16
|
action: 'auto-merged' | 'pending-review';
|
|
15
17
|
commit: string;
|
|
18
|
+
sync?: SyncResult;
|
|
16
19
|
warning?: string;
|
|
17
20
|
}>;
|
|
18
21
|
cleanup(): Promise<void>;
|
|
19
22
|
}
|
|
23
|
+
declare function ensureContentBranch(projectRoot: string): Promise<void>;
|
|
20
24
|
declare function createTransaction(projectRoot: string, branchName: string, options?: {
|
|
21
25
|
workflowOverride?: 'review' | 'auto-merge';
|
|
22
26
|
}): Promise<GitTransaction>;
|
|
23
27
|
declare function buildBranchName(scope: string, target: string, locale?: string): string;
|
|
24
28
|
//#endregion
|
|
25
|
-
export { ContextUpdate, GitTransaction, buildBranchName, createTransaction };
|
|
29
|
+
export { ContextUpdate, GitTransaction, buildBranchName, createTransaction, ensureContentBranch };
|
|
26
30
|
//# sourceMappingURL=transaction.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.mts","names":[],"sources":["../../src/git/transaction.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"transaction.d.mts","names":[],"sources":["../../src/git/transaction.ts"],"mappings":";;;UAWiB,aAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;EACA,OAAA;AAAA;AAAA,UAGe,cAAA;EACf,QAAA;EACA,MAAA;EACA,KAAA,CAAM,QAAA,GAAW,YAAA,aAAyB,OAAA,SAAgB,OAAA;EAC1D,MAAA,CAAO,OAAA,UAAiB,aAAA,GAAgB,aAAA,GAAgB,OAAA;EACxD,QAAA,IAAY,OAAA;IAAU,MAAA;IAA0C,MAAA;IAAgB,IAAA,GAAO,UAAA;IAAY,OAAA;EAAA;EACnG,OAAA,IAAW,OAAA;AAAA;AAAA,iBAGS,mBAAA,CAAoB,WAAA,WAAsB,OAAA;AAAA,iBA2I1C,iBAAA,CACpB,WAAA,UACA,UAAA,UACA,OAAA;EAAY,gBAAA;AAAA,IACX,OAAA,CAAQ,cAAA;AAAA,iBA0NK,eAAA,CAAgB,KAAA,UAAe,MAAA,UAAgB,MAAA"}
|
package/dist/git/transaction.mjs
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../
|
|
3
|
-
import
|
|
4
|
-
|
|
1
|
+
import "../serializer-CnHTtmc1.mjs";
|
|
2
|
+
import "../fs-BnIQ4dKj.mjs";
|
|
3
|
+
import "../config-B5kc2oeV.mjs";
|
|
4
|
+
import "../meta-manager--0IwAPCl.mjs";
|
|
5
|
+
import "../model-manager-DW_fOGRM.mjs";
|
|
6
|
+
import "../context-DIDt_TxX.mjs";
|
|
7
|
+
import "../id-DV_T9Ic8.mjs";
|
|
8
|
+
import { n as createTransaction, r as ensureContentBranch, t as buildBranchName } from "../transaction-B0V0_SE2.mjs";
|
|
9
|
+
export { buildBranchName, createTransaction, ensureContentBranch };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { o as readText, r as pathExists } from "./fs-
|
|
2
|
-
import { a as classifyFile, i as autoDetectSourceDirs, n as SCAN_EXTENSIONS, o as discoverFiles } from "./scan-config-
|
|
1
|
+
import { o as readText, r as pathExists } from "./fs-BnIQ4dKj.mjs";
|
|
2
|
+
import { a as classifyFile, i as autoDetectSourceDirs, n as SCAN_EXTENSIONS, o as discoverFiles } from "./scan-config-QgnJ1-52.mjs";
|
|
3
3
|
import { dirname, extname, join, relative } from "node:path";
|
|
4
4
|
//#region src/core/graph-builder.ts
|
|
5
5
|
const MAX_ORPHANS = 10;
|
|
@@ -159,4 +159,4 @@ async function buildGraph(projectRoot, options) {
|
|
|
159
159
|
//#endregion
|
|
160
160
|
export { buildGraph as t };
|
|
161
161
|
|
|
162
|
-
//# sourceMappingURL=graph-builder-
|
|
162
|
+
//# sourceMappingURL=graph-builder-tM7zj-SX.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-builder-fPrDDwnu.mjs","names":[],"sources":["../src/core/graph-builder.ts"],"sourcesContent":["import type { FileCategory, GraphNode, ProjectGraph } from '@contentrain/types'\nimport { join, relative, dirname, extname } from 'node:path'\nimport { readText, pathExists } from '../util/fs.js'\nimport {\n SCAN_EXTENSIONS,\n classifyFile,\n autoDetectSourceDirs,\n discoverFiles,\n} from './scan-config.js'\n\nexport interface BuildGraphOptions {\n paths?: string[]\n include?: string[]\n exclude?: string[]\n}\n\nconst MAX_ORPHANS = 10\n\n// ---------------------------------------------------------------------------\n// Import extraction\n// ---------------------------------------------------------------------------\n\nconst IMPORT_RE = /(?:import|export)\\s+.*?from\\s+['\"]([^'\"]+)['\"]|(?:import|require)\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g\n\nfunction extractImportPaths(content: string): string[] {\n const paths: string[] = []\n let m: RegExpExecArray | null\n // Reset lastIndex before use since we reuse the regex\n IMPORT_RE.lastIndex = 0\n while ((m = IMPORT_RE.exec(content)) !== null) {\n const p = m[1] ?? m[2]\n if (p && isLocalImport(p)) {\n paths.push(p)\n }\n }\n return paths\n}\n\nfunction isLocalImport(p: string): boolean {\n return p.startsWith('.') || p.startsWith('/')\n}\n\n// ---------------------------------------------------------------------------\n// Component name extraction from imports\n// ---------------------------------------------------------------------------\n\nconst NAMED_IMPORT_RE = /import\\s+(?:type\\s+)?(?:(\\w+)(?:\\s*,\\s*)?)?(?:\\{([^}]*)\\})?\\s+from\\s+['\"][^'\"]+['\"]/g\nconst DEFAULT_IMPORT_RE = /import\\s+(?:type\\s+)?(\\w+)\\s+from\\s+['\"][^'\"]+['\"]/g\n\nfunction isPascalCase(name: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(name)\n}\n\nfunction extractComponentNames(content: string): string[] {\n const names = new Set<string>()\n\n // Default imports: `import Button from '...'`\n DEFAULT_IMPORT_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = DEFAULT_IMPORT_RE.exec(content)) !== null) {\n const name = m[1]\n if (name && isPascalCase(name)) {\n names.add(name)\n }\n }\n\n // Named imports: `import { Button, useHook } from '...'`\n NAMED_IMPORT_RE.lastIndex = 0\n while ((m = NAMED_IMPORT_RE.exec(content)) !== null) {\n // Default part before destructuring\n const defaultName = m[1]\n if (defaultName && isPascalCase(defaultName)) {\n names.add(defaultName)\n }\n // Destructured names\n const namedPart = m[2]\n if (namedPart) {\n for (const segment of namedPart.split(',')) {\n // Handle `Foo as Bar` — take the local name (Bar)\n const parts = segment.trim().split(/\\s+as\\s+/)\n const localName = (parts[1] ?? parts[0])?.trim()\n if (localName && isPascalCase(localName)) {\n names.add(localName)\n }\n }\n }\n }\n\n return [...names]\n}\n\n// ---------------------------------------------------------------------------\n// String counting (estimate)\n// ---------------------------------------------------------------------------\n\nconst STRING_SINGLE_RE = /'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'/g\nconst STRING_DOUBLE_RE = /\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"/g\nconst STRING_TEMPLATE_RE = /`[^`\\\\]*(?:\\\\.[^`\\\\]*)*`/g\n\nfunction countStrings(content: string): number {\n // Strip import/export/require lines first so their string literals don't count\n const stripped = content.replace(/^(?:import|export)\\s+.*$/gm, '')\n .replace(/\\brequire\\s*\\([^)]*\\)/g, '')\n\n const singles = stripped.match(STRING_SINGLE_RE)?.length ?? 0\n const doubles = stripped.match(STRING_DOUBLE_RE)?.length ?? 0\n const templates = stripped.match(STRING_TEMPLATE_RE)?.length ?? 0\n\n return singles + doubles + templates\n}\n\n// ---------------------------------------------------------------------------\n// Import path resolution\n// ---------------------------------------------------------------------------\n\nconst RESOLVE_EXTENSIONS = [...SCAN_EXTENSIONS]\nconst RESOLVE_INDEX_FILES = ['index.ts', 'index.tsx', 'index.js']\n\nasync function resolveImportPath(\n importPath: string,\n importerDir: string,\n projectRoot: string,\n): Promise<string | null> {\n const base = importPath.startsWith('/')\n ? join(projectRoot, importPath)\n : join(importerDir, importPath)\n\n // If it already has an extension, check directly\n if (extname(base)) {\n if (await pathExists(base)) {\n return base\n }\n return null\n }\n\n // Try adding extensions\n for (const ext of RESOLVE_EXTENSIONS) {\n const candidate = base + ext\n if (await pathExists(candidate)) {\n return candidate\n }\n }\n\n // Try index files inside directory\n for (const idx of RESOLVE_INDEX_FILES) {\n const candidate = join(base, idx)\n if (await pathExists(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\ninterface FileInfo {\n relPath: string\n imports: string[]\n components: string[]\n strings: number\n category: FileCategory\n}\n\nexport async function buildGraph(\n projectRoot: string,\n options?: BuildGraphOptions,\n): Promise<ProjectGraph> {\n const scanDirs = options?.paths ?? await autoDetectSourceDirs(projectRoot)\n\n // ---- File discovery (shared with scanner) ----\n const filePaths = await discoverFiles(projectRoot, {\n paths: scanDirs,\n include: options?.include,\n exclude: options?.exclude,\n })\n\n // ---- Pass 1: Parse each file ----\n const fileMap = new Map<string, FileInfo>()\n\n const parsePromises = filePaths.map(async (relPath) => {\n const absPath = join(projectRoot, relPath)\n const content = await readText(absPath)\n if (content === null) return\n\n const imports = extractImportPaths(content)\n const components = extractComponentNames(content)\n const strings = countStrings(content)\n const category = classifyFile(relPath)\n\n fileMap.set(relPath, { relPath, imports, components, strings, category })\n })\n\n await Promise.all(parsePromises)\n\n // ---- Pass 2: Resolve imports and build reverse lookup ----\n const usedByMap = new Map<string, Set<string>>()\n\n // Initialize usedBy sets\n for (const relPath of fileMap.keys()) {\n usedByMap.set(relPath, new Set())\n }\n\n const resolvePromises: Promise<void>[] = []\n\n for (const [relPath, info] of fileMap) {\n const importerAbsDir = dirname(join(projectRoot, relPath))\n\n for (const rawImport of info.imports) {\n resolvePromises.push(\n resolveImportPath(rawImport, importerAbsDir, projectRoot).then((resolved) => {\n if (!resolved) return\n const resolvedRel = relative(projectRoot, resolved)\n const targetSet = usedByMap.get(resolvedRel)\n if (targetSet) {\n targetSet.add(relPath)\n }\n }),\n )\n }\n }\n\n await Promise.all(resolvePromises)\n\n // ---- Build nodes ----\n const pages: GraphNode[] = []\n const components: GraphNode[] = []\n const layouts: GraphNode[] = []\n const orphanCandidates: string[] = []\n\n let totalStrings = 0\n\n for (const [relPath, info] of fileMap) {\n const usedBy = [...(usedByMap.get(relPath) ?? [])].toSorted((a, b) => a.localeCompare(b))\n totalStrings += info.strings\n\n // Filter out nodes with 0 strings — not relevant for content extraction\n if (info.strings === 0 && info.category !== 'other') continue\n\n const node: GraphNode = {\n file: relPath,\n category: info.category,\n imports: info.imports,\n used_by: usedBy,\n strings: info.strings,\n }\n\n // Only attach components list for pages\n if (info.category === 'page' && info.components.length > 0) {\n node.components = info.components\n }\n\n switch (info.category) {\n case 'page':\n pages.push(node)\n break\n case 'component':\n components.push(node)\n break\n case 'layout':\n layouts.push(node)\n break\n default:\n // Orphan = \"other\" category with no inbound references and no outbound imports\n if (usedBy.length === 0 && info.imports.length === 0) {\n orphanCandidates.push(relPath)\n }\n break\n }\n }\n\n return {\n pages: pages.toSorted((a, b) => a.file.localeCompare(b.file)),\n components: components.toSorted((a, b) => a.file.localeCompare(b.file)),\n layouts: layouts.toSorted((a, b) => a.file.localeCompare(b.file)),\n orphan_files: orphanCandidates.toSorted((a, b) => a.localeCompare(b)).slice(0, MAX_ORPHANS),\n stats: {\n total_files: fileMap.size,\n total_components: components.length,\n total_pages: pages.length,\n total_strings_estimate: totalStrings,\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graph-builder-tM7zj-SX.mjs","names":[],"sources":["../src/core/graph-builder.ts"],"sourcesContent":["import type { FileCategory, GraphNode, ProjectGraph } from '@contentrain/types'\nimport { join, relative, dirname, extname } from 'node:path'\nimport { readText, pathExists } from '../util/fs.js'\nimport {\n SCAN_EXTENSIONS,\n classifyFile,\n autoDetectSourceDirs,\n discoverFiles,\n} from './scan-config.js'\n\nexport interface BuildGraphOptions {\n paths?: string[]\n include?: string[]\n exclude?: string[]\n}\n\nconst MAX_ORPHANS = 10\n\n// ---------------------------------------------------------------------------\n// Import extraction\n// ---------------------------------------------------------------------------\n\nconst IMPORT_RE = /(?:import|export)\\s+.*?from\\s+['\"]([^'\"]+)['\"]|(?:import|require)\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g\n\nfunction extractImportPaths(content: string): string[] {\n const paths: string[] = []\n let m: RegExpExecArray | null\n // Reset lastIndex before use since we reuse the regex\n IMPORT_RE.lastIndex = 0\n while ((m = IMPORT_RE.exec(content)) !== null) {\n const p = m[1] ?? m[2]\n if (p && isLocalImport(p)) {\n paths.push(p)\n }\n }\n return paths\n}\n\nfunction isLocalImport(p: string): boolean {\n return p.startsWith('.') || p.startsWith('/')\n}\n\n// ---------------------------------------------------------------------------\n// Component name extraction from imports\n// ---------------------------------------------------------------------------\n\nconst NAMED_IMPORT_RE = /import\\s+(?:type\\s+)?(?:(\\w+)(?:\\s*,\\s*)?)?(?:\\{([^}]*)\\})?\\s+from\\s+['\"][^'\"]+['\"]/g\nconst DEFAULT_IMPORT_RE = /import\\s+(?:type\\s+)?(\\w+)\\s+from\\s+['\"][^'\"]+['\"]/g\n\nfunction isPascalCase(name: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(name)\n}\n\nfunction extractComponentNames(content: string): string[] {\n const names = new Set<string>()\n\n // Default imports: `import Button from '...'`\n DEFAULT_IMPORT_RE.lastIndex = 0\n let m: RegExpExecArray | null\n while ((m = DEFAULT_IMPORT_RE.exec(content)) !== null) {\n const name = m[1]\n if (name && isPascalCase(name)) {\n names.add(name)\n }\n }\n\n // Named imports: `import { Button, useHook } from '...'`\n NAMED_IMPORT_RE.lastIndex = 0\n while ((m = NAMED_IMPORT_RE.exec(content)) !== null) {\n // Default part before destructuring\n const defaultName = m[1]\n if (defaultName && isPascalCase(defaultName)) {\n names.add(defaultName)\n }\n // Destructured names\n const namedPart = m[2]\n if (namedPart) {\n for (const segment of namedPart.split(',')) {\n // Handle `Foo as Bar` — take the local name (Bar)\n const parts = segment.trim().split(/\\s+as\\s+/)\n const localName = (parts[1] ?? parts[0])?.trim()\n if (localName && isPascalCase(localName)) {\n names.add(localName)\n }\n }\n }\n }\n\n return [...names]\n}\n\n// ---------------------------------------------------------------------------\n// String counting (estimate)\n// ---------------------------------------------------------------------------\n\nconst STRING_SINGLE_RE = /'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'/g\nconst STRING_DOUBLE_RE = /\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"/g\nconst STRING_TEMPLATE_RE = /`[^`\\\\]*(?:\\\\.[^`\\\\]*)*`/g\n\nfunction countStrings(content: string): number {\n // Strip import/export/require lines first so their string literals don't count\n const stripped = content.replace(/^(?:import|export)\\s+.*$/gm, '')\n .replace(/\\brequire\\s*\\([^)]*\\)/g, '')\n\n const singles = stripped.match(STRING_SINGLE_RE)?.length ?? 0\n const doubles = stripped.match(STRING_DOUBLE_RE)?.length ?? 0\n const templates = stripped.match(STRING_TEMPLATE_RE)?.length ?? 0\n\n return singles + doubles + templates\n}\n\n// ---------------------------------------------------------------------------\n// Import path resolution\n// ---------------------------------------------------------------------------\n\nconst RESOLVE_EXTENSIONS = [...SCAN_EXTENSIONS]\nconst RESOLVE_INDEX_FILES = ['index.ts', 'index.tsx', 'index.js']\n\nasync function resolveImportPath(\n importPath: string,\n importerDir: string,\n projectRoot: string,\n): Promise<string | null> {\n const base = importPath.startsWith('/')\n ? join(projectRoot, importPath)\n : join(importerDir, importPath)\n\n // If it already has an extension, check directly\n if (extname(base)) {\n if (await pathExists(base)) {\n return base\n }\n return null\n }\n\n // Try adding extensions\n for (const ext of RESOLVE_EXTENSIONS) {\n const candidate = base + ext\n if (await pathExists(candidate)) {\n return candidate\n }\n }\n\n // Try index files inside directory\n for (const idx of RESOLVE_INDEX_FILES) {\n const candidate = join(base, idx)\n if (await pathExists(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\ninterface FileInfo {\n relPath: string\n imports: string[]\n components: string[]\n strings: number\n category: FileCategory\n}\n\nexport async function buildGraph(\n projectRoot: string,\n options?: BuildGraphOptions,\n): Promise<ProjectGraph> {\n const scanDirs = options?.paths ?? await autoDetectSourceDirs(projectRoot)\n\n // ---- File discovery (shared with scanner) ----\n const filePaths = await discoverFiles(projectRoot, {\n paths: scanDirs,\n include: options?.include,\n exclude: options?.exclude,\n })\n\n // ---- Pass 1: Parse each file ----\n const fileMap = new Map<string, FileInfo>()\n\n const parsePromises = filePaths.map(async (relPath) => {\n const absPath = join(projectRoot, relPath)\n const content = await readText(absPath)\n if (content === null) return\n\n const imports = extractImportPaths(content)\n const components = extractComponentNames(content)\n const strings = countStrings(content)\n const category = classifyFile(relPath)\n\n fileMap.set(relPath, { relPath, imports, components, strings, category })\n })\n\n await Promise.all(parsePromises)\n\n // ---- Pass 2: Resolve imports and build reverse lookup ----\n const usedByMap = new Map<string, Set<string>>()\n\n // Initialize usedBy sets\n for (const relPath of fileMap.keys()) {\n usedByMap.set(relPath, new Set())\n }\n\n const resolvePromises: Promise<void>[] = []\n\n for (const [relPath, info] of fileMap) {\n const importerAbsDir = dirname(join(projectRoot, relPath))\n\n for (const rawImport of info.imports) {\n resolvePromises.push(\n resolveImportPath(rawImport, importerAbsDir, projectRoot).then((resolved) => {\n if (!resolved) return\n const resolvedRel = relative(projectRoot, resolved)\n const targetSet = usedByMap.get(resolvedRel)\n if (targetSet) {\n targetSet.add(relPath)\n }\n }),\n )\n }\n }\n\n await Promise.all(resolvePromises)\n\n // ---- Build nodes ----\n const pages: GraphNode[] = []\n const components: GraphNode[] = []\n const layouts: GraphNode[] = []\n const orphanCandidates: string[] = []\n\n let totalStrings = 0\n\n for (const [relPath, info] of fileMap) {\n const usedBy = [...(usedByMap.get(relPath) ?? [])].toSorted((a, b) => a.localeCompare(b))\n totalStrings += info.strings\n\n // Filter out nodes with 0 strings — not relevant for content extraction\n if (info.strings === 0 && info.category !== 'other') continue\n\n const node: GraphNode = {\n file: relPath,\n category: info.category,\n imports: info.imports,\n used_by: usedBy,\n strings: info.strings,\n }\n\n // Only attach components list for pages\n if (info.category === 'page' && info.components.length > 0) {\n node.components = info.components\n }\n\n switch (info.category) {\n case 'page':\n pages.push(node)\n break\n case 'component':\n components.push(node)\n break\n case 'layout':\n layouts.push(node)\n break\n default:\n // Orphan = \"other\" category with no inbound references and no outbound imports\n if (usedBy.length === 0 && info.imports.length === 0) {\n orphanCandidates.push(relPath)\n }\n break\n }\n }\n\n return {\n pages: pages.toSorted((a, b) => a.file.localeCompare(b.file)),\n components: components.toSorted((a, b) => a.file.localeCompare(b.file)),\n layouts: layouts.toSorted((a, b) => a.file.localeCompare(b.file)),\n orphan_files: orphanCandidates.toSorted((a, b) => a.localeCompare(b)).slice(0, MAX_ORPHANS),\n stats: {\n total_files: fileMap.size,\n total_components: components.length,\n total_pages: pages.length,\n total_strings_estimate: totalStrings,\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
+
import { generateEntryId as generateEntryId$1 } from "@contentrain/types";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
//#region src/util/id.ts
|
|
3
4
|
function branchTimestamp() {
|
|
4
5
|
return `${Math.floor(Date.now() / 1e3).toString()}-${randomUUID().slice(0, 4)}`;
|
|
5
6
|
}
|
|
6
|
-
function generateEntryId() {
|
|
7
|
-
return randomUUID().replace(/-/g, "").slice(0, 12);
|
|
8
|
-
}
|
|
9
7
|
//#endregion
|
|
10
|
-
export { generateEntryId as n, branchTimestamp as t };
|
|
8
|
+
export { generateEntryId$1 as n, branchTimestamp as t };
|
|
11
9
|
|
|
12
|
-
//# sourceMappingURL=id-
|
|
10
|
+
//# sourceMappingURL=id-DV_T9Ic8.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id-DV_T9Ic8.mjs","names":[],"sources":["../src/util/id.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\n\nexport function branchTimestamp(): string {\n const ts = Math.floor(Date.now() / 1000).toString()\n const suffix = randomUUID().slice(0, 4)\n return `${ts}-${suffix}`\n}\n\n// generateEntryId is now exported from @contentrain/types\nexport { generateEntryId } from '@contentrain/types'\n"],"mappings":";;;AAEA,SAAgB,kBAA0B;AAGxC,QAAO,GAFI,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,CAAC,UAAU,CAEtC,GADE,YAAY,CAAC,MAAM,GAAG,EAAE"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./
|
|
3
|
-
import "./
|
|
4
|
-
import "./
|
|
5
|
-
import
|
|
6
|
-
import "./
|
|
7
|
-
import "./
|
|
8
|
-
import "./
|
|
9
|
-
import "./
|
|
2
|
+
import "./serializer-CnHTtmc1.mjs";
|
|
3
|
+
import "./fs-BnIQ4dKj.mjs";
|
|
4
|
+
import "./config-B5kc2oeV.mjs";
|
|
5
|
+
import "./meta-manager--0IwAPCl.mjs";
|
|
6
|
+
import "./model-manager-DW_fOGRM.mjs";
|
|
7
|
+
import "./context-DIDt_TxX.mjs";
|
|
8
|
+
import "./detect-DinOQAmK.mjs";
|
|
9
|
+
import "./branch-lifecycle-wGJg25LT.mjs";
|
|
10
|
+
import { t as createServer } from "./server-BXguCuJb.mjs";
|
|
11
|
+
import "./id-DV_T9Ic8.mjs";
|
|
12
|
+
import "./transaction-B0V0_SE2.mjs";
|
|
13
|
+
import "./validator-SQYUV2JP.mjs";
|
|
14
|
+
import "./scan-config-QgnJ1-52.mjs";
|
|
15
|
+
import "./graph-builder-tM7zj-SX.mjs";
|
|
16
|
+
import "./scanner-DPrbU-oK.mjs";
|
|
10
17
|
import "./tsx-parser-CYVyBWjn.mjs";
|
|
11
|
-
import "./apply-manager-
|
|
18
|
+
import "./apply-manager-Cf5OWOJ7.mjs";
|
|
12
19
|
import { resolve } from "node:path";
|
|
13
20
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
14
21
|
//#region src/index.ts
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { resolve } from 'node:path'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { createServer } from './server.js'\n\nconst projectRoot = resolve(process.env['CONTENTRAIN_PROJECT_ROOT'] ?? process.cwd())\nconst server = createServer(projectRoot)\nconst transport = new StdioServerTransport()\n\nawait server.connect(transport)\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { resolve } from 'node:path'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { createServer } from './server.js'\n\nconst projectRoot = resolve(process.env['CONTENTRAIN_PROJECT_ROOT'] ?? process.cwd())\nconst server = createServer(projectRoot)\nconst transport = new StdioServerTransport()\n\nawait server.connect(transport)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAMA,MAAM,SAAS,aADK,QAAQ,QAAQ,IAAI,+BAA+B,QAAQ,KAAK,CAAC,CAC7C;AACxC,MAAM,YAAY,IAAI,sBAAsB;AAE5C,MAAM,OAAO,QAAQ,UAAU"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as readJson, s as writeJson, t as contentrainDir } from "./fs-
|
|
1
|
+
import { a as readJson, s as writeJson, t as contentrainDir } from "./fs-BnIQ4dKj.mjs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { rm } from "node:fs/promises";
|
|
4
4
|
//#region src/core/meta-manager.ts
|
|
@@ -50,4 +50,4 @@ async function deleteMeta(projectRoot, model, opts) {
|
|
|
50
50
|
//#endregion
|
|
51
51
|
export { readMeta as n, writeMeta as r, deleteMeta as t };
|
|
52
52
|
|
|
53
|
-
//# sourceMappingURL=meta-manager
|
|
53
|
+
//# sourceMappingURL=meta-manager--0IwAPCl.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-manager
|
|
1
|
+
{"version":3,"file":"meta-manager--0IwAPCl.mjs","names":[],"sources":["../src/core/meta-manager.ts"],"sourcesContent":["import type { ModelDefinition, EntryMeta } from '@contentrain/types'\nimport { join } from 'node:path'\nimport { rm } from 'node:fs/promises'\nimport { contentrainDir, readJson, writeJson } from '../util/fs.js'\n\ninterface MetaOpts {\n locale?: string\n entryId?: string\n slug?: string\n}\n\nfunction metaPath(projectRoot: string, model: ModelDefinition, opts: MetaOpts): string {\n const base = join(contentrainDir(projectRoot), 'meta', model.id)\n\n if (model.kind === 'document' && opts.slug) {\n return join(base, opts.slug, `${opts.locale ?? 'en'}.json`)\n }\n\n return join(base, `${opts.locale ?? 'en'}.json`)\n}\n\nexport async function readMeta(\n projectRoot: string,\n model: ModelDefinition,\n opts: MetaOpts,\n): Promise<EntryMeta | Record<string, EntryMeta> | null> {\n return readJson(metaPath(projectRoot, model, opts))\n}\n\nexport async function writeMeta(\n projectRoot: string,\n model: ModelDefinition,\n opts: MetaOpts,\n meta: EntryMeta,\n): Promise<void> {\n const filePath = metaPath(projectRoot, model, opts)\n\n if (model.kind === 'collection' && opts.entryId) {\n const existing = await readJson<Record<string, EntryMeta>>(filePath) ?? {}\n existing[opts.entryId] = meta\n await writeJson(filePath, existing)\n } else {\n await writeJson(filePath, meta)\n }\n}\n\nexport async function deleteMeta(\n projectRoot: string,\n model: ModelDefinition,\n opts: MetaOpts,\n): Promise<void> {\n if (model.kind === 'collection' && opts.entryId) {\n const filePath = metaPath(projectRoot, model, opts)\n const existing = await readJson<Record<string, EntryMeta>>(filePath)\n if (existing && opts.entryId in existing) {\n delete existing[opts.entryId]\n if (Object.keys(existing).length > 0) {\n await writeJson(filePath, existing)\n } else {\n await rm(filePath, { force: true })\n }\n }\n } else if (model.kind === 'document' && opts.slug) {\n const slugDir = join(contentrainDir(projectRoot), 'meta', model.id, opts.slug)\n if (opts.locale) {\n await rm(join(slugDir, `${opts.locale}.json`), { force: true })\n } else {\n try {\n await rm(slugDir, { recursive: true, force: true })\n } catch {\n // directory may not exist\n }\n }\n } else if (opts.locale) {\n const filePath = metaPath(projectRoot, model, opts)\n await rm(filePath, { force: true })\n } else {\n // No locale specified — remove all meta for this model (non-i18n or full cleanup)\n const metaDir = join(contentrainDir(projectRoot), 'meta', model.id)\n try {\n await rm(metaDir, { recursive: true, force: true })\n } catch {\n // directory may not exist\n }\n }\n}\n"],"mappings":";;;;AAWA,SAAS,SAAS,aAAqB,OAAwB,MAAwB;CACrF,MAAM,OAAO,KAAK,eAAe,YAAY,EAAE,QAAQ,MAAM,GAAG;AAEhE,KAAI,MAAM,SAAS,cAAc,KAAK,KACpC,QAAO,KAAK,MAAM,KAAK,MAAM,GAAG,KAAK,UAAU,KAAK,OAAO;AAG7D,QAAO,KAAK,MAAM,GAAG,KAAK,UAAU,KAAK,OAAO;;AAGlD,eAAsB,SACpB,aACA,OACA,MACuD;AACvD,QAAO,SAAS,SAAS,aAAa,OAAO,KAAK,CAAC;;AAGrD,eAAsB,UACpB,aACA,OACA,MACA,MACe;CACf,MAAM,WAAW,SAAS,aAAa,OAAO,KAAK;AAEnD,KAAI,MAAM,SAAS,gBAAgB,KAAK,SAAS;EAC/C,MAAM,WAAW,MAAM,SAAoC,SAAS,IAAI,EAAE;AAC1E,WAAS,KAAK,WAAW;AACzB,QAAM,UAAU,UAAU,SAAS;OAEnC,OAAM,UAAU,UAAU,KAAK;;AAInC,eAAsB,WACpB,aACA,OACA,MACe;AACf,KAAI,MAAM,SAAS,gBAAgB,KAAK,SAAS;EAC/C,MAAM,WAAW,SAAS,aAAa,OAAO,KAAK;EACnD,MAAM,WAAW,MAAM,SAAoC,SAAS;AACpE,MAAI,YAAY,KAAK,WAAW,UAAU;AACxC,UAAO,SAAS,KAAK;AACrB,OAAI,OAAO,KAAK,SAAS,CAAC,SAAS,EACjC,OAAM,UAAU,UAAU,SAAS;OAEnC,OAAM,GAAG,UAAU,EAAE,OAAO,MAAM,CAAC;;YAG9B,MAAM,SAAS,cAAc,KAAK,MAAM;EACjD,MAAM,UAAU,KAAK,eAAe,YAAY,EAAE,QAAQ,MAAM,IAAI,KAAK,KAAK;AAC9E,MAAI,KAAK,OACP,OAAM,GAAG,KAAK,SAAS,GAAG,KAAK,OAAO,OAAO,EAAE,EAAE,OAAO,MAAM,CAAC;MAE/D,KAAI;AACF,SAAM,GAAG,SAAS;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;UAC7C;YAID,KAAK,OAEd,OAAM,GADW,SAAS,aAAa,OAAO,KAAK,EAChC,EAAE,OAAO,MAAM,CAAC;MAC9B;EAEL,MAAM,UAAU,KAAK,eAAe,YAAY,EAAE,QAAQ,MAAM,GAAG;AACnE,MAAI;AACF,SAAM,GAAG,SAAS;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;UAC7C"}
|