@launch77/plugin-runtime 0.3.2 → 0.3.3
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/dist/index.d.ts +734 -143
- package/dist/index.js +1631 -283
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/generator.ts","../src/standard-generator.ts","../src/utils/file-operations.ts","../src/utils/metadata.ts","../src/context/index.ts","../src/context/location-parser.ts","../src/context/manifest.ts","../src/utils/name-validation.ts","../src/utils/validate-plugin-consistency.ts"],"sourcesContent":["import type { GeneratorContext } from './types.js'\n\n/**\n * Base abstract class for all plugin generators.\n *\n * The only requirement for a generator is to implement the run() method.\n * This method is called by the CLI when a plugin is installed.\n *\n * Use this base class when you need full control over the installation process.\n * For convention-based installation, extend StandardGenerator instead.\n */\nexport abstract class Generator {\n constructor(protected context: GeneratorContext) {}\n\n /**\n * Main entry point for plugin installation.\n * This method is called by the CLI and must be implemented by all generators.\n */\n abstract run(): Promise<void>\n}\n","import * as path from 'path'\nimport * as fs from 'fs/promises'\n\nimport chalk from 'chalk'\nimport { execa } from 'execa'\n\nimport { Generator } from './generator.js'\nimport { copyRecursive, pathExists } from './utils/file-operations.js'\nimport { readPluginMetadata } from './utils/metadata.js'\nimport type { PluginMetadata } from './types.js'\n\n/**\n * Standard generator with convention-over-configuration approach.\n *\n * Provides a structured lifecycle with smart defaults:\n * 1. updateDependencies() - Reads plugin.json, merges into package.json\n * 2. installDependencies() - Runs npm install\n * 3. copyTemplates() - Copies templates/ folder to app\n * 4. injectCode() - Override this for surgical code edits\n *\n * Most plugins only need to implement injectCode().\n * For full control, extend Generator instead.\n */\nexport abstract class StandardGenerator extends Generator {\n async run(): Promise<void> {\n console.log(chalk.green(`\\n✅ Installing plugin...\\n`))\n\n await this.updateDependencies()\n await this.installDependencies()\n await this.copyTemplates()\n await this.injectCode()\n\n console.log(chalk.green(`\\n✅ Plugin installed successfully!\\n`))\n this.showNextSteps()\n }\n\n protected async updateDependencies(): Promise<void> {\n const pluginJsonPath = path.join(this.context.pluginPath, 'plugin.json')\n\n if (!(await pathExists(pluginJsonPath))) return\n\n try {\n const pluginMetadata: PluginMetadata = await readPluginMetadata(this.context.pluginPath)\n\n if (!pluginMetadata.libraryDependencies || Object.keys(pluginMetadata.libraryDependencies).length === 0) {\n return\n }\n\n const packageJsonPath = path.join(this.context.appPath, 'package.json')\n const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8')\n const packageJson = JSON.parse(packageJsonContent)\n\n packageJson.dependencies = {\n ...packageJson.dependencies,\n ...pluginMetadata.libraryDependencies,\n }\n\n await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\\n', 'utf-8')\n console.log(chalk.green(' ✓ Updated package.json with dependencies'))\n } catch (error) {\n console.log(chalk.yellow(` ⚠️ Could not update dependencies: ${error}`))\n }\n }\n\n protected async installDependencies(): Promise<void> {\n try {\n console.log(chalk.cyan(' Installing dependencies...'))\n const workspaceRoot = path.dirname(path.dirname(this.context.appPath))\n\n await execa('npm', ['install'], {\n cwd: workspaceRoot,\n stdio: 'pipe',\n })\n\n console.log(chalk.green(' ✓ Dependencies installed'))\n } catch (error) {\n console.log(chalk.yellow(` ⚠️ Could not install dependencies: ${error}`))\n }\n }\n\n protected async copyTemplates(): Promise<void> {\n const templatesDir = path.join(this.context.pluginPath, 'templates')\n\n if (!(await pathExists(templatesDir))) return\n\n try {\n await copyRecursive(templatesDir, this.context.appPath)\n console.log(chalk.green(' ✓ Copied template files'))\n } catch (error) {\n console.log(chalk.yellow(` ⚠️ Could not copy template files: ${error}`))\n }\n }\n\n protected async injectCode(): Promise<void> {\n // No-op by default - plugins override this for custom code injection\n }\n\n protected showNextSteps(): void {\n // No-op by default - plugins can override to show custom next steps\n }\n}\n","import * as fs from 'fs/promises'\nimport * as path from 'path'\n\nexport async function copyRecursive(src: string, dest: string): Promise<void> {\n const stat = await fs.stat(src)\n\n if (stat.isDirectory()) {\n await fs.mkdir(dest, { recursive: true })\n const entries = await fs.readdir(src)\n\n for (const entry of entries) {\n await copyRecursive(path.join(src, entry), path.join(dest, entry))\n }\n } else {\n await fs.copyFile(src, dest)\n }\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath)\n return true\n } catch {\n return false\n }\n}\n","import * as fs from 'fs/promises'\nimport * as path from 'path'\n\nimport type { PluginMetadata, TemplateMetadata } from '../types.js'\n\n/**\n * Read and parse plugin metadata from plugin.json\n *\n * Only reads plugin-specific configuration fields:\n * - targets: where the plugin can be installed\n * - pluginDependencies: other plugins this plugin requires\n * - libraryDependencies: npm packages to inject into target\n *\n * Name and version are read from package.json during resolution.\n *\n * @param pluginPath - Absolute path to the plugin directory\n * @returns Parsed plugin metadata\n */\nexport async function readPluginMetadata(pluginPath: string): Promise<PluginMetadata> {\n const metadataPath = path.join(pluginPath, 'plugin.json')\n const content = await fs.readFile(metadataPath, 'utf-8')\n const parsed = JSON.parse(content)\n\n // Extract only plugin-specific fields, ignoring name/version/description\n return {\n targets: parsed.targets || [],\n pluginDependencies: parsed.pluginDependencies,\n libraryDependencies: parsed.libraryDependencies,\n }\n}\n\n/**\n * Read and parse template metadata from template.json\n *\n * Currently template.json contains no fields - it exists as a placeholder\n * for future template-specific configuration (e.g., deployment metadata).\n *\n * Template name and version are read from package.json during resolution.\n *\n * @param templatePath - Absolute path to the template directory\n * @returns Template metadata (currently empty)\n */\nexport async function readTemplateMetadata(templatePath: string): Promise<TemplateMetadata> {\n const templateJsonPath = path.join(templatePath, 'template.json')\n try {\n const content = await fs.readFile(templateJsonPath, 'utf-8')\n return JSON.parse(content) as TemplateMetadata\n } catch {\n // File doesn't exist or can't be read - return empty metadata\n return {}\n }\n}\n","import * as path from 'path'\n\nimport { parseLocationFromPath } from './location-parser.js'\nimport { findWorkspaceRoot, readWorkspaceManifest } from './manifest.js'\n\nimport type { Launch77Context } from './types.js'\n\n/**\n * Detect the Launch77 workspace context from the current working directory\n *\n * @param cwd - Current working directory path\n * @returns Context information about the workspace location\n */\nexport async function detectLaunch77Context(cwd: string): Promise<Launch77Context> {\n const resolvedCwd = path.resolve(cwd)\n\n // Find the workspace root\n const workspaceRoot = await findWorkspaceRoot(resolvedCwd)\n\n if (!workspaceRoot) {\n return {\n isValid: false,\n locationType: 'unknown',\n workspaceRoot: '',\n appsDir: '',\n workspaceVersion: '',\n workspaceName: '',\n packageName: '',\n }\n }\n\n // Read workspace manifest\n let manifest\n try {\n manifest = await readWorkspaceManifest(workspaceRoot)\n } catch (error) {\n // Manifest exists (we found it) but couldn't read it\n return {\n isValid: false,\n locationType: 'unknown',\n workspaceRoot: '',\n appsDir: '',\n workspaceVersion: '',\n workspaceName: '',\n packageName: '',\n }\n }\n\n // Parse the directory structure to determine location\n const parsed = parseLocationFromPath(resolvedCwd, workspaceRoot)\n\n // Workspace name is the directory name\n const workspaceName = path.basename(workspaceRoot)\n\n // Apps directory is always {workspaceRoot}/apps\n const appsDir = path.join(workspaceRoot, 'apps')\n\n // Package name: @{workspaceName}/{appName} (if in app)\n const packageName = parsed.appName ? `@${workspaceName}/${parsed.appName}` : ''\n\n return {\n isValid: true,\n locationType: parsed.locationType,\n workspaceRoot,\n appsDir,\n workspaceVersion: manifest.version,\n workspaceName,\n appName: parsed.appName,\n packageName,\n }\n}\n\n// Re-export types for convenience\nexport type { Launch77Context, Launch77LocationType, WorkspaceManifest, ParsedLocation } from './types.js'\n","import * as path from 'path'\n\nimport type { ParsedLocation } from './types.js'\n\n/**\n * Parse the directory structure to determine location context\n *\n * Based on patterns:\n * - apps/[name] → workspace-app\n * - libraries/[name] → workspace-library\n * - plugins/[name] → workspace-plugin\n * - app-templates/[name] → workspace-app-template\n * - (empty or root) → workspace-root\n *\n * @param cwdPath - Current working directory path\n * @param workspaceRoot - Root path of the workspace\n * @returns Parsed location information\n */\nexport function parseLocationFromPath(cwdPath: string, workspaceRoot: string): ParsedLocation {\n const relativePath = path.relative(workspaceRoot, cwdPath)\n\n // At workspace root\n if (!relativePath || relativePath === '.') {\n return { locationType: 'workspace-root' }\n }\n\n const parts = relativePath.split(path.sep)\n\n // apps/[app-name]/...\n if (parts[0] === 'apps' && parts.length >= 2) {\n return {\n locationType: 'workspace-app',\n appName: parts[1],\n }\n }\n\n // libraries/[lib-name]/...\n if (parts[0] === 'libraries' && parts.length >= 2) {\n return {\n locationType: 'workspace-library',\n appName: parts[1],\n }\n }\n\n // plugins/[plugin-name]/...\n if (parts[0] === 'plugins' && parts.length >= 2) {\n return {\n locationType: 'workspace-plugin',\n appName: parts[1],\n }\n }\n\n // app-templates/[template-name]/...\n if (parts[0] === 'app-templates' && parts.length >= 2) {\n return {\n locationType: 'workspace-app-template',\n appName: parts[1],\n }\n }\n\n // Somewhere else in workspace\n return { locationType: 'workspace-root' }\n}\n","import * as path from 'path'\n\nimport fs from 'fs-extra'\n\nimport type { WorkspaceManifest } from './types.js'\n\nconst WORKSPACE_MANIFEST = '.launch77/workspace.json'\n\n/**\n * Check if a directory contains a Launch77 workspace manifest\n */\nexport async function isWorkspaceRoot(dir: string): Promise<boolean> {\n const manifestPath = path.join(dir, WORKSPACE_MANIFEST)\n return await fs.pathExists(manifestPath)\n}\n\n/**\n * Read workspace manifest from a workspace root directory\n */\nexport async function readWorkspaceManifest(workspaceRoot: string): Promise<WorkspaceManifest> {\n const manifestPath = path.join(workspaceRoot, WORKSPACE_MANIFEST)\n return await fs.readJSON(manifestPath)\n}\n\n/**\n * Find the workspace root by traversing up from a starting directory\n * Looks for .launch77/workspace.json manifest file\n *\n * @param startDir - Directory to start searching from\n * @returns Path to workspace root, or null if not found\n */\nexport async function findWorkspaceRoot(startDir: string): Promise<string | null> {\n let currentDir = path.resolve(startDir)\n const rootDir = path.parse(currentDir).root\n\n while (currentDir !== rootDir) {\n if (await isWorkspaceRoot(currentDir)) {\n return currentDir\n }\n currentDir = path.dirname(currentDir)\n }\n\n return null\n}\n","/**\n * Name Validation Utilities\n *\n * Provides validation for plugin names and npm package names.\n * Used by both CLI and plugin-runtime to ensure consistent naming rules.\n */\n\nexport interface ValidationResult {\n isValid: boolean\n error?: string\n}\n\n/**\n * Validate a plugin name\n *\n * Rules:\n * - Must start with a lowercase letter\n * - Can contain lowercase letters, numbers, and hyphens\n * - Cannot contain uppercase, spaces, underscores, or special characters\n *\n * @param name - The plugin name to validate\n * @returns ValidationResult indicating if valid and error message if not\n *\n * @example\n * validatePluginName('my-plugin') // { isValid: true }\n * validatePluginName('MyPlugin') // { isValid: false, error: '...' }\n */\nexport function validatePluginName(name: string): ValidationResult {\n if (!name || name.trim().length === 0) {\n return {\n isValid: false,\n error: 'Plugin name cannot be empty',\n }\n }\n\n const trimmedName = name.trim()\n\n // Must start with a lowercase letter\n if (!/^[a-z]/.test(trimmedName)) {\n return {\n isValid: false,\n error: 'Plugin name must start with a lowercase letter (a-z)',\n }\n }\n\n // Can only contain lowercase letters, numbers, and hyphens\n if (!/^[a-z][a-z0-9-]*$/.test(trimmedName)) {\n return {\n isValid: false,\n error: 'Plugin name can only contain lowercase letters (a-z), numbers (0-9), and hyphens (-)',\n }\n }\n\n return { isValid: true }\n}\n\n/**\n * Validate an npm package name (scoped or unscoped)\n *\n * Rules for unscoped packages:\n * - Must start with a lowercase letter\n * - Can contain lowercase letters, numbers, and hyphens\n *\n * Rules for scoped packages:\n * - Format: @org/package\n * - Org must contain lowercase letters, numbers, and hyphens\n * - Package must contain lowercase letters, numbers, and hyphens\n *\n * @param name - The npm package name to validate\n * @returns ValidationResult indicating if valid and error message if not\n *\n * @example\n * isValidNpmPackageName('my-package') // { isValid: true }\n * isValidNpmPackageName('@org/my-package') // { isValid: true }\n * isValidNpmPackageName('@release') // { isValid: false, error: '...' }\n */\nexport function isValidNpmPackageName(name: string): ValidationResult {\n if (!name || name.trim().length === 0) {\n return {\n isValid: false,\n error: 'Package name cannot be empty',\n }\n }\n\n const trimmedName = name.trim()\n\n // Check if it's a scoped package\n if (trimmedName.startsWith('@')) {\n // Scoped package format: @org/package\n const scopedPattern = /^@([a-z0-9-]+)\\/([a-z0-9-]+)$/\n\n if (!scopedPattern.test(trimmedName)) {\n return {\n isValid: false,\n error: 'Scoped package must be in format @org/package where org and package contain only lowercase letters, numbers, and hyphens',\n }\n }\n\n return { isValid: true }\n }\n\n // Unscoped package - same rules as plugin/workspace names\n if (!/^[a-z][a-z0-9-]*$/.test(trimmedName)) {\n return {\n isValid: false,\n error: 'Package name must start with a lowercase letter and contain only lowercase letters (a-z), numbers (0-9), and hyphens (-)',\n }\n }\n\n return { isValid: true }\n}\n\n/**\n * Parse a plugin name input and determine its type\n *\n * Returns information about whether the input is:\n * - A scoped npm package (e.g., @org/package)\n * - An unscoped name (e.g., my-plugin)\n * - Invalid\n *\n * @param name - The plugin name to parse\n * @returns Object with type and validation info\n *\n * @example\n * parsePluginName('release')\n * // { type: 'unscoped', isValid: true, name: 'release' }\n *\n * parsePluginName('@ibm/analytics')\n * // { type: 'scoped', isValid: true, name: '@ibm/analytics', org: 'ibm', package: 'analytics' }\n *\n * parsePluginName('@release')\n * // { type: 'invalid', isValid: false, error: '...' }\n */\nexport function parsePluginName(name: string): {\n type: 'scoped' | 'unscoped' | 'invalid'\n isValid: boolean\n name?: string\n org?: string\n package?: string\n error?: string\n} {\n if (!name || name.trim().length === 0) {\n return {\n type: 'invalid',\n isValid: false,\n error: 'Plugin name cannot be empty',\n }\n }\n\n const trimmedName = name.trim()\n\n // Check if scoped\n if (trimmedName.startsWith('@')) {\n const validation = isValidNpmPackageName(trimmedName)\n\n if (!validation.isValid) {\n return {\n type: 'invalid',\n isValid: false,\n error: validation.error,\n }\n }\n\n // Extract org and package from @org/package\n const match = trimmedName.match(/^@([a-z0-9-]+)\\/([a-z0-9-]+)$/)\n if (match) {\n return {\n type: 'scoped',\n isValid: true,\n name: trimmedName,\n org: match[1],\n package: match[2],\n }\n }\n\n return {\n type: 'invalid',\n isValid: false,\n error: 'Invalid scoped package format',\n }\n }\n\n // Unscoped - validate as plugin name\n const validation = validatePluginName(trimmedName)\n\n if (!validation.isValid) {\n return {\n type: 'invalid',\n isValid: false,\n error: validation.error,\n }\n }\n\n return {\n type: 'unscoped',\n isValid: true,\n name: trimmedName,\n }\n}\n","import * as fs from 'fs/promises'\nimport * as path from 'path'\n\nimport chalk from 'chalk'\n\ninterface PackageJson {\n name?: string\n dependencies?: Record<string, string>\n}\n\ninterface PluginJson {\n libraryDependencies?: Record<string, string>\n}\n\nexport interface PluginConsistencyError {\n library: string\n packageJsonVersion: string | 'MISSING'\n pluginJsonVersion: string\n}\n\nexport interface ValidationResult {\n valid: boolean\n errors: PluginConsistencyError[]\n}\n\n/**\n * Validate that library versions in plugin.json match those in package.json\n *\n * This ensures that plugin templates (which use package.json versions during development)\n * install the same library versions for end users (which use plugin.json versions).\n *\n * @param pluginPath - Absolute path to the plugin directory\n * @returns Validation result with any errors found\n * @throws Error if package.json or plugin.json cannot be read\n */\nexport async function validatePluginConsistency(pluginPath: string): Promise<ValidationResult> {\n // Read package.json\n const packageJsonPath = path.join(pluginPath, 'package.json')\n const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8')\n const packageJson: PackageJson = JSON.parse(packageJsonContent)\n\n // Read plugin.json\n const pluginJsonPath = path.join(pluginPath, 'plugin.json')\n const pluginJsonContent = await fs.readFile(pluginJsonPath, 'utf-8')\n const pluginJson: PluginJson = JSON.parse(pluginJsonContent)\n\n const errors: PluginConsistencyError[] = []\n\n // Check each library dependency in plugin.json\n if (pluginJson.libraryDependencies) {\n for (const [library, pluginJsonVersion] of Object.entries(pluginJson.libraryDependencies)) {\n const packageJsonVersion = packageJson.dependencies?.[library]\n\n if (!packageJsonVersion) {\n // Library is in plugin.json but NOT in package.json\n errors.push({\n library,\n packageJsonVersion: 'MISSING',\n pluginJsonVersion,\n })\n } else if (packageJsonVersion !== pluginJsonVersion) {\n // Library exists in both but versions don't match\n errors.push({\n library,\n packageJsonVersion,\n pluginJsonVersion,\n })\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}\n\n/**\n * Validate plugin consistency and throw a formatted error if validation fails\n *\n * This is a convenience function for use in build scripts that should\n * fail fast with a clear error message.\n *\n * @param pluginPath - Absolute path to the plugin directory\n * @throws Error with formatted message if validation fails\n */\nexport async function validatePluginConsistencyOrThrow(pluginPath: string): Promise<void> {\n const result = await validatePluginConsistency(pluginPath)\n\n if (!result.valid) {\n // Read plugin name for error message\n const packageJsonPath = path.join(pluginPath, 'package.json')\n const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8')\n const packageJson: PackageJson = JSON.parse(packageJsonContent)\n const pluginName = packageJson.name || 'unknown'\n\n console.error(chalk.red('\\n❌ Plugin consistency validation failed!\\n'))\n console.error(chalk.yellow(`Plugin: ${pluginName}\\n`))\n console.error(chalk.white('Library versions in package.json must match plugin.json:\\n'))\n\n for (const error of result.errors) {\n console.error(chalk.white(` ${error.library}:`))\n if (error.packageJsonVersion === 'MISSING') {\n console.error(chalk.red(` ✗ package.json: MISSING (library not in dependencies)`))\n console.error(chalk.red(` ✗ plugin.json: ${error.pluginJsonVersion}`))\n } else {\n console.error(chalk.red(` ✗ package.json: ${error.packageJsonVersion}`))\n console.error(chalk.red(` ✗ plugin.json: ${error.pluginJsonVersion}`))\n }\n console.error()\n }\n\n console.error(chalk.white('Why this matters:'))\n console.error(chalk.white(' - Plugin templates use package.json versions during development'))\n console.error(chalk.white(' - End users get plugin.json versions when they install the plugin'))\n console.error(chalk.white(' - Mismatched versions cause template code to break for users\\n'))\n\n console.error(chalk.cyan('Fix: Update both files to use the same version.\\n'))\n\n throw new Error('Plugin validation failed - library versions do not match')\n }\n}\n"],"mappings":"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","names":["path","fs","stat","fs","path","path","path","path","fs","validation","fs","path","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/modules/workspace/services/workspace-service.ts","../src/modules/workspace/services/workspace-manifest-service.ts","../src/modules/workspace/utils/location-parser.ts","../src/modules/plugin/generators/generator.ts","../src/modules/plugin/generators/standard-generator.ts","../src/modules/filesystem/services/filesystem-service.ts","../src/modules/plugin/services/metadata-service.ts","../src/modules/plugin/services/plugin-service.ts","../src/modules/npm/services/npm-service.ts","../src/modules/npm/utils/npm-package.ts","../src/modules/plugin/errors/plugin-errors.ts","../src/modules/plugin/resolvers/plugin-resolver.ts","../src/modules/npm/resolvers/package-resolver.ts","../src/modules/plugin/utils/plugin-utils.ts","../src/modules/plugin/services/plugin-installer.ts","../src/modules/package-manifest/services/package-manifest-service.ts"],"sourcesContent":["import * as path from 'path'\n\nimport { WorkspaceManifestService } from './workspace-manifest-service.js'\nimport { Launch77Context } from '../types/index.js'\nimport { parseLocationFromPath } from '../utils/location-parser.js'\n\n/**\n * Validation result type\n */\nexport interface ValidationResult {\n isValid: boolean\n errors?: string[]\n}\n\n/**\n * Service responsible for workspace-related operations.\n * Handles workspace detection and workspace queries.\n */\nexport class WorkspaceService {\n private workspaceManifestService: WorkspaceManifestService\n\n constructor(workspaceManifestService?: WorkspaceManifestService) {\n this.workspaceManifestService = workspaceManifestService || new WorkspaceManifestService()\n }\n\n /**\n * Check if a directory is a Launch77 workspace root\n */\n async isWorkspaceRoot(dir: string): Promise<boolean> {\n return await this.workspaceManifestService.exists(dir)\n }\n\n /**\n * Get the workspace root directory from the current directory\n */\n async findWorkspaceRoot(startDir: string): Promise<string | null> {\n let currentDir = path.resolve(startDir)\n\n while (currentDir !== path.dirname(currentDir)) {\n if (await this.isWorkspaceRoot(currentDir)) {\n return currentDir\n }\n currentDir = path.dirname(currentDir)\n }\n\n return null\n }\n\n /**\n * Validate that we're in a Launch77 workspace context\n */\n async validateWorkspaceContext(context: Launch77Context): Promise<{ valid: boolean; errorMessage?: string }> {\n if (context.locationType === 'unknown') {\n return {\n valid: false,\n errorMessage: 'Must be run from within a Launch77 workspace.\\n\\nCreate a workspace first:\\n launch77 init my-workspace\\n cd my-workspace',\n }\n }\n\n return { valid: true }\n }\n\n /**\n * Validate a workspace context using ValidationResult format\n */\n validateContext(context: Launch77Context): ValidationResult {\n if (context.locationType === 'unknown') {\n return {\n isValid: false,\n errors: ['Must be run from within a Launch77 workspace. Create a workspace first: launch77 init my-workspace'],\n }\n }\n\n return { isValid: true }\n }\n\n /**\n * Validate an app name\n */\n validateAppName(name: string): ValidationResult {\n const trimmed = name.trim()\n\n if (!trimmed) {\n return { isValid: false, errors: ['App name cannot be empty'] }\n }\n\n // App names should be simple identifiers\n const validPattern = /^[a-z][a-z0-9-]*$/\n if (!validPattern.test(trimmed)) {\n return {\n isValid: false,\n errors: ['App name must start with lowercase letter and contain only lowercase letters, numbers, and hyphens'],\n }\n }\n\n if (trimmed.length > 50) {\n return { isValid: false, errors: ['App name must be 50 characters or less'] }\n }\n\n return { isValid: true }\n }\n\n /**\n * Detect the Launch77 workspace context from the current working directory\n *\n * @param cwd - Current working directory path\n * @returns Context information about the workspace location\n */\n async detectLaunch77Context(cwd: string): Promise<Launch77Context> {\n const resolvedCwd = path.resolve(cwd)\n\n // Find the workspace root\n const workspaceRoot = await this.findWorkspaceRoot(resolvedCwd)\n\n if (!workspaceRoot) {\n return {\n isValid: false,\n locationType: 'unknown',\n workspaceRoot: '',\n appsDir: '',\n workspaceVersion: '',\n workspaceName: '',\n packageName: '',\n }\n }\n\n // Read workspace manifest\n let manifest\n try {\n manifest = await this.workspaceManifestService.readWorkspaceManifest(workspaceRoot)\n if (!manifest) {\n // Manifest file not found\n return {\n isValid: false,\n locationType: 'unknown',\n workspaceRoot: '',\n appsDir: '',\n workspaceVersion: '',\n workspaceName: '',\n packageName: '',\n }\n }\n } catch (error) {\n // Manifest exists (we found it) but couldn't read it\n return {\n isValid: false,\n locationType: 'unknown',\n workspaceRoot: '',\n appsDir: '',\n workspaceVersion: '',\n workspaceName: '',\n packageName: '',\n }\n }\n\n // Parse the directory structure to determine location\n const parsed = parseLocationFromPath(resolvedCwd, workspaceRoot)\n\n // Workspace name is the directory name\n const workspaceName = path.basename(workspaceRoot)\n\n // Apps directory is always {workspaceRoot}/apps\n const appsDir = path.join(workspaceRoot, 'apps')\n\n // Package name: @{workspaceName}/{appName} (if in app)\n const packageName = parsed.appName ? `@${workspaceName}/${parsed.appName}` : ''\n\n return {\n isValid: true,\n locationType: parsed.locationType,\n workspaceRoot,\n appsDir,\n workspaceVersion: manifest.version,\n workspaceName,\n appName: parsed.appName,\n packageName,\n }\n }\n}\n\n/**\n * Standalone function for backward compatibility\n * Creates a new WorkspaceService instance and calls detectLaunch77Context\n */\nexport async function detectLaunch77Context(cwd: string): Promise<Launch77Context> {\n const service = new WorkspaceService()\n return service.detectLaunch77Context(cwd)\n}\n","import * as path from 'path'\n\nimport fs from 'fs-extra'\n\nimport { WorkspaceManifest } from '../types/index.js'\n\n/**\n * Service responsible for workspace manifest file operations.\n * Handles reading and writing the .launch77/workspace.json file.\n */\nexport class WorkspaceManifestService {\n private static readonly WORKSPACE_MANIFEST = '.launch77/workspace.json'\n\n /**\n * Check if a workspace manifest exists at the given root\n */\n async exists(workspaceRoot: string): Promise<boolean> {\n const manifestPath = path.join(workspaceRoot, WorkspaceManifestService.WORKSPACE_MANIFEST)\n return await fs.pathExists(manifestPath)\n }\n\n /**\n * Read the workspace manifest\n */\n async readWorkspaceManifest(workspaceRoot: string): Promise<WorkspaceManifest | null> {\n const manifestPath = path.join(workspaceRoot, WorkspaceManifestService.WORKSPACE_MANIFEST)\n\n if (!(await fs.pathExists(manifestPath))) {\n return null\n }\n\n try {\n return await fs.readJSON(manifestPath)\n } catch (error) {\n throw new Error(`Failed to read workspace manifest: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Write the workspace manifest\n */\n async writeWorkspaceManifest(workspaceRoot: string, manifest: WorkspaceManifest): Promise<void> {\n const manifestPath = path.join(workspaceRoot, WorkspaceManifestService.WORKSPACE_MANIFEST)\n\n try {\n await fs.ensureDir(path.dirname(manifestPath))\n await fs.writeJSON(manifestPath, manifest, { spaces: 2 })\n } catch (error) {\n throw new Error(`Failed to write workspace manifest: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Get the manifest file path for a workspace\n */\n getManifestPath(workspaceRoot: string): string {\n return path.join(workspaceRoot, WorkspaceManifestService.WORKSPACE_MANIFEST)\n }\n}\n","import * as path from 'path'\n\nimport type { ParsedLocation } from '../types/index.js'\n\n/**\n * Parse the directory structure to determine location context\n *\n * Based on patterns:\n * - apps/[name] → workspace-app\n * - libraries/[name] → workspace-library\n * - plugins/[name] → workspace-plugin\n * - app-templates/[name] → workspace-app-template\n * - (empty or root) → workspace-root\n *\n * @param cwdPath - Current working directory path\n * @param workspaceRoot - Root path of the workspace\n * @returns Parsed location information\n */\nexport function parseLocationFromPath(cwdPath: string, workspaceRoot: string): ParsedLocation {\n const relativePath = path.relative(workspaceRoot, cwdPath)\n\n // At workspace root\n if (!relativePath || relativePath === '.') {\n return { locationType: 'workspace-root' }\n }\n\n const parts = relativePath.split(path.sep)\n\n // apps/[app-name]/...\n if (parts[0] === 'apps' && parts.length >= 2) {\n return {\n locationType: 'workspace-app',\n appName: parts[1],\n }\n }\n\n // libraries/[lib-name]/...\n if (parts[0] === 'libraries' && parts.length >= 2) {\n return {\n locationType: 'workspace-library',\n appName: parts[1],\n }\n }\n\n // plugins/[plugin-name]/...\n if (parts[0] === 'plugins' && parts.length >= 2) {\n return {\n locationType: 'workspace-plugin',\n appName: parts[1],\n }\n }\n\n // app-templates/[template-name]/...\n if (parts[0] === 'app-templates' && parts.length >= 2) {\n return {\n locationType: 'workspace-app-template',\n appName: parts[1],\n }\n }\n\n // Somewhere else in workspace\n return { locationType: 'workspace-root' }\n}\n","import type { GeneratorContext } from '../types/index.js'\n\n/**\n * Base abstract class for all plugin generators.\n *\n * The only requirement for a generator is to implement the run() method.\n * This method is called by the CLI when a plugin is installed.\n *\n * Use this base class when you need full control over the installation process.\n * For convention-based installation, extend StandardGenerator instead.\n */\nexport abstract class Generator {\n constructor(protected context: GeneratorContext) {}\n\n /**\n * Main entry point for plugin installation.\n * This method is called by the CLI and must be implemented by all generators.\n */\n abstract run(): Promise<void>\n}\n","import * as fs from 'fs/promises'\nimport * as path from 'path'\n\nimport chalk from 'chalk'\nimport { execa } from 'execa'\n\nimport { Generator } from './generator.js'\nimport { FilesystemService } from '../../filesystem/services/filesystem-service.js'\nimport { MetadataService } from '../services/metadata-service.js'\n\nimport type { GeneratorContext, PluginMetadata } from '../types/index.js'\n\n/**\n * Standard generator with convention-over-configuration approach.\n *\n * Provides a structured lifecycle with smart defaults:\n * 1. updateDependencies() - Reads plugin.json, merges into package.json\n * 2. installDependencies() - Runs npm install\n * 3. copyTemplates() - Copies templates/ folder to app\n * 4. injectCode() - Override this for surgical code edits\n *\n * Most plugins only need to implement injectCode().\n * For full control, extend Generator instead.\n */\nexport abstract class StandardGenerator extends Generator {\n protected filesystemService: FilesystemService\n protected metadataService: MetadataService\n\n constructor(context: GeneratorContext) {\n super(context)\n this.filesystemService = new FilesystemService()\n this.metadataService = new MetadataService()\n }\n\n async run(): Promise<void> {\n console.log(chalk.green(`\\n✅ Installing plugin...\\n`))\n\n await this.updateDependencies()\n await this.installDependencies()\n await this.copyTemplates()\n await this.injectCode()\n\n console.log(chalk.green(`\\n✅ Plugin installed successfully!\\n`))\n this.showNextSteps()\n }\n\n protected async updateDependencies(): Promise<void> {\n const pluginJsonPath = path.join(this.context.pluginPath, 'plugin.json')\n\n if (!(await this.filesystemService.pathExists(pluginJsonPath))) return\n\n try {\n const pluginMetadata: PluginMetadata = await this.metadataService.readPluginMetadata(this.context.pluginPath)\n\n if (!pluginMetadata.libraryDependencies || Object.keys(pluginMetadata.libraryDependencies).length === 0) {\n return\n }\n\n const packageJsonPath = path.join(this.context.appPath, 'package.json')\n const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8')\n const packageJson = JSON.parse(packageJsonContent)\n\n packageJson.dependencies = {\n ...packageJson.dependencies,\n ...pluginMetadata.libraryDependencies,\n }\n\n await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\\n', 'utf-8')\n console.log(chalk.green(' ✓ Updated package.json with dependencies'))\n } catch (error) {\n console.log(chalk.yellow(` ⚠️ Could not update dependencies: ${error}`))\n }\n }\n\n protected async installDependencies(): Promise<void> {\n try {\n console.log(chalk.cyan(' Installing dependencies...'))\n const workspaceRoot = path.dirname(path.dirname(this.context.appPath))\n\n await execa('npm', ['install'], {\n cwd: workspaceRoot,\n stdio: 'pipe',\n })\n\n console.log(chalk.green(' ✓ Dependencies installed'))\n } catch (error) {\n console.log(chalk.yellow(` ⚠️ Could not install dependencies: ${error}`))\n }\n }\n\n protected async copyTemplates(): Promise<void> {\n const templatesDir = path.join(this.context.pluginPath, 'templates')\n\n if (!(await this.filesystemService.pathExists(templatesDir))) return\n\n try {\n await this.filesystemService.copyRecursive(templatesDir, this.context.appPath)\n console.log(chalk.green(' ✓ Copied template files'))\n } catch (error) {\n console.log(chalk.yellow(` ⚠️ Could not copy template files: ${error}`))\n }\n }\n\n protected async injectCode(): Promise<void> {\n // No-op by default - plugins override this for custom code injection\n }\n\n protected showNextSteps(): void {\n // No-op by default - plugins can override to show custom next steps\n }\n}\n","import * as path from 'path'\n\nimport fs from 'fs-extra'\n\n/**\n * Service responsible for file system operations.\n * Provides an abstraction layer over fs operations with proper error handling.\n */\nexport class FilesystemService {\n /**\n * Check if a path exists\n */\n async pathExists(filePath: string): Promise<boolean> {\n try {\n return await fs.pathExists(filePath)\n } catch {\n return false\n }\n }\n\n /**\n * Copy a file or directory recursively\n */\n async copyRecursive(source: string, destination: string, options?: { overwrite?: boolean }): Promise<void> {\n try {\n await fs.copy(source, destination, {\n overwrite: options?.overwrite ?? true,\n errorOnExist: false,\n })\n } catch (error) {\n throw new Error(`Failed to copy from ${source} to ${destination}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Read a JSON file\n */\n async readJSON<T = unknown>(filePath: string): Promise<T> {\n try {\n return await fs.readJSON(filePath)\n } catch (error) {\n throw new Error(`Failed to read JSON from ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Write a JSON file\n */\n async writeJSON(filePath: string, data: unknown, options?: { spaces?: number }): Promise<void> {\n try {\n await fs.writeJSON(filePath, data, { spaces: options?.spaces ?? 2 })\n } catch (error) {\n throw new Error(`Failed to write JSON to ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Read a text file\n */\n async readFile(filePath: string, encoding: BufferEncoding = 'utf8'): Promise<string> {\n try {\n return await fs.readFile(filePath, encoding)\n } catch (error) {\n throw new Error(`Failed to read file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Write a text file\n */\n async writeFile(filePath: string, content: string, encoding: BufferEncoding = 'utf8'): Promise<void> {\n try {\n await fs.writeFile(filePath, content, encoding)\n } catch (error) {\n throw new Error(`Failed to write file ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Create a directory (including parent directories)\n */\n async ensureDir(dirPath: string): Promise<void> {\n try {\n await fs.ensureDir(dirPath)\n } catch (error) {\n throw new Error(`Failed to create directory ${dirPath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Remove a file or directory\n */\n async remove(filePath: string): Promise<void> {\n try {\n await fs.remove(filePath)\n } catch (error) {\n throw new Error(`Failed to remove ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * List files in a directory\n */\n async readDir(dirPath: string): Promise<string[]> {\n try {\n return await fs.readdir(dirPath)\n } catch (error) {\n throw new Error(`Failed to read directory ${dirPath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Get file or directory stats\n */\n async getStats(filePath: string): Promise<fs.Stats> {\n try {\n return await fs.stat(filePath)\n } catch (error) {\n throw new Error(`Failed to get stats for ${filePath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Check if a path is a directory\n */\n async isDirectory(filePath: string): Promise<boolean> {\n try {\n const stats = await this.getStats(filePath)\n return stats.isDirectory()\n } catch {\n return false\n }\n }\n\n /**\n * Check if a path is a file\n */\n async isFile(filePath: string): Promise<boolean> {\n try {\n const stats = await this.getStats(filePath)\n return stats.isFile()\n } catch {\n return false\n }\n }\n\n /**\n * Move a file or directory\n */\n async move(source: string, destination: string, options?: { overwrite?: boolean }): Promise<void> {\n try {\n await fs.move(source, destination, {\n overwrite: options?.overwrite ?? false,\n })\n } catch (error) {\n throw new Error(`Failed to move from ${source} to ${destination}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Create a temporary directory\n */\n async createTempDir(prefix: string): Promise<string> {\n const os = await import('os')\n try {\n return await fs.mkdtemp(path.join(os.tmpdir(), prefix))\n } catch (error) {\n throw new Error(`Failed to create temp directory: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n}\n","import * as path from 'path'\n\nimport fs from 'fs-extra'\n\nimport { PluginMetadata, TemplateMetadata } from '../types/index.js'\n\n/**\n * Service responsible for reading and managing metadata for plugins and templates.\n * Handles JSON file reading and parsing without mixing validation concerns.\n */\nexport class MetadataService {\n /**\n * Read plugin metadata from a plugin directory\n */\n async readPluginMetadata(pluginPath: string): Promise<PluginMetadata> {\n const metadataPath = path.join(pluginPath, 'plugin.json')\n\n if (!(await fs.pathExists(metadataPath))) {\n throw new Error(`Plugin metadata file not found at: ${metadataPath}`)\n }\n\n try {\n const fullMetadata = await fs.readJSON(metadataPath)\n\n // Extract only the metadata fields, excluding name and version\n // which should come from package.json\n const { name: _name, version: _version, ...metadata } = fullMetadata\n\n return metadata as PluginMetadata\n } catch (error) {\n throw new Error(`Failed to read plugin metadata: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Read template metadata from a template directory\n */\n async readTemplateMetadata(templatePath: string): Promise<TemplateMetadata> {\n const metadataPath = path.join(templatePath, 'template.json')\n\n if (!(await fs.pathExists(metadataPath))) {\n throw new Error(`Template metadata file not found at: ${metadataPath}`)\n }\n\n try {\n const metadata = await fs.readJSON(metadataPath)\n return metadata as TemplateMetadata\n } catch (error) {\n throw new Error(`Failed to read template metadata: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Check if a plugin metadata file exists\n */\n async hasPluginMetadata(pluginPath: string): Promise<boolean> {\n const metadataPath = path.join(pluginPath, 'plugin.json')\n return await fs.pathExists(metadataPath)\n }\n\n /**\n * Check if a template metadata file exists\n */\n async hasTemplateMetadata(templatePath: string): Promise<boolean> {\n const metadataPath = path.join(templatePath, 'template.json')\n return await fs.pathExists(metadataPath)\n }\n\n /**\n * Write plugin metadata to a directory\n */\n async writePluginMetadata(pluginPath: string, metadata: PluginMetadata): Promise<void> {\n const metadataPath = path.join(pluginPath, 'plugin.json')\n\n try {\n await fs.writeJSON(metadataPath, metadata, { spaces: 2 })\n } catch (error) {\n throw new Error(`Failed to write plugin metadata: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Write template metadata to a directory\n */\n async writeTemplateMetadata(templatePath: string, metadata: TemplateMetadata): Promise<void> {\n const metadataPath = path.join(templatePath, 'template.json')\n\n try {\n await fs.writeJSON(metadataPath, metadata, { spaces: 2 })\n } catch (error) {\n throw new Error(`Failed to write template metadata: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n}\n","import * as fs from 'fs/promises'\nimport * as path from 'path'\n\nimport chalk from 'chalk'\nimport { execa } from 'execa'\nimport fsExtra from 'fs-extra'\n\nimport { MetadataService } from './metadata-service.js'\nimport { NpmService } from '../../npm/services/npm-service.js'\nimport { downloadNpmPackage } from '../../npm/utils/npm-package.js'\nimport { PluginInstallationError, InvalidPluginContextError, MissingPluginTargetsError, createInvalidTargetError, PluginResolutionError, PluginDirectoryNotFoundError, InvalidPluginNameError } from '../errors/plugin-errors.js'\nimport { PluginResolver } from '../resolvers/plugin-resolver.js'\nimport { mapLocationTypeToTarget } from '../utils/plugin-utils.js'\n\nimport type { PackageManifest, InstalledPluginMetadata } from '../../package-manifest/services/package-manifest-service.js'\nimport type { Launch77Context } from '../../workspace/index.js'\nimport type { PluginMetadata } from '../types/index.js'\nimport type { InstallPluginRequest, InstallPluginResult, DeletePluginRequest, DeletePluginResult, Target } from '../types/plugin-service-types.js'\n\n/**\n * Validation result type for plugin operations\n */\nexport interface ValidationResult {\n isValid: boolean\n errors?: string[]\n}\n\n/**\n * Plugin consistency error type\n */\nexport interface PluginConsistencyError {\n library: string\n packageJsonVersion: string | 'MISSING'\n pluginJsonVersion: string\n}\n\nexport class PluginService {\n private pluginResolver: PluginResolver\n private metadataService: MetadataService\n private npmService: NpmService\n\n constructor() {\n this.pluginResolver = new PluginResolver()\n this.metadataService = new MetadataService()\n this.npmService = new NpmService()\n }\n\n /**\n * Validate a plugin name\n */\n validatePluginName(name: string): ValidationResult {\n const trimmed = name.trim()\n\n if (!trimmed) {\n return { isValid: false, errors: ['Plugin name cannot be empty'] }\n }\n\n // Handle scoped packages\n if (trimmed.startsWith('@')) {\n const parts = trimmed.split('/')\n if (parts.length !== 2 || !parts[0].slice(1) || !parts[1]) {\n return { isValid: false, errors: ['Scoped package must be in format @org/package'] }\n }\n\n const scope = parts[0].slice(1)\n const packageName = parts[1]\n\n if (!this.isValidPackageNamePart(scope)) {\n return { isValid: false, errors: [`Invalid scope: ${scope}`] }\n }\n\n if (!this.isValidPackageNamePart(packageName)) {\n return { isValid: false, errors: [`Invalid package name: ${packageName}`] }\n }\n } else {\n // Unscoped package\n if (!this.isValidPackageNamePart(trimmed)) {\n return { isValid: false, errors: [`Invalid package name: ${trimmed}`] }\n }\n }\n\n return { isValid: true }\n }\n\n /**\n * Validate plugin metadata\n */\n validatePluginMetadata(metadata: PluginMetadata): ValidationResult {\n const errors: string[] = []\n\n if (!metadata.targets || metadata.targets.length === 0) {\n errors.push('Plugin must specify at least one target')\n }\n\n if (metadata.showcaseUrl) {\n const showcaseValidation = this.validateShowcaseUrl(metadata.showcaseUrl)\n if (!showcaseValidation.isValid) {\n errors.push(showcaseValidation.errors?.[0] || 'Invalid showcase URL')\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors: errors.length > 0 ? errors : undefined,\n }\n }\n\n /**\n * Validate a showcase URL\n * Note: This is primarily used by the webapp template\n */\n validateShowcaseUrl(url: string | undefined): ValidationResult {\n // Optional field - undefined is valid\n if (!url) {\n return { isValid: true }\n }\n\n // Must be a relative URL starting with /\n if (!url.startsWith('/')) {\n return {\n isValid: false,\n errors: ['Showcase URL must be a relative path starting with /'],\n }\n }\n\n // Prevent external URLs (protocol-relative or absolute)\n if (url.includes('://') || url.startsWith('//')) {\n return {\n isValid: false,\n errors: ['Showcase URL cannot be an external URL'],\n }\n }\n\n // Validate URL format by trying to construct a URL\n try {\n // Use a dummy base to validate the relative path\n new URL(url, 'http://example.com')\n return { isValid: true }\n } catch {\n return {\n isValid: false,\n errors: ['Invalid URL format'],\n }\n }\n }\n\n /**\n * Validate plugin consistency between plugin.json and package.json\n */\n async validatePluginConsistency(pluginPath: string): Promise<ValidationResult> {\n const errors: string[] = []\n\n try {\n const packageJsonPath = path.join(pluginPath, 'package.json')\n const pluginJsonPath = path.join(pluginPath, 'plugin.json')\n\n if (!(await fsExtra.pathExists(packageJsonPath))) {\n errors.push('package.json not found')\n return { isValid: false, errors }\n }\n\n if (!(await fsExtra.pathExists(pluginJsonPath))) {\n errors.push('plugin.json not found')\n return { isValid: false, errors }\n }\n\n const packageJson = await fsExtra.readJSON(packageJsonPath)\n const pluginJson = await fsExtra.readJSON(pluginJsonPath)\n\n // Check if plugin.json has dependencies that should be in package.json\n if (pluginJson.dependencies) {\n const packageDeps = packageJson.dependencies || {}\n const packageDevDeps = packageJson.devDependencies || {}\n\n for (const [dep, version] of Object.entries(pluginJson.dependencies)) {\n if (!packageDeps[dep] && !packageDevDeps[dep]) {\n errors.push(`Dependency '${dep}' specified in plugin.json but not in package.json`)\n } else {\n const packageVersion = packageDeps[dep] || packageDevDeps[dep]\n if (packageVersion !== version) {\n errors.push(`Dependency '${dep}' version mismatch: plugin.json has '${version}', package.json has '${packageVersion}'`)\n }\n }\n }\n }\n\n // Check if devDependencies in plugin.json match package.json\n if (pluginJson.devDependencies) {\n const packageDevDeps = packageJson.devDependencies || {}\n\n for (const [dep, version] of Object.entries(pluginJson.devDependencies)) {\n if (!packageDevDeps[dep]) {\n errors.push(`Dev dependency '${dep}' specified in plugin.json but not in package.json`)\n } else if (packageDevDeps[dep] !== version) {\n errors.push(`Dev dependency '${dep}' version mismatch: plugin.json has '${version}', package.json has '${packageDevDeps[dep]}'`)\n }\n }\n }\n } catch (error) {\n errors.push(`Failed to validate plugin consistency: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n\n return {\n isValid: errors.length === 0,\n errors: errors.length > 0 ? errors : undefined,\n }\n }\n\n /**\n * Check if a package name part is valid\n */\n private isValidPackageNamePart(part: string): boolean {\n // npm package name rules:\n // - Must be lowercase\n // - Can contain letters, numbers, hyphens, periods, underscores\n // - Cannot start with a number or period\n // - Cannot contain spaces or other special characters\n const validPattern = /^[a-z][a-z0-9._-]*$/\n return validPattern.test(part)\n }\n\n /**\n * Validate plugin name, resolve its location, and download if needed\n */\n private async validateAndResolvePlugin(pluginName: string, workspaceRoot: string, logger: (message: string) => void): Promise<{ pluginPath: string; source: 'local' | 'npm'; npmPackage?: string; version: string }> {\n logger(chalk.blue(`\\n🔍 Resolving plugin \"${pluginName}\"...`))\n logger(` ├─ Validating plugin name...`)\n\n const validation = this.pluginResolver.validateInput(pluginName)\n if (!validation.isValid) {\n throw new PluginResolutionError(pluginName, validation.error || 'Invalid plugin name')\n }\n logger(` │ └─ ${chalk.green('✓')} Valid plugin name`)\n\n logger(` ├─ Checking local workspace: ${chalk.dim(`plugins/${pluginName}`)}`)\n const resolution = await this.pluginResolver.resolveLocation(pluginName, workspaceRoot)\n\n let pluginPath: string\n let version: string\n\n if (resolution.source === 'local') {\n logger(` │ └─ ${chalk.green('✓')} Found local plugin`)\n pluginPath = resolution.localPath!\n version = resolution.version! // Local plugins always have version after verification\n } else {\n logger(` │ └─ ${chalk.dim('Not found locally')}`)\n logger(` ├─ Resolving to npm package: ${chalk.cyan(resolution.npmPackage)}`)\n\n pluginPath = await this.downloadNpmPlugin(resolution.npmPackage!, workspaceRoot, logger)\n\n // Read version from downloaded package\n const packageJsonPath = path.join(pluginPath, 'package.json')\n const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8')\n const packageJson = JSON.parse(packageJsonContent)\n version = packageJson.version\n }\n\n logger(` └─ ${chalk.green('✓')} Plugin resolved\\n`)\n\n return {\n pluginPath,\n source: resolution.source,\n npmPackage: resolution.npmPackage,\n version,\n }\n }\n\n /**\n * Read plugin metadata and validate it supports the current target\n */\n private async validatePluginTargets(pluginPath: string, pluginName: string, currentTarget: Target): Promise<PluginMetadata> {\n const metadata = await this.metadataService.readPluginMetadata(pluginPath)\n\n if (!metadata.targets || metadata.targets.length === 0) {\n throw new MissingPluginTargetsError(pluginName)\n }\n\n if (!metadata.targets.includes(currentTarget)) {\n throw createInvalidTargetError(pluginName, currentTarget, metadata.targets)\n }\n\n return metadata\n }\n\n /**\n * Check if plugin is already installed and return early-exit result if so\n */\n private async checkExistingInstallation(pluginName: string, packagePath: string, logger: (message: string) => void): Promise<InstallPluginResult | null> {\n const existingInstallation = await this.isPluginInstalled(pluginName, packagePath)\n if (existingInstallation) {\n logger(chalk.yellow(`\\nℹ️ Plugin '${pluginName}' is already installed in this package.\\n`))\n logger(`Package: ${chalk.cyan(existingInstallation.package)} (${existingInstallation.source})`)\n logger(`Version: ${existingInstallation.version}`)\n logger(`Installed: ${existingInstallation.installedAt}\\n`)\n logger(chalk.gray('To reinstall: Remove from package.json launch77.installedPlugins'))\n logger(chalk.gray('(plugin:remove command coming soon)\\n'))\n return {\n pluginName,\n filesInstalled: false,\n packageJsonUpdated: false,\n dependenciesInstalled: false,\n }\n }\n return null\n }\n\n /**\n * Install a plugin to the current package\n */\n async installPlugin(request: InstallPluginRequest, context: Launch77Context, logger: (message: string) => void = console.log): Promise<InstallPluginResult> {\n const { pluginName } = request\n\n const currentTarget: Target = mapLocationTypeToTarget(context.locationType)\n\n const { pluginPath, source, npmPackage, version } = await this.validateAndResolvePlugin(pluginName, context.workspaceRoot, logger)\n await this.validatePluginTargets(pluginPath, pluginName, currentTarget)\n\n const packagePath = this.getPackagePath(context)\n const earlyExit = await this.checkExistingInstallation(pluginName, packagePath, logger)\n if (earlyExit) return earlyExit\n\n await this.runGenerator(pluginPath, packagePath, context)\n\n const packageName = source === 'npm' ? npmPackage! : pluginName\n await this.writePluginManifest(packagePath, {\n pluginName,\n packageName,\n version,\n source,\n })\n\n return {\n pluginName,\n filesInstalled: true,\n packageJsonUpdated: true,\n dependenciesInstalled: true,\n }\n }\n\n /**\n * Download and install an npm plugin package\n */\n private async downloadNpmPlugin(npmPackage: string, workspaceRoot: string, logger: (message: string) => void): Promise<string> {\n logger(` └─ Installing from npm: ${chalk.cyan(npmPackage)}...`)\n\n const result = await downloadNpmPackage({\n packageName: npmPackage,\n workspaceRoot,\n })\n\n return result.packagePath\n }\n\n private getPackagePath(context: Launch77Context): string {\n // Determine the base directory based on location type\n switch (context.locationType) {\n case 'workspace-app':\n return path.join(context.appsDir, context.appName!)\n case 'workspace-library':\n return path.join(context.workspaceRoot, 'libraries', context.appName!)\n case 'workspace-plugin':\n return path.join(context.workspaceRoot, 'plugins', context.appName!)\n case 'workspace-app-template':\n return path.join(context.workspaceRoot, 'app-templates', context.appName!)\n default:\n throw new InvalidPluginContextError(`Cannot install plugin from ${context.locationType}`)\n }\n }\n\n private async runGenerator(pluginPath: string, appPath: string, context: Launch77Context): Promise<void> {\n try {\n const generatorPath = path.join(pluginPath, 'dist/generator.js')\n\n const args = [generatorPath, `--appPath=${appPath}`, `--appName=${context.appName}`, `--workspaceName=${context.workspaceName}`, `--pluginPath=${pluginPath}`]\n\n await execa('node', args, {\n cwd: pluginPath,\n stdio: 'inherit',\n })\n } catch (error) {\n throw new PluginInstallationError(`Generator failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined)\n }\n }\n\n private async isPluginInstalled(pluginName: string, packagePath: string): Promise<InstalledPluginMetadata | null> {\n try {\n const packageJsonPath = path.join(packagePath, 'package.json')\n const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8')\n const packageJson = JSON.parse(packageJsonContent)\n\n const manifest = packageJson.launch77 as PackageManifest | undefined\n\n if (manifest?.installedPlugins?.[pluginName]) {\n return manifest.installedPlugins[pluginName]\n }\n\n return null\n } catch (error) {\n // If package.json doesn't exist or can't be read, assume not installed\n return null\n }\n }\n\n /**\n * Write plugin installation metadata to the target package's package.json\n */\n private async writePluginManifest(packagePath: string, installationInfo: { pluginName: string; packageName: string; version: string; source: 'local' | 'npm' }): Promise<void> {\n try {\n const packageJsonPath = path.join(packagePath, 'package.json')\n const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8')\n const packageJson = JSON.parse(packageJsonContent)\n\n if (!packageJson.launch77) {\n packageJson.launch77 = {}\n }\n\n if (!packageJson.launch77.installedPlugins) {\n packageJson.launch77.installedPlugins = {}\n }\n\n const manifest = packageJson.launch77 as PackageManifest\n\n manifest.installedPlugins![installationInfo.pluginName] = {\n package: installationInfo.packageName,\n version: installationInfo.version,\n installedAt: new Date().toISOString(),\n source: installationInfo.source,\n }\n\n await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\\n', 'utf-8')\n } catch (error) {\n throw new PluginInstallationError(`Failed to write plugin manifest: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined)\n }\n }\n\n /**\n * Delete a plugin from the workspace\n */\n async deletePlugin(request: DeletePluginRequest, context: Launch77Context): Promise<DeletePluginResult> {\n const { pluginName } = request\n\n // 1. Validate plugin name\n const nameValidation = this.validatePluginName(pluginName)\n if (!nameValidation.isValid) {\n throw new InvalidPluginNameError(nameValidation.errors?.[0] || 'Invalid plugin name')\n }\n\n // 2. Validate workspace context\n if (context.locationType === 'unknown') {\n throw new Error('Must be run from within a Launch77 workspace. Create a workspace first: launch77 init my-workspace')\n }\n\n // 3. Determine plugin path\n const pluginPath = path.join(context.workspaceRoot, 'plugins', pluginName)\n\n // 4. Check if plugin exists\n if (!(await fsExtra.pathExists(pluginPath))) {\n throw new PluginDirectoryNotFoundError(pluginName, pluginPath)\n }\n\n // 5. Delete the plugin directory\n await fsExtra.remove(pluginPath)\n\n // 6. Update dependencies\n await this.npmService.install(context.workspaceRoot)\n\n return {\n pluginName,\n }\n }\n}\n","import * as os from 'os'\nimport * as path from 'path'\n\nimport { execa } from 'execa'\nimport fs from 'fs-extra'\n\n/**\n * Result of downloading an npm package\n */\nexport interface DownloadPackageResult {\n path: string\n version: string\n name: string\n}\n\n/**\n * Options for downloading an npm package\n */\nexport interface DownloadPackageOptions {\n packageName: string\n}\n\n/**\n * Validation result for npm package names\n */\nexport interface ValidationResult {\n isValid: boolean\n error?: string\n}\n\n/**\n * Service responsible for NPM operations.\n * Provides a clean abstraction over npm commands and package management.\n */\nexport class NpmService {\n /**\n * Validate an npm package name (scoped or unscoped)\n *\n * Rules for unscoped packages:\n * - Must start with a lowercase letter\n * - Can contain lowercase letters, numbers, hyphens, periods, underscores\n *\n * Rules for scoped packages:\n * - Format: @org/package\n * - Both org and package follow npm naming rules\n *\n * @param name - The npm package name to validate\n * @returns ValidationResult indicating if valid and error message if not\n */\n validatePackageName(name: string): ValidationResult {\n if (!name || name.trim().length === 0) {\n return {\n isValid: false,\n error: 'Package name cannot be empty',\n }\n }\n\n const trimmedName = name.trim()\n\n // Check if it's a scoped package\n if (trimmedName.startsWith('@')) {\n const scopedPattern = /^@([a-z0-9._-]+)\\/([a-z0-9._-]+)$/\n\n if (!scopedPattern.test(trimmedName)) {\n return {\n isValid: false,\n error: 'Scoped package must be in format @org/package where org and package contain only lowercase letters, numbers, hyphens, periods, and underscores',\n }\n }\n\n return { isValid: true }\n }\n\n // Unscoped package - npm package name rules:\n // - Must be lowercase\n // - Can contain letters, numbers, hyphens, periods, underscores\n // - Cannot start with a period or underscore\n const validPattern = /^[a-z0-9][a-z0-9._-]*$/\n if (!validPattern.test(trimmedName)) {\n return {\n isValid: false,\n error: 'Package name must be lowercase and contain only letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_)',\n }\n }\n\n return { isValid: true }\n }\n\n /**\n * Parse a package name input and determine its type\n *\n * Returns information about whether the input is:\n * - A scoped npm package (e.g., @org/package)\n * - An unscoped name (e.g., my-package)\n * - Invalid\n */\n parsePackageName(name: string): {\n type: 'scoped' | 'unscoped' | 'invalid'\n isValid: boolean\n name?: string\n org?: string\n package?: string\n error?: string\n } {\n if (!name || name.trim().length === 0) {\n return {\n type: 'invalid',\n isValid: false,\n error: 'Package name cannot be empty',\n }\n }\n\n const trimmedName = name.trim()\n const validation = this.validatePackageName(trimmedName)\n\n if (!validation.isValid) {\n return {\n type: 'invalid',\n isValid: false,\n error: validation.error,\n }\n }\n\n // Check if scoped\n if (trimmedName.startsWith('@')) {\n // Extract org and package from @org/package\n const match = trimmedName.match(/^@([a-z0-9._-]+)\\/([a-z0-9._-]+)$/)\n if (match) {\n return {\n type: 'scoped',\n isValid: true,\n name: trimmedName,\n org: match[1],\n package: match[2],\n }\n }\n }\n\n return {\n type: 'unscoped',\n isValid: true,\n name: trimmedName,\n }\n }\n\n /**\n * Install npm dependencies in a directory\n */\n async install(cwd: string): Promise<void> {\n try {\n await execa('npm', ['install'], { cwd })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Failed to install npm dependencies: ${message}`)\n }\n }\n\n /**\n * Install npm dependencies with legacy peer deps flag\n */\n async installWithLegacyPeerDeps(cwd: string): Promise<void> {\n try {\n await execa('npm', ['install', '--legacy-peer-deps'], { cwd })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Failed to install npm dependencies: ${message}`)\n }\n }\n\n /**\n * Download an npm package to a temporary directory\n */\n async downloadPackage(options: DownloadPackageOptions): Promise<DownloadPackageResult> {\n const { packageName } = options\n\n // Create a temporary directory for the download\n const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'npm-download-'))\n\n try {\n // Use npm pack to download the package\n const { stdout } = await execa('npm', ['pack', packageName, '--json'], {\n cwd: tempDir,\n })\n\n const packResult = JSON.parse(stdout)\n const tarballName = Array.isArray(packResult) ? packResult[0].filename : packResult.filename\n\n if (!tarballName) {\n throw new Error('Failed to get tarball name from npm pack')\n }\n\n // Extract the tarball\n const tarballPath = path.join(tempDir, tarballName)\n await execa('tar', ['-xzf', tarballPath], { cwd: tempDir })\n\n // The package is extracted to a 'package' directory\n const packagePath = path.join(tempDir, 'package')\n\n // Read package.json to get name and version\n const packageJsonPath = path.join(packagePath, 'package.json')\n const packageJson = await fs.readJSON(packageJsonPath)\n\n return {\n path: packagePath,\n version: packageJson.version,\n name: packageJson.name,\n }\n } catch (error) {\n // Clean up on error\n await fs.remove(tempDir).catch(() => {})\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Failed to download npm package '${packageName}': ${message}`)\n }\n }\n\n /**\n * Get information about an npm package\n */\n async getPackageInfo(packageName: string): Promise<unknown> {\n try {\n const { stdout } = await execa('npm', ['view', packageName, '--json'])\n return JSON.parse(stdout)\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Failed to get package info for '${packageName}': ${message}`)\n }\n }\n\n /**\n * Check if a package exists on npm\n */\n async packageExists(packageName: string): Promise<boolean> {\n try {\n await execa('npm', ['view', packageName, 'name'])\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Install a specific package as a dependency\n */\n async installPackage(packageName: string, cwd: string, isDev = false): Promise<void> {\n try {\n const args = ['install', packageName]\n if (isDev) {\n args.push('--save-dev')\n }\n await execa('npm', args, { cwd })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Failed to install package '${packageName}': ${message}`)\n }\n }\n\n /**\n * Uninstall a package\n */\n async uninstallPackage(packageName: string, cwd: string): Promise<void> {\n try {\n await execa('npm', ['uninstall', packageName], { cwd })\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(`Failed to uninstall package '${packageName}': ${message}`)\n }\n }\n\n /**\n * Clean up a temporary download directory\n */\n async cleanupDownload(downloadPath: string): Promise<void> {\n // Find the temp directory (parent of 'package' directory)\n const tempDir = path.dirname(downloadPath)\n if (tempDir.includes('npm-download-')) {\n await fs.remove(tempDir).catch(() => {})\n }\n }\n}\n","import * as path from 'path'\n\nimport { execa } from 'execa'\n\nimport { NpmInstallationError } from '../../plugin/errors/plugin-errors.js'\n\n/**\n * Options for downloading an npm package\n */\nexport interface DownloadNpmPackageOptions {\n /** The npm package name to download */\n packageName: string\n /** The workspace root directory where node_modules will be */\n workspaceRoot: string\n /** Optional logger function for status messages */\n logger?: (message: string) => void\n}\n\n/**\n * Result of downloading an npm package\n */\nexport interface DownloadNpmPackageResult {\n /** Full path to the downloaded package in node_modules */\n packagePath: string\n /** The package name that was downloaded */\n packageName: string\n}\n\n/**\n * Download and install an npm package to workspace node_modules\n *\n * This function:\n * - Runs `npm install {packageName} --save-dev` in the workspace root\n * - Adds the package to workspace package.json devDependencies\n * - Returns the path to the installed package in node_modules\n *\n * @param options - Download options\n * @returns The path to the installed package\n * @throws NpmInstallationError if the download fails\n *\n * @example\n * const result = await downloadNpmPackage({\n * packageName: '@launch77-shared/plugin-release',\n * workspaceRoot: '/path/to/workspace',\n * logger: (msg) => console.log(msg)\n * })\n * // result.packagePath: '/path/to/workspace/node_modules/@launch77-shared/plugin-release'\n */\nexport async function downloadNpmPackage(options: DownloadNpmPackageOptions): Promise<DownloadNpmPackageResult> {\n const { packageName, workspaceRoot, logger } = options\n\n if (logger) {\n logger(`Installing from npm: ${packageName}...`)\n }\n\n try {\n // Install the npm package to the workspace\n await execa('npm', ['install', packageName, '--save-dev'], {\n cwd: workspaceRoot,\n stdio: 'pipe', // Capture output for clean logging\n })\n\n // Return path to installed package in node_modules\n const packagePath = path.join(workspaceRoot, 'node_modules', packageName)\n\n return {\n packagePath,\n packageName,\n }\n } catch (error) {\n throw new NpmInstallationError(packageName, error instanceof Error ? error : undefined)\n }\n}\n","export class PluginNotFoundError extends Error {\n constructor(pluginName: string) {\n super(`Plugin '${pluginName}' not found.`)\n this.name = 'PluginNotFoundError'\n }\n}\n\nexport class InvalidPluginContextError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InvalidPluginContextError'\n }\n}\n\n/**\n * Factory function to create standardized InvalidPluginContextError\n * for when plugin:install is run outside of a package directory\n */\nexport function createInvalidContextError(currentLocation: string): InvalidPluginContextError {\n return new InvalidPluginContextError(\n `plugin:install must be run from within a package directory.\n\nCurrent location: ${currentLocation}\nExpected: apps/<name>/, libraries/<name>/, plugins/<name>/, or app-templates/<name>/\n\nNavigate to a package directory:\n cd apps/<app-name>/\n cd libraries/<lib-name>/\n cd plugins/<plugin-name>/\n cd app-templates/<template-name>/`\n )\n}\n\n/**\n * Error when plugin.json is missing the required 'targets' field\n */\nexport class MissingPluginTargetsError extends Error {\n constructor(pluginName: string) {\n super(`Plugin '${pluginName}' is missing the required 'targets' field in plugin.json.\n\nThe plugin.json file must include a 'targets' array specifying which package types\nthe plugin can be installed into.\n\nExample plugin.json:\n{\n \"name\": \"${pluginName}\",\n \"version\": \"1.0.0\",\n \"targets\": [\"app\", \"library\", \"plugin\", \"app-template\"],\n \"pluginDependencies\": {},\n \"libraryDependencies\": {}\n}`)\n this.name = 'MissingPluginTargetsError'\n }\n}\n\n/**\n * Factory function to create error when plugin targets don't match current location\n */\nexport function createInvalidTargetError(pluginName: string, currentTarget: string, allowedTargets: string[]): InvalidPluginContextError {\n const targetLocations = allowedTargets.map((target) => {\n switch (target) {\n case 'app':\n return 'apps/<name>/'\n case 'library':\n return 'libraries/<name>/'\n case 'plugin':\n return 'plugins/<name>/'\n case 'app-template':\n return 'app-templates/<name>/'\n default:\n return target\n }\n })\n\n return new InvalidPluginContextError(\n `Plugin '${pluginName}' cannot be installed in a '${currentTarget}' package.\n\nThis plugin can only be installed in: ${allowedTargets.join(', ')}\n\nAllowed locations:\n${targetLocations.map((loc) => ` ${loc}`).join('\\n')}`\n )\n}\n\nexport class PluginInstallationError extends Error {\n constructor(\n message: string,\n public readonly cause?: Error\n ) {\n super(message)\n this.name = 'PluginInstallationError'\n }\n}\n\n/**\n * Error when plugin resolution fails\n */\nexport class PluginResolutionError extends Error {\n constructor(pluginName: string, reason: string) {\n super(`Failed to resolve plugin '${pluginName}': ${reason}`)\n this.name = 'PluginResolutionError'\n }\n}\n\n/**\n * Error when npm package installation fails\n */\nexport class NpmInstallationError extends Error {\n constructor(\n packageName: string,\n public readonly cause?: Error\n ) {\n super(`Failed to install npm package '${packageName}'.\n\nPlease check:\n- Your internet connection\n- npm registry access (https://registry.npmjs.org)\n- Package exists: https://www.npmjs.com/package/${packageName}\n\n${cause ? `\\nOriginal error: ${cause.message}` : ''}`)\n this.name = 'NpmInstallationError'\n }\n}\n\n/**\n * Error when plugin directory is not found for deletion\n */\nexport class PluginDirectoryNotFoundError extends Error {\n constructor(pluginName: string, expectedPath: string) {\n super(`Plugin '${pluginName}' does not exist.\\n\\n` + `Expected location: ${expectedPath}\\n\\n` + `Available plugins:\\n` + ` cd plugins/\\n` + ` ls`)\n this.name = 'PluginDirectoryNotFoundError'\n }\n}\n\n/**\n * Error when plugin name validation fails\n */\nexport class InvalidPluginNameError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InvalidPluginNameError'\n }\n}\n","import * as path from 'path'\n\nimport fs from 'fs-extra'\n\nimport { PackageResolver } from '../../npm/resolvers/package-resolver.js'\n\n/**\n * Plugin resolver implementation\n *\n * Resolves plugins from:\n * - Local workspace plugins/ directory\n * - npm packages with @launch77-shared/plugin- prefix\n */\nexport class PluginResolver extends PackageResolver {\n protected getFolderName(): string {\n return 'plugins'\n }\n\n protected getPackagePrefix(): string {\n return '@launch77-shared/plugin-'\n }\n\n protected async verify(localPath: string): Promise<boolean> {\n // Verify it's a valid plugin (has plugin.json, dist/generator.js, and package.json with version)\n const hasPluginJson = await fs.pathExists(path.join(localPath, 'plugin.json'))\n const hasGenerator = await fs.pathExists(path.join(localPath, 'dist/generator.js'))\n const hasPackageJson = await fs.pathExists(path.join(localPath, 'package.json'))\n\n if (!hasPluginJson || !hasGenerator || !hasPackageJson) {\n return false\n }\n\n // Verify package.json has a version field\n try {\n const packageJson = await fs.readJson(path.join(localPath, 'package.json'))\n return !!packageJson.version\n } catch {\n return false\n }\n }\n}\n","import * as path from 'path'\n\nimport fs from 'fs-extra'\n\nimport { NpmService } from '../services/npm-service.js'\n\nimport type { ValidationResult } from '../services/npm-service.js'\n\n/**\n * Base interface for package resolution results\n */\nexport interface PackageResolution {\n /** The source of the package */\n source: 'local' | 'npm'\n /** The resolved name/package to use */\n resolvedName: string\n /** The local path if source is 'local' */\n localPath?: string\n /** The npm package name if source is 'npm' */\n npmPackage?: string\n /** The version from package.json (required for local packages, undefined for npm until installed) */\n version?: string\n}\n\n/**\n * Abstract base class for resolving Launch77 packages\n *\n * Provides generic resolution logic for finding packages in:\n * 1. Local workspace directory (e.g., plugins/, app-templates/)\n * 2. npm packages with configured prefix (e.g., @launch77-shared/plugin-*, @launch77-shared/app-template-*)\n *\n * Concrete implementations must provide:\n * - Folder name for local resolution\n * - Package prefix for npm resolution\n * - Verification logic to validate local packages\n */\nexport abstract class PackageResolver {\n protected npmService: NpmService\n\n constructor() {\n this.npmService = new NpmService()\n }\n\n /**\n * Get the local folder name where packages of this type are stored\n * @example 'plugins' or 'app-templates'\n */\n protected abstract getFolderName(): string\n\n /**\n * Get the npm package prefix for unscoped packages\n * @example '@launch77-shared/plugin-' or '@launch77-shared/app-template-'\n */\n protected abstract getPackagePrefix(): string\n\n /**\n * Verify that a local package is valid and complete\n * @param localPath - The local directory path to verify\n * @returns true if the package is valid, false otherwise\n */\n protected abstract verify(localPath: string): Promise<boolean>\n\n /**\n * Validate package input name\n *\n * Accepts:\n * - Unscoped names (e.g., \"release\", \"my-package\")\n * - Scoped npm packages (e.g., \"@ibm/package-name\")\n *\n * Rejects:\n * - Invalid formats\n * - Empty strings\n * - Names with invalid characters\n *\n * @param name - The package name to validate\n * @returns ValidationResult with isValid and optional error message\n *\n * @example\n * validateInput('release') // { isValid: true }\n * validateInput('@ibm/analytics') // { isValid: true }\n * validateInput('@invalid') // { isValid: false, error: '...' }\n */\n validateInput(name: string): ValidationResult {\n if (!name || name.trim().length === 0) {\n return {\n isValid: false,\n error: 'Package name cannot be empty',\n }\n }\n\n const trimmedName = name.trim()\n\n // Parse the name to determine type and validate\n const parsed = this.npmService.parsePackageName(trimmedName)\n\n if (!parsed.isValid) {\n return {\n isValid: false,\n error: parsed.error,\n }\n }\n\n // If it's scoped, it must be a valid npm package name\n if (parsed.type === 'scoped') {\n return this.npmService.validatePackageName(trimmedName)\n }\n\n // Unscoped names are valid for both local and npm\n return { isValid: true }\n }\n\n /**\n * Convert an unscoped package name to an npm package name\n *\n * Rules:\n * - Unscoped names: prefix with configured package prefix\n * - Scoped names: use as-is\n *\n * @param name - The package name (must be validated first)\n * @returns The npm package name\n *\n * @example\n * toNpmPackageName('release') // '@launch77-shared/plugin-release' (for PluginResolver)\n * toNpmPackageName('@ibm/analytics') // '@ibm/analytics'\n */\n toNpmPackageName(name: string): string {\n const trimmedName = name.trim()\n\n // If already scoped, use as-is\n if (trimmedName.startsWith('@')) {\n return trimmedName\n }\n\n // Otherwise, convert using configured prefix\n return `${this.getPackagePrefix()}${trimmedName}`\n }\n\n /**\n * Read version from package.json\n * @param packagePath - The path to the package directory\n * @returns The version string from package.json\n * @throws If package.json doesn't exist, can't be read, or is missing the version field\n */\n private async readVersion(packagePath: string): Promise<string> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n try {\n const packageJson = await fs.readJson(packageJsonPath)\n if (!packageJson.version) {\n throw new Error(`Invalid package structure: package.json at ${packagePath} is missing required version field. ` + `All Launch77 packages must include a valid package.json with a version field.`)\n }\n return packageJson.version\n } catch (error) {\n // Re-throw our own error messages\n if (error instanceof Error && error.message.includes('Invalid package structure')) {\n throw error\n }\n // File not found or invalid JSON\n throw new Error(`Invalid package structure: package.json not found or invalid at ${packagePath}. ` + `All Launch77 packages must include a valid package.json with a version field.`)\n }\n }\n\n /**\n * Resolve package location from name\n *\n * Resolution order:\n * 1. Check local workspace directory (configured by getFolderName())\n * 2. Verify local package is valid (using verify())\n * 3. Fall back to npm package name (with configured prefix)\n * 4. Read version from package.json (if available)\n *\n * @param name - The package name to resolve\n * @param workspaceRoot - The workspace root directory\n * @returns PackageResolution with source, resolved location, and version\n *\n * @example\n * // Local package found\n * await resolveLocation('my-package', '/workspace')\n * // { source: 'local', resolvedName: 'my-package', localPath: '/workspace/plugins/my-package', version: '1.0.0' }\n *\n * // Not found locally, resolve to npm\n * await resolveLocation('release', '/workspace')\n * // { source: 'npm', resolvedName: 'release', npmPackage: '@launch77-shared/plugin-release' }\n *\n * // Scoped package always resolves to npm\n * await resolveLocation('@ibm/analytics', '/workspace')\n * // { source: 'npm', resolvedName: '@ibm/analytics', npmPackage: '@ibm/analytics' }\n */\n async resolveLocation(name: string, workspaceRoot: string): Promise<PackageResolution> {\n const trimmedName = name.trim()\n const parsed = this.npmService.parsePackageName(trimmedName)\n\n // If scoped, always use npm (local packages are never scoped)\n if (parsed.type === 'scoped') {\n return {\n source: 'npm',\n resolvedName: trimmedName,\n npmPackage: trimmedName,\n }\n }\n\n // Check local workspace directory\n const localPath = path.join(workspaceRoot, this.getFolderName(), trimmedName)\n const localExists = await fs.pathExists(localPath)\n\n if (localExists) {\n // Verify it's a valid package\n const isValid = await this.verify(localPath)\n\n if (isValid) {\n const version = await this.readVersion(localPath)\n return {\n source: 'local',\n resolvedName: trimmedName,\n localPath,\n version,\n }\n }\n }\n\n // Not found locally or invalid, resolve to npm package\n const npmPackage = this.toNpmPackageName(trimmedName)\n\n return {\n source: 'npm',\n resolvedName: trimmedName,\n npmPackage,\n }\n }\n}\n","import { Launch77LocationType } from '../../workspace/index.js'\nimport { createInvalidContextError } from '../errors/plugin-errors.js'\nimport { Target } from '../types/plugin-service-types.js'\n\n/**\n * Maps the location type from Launch77Context.locationType to a Target for plugin operations.\n */\nexport function mapLocationTypeToTarget(locationType: Launch77LocationType): Target {\n switch (locationType) {\n case 'workspace-app':\n return 'app'\n case 'workspace-library':\n return 'library'\n case 'workspace-plugin':\n return 'plugin'\n case 'workspace-app-template':\n return 'app-template'\n default:\n throw createInvalidContextError(locationType)\n }\n}\n","import * as path from 'path'\n\nimport { execa } from 'execa'\n\nimport { FilesystemService } from '../../filesystem/services/filesystem-service.js'\nimport { InstalledPluginMetadata } from '../../package-manifest/services/package-manifest-service.js'\nimport { Launch77Context } from '../../workspace/index.js'\nimport { GeneratorContext, PluginMetadata } from '../types/index.js'\nimport { Target } from '../types/plugin-service-types.js'\n\n/**\n * Resolved plugin information for installation\n */\nexport interface ResolvedPlugin {\n name: string\n version: string\n path: string\n source: 'local' | 'npm'\n metadata?: PluginMetadata\n}\n\n/**\n * Type for package.json structure with launch77 section\n */\ninterface PackageJsonWithLaunch77 {\n name?: string\n version?: string\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n launch77?: {\n installedPlugins?: Record<string, InstalledPluginMetadata>\n template?: unknown\n }\n [key: string]: unknown\n}\n\n/**\n * Service responsible for plugin installation workflow.\n * Handles generator execution, dependency management, and installation tracking.\n */\nexport class PluginInstaller {\n private filesystemService: FilesystemService\n\n constructor(filesystemService?: FilesystemService) {\n this.filesystemService = filesystemService || new FilesystemService()\n }\n\n /**\n * Install a plugin into the target location\n */\n async install(plugin: ResolvedPlugin, target: Target, targetPath: string, context: Launch77Context, logger?: (message: string) => void): Promise<void> {\n // Run the plugin's generator\n await this.runGenerator(plugin, target, targetPath, context, logger)\n\n // Track the installation\n await this.trackInstallation(plugin, targetPath)\n }\n\n /**\n * Run a plugin's generator\n */\n async runGenerator(plugin: ResolvedPlugin, _target: Target, targetPath: string, launch77Context: Launch77Context, logger?: (message: string) => void): Promise<void> {\n const generatorPath = path.join(plugin.path, 'dist', 'generator.js')\n\n if (!(await this.filesystemService.pathExists(generatorPath))) {\n throw new Error(`Plugin generator not found at: ${generatorPath}`)\n }\n\n logger?.('Running plugin generator...')\n\n try {\n // Import the generator module\n const generatorModule = await import(generatorPath)\n const GeneratorClass = generatorModule.default || generatorModule.Generator\n\n if (!GeneratorClass) {\n throw new Error('Plugin generator does not export a valid Generator class')\n }\n\n // Create generator context\n const context: GeneratorContext = {\n appPath: targetPath,\n appName: launch77Context.appName || '',\n workspaceName: launch77Context.workspaceName || '',\n pluginPath: plugin.path,\n }\n\n // Instantiate and run the generator\n const generator = new GeneratorClass(context)\n\n if (typeof generator.run !== 'function') {\n throw new Error('Plugin generator does not have a run() method')\n }\n\n await generator.run()\n } catch (error) {\n throw new Error(`Failed to run plugin generator: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Track plugin installation in package.json\n */\n async trackInstallation(plugin: ResolvedPlugin, targetPath: string): Promise<void> {\n const packageJsonPath = path.join(targetPath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n throw new Error(`package.json not found at: ${packageJsonPath}`)\n }\n\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n\n // Initialize launch77 section if it doesn't exist\n if (!packageJson.launch77) {\n packageJson.launch77 = {}\n }\n\n if (!packageJson.launch77.installedPlugins) {\n packageJson.launch77.installedPlugins = {}\n }\n\n // Create installation record\n const installationRecord: InstalledPluginMetadata = {\n package: plugin.name,\n version: plugin.version,\n installedAt: new Date().toISOString(),\n source: plugin.source,\n }\n\n // Extract the plugin key from the package name\n const pluginKey = this.extractPluginKey(plugin.name)\n\n // Add or update the plugin record\n packageJson.launch77.installedPlugins[pluginKey] = installationRecord\n\n // Write updated package.json\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n }\n\n /**\n * Check if a plugin is already installed\n */\n async isInstalled(pluginName: string, targetPath: string): Promise<boolean> {\n const packageJsonPath = path.join(targetPath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n return false\n }\n\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n const pluginKey = this.extractPluginKey(pluginName)\n\n return !!packageJson.launch77?.installedPlugins?.[pluginKey]\n }\n\n /**\n * Get installed plugin metadata\n */\n async getInstalledPlugin(pluginName: string, targetPath: string): Promise<InstalledPluginMetadata | null> {\n const packageJsonPath = path.join(targetPath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n return null\n }\n\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n const pluginKey = this.extractPluginKey(pluginName)\n\n return packageJson.launch77?.installedPlugins?.[pluginKey] || null\n }\n\n /**\n * Uninstall a plugin\n */\n async uninstall(pluginName: string, targetPath: string): Promise<void> {\n const packageJsonPath = path.join(targetPath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n throw new Error(`package.json not found at: ${packageJsonPath}`)\n }\n\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n const pluginKey = this.extractPluginKey(pluginName)\n\n if (!packageJson.launch77?.installedPlugins?.[pluginKey]) {\n throw new Error(`Plugin '${pluginName}' is not installed`)\n }\n\n // Remove the plugin record\n delete packageJson.launch77.installedPlugins[pluginKey]\n\n // Clean up empty objects\n if (Object.keys(packageJson.launch77.installedPlugins).length === 0) {\n delete packageJson.launch77.installedPlugins\n }\n\n if (Object.keys(packageJson.launch77).length === 0) {\n delete packageJson.launch77\n }\n\n // Write updated package.json\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n }\n\n /**\n * Install npm dependencies\n */\n async installDependencies(targetPath: string): Promise<void> {\n try {\n await execa('npm', ['install'], { cwd: targetPath })\n } catch (error) {\n // Try with legacy peer deps if regular install fails\n try {\n await execa('npm', ['install', '--legacy-peer-deps'], { cwd: targetPath })\n } catch (retryError) {\n throw new Error(`Failed to install dependencies: ${retryError instanceof Error ? retryError.message : 'Unknown error'}`)\n }\n }\n }\n\n /**\n * Extract plugin key from package name\n */\n private extractPluginKey(packageName: string): string {\n // Remove scope and plugin- prefix\n // @launch77-shared/plugin-ui -> ui\n // @company/plugin-analytics -> analytics\n // plugin-test -> test\n let key = packageName\n\n // Remove scope if present\n if (key.startsWith('@')) {\n const parts = key.split('/')\n key = parts[1] || key\n }\n\n // Remove plugin- prefix\n if (key.startsWith('plugin-')) {\n key = key.substring('plugin-'.length)\n }\n\n return key\n }\n}\n","import * as path from 'path'\n\nimport { FilesystemService } from '../../filesystem/services/filesystem-service.js'\n\n/**\n * Metadata about an installed plugin\n */\nexport interface InstalledPluginMetadata {\n package: string\n version: string\n installedAt: string\n source: 'local' | 'npm'\n}\n\n/**\n * Reference to the template used to create this package\n */\nexport interface TemplateReference {\n package: string\n version: string\n source: 'local' | 'npm'\n createdAt: string\n}\n\n/**\n * The launch77 section within package.json\n */\nexport interface PackageManifest {\n installedPlugins?: Record<string, InstalledPluginMetadata>\n template?: TemplateReference\n}\n\n/**\n * Type for package.json structure with launch77 section\n */\ninterface PackageJsonWithLaunch77 {\n name?: string\n version?: string\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n launch77?: PackageManifest\n [key: string]: unknown\n}\n\n/**\n * Service responsible for package manifest operations.\n * Handles reading and writing launch77 metadata in package.json files.\n * The \"package manifest\" refers to the launch77 section within package.json.\n */\nexport class PackageManifestService {\n private filesystemService: FilesystemService\n\n constructor(filesystemService?: FilesystemService) {\n this.filesystemService = filesystemService || new FilesystemService()\n }\n\n /**\n * Read the launch77 section (package manifest) from a package.json\n */\n async readPackageManifest(packagePath: string): Promise<PackageManifest | null> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n return null\n }\n\n try {\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n return packageJson.launch77 || null\n } catch (error) {\n throw new Error(`Failed to read package manifest from ${packageJsonPath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Write the launch77 section (package manifest) to a package.json\n */\n async writePackageManifest(packagePath: string, manifest: PackageManifest): Promise<void> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n throw new Error(`package.json not found at: ${packageJsonPath}`)\n }\n\n try {\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n packageJson.launch77 = manifest\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n } catch (error) {\n throw new Error(`Failed to write package manifest to ${packageJsonPath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Add an installed plugin to the manifest\n */\n async addInstalledPlugin(packagePath: string, pluginKey: string, metadata: InstalledPluginMetadata): Promise<void> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n throw new Error(`package.json not found at: ${packageJsonPath}`)\n }\n\n try {\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n\n // Initialize launch77 section if needed\n if (!packageJson.launch77) {\n packageJson.launch77 = {}\n }\n\n if (!packageJson.launch77.installedPlugins) {\n packageJson.launch77.installedPlugins = {}\n }\n\n // Add the plugin\n packageJson.launch77.installedPlugins[pluginKey] = metadata\n\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n } catch (error) {\n throw new Error(`Failed to add plugin to package manifest: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Remove an installed plugin from the manifest\n */\n async removeInstalledPlugin(packagePath: string, pluginKey: string): Promise<void> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n throw new Error(`package.json not found at: ${packageJsonPath}`)\n }\n\n try {\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n\n if (!packageJson.launch77?.installedPlugins?.[pluginKey]) {\n throw new Error(`Plugin '${pluginKey}' is not installed`)\n }\n\n // Remove the plugin\n delete packageJson.launch77.installedPlugins[pluginKey]\n\n // Clean up empty objects\n if (Object.keys(packageJson.launch77.installedPlugins).length === 0) {\n delete packageJson.launch77.installedPlugins\n }\n\n if (Object.keys(packageJson.launch77).length === 0) {\n delete packageJson.launch77\n }\n\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n } catch (error) {\n throw new Error(`Failed to remove plugin from package manifest: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Get installed plugins from the manifest\n */\n async getInstalledPlugins(packagePath: string): Promise<Record<string, InstalledPluginMetadata>> {\n const manifest = await this.readPackageManifest(packagePath)\n return manifest?.installedPlugins || {}\n }\n\n /**\n * Check if a plugin is installed\n */\n async isPluginInstalled(packagePath: string, pluginKey: string): Promise<boolean> {\n const installedPlugins = await this.getInstalledPlugins(packagePath)\n return !!installedPlugins[pluginKey]\n }\n\n /**\n * Get a specific installed plugin metadata\n */\n async getInstalledPlugin(packagePath: string, pluginKey: string): Promise<InstalledPluginMetadata | null> {\n const installedPlugins = await this.getInstalledPlugins(packagePath)\n return installedPlugins[pluginKey] || null\n }\n\n /**\n * Update package.json dependencies\n */\n async addDependency(packagePath: string, packageName: string, version: string, isDev = false): Promise<void> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n throw new Error(`package.json not found at: ${packageJsonPath}`)\n }\n\n try {\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n\n const depsKey = isDev ? 'devDependencies' : 'dependencies'\n\n if (!packageJson[depsKey]) {\n packageJson[depsKey] = {}\n }\n\n packageJson[depsKey][packageName] = version\n\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n } catch (error) {\n throw new Error(`Failed to add dependency: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Remove a dependency from package.json\n */\n async removeDependency(packagePath: string, packageName: string): Promise<void> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n\n if (!(await this.filesystemService.pathExists(packageJsonPath))) {\n throw new Error(`package.json not found at: ${packageJsonPath}`)\n }\n\n try {\n const packageJson = await this.filesystemService.readJSON<PackageJsonWithLaunch77>(packageJsonPath)\n\n // Check both dependencies and devDependencies\n if (packageJson.dependencies?.[packageName]) {\n delete packageJson.dependencies[packageName]\n if (Object.keys(packageJson.dependencies).length === 0) {\n delete packageJson.dependencies\n }\n }\n\n if (packageJson.devDependencies?.[packageName]) {\n delete packageJson.devDependencies[packageName]\n if (Object.keys(packageJson.devDependencies).length === 0) {\n delete packageJson.devDependencies\n }\n }\n\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n } catch (error) {\n throw new Error(`Failed to remove dependency: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Get the package.json content\n */\n async readPackageJson(packagePath: string): Promise<unknown> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n return await this.filesystemService.readJSON(packageJsonPath)\n }\n\n /**\n * Write the package.json content\n */\n async writePackageJson(packagePath: string, packageJson: unknown): Promise<void> {\n const packageJsonPath = path.join(packagePath, 'package.json')\n await this.filesystemService.writeJSON(packageJsonPath, packageJson)\n }\n}\n"],"mappings":"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","names":["path","path","fs","path","path","fs","os","path","fs","fs","path","chalk","execa","path","execa","fs","path","execa","execa","path","fs","path","fs","fs","fs","chalk","execa","path","execa","execa","path"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@launch77/plugin-runtime",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "tsup",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
|
23
|
-
"lint": "eslint src/**/*.ts",
|
|
23
|
+
"lint": "eslint 'src/**/*.ts'",
|
|
24
|
+
"lint:fix": "eslint 'src/**/*.ts' --fix",
|
|
24
25
|
"test": "vitest run",
|
|
25
26
|
"test:integration": "vitest run --config vitest.integration.config.ts"
|
|
26
27
|
},
|