@crossdelta/platform-sdk 0.19.0 → 0.19.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.
Files changed (46) hide show
  1. package/README.md +27 -5
  2. package/bin/chunk-634PL24Z.mjs +20 -0
  3. package/bin/cli.mjs +604 -0
  4. package/bin/config-CKQHYOF4.mjs +2 -0
  5. package/bin/docs/generators/code-style.md +79 -0
  6. package/bin/docs/generators/natural-language.md +117 -0
  7. package/bin/docs/generators/service.md +129 -60
  8. package/bin/templates/hono-microservice/Dockerfile.hbs +3 -1
  9. package/bin/templates/hono-microservice/src/config/env.ts.hbs +3 -0
  10. package/bin/templates/nest-microservice/Dockerfile.hbs +6 -2
  11. package/bin/templates/nest-microservice/src/config/env.ts.hbs +17 -0
  12. package/bin/templates/nest-microservice/src/main.ts.hbs +2 -1
  13. package/bin/templates/workspace/.github/actions/prepare-build-context/action.yml +58 -6
  14. package/bin/templates/workspace/.github/workflows/build-and-deploy.yml.hbs +25 -3
  15. package/bin/templates/workspace/.github/workflows/publish-packages.yml +6 -8
  16. package/bin/templates/workspace/biome.json.hbs +4 -1
  17. package/bin/templates/workspace/infra/package.json.hbs +2 -2
  18. package/bin/templates/workspace/package.json.hbs +1 -0
  19. package/bin/templates/workspace/packages/contracts/README.md.hbs +5 -5
  20. package/bin/templates/workspace/packages/contracts/package.json.hbs +15 -6
  21. package/bin/templates/workspace/packages/contracts/src/index.ts +1 -1
  22. package/bin/templates/workspace/packages/contracts/tsconfig.json.hbs +6 -1
  23. package/bin/templates/workspace/turbo.json +8 -11
  24. package/bin/templates/workspace/turbo.json.hbs +6 -5
  25. package/dist/facade.d.mts +840 -0
  26. package/dist/facade.d.ts +840 -0
  27. package/dist/facade.js +2294 -0
  28. package/dist/facade.js.map +1 -0
  29. package/dist/facade.mjs +2221 -0
  30. package/dist/facade.mjs.map +1 -0
  31. package/dist/plugin-types-DQOv97Zh.d.mts +180 -0
  32. package/dist/plugin-types-DQOv97Zh.d.ts +180 -0
  33. package/dist/plugin-types.d.mts +1 -0
  34. package/dist/plugin-types.d.ts +1 -0
  35. package/dist/plugin-types.js +19 -0
  36. package/dist/plugin-types.js.map +1 -0
  37. package/dist/plugin-types.mjs +1 -0
  38. package/dist/plugin-types.mjs.map +1 -0
  39. package/dist/plugin.d.mts +31 -0
  40. package/dist/plugin.d.ts +31 -0
  41. package/dist/plugin.js +105 -0
  42. package/dist/plugin.js.map +1 -0
  43. package/dist/plugin.mjs +75 -0
  44. package/dist/plugin.mjs.map +1 -0
  45. package/package.json +118 -99
  46. package/bin/cli.js +0 -540
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/src/config/constants.ts","../cli/src/utils/ascii-chart.ts","../cli/src/core/errors/types.ts","../cli/src/core/errors/cli-error.ts","../cli/src/core/errors/handler.ts","../cli/src/core/errors/index.ts","../cli/src/core/filesystem/watcher.ts","../cli/src/utils/create-workflow-command.ts","../cli/src/utils/debounce.ts","../cli/src/utils/deep.ts","../cli/src/utils/process.ts","../cli/src/utils/environment.ts","../cli/src/utils/fs.ts","../cli/src/utils/logger.ts","../cli/src/utils/merge-contexts.ts","../cli/src/utils/tasks.ts","../cli/src/utils/index.ts","../cli/src/core/packages/config.ts","../cli/src/core/facade/index.ts","../cli/src/core/plugins/loader.ts","../cli/src/core/capabilities/config.ts","../cli/src/core/capabilities/lowering.ts","../cli/src/core/capabilities/types.ts","../cli/src/core/capabilities/parser.ts","../cli/src/core/effects/changes.ts","../cli/src/core/events/index-manager.ts","../cli/src/core/effects/stream.handler.ts","../cli/src/core/effects/handlers.ts","../cli/src/core/flows/service-generation.flow.ts","../cli/src/core/operations/types.ts","../cli/src/commands/create/hono-microservice/templates.ts","../cli/src/core/esm.ts","../cli/src/core/filesystem/index.ts","../cli/src/core/templates/renderer.ts","../cli/src/core/templates/strings.ts","../cli/src/core/templates/hono-bun.template.ts","../cli/src/commands/create/nest-microservice/templates.ts","../cli/src/core/templates/nest.template.ts","../cli/src/core/templates/index.ts","../cli/src/core/flows/effect-builder.ts","../cli/src/core/policies/service-layout.ts","../cli/src/core/flows/port-allocation.ts","../cli/src/core/plugins/types.ts","../cli/src/core/facade/context.ts","../cli/src/core/facade/tools.ts"],"sourcesContent":["/** Binary name used in commands and help text */\nexport const BIN_NAME = 'pf' as const\n\n/** CLI version (read from package.json) */\nexport const CLI_VERSION = process.env.npm_package_version || '0.0.0'\n\n/** Supported package manager lock files */\nexport const LOCK_FILES = [\n 'bun.lock',\n 'bun.lockb',\n 'package-lock.json',\n 'yarn.lock',\n 'pnpm-lock.yaml',\n] as const\n\n/** Default turbo task for development mode */\nexport const DEV_TASK = 'start:dev' as const\n\n/**\n * File patterns for event-driven architecture\n */\nexport const FILE_PATTERNS = {\n /** Event handler file suffix */\n HANDLER: '.handler.ts',\n /** Event definition file suffix */\n EVENT: '.event.ts',\n /** Mock data file suffix */\n MOCK: '.mock.json',\n /** Glob pattern for event handlers */\n HANDLER_GLOB: '**/*.handler.ts',\n /** Glob pattern for mock files */\n MOCK_GLOB: '**/*.mock.json',\n} as const\n\n/**\n * Standard directory paths within a workspace\n */\nexport const WORKSPACE_PATHS = {\n /** Contracts package location */\n CONTRACTS: 'packages/contracts',\n /** Events directory within contracts */\n EVENTS: 'src/events',\n /** Infrastructure package location */\n INFRA: 'infra',\n /** Services directory */\n SERVICES: 'services',\n} as const\n\n/**\n * CLI Exit Codes\n *\n * Exit codes follow Unix conventions:\n * - 0: Success\n * - 1: General errors\n * - 2: Misuse of shell command / usage errors\n * - 64-78: Reserved for application-specific errors (BSD sysexits.h)\n * - 130: Ctrl+C (SIGINT)\n *\n * Use these via the typed error classes in core/errors/:\n * - WorkspaceError → 64\n * - ValidationError → 65\n * - ConfigError → 66\n * - IoError → 74\n * - PermissionError → 77\n * - CancelledError → 130\n *\n * @see cli/src/core/errors/types.ts for the ExitCode enum\n */\n","import chalk, { type ForegroundColorName } from 'chalk'\n\nexport type Entry = {\n label: string\n value: number\n color?: ForegroundColorName\n barColor?: ForegroundColorName\n}\n\ntype Options = {\n title?: string\n maxBarWidth?: number\n unit?: string\n footer?: string\n barColor?: ForegroundColorName\n labelColor?: ForegroundColorName\n}\n\n/**\n * Generates an ASCII bar chart from an array of entries.\n *\n * @param entries - An array of entries, each containing a label and a value.\n * @param options - Optional configuration for the chart, including title, maximum bar width, and unit.\n * @returns The ASCII bar chart as a string.\n */\nexport function generateAsciiBarChart(entries: Entry[], options?: Options): string {\n if (entries.length === 0) {\n return 'No entries to display.'\n }\n\n const title = options?.title || 'Benchmark Results'\n const footer = options?.footer || ''\n const maxBarWidth = options?.maxBarWidth || 50\n const unit = options?.unit || ''\n const maxValue = Math.max(...entries.map((e) => e.value))\n const lines: string[] = []\n\n lines.push('')\n lines.push(title)\n lines.push('')\n\n for (const entry of entries) {\n const barSymbol = getBarSymbol(entry.barColor ?? options?.barColor)\n const line = formatBarLine(entry, maxValue, maxBarWidth, barSymbol, unit, options?.labelColor)\n lines.push(line)\n }\n\n if (footer) {\n lines.push('')\n lines.push(footer)\n }\n\n return lines.join('\\n')\n}\n\n/**\n * Returns the bar symbol with optional color.\n * @param barColor - The color of the bar.\n * @returns The bar symbol.\n */\nfunction getBarSymbol(barColor?: ForegroundColorName): string {\n return barColor ? chalk[barColor]('▇') : '▇'\n}\n\n/**\n * Formats a single bar line for the chart.\n * @param entry - The entry.\n * @param maxValue - The maximum value in the dataset.\n * @param maxBarWidth - The maximum width of the bar.\n * @param barSymbol - The symbol used for the bar.\n * @param unit - The unit to display with the value.\n * @param labelColor - The color of the label.\n * @returns The formatted bar line.\n */\nfunction formatBarLine(\n entry: Entry,\n maxValue: number,\n maxBarWidth: number,\n barSymbol: string,\n unit: string,\n labelColor?: ForegroundColorName,\n): string {\n const barLength = Math.round((entry.value / maxValue) * maxBarWidth)\n const bar = entry.barColor ? chalk[entry.barColor](barSymbol.repeat(barLength)) : barSymbol.repeat(barLength)\n const color: ForegroundColorName = (entry.color ?? labelColor) as ForegroundColorName\n const label = chalk.bold(color ? chalk[color](entry.label.padEnd(12)) : entry.label.padEnd(12))\n return `${label} ${bar} ${entry.value.toLocaleString()}${unit ? ` ${unit}` : ''}`\n}\n","/**\n * CLI Error Types\n *\n * Exit codes follow Unix conventions:\n * - 0: Success\n * - 1: General errors\n * - 2: Misuse of shell command\n * - 64-78: Reserved for application-specific errors (BSD sysexits.h)\n * - 130: Ctrl+C (SIGINT)\n */\n\n/** Standard CLI exit codes */\nexport const ExitCode = {\n SUCCESS: 0,\n GENERAL_ERROR: 1,\n USAGE_ERROR: 2,\n WORKSPACE_ERROR: 64,\n VALIDATION_ERROR: 65,\n CONFIG_ERROR: 66,\n IO_ERROR: 74,\n PERMISSION_ERROR: 77,\n CANCELLED: 130,\n} as const\n\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode]\n\n/** Error category for grouping and filtering */\nexport type ErrorCategory =\n | 'workspace'\n | 'validation'\n | 'config'\n | 'io'\n | 'network'\n | 'process'\n | 'user'\n","/**\n * CLI Error Classes\n *\n * Typed error system for consistent error handling across the CLI.\n * All CLI errors extend CliError and include exit codes for proper process termination.\n */\n\nimport { type ErrorCategory, ExitCode, type ExitCodeValue } from './types'\n\nexport interface CliErrorOptions {\n cause?: Error\n hint?: string\n category?: ErrorCategory\n}\n\n/**\n * Base error class for all CLI errors.\n * Provides exit code, category, and optional hint for user guidance.\n */\nexport class CliError extends Error {\n readonly exitCode: ExitCodeValue\n readonly category: ErrorCategory\n readonly hint?: string\n readonly cause?: Error\n\n constructor(\n message: string,\n exitCode: ExitCodeValue = ExitCode.GENERAL_ERROR,\n options: CliErrorOptions = {},\n ) {\n super(message)\n this.name = 'CliError'\n this.exitCode = exitCode\n this.category = options.category ?? 'process'\n this.hint = options.hint\n this.cause = options.cause\n }\n\n /** Format error for user display (no stack trace) */\n toUserMessage(): string {\n const parts = [this.message]\n if (this.hint) parts.push(`\\nHint: ${this.hint}`)\n return parts.join('')\n }\n}\n\n/**\n * Error thrown when not in a valid workspace directory.\n */\nexport class WorkspaceError extends CliError {\n constructor(message: string, options: CliErrorOptions = {}) {\n super(message, ExitCode.WORKSPACE_ERROR, {\n ...options,\n category: 'workspace',\n })\n this.name = 'WorkspaceError'\n }\n}\n\n/**\n * Error thrown for invalid user input or arguments.\n */\nexport class ValidationError extends CliError {\n readonly field?: string\n\n constructor(message: string, field?: string, options: CliErrorOptions = {}) {\n super(message, ExitCode.VALIDATION_ERROR, {\n ...options,\n category: 'validation',\n })\n this.name = 'ValidationError'\n this.field = field\n }\n}\n\n/**\n * Error thrown for configuration issues (missing files, invalid format).\n */\nexport class ConfigError extends CliError {\n readonly configPath?: string\n\n constructor(message: string, configPath?: string, options: CliErrorOptions = {}) {\n super(message, ExitCode.CONFIG_ERROR, {\n ...options,\n category: 'config',\n })\n this.name = 'ConfigError'\n this.configPath = configPath\n }\n}\n\n/**\n * Error thrown for file system operations (read/write failures).\n */\nexport class IoError extends CliError {\n readonly path?: string\n\n constructor(message: string, path?: string, options: CliErrorOptions = {}) {\n super(message, ExitCode.IO_ERROR, {\n ...options,\n category: 'io',\n })\n this.name = 'IoError'\n this.path = path\n }\n}\n\n/**\n * Error thrown when user cancels an operation.\n */\nexport class CancelledError extends CliError {\n constructor(message = 'Operation cancelled', options: CliErrorOptions = {}) {\n super(message, ExitCode.CANCELLED, {\n ...options,\n category: 'user',\n })\n this.name = 'CancelledError'\n }\n}\n\n/**\n * Error thrown for command usage issues (wrong arguments, missing options).\n */\nexport class UsageError extends CliError {\n constructor(message: string, options: CliErrorOptions = {}) {\n super(message, ExitCode.USAGE_ERROR, {\n ...options,\n category: 'validation',\n })\n this.name = 'UsageError'\n }\n}\n","/**\n * Error Handler\n *\n * Centralized error handling for CLI commands.\n * Converts errors to user-friendly messages and appropriate exit codes.\n */\n\nimport chalk from 'chalk'\nimport { CancelledError, CliError } from './cli-error'\nimport { ExitCode } from './types'\n\n/**\n * Type guard to check if a value is an Error instance.\n */\nexport const isError = (value: unknown): value is Error =>\n value instanceof Error\n\n/**\n * Safely extract error message from unknown error value.\n * Handles Error instances, strings, and other types.\n */\nexport const getErrorMessage = (error: unknown): string => {\n if (isError(error)) return error.message\n if (typeof error === 'string') return error\n return String(error)\n}\n\n/** Error names that indicate prompt cancellation */\nconst PROMPT_CANCELLATION_NAMES = [\n 'ExitPromptError',\n]\n\n/** Message patterns that indicate user cancellation */\nconst CANCELLATION_MESSAGE_PATTERNS = [\n 'Cancelled prompt',\n 'User force closed',\n]\n\n/** Error codes that indicate cancellation ONLY when accompanied by prompt signal */\nconst CANCELLATION_CODES = [\n 'ERR_USE_AFTER_CLOSE',\n]\n\n/**\n * Check if error has a prompt-related signal (name or message pattern).\n * Used to determine if error codes should be treated as cancellation.\n */\nconst hasPromptSignal = (error: Error): boolean =>\n PROMPT_CANCELLATION_NAMES.some((name) => error.name?.includes(name)) ||\n CANCELLATION_MESSAGE_PATTERNS.some((pattern) => error.message?.includes(pattern))\n\n/**\n * Check if error is a user cancellation (Ctrl+C, ESC, etc.)\n *\n * To avoid masking real bugs, error codes like ERR_USE_AFTER_CLOSE\n * are only treated as cancellation when accompanied by a prompt signal.\n */\nexport const isCancellationError = (error: unknown): boolean => {\n if (error instanceof CancelledError) return true\n if (!(error instanceof Error)) return false\n\n // Check for prompt-related error names\n if (PROMPT_CANCELLATION_NAMES.some((name) => error.name?.includes(name))) {\n return true\n }\n\n // Check for cancellation message patterns\n if (CANCELLATION_MESSAGE_PATTERNS.some((pattern) => error.message?.includes(pattern))) {\n return true\n }\n\n // Check error.code only if there's a prompt signal\n const errorCode = (error as NodeJS.ErrnoException).code\n if (errorCode && CANCELLATION_CODES.includes(errorCode)) {\n // Only treat as cancellation if there's also a prompt signal\n return hasPromptSignal(error)\n }\n\n return false\n}\n\n/**\n * Format error for display to user.\n * CliErrors use their toUserMessage(), others get a generic format.\n */\nexport const formatError = (error: unknown): string => {\n if (error instanceof CliError) {\n const message = error.toUserMessage()\n return chalk.red(`✖ ${message || 'Unexpected error (re-run with DEBUG=true for details)'}`)\n }\n\n if (error instanceof Error) {\n const message = error.message?.trim()\n if (!message) {\n return chalk.red('✖ Unexpected error (re-run with DEBUG=true for details)')\n }\n return chalk.red(`✖ ${message}`)\n }\n\n const str = String(error)\n if (!str || str === 'undefined' || str === 'null') {\n return chalk.red('✖ Unexpected error (re-run with DEBUG=true for details)')\n }\n return chalk.red(`✖ ${str}`)\n}\n\n/**\n * Get appropriate exit code for an error.\n */\nexport const getExitCode = (error: unknown): number => {\n if (error instanceof CliError) return error.exitCode\n if (isCancellationError(error)) return ExitCode.CANCELLED\n return ExitCode.GENERAL_ERROR\n}\n\nexport interface HandleErrorOptions {\n /** Print stack trace for debugging */\n debug?: boolean\n /** Exit process after handling (default: true) */\n exit?: boolean\n /** Custom logger (default: console.error) */\n logger?: (message: string) => void\n}\n\n/**\n * Handle an error with appropriate user messaging and exit code.\n *\n * @example\n * try {\n * await someCommand()\n * } catch (error) {\n * handleError(error)\n * }\n */\nexport const handleError = (\n error: unknown,\n options: HandleErrorOptions = {},\n): void => {\n const { debug = process.env.DEBUG === 'true', exit = true, logger = console.error } = options\n\n // Silent exit for cancellations\n if (isCancellationError(error)) {\n if (exit) process.exit(ExitCode.CANCELLED)\n return\n }\n\n // Print error message\n logger(formatError(error))\n\n // Print stack trace in debug mode\n if (debug && error instanceof Error && error.stack) {\n logger(chalk.dim(error.stack))\n }\n\n // Print hint if available\n if (error instanceof CliError && error.hint) {\n logger(chalk.dim(`\\nHint: ${error.hint}`))\n }\n\n if (exit) {\n process.exit(getExitCode(error))\n }\n}\n\n/**\n * Wrap an async function with error handling.\n * Useful for command action handlers.\n *\n * @example\n * command.action(withErrorHandling(async () => {\n * await doSomething()\n * }))\n */\nexport const withErrorHandling = <T extends unknown[], R>(\n fn: (...args: T) => Promise<R>,\n options?: HandleErrorOptions,\n): ((...args: T) => Promise<R | undefined>) => {\n return async (...args: T): Promise<R | undefined> => {\n try {\n return await fn(...args)\n } catch (error) {\n handleError(error, options)\n return undefined\n }\n }\n}\n","/**\n * CLI Error System\n *\n * Typed errors with exit codes for consistent error handling.\n */\n\nexport * from './cli-error'\nexport * from './handler'\nexport * from './types'\n","import { existsSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport chokidar, { type FSWatcher } from 'chokidar'\nimport { debounce } from '../../utils'\nimport { getWorkspacePackageJson } from '../packages/config'\nimport type { WorkspacePathConfig } from '../packages/types'\n\nexport const GENERATION_LOCK_FILE = '.pf-generating'\n\nconst getLockFilePath = (root: string) => join(root, GENERATION_LOCK_FILE)\n\nconst isGenerating = (root: string): boolean => existsSync(getLockFilePath(root))\n\nexport const createLockFile = (root: string): void => {\n writeFileSync(getLockFilePath(root), '', 'utf-8')\n}\n\nexport const removeLockFile = (root: string): void => {\n const lockFile = getLockFilePath(root)\n if (existsSync(lockFile)) unlinkSync(lockFile)\n}\n\nexport const getWatchablePaths = (root: string): Array<Required<Pick<WorkspacePathConfig, 'path'>> & WorkspacePathConfig> => {\n const pkg = getWorkspacePackageJson(root)\n const paths = pkg?.pf?.paths\n\n if (!paths) return [{ path: 'services' }, { path: 'apps' }]\n\n return Object.values(paths)\n .filter((config): config is Required<Pick<WorkspacePathConfig, 'path'>> & WorkspacePathConfig =>\n typeof config === 'object' && config !== null && config.watch === true && typeof config.path === 'string'\n )\n}\n\n/**\n * Watch for workspace changes that require a restart.\n *\n * Strategy:\n * 1. Lock file removal (.pf-generating) -> pf new completed\n * 2. Service directory watch with usePolling -> catches rm -rf reliably\n * 3. Package.json changes -> dependency updates\n *\n * Why usePolling for directories?\n * - Linux inotify misses rm -rf because it's too fast\n * - usePolling with 1s interval reliably catches deletions\n * - Only used for top-level service dirs (low overhead)\n */\nexport const observeWorkspacePackages = (root: string, onChange: () => Promise<void>): () => Promise<void> => {\n removeLockFile(root)\n\n const dirs = getWatchablePaths(root)\n const lockFilePath = getLockFilePath(root)\n\n const guardedOnChange = async () => {\n if (isGenerating(root)) return\n await onChange()\n }\n\n const debouncedOnChange = debounce(guardedOnChange, 300)\n\n const watchers: FSWatcher[] = []\n\n // Lock file removal triggers immediate restart after pf new\n watchers.push(\n chokidar\n .watch(lockFilePath, { ignoreInitial: true })\n .on('unlink', () => onChange())\n )\n\n // Watch service directories with usePolling (inotify misses rm -rf)\n for (const dir of dirs) {\n const basePath = join(root, dir.path)\n if (!existsSync(basePath)) continue\n\n const ignored = dir.ignorePatterns?.map((pattern) => join(basePath, pattern))\n\n watchers.push(\n chokidar\n .watch(basePath, {\n ignoreInitial: true,\n depth: 0,\n ignored,\n usePolling: true,\n interval: 1000,\n })\n .on('addDir', (dirPath) => dirPath !== basePath && debouncedOnChange())\n .on('unlinkDir', (dirPath) => dirPath !== basePath && debouncedOnChange())\n )\n\n // Watch package.json without polling (inotify works fine for file changes)\n watchers.push(\n chokidar\n .watch(`${basePath}/*/package.json`, { ignoreInitial: true, ignored })\n .on('add', debouncedOnChange)\n .on('change', debouncedOnChange)\n )\n }\n\n return async () => {\n await Promise.all(watchers.map(w => w.close()))\n }\n}\n","import chalk from 'chalk'\nimport { Command } from 'commander'\nimport { Listr } from 'listr2'\nimport { handleError as handleCliError } from '../core/errors'\nimport { createLockFile, removeLockFile } from '../core/filesystem/watcher'\nimport { findWorkspaceRoot } from '../core/packages/config'\nimport type { BaseTask } from '../tasks'\n\n/**\n * Configuration interface for defining a CLI command workflow.\n *\n * @template Args - The type of the arguments passed to the command.\n * @template Options - The type of the options passed to the command.\n * @template Context - The type of the context used during task execution.\n */\nexport interface CommandConfig<Args, Options, Context> {\n /**\n * The name of the command.\n */\n name: string\n\n /**\n * A brief description of the command.\n */\n description: string\n\n /**\n * A list of arguments for the command, where each argument is defined as a tuple\n * containing the argument name and its description.\n */\n arguments?: [string, string][]\n\n /**\n * A list of options for the command, where each option is defined as a tuple\n * containing the option flag and its description.\n */\n options?: [string, string][]\n\n /**\n * An example usage string to be displayed in the help text.\n */\n exampleUsage?: string\n\n /**\n * Additional information to be displayed in the help text, such as project types.\n * This can be a string or a function that returns a string.\n */\n additionalInfo?: string | (() => string)\n\n /**\n * A function to build the context for the command. The context is used during\n * task execution and can be built asynchronously.\n *\n * @param args - The parsed arguments passed to the command.\n * @param options - The parsed options passed to the command.\n * @returns A promise resolving to the context or the context itself.\n */\n buildContext: (args: Args, options: Options) => Promise<Context> | Context\n\n /**\n * Optional function to determine if the standard workflow should be skipped.\n * When this returns true, onSkipWorkflow will be called instead of the normal workflow.\n *\n * @param args - The parsed arguments passed to the command.\n * @param options - The parsed options passed to the command.\n * @returns True to skip the workflow, false to continue normally.\n */\n shouldSkipWorkflow?: (args: Args, options: Options) => boolean\n\n /**\n * Handler function called when shouldSkipWorkflow returns true.\n * Use this to implement alternative behavior (e.g., AI-powered generation).\n *\n * @param args - The parsed arguments passed to the command.\n * @param options - The parsed options passed to the command.\n */\n onSkipWorkflow?: (args: Args, options: Options) => Promise<void> | void\n\n /**\n * A list of tasks to be executed as prompts before the main execution tasks.\n * These tasks can be used to gather additional input or perform setup steps.\n */\n prompts?: BaseTask<Context>[]\n\n /**\n * A list of tasks to be executed as the main workflow of the command.\n */\n actions: BaseTask<Context>[]\n\n /**\n * A callback function to be executed after all tasks are completed.\n *\n * @param ctx - The context used during task execution.\n */\n onComplete?: (ctx: Context) => void | Promise<void>\n}\n\n/**\n * Creates a command for the CLI workflow.\n *\n * This function sets up a command with arguments, options, and tasks to be executed\n * when the command is run.\n *\n * It uses the `commander` library for command-line interface and `listr2` for task management.\n */\nexport const createWorkflowCommand = <Args, Options = unknown, Context = unknown>(\n config: CommandConfig<Args, Options, Context>,\n) => {\n const cmd = new Command(config.name).description(config.description).showHelpAfterError()\n\n config.arguments?.forEach(([arg, desc]) => {\n cmd.argument(arg, desc)\n })\n config.options?.forEach(([flag, desc]) => {\n cmd.option(flag, desc)\n })\n\n if (config.exampleUsage) {\n cmd.addHelpText('after', () => `${chalk.cyan.bold('\\nExample:')}\\n${chalk.bold(config.exampleUsage)}\\n`)\n }\n\n if (config.additionalInfo) {\n cmd.addHelpText('after', () => {\n const info = typeof config.additionalInfo === 'function' ? config.additionalInfo() : config.additionalInfo\n return info ?? ''\n })\n }\n\n const executeWorkflow = async (context: Context) => {\n if (config.prompts?.length) {\n await new Listr(resolveTasks(config.prompts, context), {\n rendererOptions: { lazy: true, showErrorMessage: false },\n }).run(context)\n }\n\n await new Listr(resolveTasks(config.actions, context), {\n rendererOptions: { lazy: false, showErrorMessage: false },\n }).run(context)\n\n await config.onComplete?.(context)\n }\n\n const setupLockFile = (): string | null => {\n try {\n const root = findWorkspaceRoot()\n createLockFile(root)\n return root\n } catch {\n return null\n }\n }\n\n cmd.action(async (...args: unknown[]) => {\n let workspaceRoot: string | null = null\n\n try {\n const command = args.at(-1) as Command\n const rawArgs = command.args\n const options = command.opts() as Options\n const argsObj = mapArgsToObject<Args>(config.arguments ?? [], rawArgs)\n\n if (config.shouldSkipWorkflow?.(argsObj, options)) {\n await config.onSkipWorkflow?.(argsObj, options)\n return\n }\n\n const context = await config.buildContext(argsObj, options)\n workspaceRoot = setupLockFile()\n\n await executeWorkflow(context)\n } catch (error) {\n // Use centralized error handler with exit disabled (we handle cleanup first)\n handleCliError(error, { exit: false })\n } finally {\n if (workspaceRoot) {\n removeLockFile(workspaceRoot)\n }\n }\n })\n\n return cmd\n}\n\n/**\n * Maps command-line arguments to an object based on the provided argument definitions.\n */\nconst mapArgsToObject = <Args>(argDefs: [string, string][], rawArgs: unknown[]): Args => {\n const entries = argDefs.map(([argDef], index) => {\n const name = argDef.replace(/[<>[\\]]/g, '')\n return [name, rawArgs[index]]\n })\n\n return Object.fromEntries(entries) as Args\n}\n\n/**\n * Resolves tasks by executing any functions in the task array and returning the resolved tasks.\n */\nconst resolveTasks = <Ctx>(tasks: BaseTask<Ctx>[], ctx: Ctx): BaseTask<Ctx>[] =>\n tasks.map((task) => (typeof task === 'function' ? (task as (ctx: Ctx) => BaseTask<Ctx>)(ctx) : task))\n","/**\n * Creates a debounced version of an async function that delays execution\n * until after `wait` milliseconds have elapsed since the last call.\n *\n * @param fn - The async function to debounce\n * @param wait - The number of milliseconds to delay\n * @returns A debounced version of the function that returns a Promise\n */\nexport const debounce = <T extends (...args: any[]) => Promise<any>>(\n fn: T,\n wait: number\n): ((...args: Parameters<T>) => Promise<void>) => {\n let timeout: NodeJS.Timeout | null = null\n\n return (...args: Parameters<T>): Promise<void> => {\n if (timeout) clearTimeout(timeout)\n\n return new Promise<void>((resolve) => {\n timeout = setTimeout(async () => {\n timeout = null\n await fn(...args)\n resolve()\n }, wait)\n })\n }\n}\n","/**\n * Sets a value at a given path in an object, creating nested objects as needed.\n */\nexport function setDeep(obj: Record<string, unknown>, path: string, value: any) {\n const keys = path.split('.')\n let current = obj\n\n while (keys.length > 1) {\n const key = keys.shift() as string\n if (!(key in current)) current[key] = {}\n current = current[key] as Record<string, unknown>\n }\n current[keys[0]] = value\n}\n","import { execaSync } from 'execa'\n\n/**\n * Checks if a command is available on the system.\n * @param command The command to check.\n * @returns {boolean} True if the command is available, false otherwise.\n */\nexport function isCommandAvailable(command: string): boolean {\n try {\n execaSync(command, ['--version'])\n return true\n } catch {\n return false\n }\n}\n","import { isCommandAvailable } from './process'\n\ntype Editor = 'code' | 'phpstorm'\n\n/**\n * Detects the available editor on the system.\n * @returns {string} The name of the detected editor.\n */\nexport const detectEditor = (): Editor => {\n if (isCommandAvailable('code')) return 'code'\n if (isCommandAvailable('phpstorm')) return 'phpstorm'\n\n return 'code'\n}\n","import { readdirSync } from 'node:fs'\nimport { dirname, isAbsolute, join, normalize, resolve, sep } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { packageUpSync } from 'package-up'\nimport { rimraf } from 'rimraf'\n\nimport { IoError } from '../core/errors'\nimport { findWorkspaceRoot, isInWorkspace } from '../core/packages/config'\n\n/**\n * Get the filename for the current module.\n * Uses static import for ESM compatibility.\n */\nconst getModuleFilename = (): string => {\n // In ESM context (CLI is always ESM)\n if (typeof import.meta?.url === 'string') {\n return fileURLToPath(import.meta.url)\n }\n // Fallback to cwd\n return process.cwd()\n}\n\n/**\n * Resolves the absolute path of a given path relative to the workspace root.\n * Falls back to process.cwd() if not in a workspace.\n *\n * @param path - The path to resolve.\n */\nexport const absolutePath = (path: string) => {\n const base = isInWorkspace() ? findWorkspaceRoot() : process.cwd()\n return join(base, path)\n}\n\n/**\n * Validates that a file path is safe to write within a base directory.\n * Prevents path traversal attacks by rejecting:\n * - Empty paths\n * - Absolute paths\n * - Paths containing '..' that escape the base directory\n * - Windows drive paths (e.g., 'C:\\')\n *\n * @param filePath - The relative path to validate\n * @param baseDir - The base directory that filePath must stay within\n * @returns The resolved absolute path if safe\n * @throws IoError if the path is unsafe\n */\nexport const validateSafePath = (filePath: string, baseDir: string): string => {\n // Reject empty or whitespace-only paths\n if (!filePath || !filePath.trim()) {\n throw new IoError(\n 'Path cannot be empty',\n filePath,\n { hint: 'Provide a valid relative path' },\n )\n }\n\n // Reject absolute paths (Unix and Windows)\n if (isAbsolute(filePath)) {\n throw new IoError(\n `Absolute paths are not allowed: ${filePath}`,\n filePath,\n { hint: 'Use a relative path within the target directory' },\n )\n }\n\n // Reject Windows drive letters (e.g., 'C:', 'D:')\n if (/^[a-zA-Z]:/.test(filePath)) {\n throw new IoError(\n `Windows drive paths are not allowed: ${filePath}`,\n filePath,\n { hint: 'Use a relative path within the target directory' },\n )\n }\n\n // Normalize path separators to Unix-style for consistent checking\n const unixPath = filePath.replace(/\\\\/g, '/')\n\n // Check for path traversal patterns before normalization\n // This catches attempts to use .. in various forms\n const segments = unixPath.split('/')\n if (segments.some((segment) => segment === '..')) {\n throw new IoError(\n `Path traversal not allowed: ${filePath}`,\n filePath,\n { hint: 'The path must stay within the target directory' },\n )\n }\n\n // Normalize the path to resolve . segments\n const normalizedPath = normalize(filePath)\n\n // Resolve the full path and verify it's within baseDir\n const resolvedBase = resolve(baseDir)\n const resolvedFull = resolve(baseDir, normalizedPath)\n\n // Ensure the resolved path is within or equal to baseDir\n if (!resolvedFull.startsWith(resolvedBase + sep) && resolvedFull !== resolvedBase) {\n throw new IoError(\n `Path escapes target directory: ${filePath}`,\n filePath,\n { hint: 'The path must stay within the target directory' },\n )\n }\n\n return resolvedFull\n}\n\n/**\n * Checks if a directory is empty.\n *\n * @param dir - The directory to check.\n */\nexport const isEmptyDir = (dir: string) => {\n try {\n return readdirSync(dir).length === 0\n } catch {\n return true\n }\n}\n\nexport const isProjectDir = () => {\n try {\n return getProjectRoot() !== undefined\n } catch {\n return false\n }\n}\n\nexport function getCliRoot(): string {\n const packageJsonPath = packageUpSync({ cwd: dirname(getModuleFilename()) })\n\n if (!packageJsonPath) {\n throw new Error('Could not find package.json')\n }\n\n return dirname(packageJsonPath)\n}\n\nexport function getProjectRoot(): string {\n const packageJsonPath = packageUpSync()\n\n if (!packageJsonPath) {\n throw new Error('You are not in a project directory')\n }\n\n return dirname(packageJsonPath)\n}\n\n/**\n * Executes a command synchronously.\n *\n * @param dir - The directory to remove.\n * @returns\n */\nexport const removeDir = (dir: string) => rimraf(dir)\n\n/**\n * Resolves the path of a defined package file.\n *\n * @param pkgName - The name of the package to resolve.\n * @param path - The path to resolve from the package.\n * @returns The resolved path.\n */\nexport const resolveFromPackage = (pkgName: string, path: string): string =>\n resolve(require.resolve(pkgName), `../${path}`)\n","import chalk from 'chalk'\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'\n\nconst LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n}\n\nconst isLogLevel = (value: string | undefined): value is LogLevel =>\n value === 'debug' || value === 'info' || value === 'warn' || value === 'error' || value === 'silent'\n\nconst getLogLevel = (): LogLevel => {\n const envLevel = process.env.LOG_LEVEL\n if (isLogLevel(envLevel)) return envLevel\n if (process.env.DEBUG === 'true') return 'debug'\n if (process.env.VERBOSE === 'true') return 'debug'\n return 'info'\n}\n\nconst shouldLog = (level: LogLevel): boolean => {\n const currentLevel = getLogLevel()\n return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[currentLevel]\n}\n\n/** Check if debug mode is enabled */\nexport const isDebug = (): boolean => getLogLevel() === 'debug'\n\n/** Check if verbose mode is enabled */\nexport const isVerbose = (): boolean => process.env.VERBOSE === 'true' || isDebug()\n\nexport const logger = {\n logs: [] as { message: string; context?: string }[],\n breakLine: () => {\n console.log()\n return logger\n },\n success: (msg: string, ...optionalParams: unknown[]) => {\n console.log(chalk.green(`✔ ${msg}`), ...optionalParams)\n return logger\n },\n info: (msg: string, ...optionalParams: unknown[]) => {\n if (shouldLog('info')) {\n console.log(chalk.cyan(`🛈 ${msg}`), ...optionalParams)\n }\n return logger\n },\n warn: (msg: string, ...optionalParams: unknown[]) => {\n if (shouldLog('warn')) {\n console.warn(chalk.yellow(`⚠︎ ${msg}`), ...optionalParams)\n }\n return logger\n },\n error: (msg: string, ...optionalParams: unknown[]) => {\n if (shouldLog('error')) {\n console.error(chalk.red(`✖ ${msg}`), ...optionalParams)\n }\n return logger\n },\n debug: (msg: string, ...optionalParams: unknown[]) => {\n if (shouldLog('debug')) {\n console.log(chalk.dim(`[debug] ${msg}`), ...optionalParams)\n }\n return logger\n },\n log: (msg: string, ...optionalParams: unknown[]) => {\n console.log(msg, ...optionalParams)\n\n logger.logs.push({ message: msg, context: optionalParams.join() })\n\n return logger\n },\n /**\n * Retrieves logs filtered by context.\n *\n * @param context - The context to filter logs by.\n * If not provided, all logs will be returned.\n */\n getStoredLogs: (context?: string) =>\n context ? logger.logs.filter((log) => log.context?.includes(context)) : logger.logs,\n /**\n * Logs a message with a specific context.\n * This is useful for filtering logs based on the context.\n *\n * @param message - The message to log.\n * @param context - The context of the log.\n */\n storeLog: (message: string, context: string) => logger.logs.push({ message, context }),\n}\n","/**\n * Utility type to merge multiple context types into one.\n */\nexport type MergeContexts<T extends readonly unknown[]> = T extends [infer First, ...infer Rest]\n ? First & MergeContexts<Rest>\n : unknown\n","import chalk from 'chalk'\nimport type { ListrContext, ListrTaskWrapper } from 'listr2'\n\n/**\n * Executes a task with a timer, updating the task title with elapsed time.\n * Provides an optional live getter for elapsed seconds to the work function.\n *\n * @example\n * ```ts\n * await withTaskTimer(task, (getElapsed) => {\n * if (getElapsed) console.log(getElapsed()) // e.g., 5\n * await someAsyncOperation()\n * })\n * ```\n *\n * @param task - The task wrapper object for Listr.\n * @param work - The asynchronous function to execute within the task.\n */\nexport async function withTaskTimer<T>(\n task: ListrTaskWrapper<ListrContext, any, any>,\n work: (getElapsed: () => number) => Promise<T>,\n): Promise<T> {\n const start = Date.now()\n const originTitle = task.title\n const getElapsed = () => Math.floor((Date.now() - start) / 1000)\n\n const interval = setInterval(() => {\n if (getElapsed() > 1) {\n task.title = `${originTitle} (${getElapsed()}s)`\n }\n }, 1000)\n\n try {\n return await work(getElapsed)\n } finally {\n clearInterval(interval)\n }\n}\n\nexport interface ProgressStep<Ctx> {\n title: string\n fn: (ctx: Ctx, task: ListrTaskWrapper<Ctx, any, any>) => Promise<void>\n}\n\n/**\n * Runs a series of steps with progress output in Listr2.\n *\n * @param ctx - The task context.\n * @param task - The current Listr task wrapper.\n * @param steps - The array of steps to run.\n */\nexport async function runWithProgressSteps<Ctx>(\n task: ListrTaskWrapper<Ctx, any, any>,\n steps: ProgressStep<Ctx>[],\n ctx?: Ctx,\n) {\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n task.output = chalk.dim(`[${i + 1}/${steps.length}] ${step.title}`)\n await step.fn(ctx ?? ({} as Ctx), task)\n }\n}\n","export * from './ascii-chart'\nexport * from './create-workflow-command'\nexport * from './debounce'\nexport * from './deep'\nexport * from './environment'\nexport * from './fs'\nexport * from './logger'\nexport * from './merge-contexts'\nexport * from './process'\nexport * from './tasks'\n","import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\nimport { LOCK_FILES } from '../../config/constants'\nimport { getCliRoot } from '../../utils'\nimport type { GeneratorConfig, PkgJson } from './types'\n\n// fs-extra replacements using native node:fs\nconst readJsonSync = (path: string) => JSON.parse(readFileSync(path, 'utf-8'))\nconst readJSONSync = readJsonSync\nconst writeJsonSync = (path: string, data: unknown, _options?: unknown) =>\n writeFileSync(path, `${JSON.stringify(data, null, 2)}\\n`, 'utf-8')\n\n// ============================================================================\n// Types & Constants\n// ============================================================================\n\ninterface WorkspacePaths {\n services: string\n apps: string\n packages: string\n contracts: string\n}\n\ninterface ContractsConfig {\n packagePath: string\n eventsPath: string\n indexPath: string\n relativePath: string\n packageName: string\n}\n\nconst DEFAULT_PLUGINS = ['@crossdelta/cloudevents']\n\nconst DEFAULT_WORKSPACE_PATHS: WorkspacePaths = {\n services: 'services',\n apps: 'apps',\n packages: 'packages',\n contracts: 'packages/contracts',\n}\n\nconst DEFAULT_GENERATOR_CONFIG: GeneratorConfig = {\n docs: {\n base: ['service.md'],\n frameworks: {},\n },\n serviceTypes: {\n hono: { commandType: 'hono-micro', entryPoint: 'src/index.ts', skipFiles: [] },\n nest: { commandType: 'nest-micro', entryPoint: 'src/main.ts', skipFiles: [] },\n },\n}\n\n// ============================================================================\n// Helper Functions (Pure)\n// ============================================================================\n\n/**\n * Safely parse JSON file\n */\nconst parseJsonFile = <T>(path: string): T | null => {\n if (!existsSync(path)) return null\n try {\n return JSON.parse(readFileSync(path, 'utf-8')) as T\n } catch {\n return null\n }\n}\n\n/**\n * Extract path value from config (handles both string and object formats)\n */\nconst extractPathValue = (pathConfig: unknown, defaultValue: string): string => {\n if (typeof pathConfig === 'string') return pathConfig\n if (typeof pathConfig === 'object' && pathConfig !== null && 'path' in pathConfig) {\n return (pathConfig as { path: string }).path\n }\n return defaultValue\n}\n\n/**\n * Get directory name from path\n */\nconst getDirName = (path: string): string => path.split('/').pop() || 'workspace'\n\n/**\n * Navigate up directory tree\n */\nconst getParentDir = (dir: string): string | null => {\n const parent = dir.slice(0, dir.lastIndexOf('/'))\n return parent === dir ? null : parent\n}\n\n/**\n * Split key path into array\n */\nconst splitKeyPath = (keyPath: string): string[] => keyPath.split('.')\n\n// ============================================================================\n// Workspace Detection (Pure)\n// ============================================================================\n\n/**\n * Check if directory has workspace indicators\n */\nconst hasWorkspaceIndicators = (pkg: PkgJson, dir: string): boolean => {\n if (!pkg.workspaces) return false\n if (pkg.pf) return true\n if (existsSync(join(dir, 'turbo.json'))) return true\n\n const hasLockFile = LOCK_FILES.some((f) => existsSync(join(dir, f)))\n const hasInfraDir = existsSync(join(dir, 'infra'))\n return hasLockFile && hasInfraDir\n}\n\n/**\n * Check if a directory looks like a workspace root\n */\nconst isWorkspaceRoot = (dir: string): boolean => {\n const pkg = parseJsonFile<PkgJson>(join(dir, 'package.json'))\n return pkg ? hasWorkspaceIndicators(pkg, dir) : false\n}\n\n/**\n * Find workspace root by traversing up from start directory\n */\nconst findWorkspaceRootDir = (startDir: string): string | null => {\n let dir: string | null = startDir\n\n while (dir) {\n if (isWorkspaceRoot(dir)) return dir\n dir = getParentDir(dir)\n }\n\n return null\n}\n\n/**\n * Check if currently in a workspace (non-throwing version)\n */\nexport const isInWorkspace = (): boolean => findWorkspaceRootDir(process.cwd()) !== null\n\n/**\n * Find the workspace root by looking for workspace indicators\n * Throws if not in a workspace\n */\nexport const findWorkspaceRoot = (): string => {\n const root = findWorkspaceRootDir(process.cwd())\n\n if (!root) {\n throw new Error(\n `\\n\\x1b[31m✖\\x1b[0m Not in a workspace directory\\n\\n` +\n `Current directory: ${process.cwd()}\\n\\n` +\n `This command must be run from within a workspace created with \\x1b[36mpf new workspace\\x1b[0m\\n` +\n `\\n` +\n `To create a new workspace, run:\\n\\n` +\n ` \\x1b[36mpf new workspace my-platform\\x1b[0m\\n`,\n )\n }\n\n return root\n}\n\n// ============================================================================\n// Package.json Operations\n// ============================================================================\n\n/**\n * Load and parse the workspace root package.json\n * Returns null if not found or invalid\n */\nexport const getWorkspacePackageJson = (workspaceRoot?: string): PkgJson | null => {\n const root = workspaceRoot ?? findWorkspaceRoot()\n return parseJsonFile<PkgJson>(join(root, 'package.json'))\n}\n\n/**\n * Get workspace paths configuration from package.json\n * Returns configured paths or defaults\n */\nexport const getWorkspacePathsConfig = (workspaceRoot?: string): WorkspacePaths => {\n const pkg = getWorkspacePackageJson(workspaceRoot)\n if (!pkg?.pf?.paths) return DEFAULT_WORKSPACE_PATHS\n\n const { paths } = pkg.pf\n\n return {\n services: extractPathValue(paths.services, DEFAULT_WORKSPACE_PATHS.services),\n apps: extractPathValue(paths.apps, DEFAULT_WORKSPACE_PATHS.apps),\n packages: extractPathValue(paths.packages, DEFAULT_WORKSPACE_PATHS.packages),\n contracts: extractPathValue(paths.contracts, DEFAULT_WORKSPACE_PATHS.contracts),\n }\n}\n\n/**\n * Get pf configuration from workspace package.json\n *\n * @example\n * // package.json\n * {\n * \"pf\": {\n * \"plugins\": [\"@crossdelta/cloudevents\", \"./local-plugin\"]\n * }\n * }\n */\nexport const getPfConfig = (workspaceRoot?: string): { plugins: string[], dev: { filter: string[] } } => {\n const pkg = getWorkspacePackageJson(workspaceRoot)\n return {\n plugins: pkg?.pf?.plugins ?? DEFAULT_PLUGINS,\n dev: {\n filter: pkg?.pf?.dev?.filter ?? [],\n },\n }\n}\n\n/**\n * Get contracts package configuration from workspace package.json\n * Returns absolute paths to contracts package directories\n */\nexport const getContractsConfig = (workspaceRoot?: string): ContractsConfig => {\n const root = workspaceRoot ?? findWorkspaceRoot()\n const paths = getWorkspacePathsConfig(root)\n const contractsPath = join(root, paths.contracts)\n const contractsPkg = parseJsonFile<PkgJson>(join(contractsPath, 'package.json'))\n const packageName = contractsPkg?.name ?? `${getRootPackageScope()}/contracts`\n\n return {\n packagePath: contractsPath,\n eventsPath: join(contractsPath, 'src', 'events'),\n indexPath: join(contractsPath, 'src', 'index.ts'),\n relativePath: paths.contracts,\n packageName,\n }\n}\n\n/**\n * Get the package scope from the root package.json name\n * Returns the scope with @ prefix (e.g., '@my-org')\n * Falls back to workspace directory name if package.json is missing or invalid\n */\nexport const getRootPackageScope = (): string => {\n const rootPath = findWorkspaceRoot()\n const pkg = parseJsonFile<PkgJson>(join(rootPath, 'package.json'))\n const fallbackScope = `@${getDirName(rootPath)}`\n\n if (!pkg?.name) return fallbackScope\n\n // If already scoped (@scope/name), extract the scope\n if (pkg.name.startsWith('@')) {\n return pkg.name.split('/')[0]\n }\n\n // Otherwise use the name as scope\n return `@${pkg.name}`\n}\n\n// ============================================================================\n// Nested Field Operations (Pure)\n// ============================================================================\n\n/**\n * Get nested field value from object using key path\n */\nconst getNestedField = <T = unknown>(obj: Record<string, unknown>, keyPath: string): T | undefined => {\n const keys = splitKeyPath(keyPath)\n let current: unknown = obj\n\n for (const key of keys) {\n if (current === null || typeof current !== 'object' || !(key in current)) {\n return undefined\n }\n current = (current as Record<string, unknown>)[key]\n }\n\n return current as T\n}\n\n/**\n * Set nested field in object using key path (mutates obj)\n */\nconst setNestedField = (obj: Record<string, unknown>, keyPath: string, value: unknown): void => {\n const keys = splitKeyPath(keyPath)\n const lastKey = keys[keys.length - 1]\n let current = obj\n\n for (const key of keys.slice(0, -1)) {\n if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {\n current[key] = {}\n }\n current = current[key] as Record<string, unknown>\n }\n\n current[lastKey] = value\n}\n\n/**\n * Get a field from the package.json file\n */\nexport const getPackageJsonField = <T = unknown>(keyPath: string, directory = process.cwd()): T | undefined => {\n const packageJson = readJsonSync(join(directory, 'package.json')) as Record<string, unknown>\n return getNestedField<T>(packageJson, keyPath)\n}\n\n/**\n * Update a field in the package.json file\n */\nexport const updatePackageJsonField = (keyPath: string, value: unknown, directory = process.cwd()): void => {\n const packageJsonPath = join(directory, 'package.json')\n const packageJson = readJsonSync(packageJsonPath) as Record<string, unknown>\n\n setNestedField(packageJson, keyPath, value)\n writeJsonSync(packageJsonPath, packageJson, { spaces: 2, EOL: '\\n', encoding: 'utf-8' })\n}\n\n// ============================================================================\n// CLI Package Config\n// ============================================================================\n\n/**\n * Read the CLI package.json file\n */\nexport const readPackageConfig = (relativePath: string): unknown => {\n const root = getCliRoot()\n return readJSONSync(resolve(root, relativePath))\n}\n\n/**\n * CLI package.json content (lazy loaded to avoid circular dependency issues)\n */\nlet _pkgJson: PkgJson | null = null\nexport const getPkgJson = (): PkgJson => {\n if (!_pkgJson) {\n _pkgJson = readPackageConfig('package.json') as PkgJson\n }\n return _pkgJson\n}\n\n/**\n * @deprecated Use getPkgJson() instead - this exists for backward compatibility\n */\nexport const pkgJson: PkgJson = new Proxy({} as PkgJson, {\n get: (_, prop) => getPkgJson()[prop as keyof PkgJson],\n})\n\n/**\n * Get generator config from package.json's generatorConfig\n * Returns full config with defaults for missing values\n */\nexport const getGeneratorConfig = (): GeneratorConfig => getPkgJson().generatorConfig ?? DEFAULT_GENERATOR_CONFIG\n\n// ============================================================================\n// Service Discovery\n// ============================================================================\n\n/**\n * Discover available services in the workspace\n * Returns relative paths to service directories (e.g., 'services/api-gateway')\n */\nexport const discoverAvailableServices = (workspaceRoot?: string): string[] => {\n const root = workspaceRoot ?? findWorkspaceRoot()\n const paths = getWorkspacePathsConfig(root)\n const servicesDir = join(root, paths.services)\n\n if (!existsSync(servicesDir)) return []\n\n try {\n const entries = readdirSync(servicesDir, { withFileTypes: true })\n return entries\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))\n .map((entry) => `${paths.services}/${entry.name}`)\n .sort()\n } catch {\n return []\n }\n}\n","/**\n * Platform SDK Facade\n *\n * Stable API surface for external integrations (MCP adapters, extensions, etc.)\n * This facade isolates internal implementation details and provides version stability.\n *\n * Design Philosophy:\n * - Minimal surface area: Only expose what's needed for tool/flow execution\n * - Semantic versioning: Breaking changes bump major version\n * - Internal freedom: Implementation can change without affecting consumers\n *\n * Consumers:\n * - @crossdelta/pf-mcp (MCP server adapter)\n * - Future extensions (VS Code, etc.)\n */\n\nimport { readdir } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { FlowContext, FlowResult, FlowRunOptions } from '@crossdelta/flowcore'\nimport { runFlow as flowcoreRunFlow } from '@crossdelta/flowcore'\n\nimport { loadPluginFromModule } from '../plugins/loader'\nimport type { LoadedPlugin, PfPlugin, PfPluginContext } from '../plugins/types'\n\nexport { deriveEventNames } from '@crossdelta/cloudevents'\nexport type { FlowContext, FlowResult, FlowRunOptions } from '@crossdelta/flowcore'\nexport {\n type CapabilitiesConfig,\n getRegisteredProviders,\n loadCapabilitiesConfig,\n loadCapabilitiesConfigFromWorkspace,\n lookupProvider,\n lowerSpecToCapabilities,\n type ParseResult,\n type ProviderLookup,\n parseServicePrompt,\n resolveProvider,\n type ServiceMetadata,\n type ServiceSpec,\n} from '../capabilities'\nexport type {\n Change,\n EffectHandlerOptions,\n EffectResult,\n EffectRuntimeContext,\n} from '../effects'\nexport { applyEffects } from '../effects'\nexport { aggregateChanges, formatChangeDetails, formatChangeSummary } from '../effects/changes'\nexport type {\n ServiceGenerationInputs,\n ServiceMeta,\n} from '../flows/service-generation.flow'\nexport { planServiceGeneration } from '../flows/service-generation.flow'\nexport type {\n Artifact,\n Diagnostic,\n NextAction,\n OperationResult,\n} from '../operations/types'\nexport { err as createErrResult, ok as createOkResult } from '../operations/types'\nexport { findWorkspaceRoot } from '../packages/config'\nexport type {\n ElicitInputEffect,\n ElicitInputField,\n EnvAddEffect,\n FileWriteEffect,\n InfraAddEffect,\n LoadedPlugin,\n PfCommand,\n PfCommandArg,\n PfCommandOption,\n PfCommandResult,\n PfEffect,\n PfPlugin,\n PfPluginContext,\n PfWorkspaceContext,\n} from '../plugins/types'\nexport { isElicitInputEffect } from '../plugins/types'\nexport type {\n CodingConstraints,\n ForbiddenPattern,\n FrameworkLayout,\n PathGuards,\n PlannedFile,\n PolicyValidationResult,\n PolicyViolation,\n ServiceFramework,\n} from '../policies'\nexport {\n getFrameworkPolicy,\n SERVICE_LAYOUT_POLICY_VERSION,\n serviceLayoutPolicy,\n validateGeneratedFiles,\n} from '../policies'\nexport { createContext, createContextFromWorkspace } from './context'\nexport { collectExecutableToolSpecs, collectToolSpecs } from './tools'\nexport type {\n CommandLikeResult,\n ExecutableToolSpec,\n ToolInputSchema,\n ToolPropertySchema,\n ToolSpec,\n} from './types'\n\nexport const loadPlugins = async (moduleNames: string[], context: PfPluginContext): Promise<LoadedPlugin[]> =>\n Promise.all(moduleNames.map((moduleName) => loadPluginFromModule(moduleName, context)))\n\nexport const runFlow = async <TContext extends FlowContext = FlowContext>(\n plugin: PfPlugin,\n flowName: string,\n options: FlowRunOptions<TContext>,\n): Promise<FlowResult<TContext>> => {\n const flow = plugin.flows.find((f) => f.name === flowName)\n if (!flow) {\n throw new Error(`Flow '${flowName}' not found in plugin '${plugin.name}'`)\n }\n\n const steps = await flow.getSteps(options.initialContext)\n return flowcoreRunFlow(steps as Parameters<typeof flowcoreRunFlow<TContext>>[0], options) as Promise<\n FlowResult<TContext>\n >\n}\n\n/**\n * Get the absolute path to the generator docs directory\n *\n * @returns Absolute path to packages/platform-sdk/bin/docs/generators (built artifacts)\n */\nexport const getGeneratorDocsDir = (): string => {\n if (typeof import.meta?.url === 'string') {\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = dirname(__filename)\n return join(__dirname, '../bin/docs/generators')\n }\n\n // Fallback for CJS (tsup injects __dirname)\n if (typeof __dirname !== 'undefined') {\n return join(__dirname, '../bin/docs/generators')\n }\n\n throw new Error('Cannot determine docs directory: neither import.meta.url nor __dirname available')\n}\n\n/**\n * List all available generator documentation files\n *\n * @returns Array of doc filenames (without .md extension)\n */\nexport const listGeneratorDocs = async (): Promise<string[]> => {\n const docsDir = getGeneratorDocsDir()\n const files = await readdir(docsDir)\n return files.filter((f) => f.endsWith('.md')).map((f) => f.replace('.md', ''))\n}\n","/**\n * Plugin Loader\n *\n * pf owns the plugin interface. Plugins MUST conform exactly.\n * Strict validation - no duck-typing, no fallbacks.\n */\nimport type { LoadedPlugin, PfPlugin, PfPluginContext, PfWorkspaceContext } from './types'\n\nconst defaultLogger: PfPluginContext['logger'] = {\n debug: () => {},\n info: console.log,\n warn: console.warn,\n error: console.error,\n}\n\nconst isObject = (val: unknown): val is Record<string, unknown> =>\n val !== null && typeof val === 'object'\n\nconst isNonEmptyString = (val: unknown): val is string =>\n typeof val === 'string' && val.length > 0\n\nconst isString = (val: unknown): val is string =>\n typeof val === 'string'\n\nconst isFunction = (val: unknown): val is (...args: unknown[]) => unknown =>\n typeof val === 'function'\n\n/**\n * Validates a single command conforms to PfCommand interface\n */\nconst validateCommand = (cmd: unknown, index: number): string[] => {\n if (!isObject(cmd)) return [`commands[${index}]: must be an object`]\n\n return [\n !isNonEmptyString(cmd.name) && `commands[${index}]: missing or invalid 'name'`,\n !isString(cmd.description) && `commands[${index}]: missing or invalid 'description'`,\n !Array.isArray(cmd.args) && `commands[${index}]: missing 'args' array`,\n !Array.isArray(cmd.options) && `commands[${index}]: missing 'options' array`,\n !isFunction(cmd.run) && `commands[${index}]: missing 'run' function`,\n ].filter((e): e is string => e !== false)\n}\n\n/**\n * Validates that an object conforms to the PfPlugin interface\n */\nexport const validatePlugin = (obj: unknown): obj is PfPlugin => {\n if (!isObject(obj)) return false\n\n return (\n isNonEmptyString(obj.name) &&\n isString(obj.version) &&\n Array.isArray(obj.commands) &&\n Array.isArray(obj.flows) &&\n isFunction(obj.setup)\n )\n}\n\n/**\n * Detailed validation with error messages\n */\nexport const validatePluginStrict = (obj: unknown): string[] => {\n if (!isObject(obj)) return ['Plugin must be an object']\n\n const baseErrors = [\n !isNonEmptyString(obj.name) && \"Missing or invalid 'name'\",\n !isString(obj.version) && \"Missing or invalid 'version'\",\n !Array.isArray(obj.commands) && \"Missing 'commands' array\",\n !Array.isArray(obj.flows) && \"Missing 'flows' array\",\n !isFunction(obj.setup) && \"Missing 'setup' function\",\n ].filter((e): e is string => e !== false)\n\n const commandErrors = Array.isArray(obj.commands)\n ? obj.commands.flatMap((cmd, i) => validateCommand(cmd, i))\n : []\n\n return [...baseErrors, ...commandErrors]\n}\n\n/**\n * Create a plugin context from workspace discovery\n */\nexport const createPluginContext = (\n workspace: PfWorkspaceContext,\n logger: PfPluginContext['logger'] = defaultLogger,\n): PfPluginContext => ({\n workspace,\n logger,\n})\n\n/**\n * Load and initialize a plugin from a module\n *\n * @param moduleName - The module to import (e.g., '@crossdelta/cloudevents')\n * @param context - Full plugin context with workspace info\n */\nexport const loadPluginFromModule = async (\n moduleName: string,\n context: PfPluginContext,\n): Promise<LoadedPlugin> => {\n const { logger } = context\n\n logger.debug(`Loading plugin from module: ${moduleName}`)\n\n const mod = await import(moduleName)\n\n const createPlugin = mod.createPfPlugin || mod.default?.createPfPlugin\n if (!isFunction(createPlugin)) {\n throw new Error(`Module ${moduleName} does not export createPfPlugin`)\n }\n\n const plugin = createPlugin({\n contractsPath: context.workspace.contracts.path,\n contractsPackage: context.workspace.contracts.packageName,\n availableServices: context.workspace.availableServices,\n })\n\n const errors = validatePluginStrict(plugin)\n if (errors.length > 0) {\n throw new Error(`Plugin from ${moduleName} does not conform to PfPlugin interface:\\n - ${errors.join('\\n - ')}`)\n }\n\n const validatedPlugin = plugin as PfPlugin\n\n logger.debug(`Loaded plugin: ${validatedPlugin.name} v${validatedPlugin.version}`)\n\n await validatedPlugin.setup(context)\n\n return {\n plugin: validatedPlugin,\n source: moduleName,\n }\n}\n","/**\n * Capability Configuration\n *\n * Manages capability/provider configuration from workspace package.json.\n * Single Source of Truth: workspaceConfig.pf.capabilities\n *\n * NO BUILT-IN DEFAULTS:\n * - Provider metadata (deps/envVars/adapterFile) comes ONLY from workspace config\n * - Unknown providers trigger elicitation (interactive) or error (strict)\n * - This enables teams to define their own providers without hardcoded assumptions\n */\n\nimport { z } from 'zod'\n\n// ============================================================================\n// Types: Provider Metadata\n// ============================================================================\n\nexport const ProviderMetaSchema = z.object({\n dependencies: z.record(z.string(), z.string()).default({}),\n envVars: z\n .array(\n z.object({\n key: z.string(),\n description: z.string(),\n required: z.boolean().default(true),\n }),\n )\n .default([]),\n /** Custom adapter filename (e.g., 'push-notification.adapter.ts') */\n adapterFile: z.string().optional(),\n})\n\nexport type ProviderMeta = z.infer<typeof ProviderMetaSchema>\n\n// ============================================================================\n// Types: Capability Configuration\n// ============================================================================\n\nexport const NotifierDefaultsSchema = z\n .object({\n push: z.string().optional(),\n email: z.string().optional(),\n slack: z.string().optional(),\n sms: z.string().optional(),\n })\n .optional()\n\nexport const NotifierConfigSchema = z.object({\n defaults: NotifierDefaultsSchema,\n providers: z\n .object({\n push: z.record(z.string(), ProviderMetaSchema).optional(),\n email: z.record(z.string(), ProviderMetaSchema).optional(),\n slack: z.record(z.string(), ProviderMetaSchema).optional(),\n sms: z.record(z.string(), ProviderMetaSchema).optional(),\n })\n .optional(),\n})\n\nexport const CapabilitiesConfigSchema = z.object({\n notifier: NotifierConfigSchema.optional(),\n})\n\nexport type CapabilitiesConfig = z.infer<typeof CapabilitiesConfigSchema>\nexport type NotifierChannel = 'push' | 'email' | 'slack' | 'sms'\n\n// ============================================================================\n// Registered Providers (from Workspace Config ONLY)\n// ============================================================================\n\n/**\n * Get registered providers from workspace config.\n * Returns empty arrays if no config - NO BUILT-IN FALLBACKS.\n * Pure function.\n */\nexport const getRegisteredProviders = (\n workspaceConfig?: CapabilitiesConfig,\n): Record<NotifierChannel, string[]> => ({\n push: Object.keys(workspaceConfig?.notifier?.providers?.push ?? {}),\n email: Object.keys(workspaceConfig?.notifier?.providers?.email ?? {}),\n slack: Object.keys(workspaceConfig?.notifier?.providers?.slack ?? {}),\n sms: Object.keys(workspaceConfig?.notifier?.providers?.sms ?? {}),\n})\n\n/**\n * Get default provider for channel from workspace config.\n * Returns undefined if no default configured (triggers elicitation).\n * Pure function.\n */\nexport const getDefaultProvider = (\n channel: NotifierChannel,\n workspaceConfig?: CapabilitiesConfig,\n): string | undefined => workspaceConfig?.notifier?.defaults?.[channel]\n\n// ============================================================================\n// Centralized Provider Lookup (Workspace Config ONLY)\n// ============================================================================\n\nexport interface ProviderLookupResult {\n found: true\n provider: string\n meta: ProviderMeta\n source: 'workspace' | 'inferred'\n}\n\nexport interface ProviderNotFoundResult {\n found: false\n channel: NotifierChannel\n provider: string\n availableProviders: string[]\n configSnippet: string\n}\n\nexport type ProviderLookup = ProviderLookupResult | ProviderNotFoundResult\n\nexport const lookupProvider = (\n channel: NotifierChannel,\n provider: string,\n workspaceConfig?: CapabilitiesConfig,\n): ProviderLookup => {\n const meta = workspaceConfig?.notifier?.providers?.[channel]?.[provider] as ProviderMeta | undefined\n\n if (meta) {\n return { found: true, provider, meta, source: 'workspace' }\n }\n\n const availableProviders = Object.keys(workspaceConfig?.notifier?.providers?.[channel] ?? {})\n const configSnippet = generateConfigSnippet(channel, provider)\n\n return {\n found: false,\n channel,\n provider,\n availableProviders,\n configSnippet,\n }\n}\n\n// ============================================================================\n// Provider Name Helpers (Pure)\n// ============================================================================\n\n/**\n * Normalize provider name: lowercase, trim, whitespace→hyphens, remove special chars.\n * Pure function.\n *\n * @example normalizeProviderName('Pusher Beams') → 'pusher-beams'\n * @example normalizeProviderName(' OneSignal ') → 'onesignal'\n * @example normalizeProviderName('My_Custom Provider!') → 'my-custom-provider'\n */\nexport const normalizeProviderName = (name: string): string =>\n name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-]/g, '')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n\n/**\n * Extract provider mention from prompt using common patterns.\n * Returns raw extracted string (NOT normalized).\n * Pure function.\n *\n * Patterns: \"via X\", \"using X\", \"with X\", \"über X\", \"per X\"\n *\n * @example extractProviderFromPrompt('send push via OneSignal') → 'OneSignal'\n * @example extractProviderFromPrompt('send push') → undefined\n */\nexport const extractProviderFromPrompt = (prompt: string): string | undefined => {\n // Match \"via/using/with/über/per <provider>\" patterns\n // Provider can be: word chars, spaces (for multi-word), and hyphens\n const patterns = [\n /(?:via|using|with|über|per)\\s+([\\w\\s-]+?)(?:\\s+(?:for|to|and|,|\\.|$))/i,\n /(?:via|using|with|über|per)\\s+([\\w-]+)/i,\n ]\n\n for (const pattern of patterns) {\n const match = prompt.match(pattern)\n if (match?.[1]) {\n return match[1].trim()\n }\n }\n\n return undefined\n}\n\n/**\n * Build package.json config snippet for registering a provider.\n * Alias for generateConfigSnippet (DRY).\n * Pure function.\n */\nexport const buildProviderConfigSnippet = (channel: NotifierChannel, provider: string): string =>\n generateConfigSnippet(channel, provider)\n\n/**\n * Generate package.json snippet for adding a new provider.\n * Pure function.\n */\nexport const generateConfigSnippet = (channel: NotifierChannel, provider: string): string => {\n const snippet = {\n pf: {\n capabilities: {\n notifier: {\n providers: {\n [channel]: {\n [provider]: {\n dependencies: { 'your-package': '^1.0.0' },\n envVars: [{ key: 'YOUR_API_KEY', description: 'API key for provider', required: true }],\n },\n },\n },\n },\n },\n },\n }\n return JSON.stringify(snippet, null, 2)\n}\n\n// ============================================================================\n// Apply Default Provider (Pure)\n// ============================================================================\n\nexport interface ApplyDefaultResult {\n provider: string\n source: 'explicit' | 'default'\n}\n\nexport interface NeedElicitationResult {\n needsElicitation: true\n channel: NotifierChannel\n availableProviders: string[]\n}\n\nexport type ResolveProviderResult =\n | ({ resolved: true } & ApplyDefaultResult)\n | ({ resolved: false } & NeedElicitationResult)\n\n/**\n * Resolve provider - use explicit if provided, else check defaults, else elicit.\n * Pure function.\n */\nexport const resolveProvider = (\n channel: NotifierChannel,\n explicitProvider: string | undefined,\n workspaceConfig?: CapabilitiesConfig,\n): ResolveProviderResult => {\n // 1. Explicit provider wins\n if (explicitProvider) {\n return { resolved: true, provider: explicitProvider, source: 'explicit' }\n }\n\n // 2. Check workspace defaults\n const defaultProvider = getDefaultProvider(channel, workspaceConfig)\n if (defaultProvider) {\n return { resolved: true, provider: defaultProvider, source: 'default' }\n }\n\n // 3. No default -> elicitation needed\n const availableProviders = Object.keys(workspaceConfig?.notifier?.providers?.[channel] ?? {})\n return {\n resolved: false,\n needsElicitation: true,\n channel,\n availableProviders,\n }\n}\n\n// ============================================================================\n// Load Capabilities Config from Workspace (Effect - wraps workspaceConfig)\n// ============================================================================\n\n/**\n * Load capabilities config from workspace package.json.\n * Returns undefined if no config or parsing fails.\n *\n * NOTE: This is the ONLY place that reads from workspace config.\n * CLI and MCP both use this function via the capabilities module.\n */\nexport const loadCapabilitiesConfig = (\n workspacePkg: Record<string, unknown> | null,\n): CapabilitiesConfig | undefined => {\n if (!workspacePkg) return undefined\n\n const pfConfig = workspacePkg.pf as Record<string, unknown> | undefined\n if (!pfConfig?.capabilities) return undefined\n\n const result = CapabilitiesConfigSchema.safeParse(pfConfig.capabilities)\n return result.success ? result.data : undefined\n}\n\n/**\n * Load capabilities config from workspace root.\n * Convenience wrapper that integrates with packages/config.ts.\n *\n * Usage (CLI/MCP):\n * ```ts\n * import { loadCapabilitiesConfigFromWorkspace } from './capabilities/config'\n * const config = loadCapabilitiesConfigFromWorkspace()\n * const registry = createDefaultRegistry(config)\n * ```\n */\nexport const loadCapabilitiesConfigFromWorkspace = (\n getWorkspacePackageJson: () => Record<string, unknown> | null,\n): CapabilitiesConfig | undefined => {\n const pkg = getWorkspacePackageJson()\n return loadCapabilitiesConfig(pkg)\n}\n\n","/**\n * Capability Lowering\n *\n * Converts ServiceSpec to metadata (files, deps, env vars, postCommands).\n * Pure, deterministic - no side effects, no defaults, no guessing.\n */\n\nimport type { ServiceSpec } from './types'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ServiceMetadata {\n files: {\n path: string\n intent: string\n inputs?: Record<string, unknown>\n layer?: 'handler' | 'useCase' | 'adapter' | 'service'\n kind?: 'event-consumer' | 'notifier' | 'http-client' | 'persistence'\n }[]\n dependencies: Record<string, string>\n envVars: {\n key: string\n description: string\n required: boolean\n }[]\n postCommands: string[]\n}\n\n// ============================================================================\n// Main Lowering Function\n// ============================================================================\n\n/**\n * Lower ServiceSpec to ServiceMetadata (files, deps, env vars, postCommands).\n * AI generates file content based on intents.\n */\nexport const lowerSpecToCapabilities = (\n spec: ServiceSpec,\n serviceDir: string,\n): ServiceMetadata => {\n const metadata: ServiceMetadata = {\n files: [],\n dependencies: {},\n envVars: [],\n postCommands: [],\n }\n\n // Process event consumers (handlers)\n // Note: --fields with default schema to skip interactive prompt\n for (const trigger of spec.triggers) {\n if (trigger.type === 'event') {\n metadata.postCommands.push(`pf cloudevents add ${trigger.eventType} --service ${serviceDir} --fields \"id:string\"`)\n }\n }\n\n // Process notifier actions (adapters + use-cases)\n // AI determines dependencies and env vars based on provider name\n for (const action of spec.actions) {\n if (action.type === 'notify' && action.provider) {\n metadata.files.push({\n path: `${serviceDir}/src/adapters/${action.channel}.adapter.ts`,\n intent: `${action.channel} adapter using ${action.provider}`,\n layer: 'adapter',\n kind: 'notifier',\n })\n\n metadata.files.push({\n path: `${serviceDir}/src/use-cases/send-${action.channel}.use-case.ts`,\n intent: `send ${action.channel} notification`,\n layer: 'useCase',\n })\n }\n }\n\n return metadata\n}\n","/**\n * Capability Types\n *\n * Core types for the deterministic planning system.\n * AI generates content ONLY - paths/structure come from policy.\n *\n * Pipeline:\n * 1. Parser: NL prompt -> ServiceSpec (with explicit provider if mentioned)\n * 2. Lowering: ServiceSpec -> CapabilityInvocation[] (pure, deterministic)\n * 3. Planning: Invocations -> GenerationPlan (deterministic, policy-based paths)\n * 4. Content Generation: Plan.files -> AI fills content (constrained)\n * 5. Validation: Check generated files against policy + patterns\n */\n\nimport { z } from 'zod'\n\n// ============================================================================\n// Service Specification (Parser Output)\n// ============================================================================\n\nexport const EventTriggerSchema = z.object({\n type: z.literal('event'),\n eventType: z.string(),\n stream: z.string().optional(),\n})\n\nexport const HttpTriggerSchema = z.object({\n type: z.literal('http'),\n method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).optional(),\n path: z.string().optional(),\n})\n\nexport const TriggerSchema = z.discriminatedUnion('type', [EventTriggerSchema, HttpTriggerSchema])\n\nexport const EmitEventActionSchema = z.object({\n type: z.literal('emit.event'),\n eventType: z.string(),\n})\n\nexport const NotifyActionSchema = z.object({\n type: z.literal('notify'),\n channel: z.enum(['push', 'email', 'slack', 'sms']),\n /** Must be explicitly provided by user or elicited - NO defaults */\n provider: z.string().optional(),\n})\n\nexport const CallHttpActionSchema = z.object({\n type: z.literal('call.http'),\n name: z.string().optional(),\n baseUrl: z.string().optional(),\n})\n\nexport const PersistActionSchema = z.object({\n type: z.literal('persist'),\n store: z.enum(['db', 'kv', 'cache']),\n entity: z.string().optional(),\n})\n\nexport const ActionSchema = z.discriminatedUnion('type', [\n EmitEventActionSchema,\n NotifyActionSchema,\n CallHttpActionSchema,\n PersistActionSchema,\n])\n\nexport const ServiceSpecSchema = z.object({\n serviceName: z.string().regex(/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/),\n framework: z.enum(['hono', 'nest']).default('hono'),\n triggers: z.array(TriggerSchema).min(1),\n actions: z.array(ActionSchema).default([]),\n})\n\nexport type Trigger = z.infer<typeof TriggerSchema>\nexport type Action = z.infer<typeof ActionSchema>\nexport type ServiceSpec = z.infer<typeof ServiceSpecSchema>\n\n// ============================================================================\n// Elicitation (Missing Required Info)\n// ============================================================================\n\nexport interface ElicitField {\n path: string\n prompt: string\n type: 'string' | 'enum'\n options?: string[]\n required: boolean\n}\n\nexport type ParseResult =\n | { complete: true; spec: ServiceSpec }\n | { complete: false; fields: ElicitField[]; partialSpec: Partial<ServiceSpec> }\n\n// ============================================================================\n// Capability Invocation (Lowering Output)\n// ============================================================================\n\nexport interface CapabilityInvocation {\n capability: string\n config: Record<string, unknown>\n source: { type: 'trigger' | 'action'; index: number }\n}\n\n// ============================================================================\n// File Descriptor (Planning Output - Deterministic)\n// ============================================================================\n\n/** Layer determines constraints for AI content generation */\nexport type FileLayer = 'domain' | 'useCase' | 'adapter' | 'infra' | 'config'\n\n/** Kind of file for context */\nexport type FileKind = 'handler' | 'adapter' | 'service' | 'useCase' | 'contract' | 'config' | 'test'\n\n/**\n * Constraints for AI content generation.\n * Pure functions that validate generated content.\n */\nexport interface ContentConstraints {\n /** Forbidden patterns (regex strings) */\n forbiddenPatterns?: string[]\n /** Required exports */\n requiredExports?: string[]\n /** Required function signatures */\n requiredSignatures?: Array<{\n name: string\n params: string[]\n returnType: string\n }>\n /** Max lines (soft limit for AI guidance) */\n maxLines?: number\n}\n\n/**\n * File descriptor - deterministic, from policy.\n * AI fills `content` field, everything else is predetermined.\n */\nexport interface FileDescriptor {\n /** Absolute path (from servicePolicy layout) */\n path: string\n /** Layer for constraint enforcement */\n layer: FileLayer\n /** Kind of file */\n kind: FileKind\n /** Human-readable intent for AI */\n intent: string\n /** Constraints for content generation */\n constraints: ContentConstraints\n /** Inputs for AI (event type, schema fields, etc.) */\n inputs: Record<string, unknown>\n /** Generated content (filled by AI) */\n content?: string\n}\n\n// ============================================================================\n// Generation Plan (Registry Output - Deterministic)\n// ============================================================================\n\nexport interface GenerationPlan {\n /** Service name */\n serviceName: string\n /** Service directory (relative to workspace) */\n serviceDir: string\n /** Files to generate (paths from policy, content from AI) */\n files: FileDescriptor[]\n /** Dependencies to add to package.json */\n dependencies: Record<string, string>\n /** Environment variables needed */\n envVars: Array<{ key: string; description: string; required: boolean }>\n /** Post-generation commands (e.g., pf cloudevents add) */\n postCommands?: string[]\n /** Metadata for debugging/logging */\n metadata: Record<string, unknown>\n}\n\n// ============================================================================\n// Capability Definition (Registry Plugin)\n// ============================================================================\n\nexport interface CapabilityContext {\n serviceName: string\n serviceDir: string\n workspaceRoot: string\n workspaceScope: string\n /** Policy-defined paths - capability MUST use these */\n paths: {\n events: string\n useCases: string\n adapters: string\n routes: string\n contracts: string\n }\n}\n\nexport interface CapabilityPlanResult {\n files: FileDescriptor[]\n dependencies: Record<string, string>\n envVars: Array<{ key: string; description: string; required: boolean }>\n postCommands?: string[]\n metadata?: Record<string, unknown>\n}\n\nexport type CapabilityPlanFn = (\n invocation: CapabilityInvocation,\n context: CapabilityContext,\n) => CapabilityPlanResult\n\nexport interface CapabilityDefinition {\n id: string\n description: string\n requiredConfig: string[]\n optionalConfig?: string[]\n /** Pure function: invocation -> plan fragment */\n plan: CapabilityPlanFn\n}\n\n// ============================================================================\n// AI Content Generator (Effect - Stubable)\n// ============================================================================\n\nexport interface AIContentGenerator {\n /**\n * Generate content for a single file.\n * MUST respect FileDescriptor.constraints.\n */\n generateContent(descriptor: FileDescriptor): Promise<string>\n}\n\n// ============================================================================\n// Validation Result\n// ============================================================================\n\nexport interface ValidationViolation {\n file: string\n rule: string\n message: string\n line?: number\n severity: 'error' | 'warning'\n}\n\nexport interface ValidationResult {\n valid: boolean\n violations: ValidationViolation[]\n}\n\n// ============================================================================\n// Execution Mode (Interactive vs Strict)\n// ============================================================================\n\n/**\n * Execution mode for capability planning.\n * - 'interactive': Unknown providers trigger elicitation (MCP/Chat)\n * - 'strict': Unknown providers throw errors (CLI/CI)\n */\nexport type ExecutionMode = 'interactive' | 'strict'\n\n/**\n * Elicitation result for unknown provider in interactive mode.\n * Returned instead of throwing error.\n */\nexport interface ProviderElicitationResult {\n needsElicitation: true\n channel: string\n provider: string\n message: string\n freeTextAllowed: boolean\n options: string[]\n configSnippet: string\n}\n","/**\n * ServiceSpec Parser\n *\n * Converts natural language prompts to validated ServiceSpec.\n * CRITICAL: Explicit provider mentions MUST land in spec - NO defaults.\n * Missing required info triggers elicitation.\n *\n * Provider detection uses keyword matching + workspace config validation.\n * Pure functions - no side effects, AI abstracted behind interface.\n */\n\nimport {\n type CapabilitiesConfig,\n extractProviderFromPrompt,\n getDefaultProvider,\n getRegisteredProviders,\n type NotifierChannel,\n normalizeProviderName,\n} from './config'\nimport type { Action, ElicitField, ParseResult, ServiceSpec, Trigger } from './types'\nimport { ServiceSpecSchema } from './types'\n\n// ============================================================================\n// Prompt Interpreter Interface (Abstracts AI)\n// ============================================================================\n\nexport interface RawServiceSpec {\n serviceName?: string\n framework?: string\n triggers?: Array<Record<string, unknown>>\n actions?: Array<Record<string, unknown>>\n}\n\nexport interface PromptInterpreter {\n extract(prompt: string): Promise<RawServiceSpec>\n}\n\n// ============================================================================\n// Provider Detection (Pure) - Keyword Matching\n// ============================================================================\n\n/**\n * Known provider keywords for detection in prompts.\n * This is NOT metadata - just patterns to recognize provider mentions.\n * Actual provider metadata comes from workspace config.\n */\nconst PROVIDER_KEYWORDS: Record<string, { channel: NotifierChannel; provider: string }> = {\n 'pusher beams': { channel: 'push', provider: 'pusher-beams' },\n 'pusher-beams': { channel: 'push', provider: 'pusher-beams' },\n pusherbeams: { channel: 'push', provider: 'pusher-beams' },\n firebase: { channel: 'push', provider: 'firebase' },\n onesignal: { channel: 'push', provider: 'onesignal' },\n expo: { channel: 'push', provider: 'expo' },\n resend: { channel: 'email', provider: 'resend' },\n sendgrid: { channel: 'email', provider: 'sendgrid' },\n ses: { channel: 'email', provider: 'ses' },\n postmark: { channel: 'email', provider: 'postmark' },\n 'slack-webhook': { channel: 'slack', provider: 'slack-webhook' },\n 'slack webhook': { channel: 'slack', provider: 'slack-webhook' },\n 'slack-api': { channel: 'slack', provider: 'slack-api' },\n twilio: { channel: 'sms', provider: 'twilio' },\n vonage: { channel: 'sms', provider: 'vonage' },\n}\n\n/**\n * Detect explicit provider mention in prompt.\n * Returns provider name if found, undefined otherwise.\n *\n * Detection order:\n * 1. Keyword patterns (e.g., \"pusher beams\" → \"pusher-beams\")\n * 2. Workspace-registered providers (direct mention)\n * 3. Raw extraction from \"via X\" / \"using X\" patterns (fallback)\n *\n * Raw extraction enables unknown providers to flow through parsing.\n * Validation happens later in plan phase.\n *\n * Pure function.\n */\nexport const detectProvider = (\n prompt: string,\n channel: string,\n workspaceConfig?: CapabilitiesConfig,\n): string | undefined => {\n const lowerPrompt = prompt.toLowerCase()\n\n // 1. Check keyword patterns for this channel (aliases)\n for (const [keyword, info] of Object.entries(PROVIDER_KEYWORDS)) {\n if (info.channel === channel && lowerPrompt.includes(keyword)) {\n return info.provider\n }\n }\n\n // 2. Check workspace-registered providers\n const registeredProviders = getRegisteredProviders(workspaceConfig)\n const channelProviders = registeredProviders[channel as NotifierChannel] ?? []\n\n for (const provider of channelProviders) {\n const patterns = [provider, provider.replace('-', ' '), provider.replace('-', '')]\n if (patterns.some((p) => lowerPrompt.includes(p.toLowerCase()))) {\n return provider\n }\n }\n\n // 3. Raw extraction from \"via X\" / \"using X\" patterns\n // This allows unknown providers to flow through - validation in plan phase\n const rawProvider = extractProviderFromPrompt(prompt)\n if (rawProvider) {\n return normalizeProviderName(rawProvider)\n }\n\n return undefined\n}\n\n// ============================================================================\n// Inference Functions (Pure - Pattern Matching Fallback)\n// ============================================================================\n\nexport const inferServiceName = (prompt: string): string | undefined => {\n const patterns = [\n // \"create a notifications service\" / \"build order-processor service\"\n /(?:create|build|make|erstelle)\\s+(?:a\\s+)?(?:an?\\s+)?([a-z][a-z0-9-]*)\\s+service/i,\n // \"notifications service that listens\" / \"order-processor service which handles\"\n /([a-z][a-z0-9-]*)\\s+service\\s+(?:that|which|to|consumes|listens|handles)/i,\n // \"service called notifications\" / \"service named order-processor\"\n /service\\s+(?:called|named)\\s+([a-z][a-z0-9-]*)/i,\n // \"a notifications service\" / \"an order-processor service\" (at start)\n /^(?:a|an)\\s+([a-z][a-z0-9-]*)\\s+service/i,\n // Simple: \"notifications service\" at start of prompt\n /^([a-z][a-z0-9-]*)\\s+service\\b/i,\n ]\n for (const pattern of patterns) {\n const match = prompt.match(pattern)\n if (match?.[1]) {\n return match[1].toLowerCase().replace(/\\s+/g, '-')\n }\n }\n return undefined\n}\n\nexport const inferTriggers = (prompt: string): Trigger[] => {\n const triggers: Trigger[] = []\n\n // Pattern 1: \"listens to X events\", \"consumes X event\", \"handles X\", \"reacts to X\", \"when X\"\n const eventPatterns = [\n /(?:listens?\\s+(?:to|for)|consumes?|handles?|reacts?\\s+to|when)\\s+([a-z][a-z0-9.]*)\\s+events?/gi,\n /on\\s+([a-z][a-z0-9.]*)\\s+event/gi,\n ]\n for (const pattern of eventPatterns) {\n for (const match of prompt.matchAll(pattern)) {\n const eventType = match[1].toLowerCase()\n if (!triggers.some((t) => t.type === 'event' && t.eventType === eventType)) {\n triggers.push({ type: 'event', eventType })\n }\n }\n }\n\n // Pattern 2: Direct event type mentions (e.g., \"order.created\", \"user.signup\")\n // Only match if it looks like an event type (word.word format)\n const directEventPattern = /\\b([a-z][a-z0-9]*\\.[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9]*)?)\\b/gi\n for (const match of prompt.matchAll(directEventPattern)) {\n const eventType = match[1].toLowerCase()\n // Avoid false positives like \"package.json\", \"index.ts\"\n if (!eventType.includes('.json') && !eventType.includes('.ts') && !eventType.includes('.js')) {\n if (!triggers.some((t) => t.type === 'event' && t.eventType === eventType)) {\n triggers.push({ type: 'event', eventType })\n }\n }\n }\n\n return triggers\n}\n\nexport const inferActions = (prompt: string, workspaceConfig?: CapabilitiesConfig): Action[] => {\n const actions: Action[] = []\n\n // Push notifications - detect provider (with workspace config support)\n if (/push\\s+notification|send\\s+push|notify.*push/i.test(prompt)) {\n const provider = detectProvider(prompt, 'push', workspaceConfig)\n actions.push({ type: 'notify', channel: 'push', provider })\n }\n\n // Email - detect provider\n if (/send\\s+email|email\\s+notification/i.test(prompt)) {\n const provider = detectProvider(prompt, 'email', workspaceConfig)\n actions.push({ type: 'notify', channel: 'email', provider })\n }\n\n // Slack - detect provider\n if (/slack\\s+(?:message|notification)/i.test(prompt)) {\n const provider = detectProvider(prompt, 'slack', workspaceConfig)\n actions.push({ type: 'notify', channel: 'slack', provider })\n }\n\n // SMS - detect provider\n if (/sms|text\\s+message/i.test(prompt)) {\n const provider = detectProvider(prompt, 'sms', workspaceConfig)\n actions.push({ type: 'notify', channel: 'sms', provider })\n }\n\n // Emit event\n const emitMatch = prompt.match(/emit(?:s)?\\s+([a-z][a-z0-9.]*)\\s+event/i)\n if (emitMatch) {\n actions.push({ type: 'emit.event', eventType: emitMatch[1].toLowerCase() })\n }\n\n return actions\n}\n\n// ============================================================================\n// Elicitation Detection (Pure) - Supports Workspace Defaults\n// ============================================================================\n\n/**\n * Find fields that require elicitation.\n * Checks workspace defaults before requiring elicitation.\n *\n * Behavior:\n * - If provider explicitly in spec: no elicitation\n * - If no provider but workspace has default: use default (no elicitation)\n * - If no provider and no default: elicitation required\n */\nexport const findMissingFields = (raw: RawServiceSpec, workspaceConfig?: CapabilitiesConfig): ElicitField[] => {\n const missing: ElicitField[] = []\n\n if (!raw.serviceName) {\n missing.push({\n path: 'serviceName',\n prompt: 'What should the service be named? (kebab-case, e.g., \"order-notifications\")',\n type: 'string',\n required: true,\n })\n }\n\n if (!raw.triggers || raw.triggers.length === 0) {\n missing.push({\n path: 'triggers[0].eventType',\n prompt: 'What event should trigger this service? (e.g., \"order.created\")',\n type: 'string',\n required: true,\n })\n }\n\n // Check actions for missing required fields\n raw.actions?.forEach((action, index) => {\n if (action.type === 'notify' && !action.provider) {\n const channel = action.channel as NotifierChannel\n\n // Check workspace defaults first\n const defaultProvider = getDefaultProvider(channel, workspaceConfig)\n if (!defaultProvider) {\n // No default -> elicitation required\n const registeredProviders = getRegisteredProviders(workspaceConfig)\n const availableProviders = registeredProviders[channel] ?? []\n missing.push({\n path: `actions[${index}].provider`,\n prompt:\n availableProviders.length > 0\n ? `Which provider for ${channel} notifications?`\n : `Which provider for ${channel} notifications? (No providers registered - add to package.json pf.capabilities)`,\n type: 'enum',\n options: availableProviders,\n required: true,\n })\n }\n // If default exists, will be applied in applyDefaults\n }\n\n if (action.type === 'call.http' && !action.baseUrl) {\n missing.push({\n path: `actions[${index}].baseUrl`,\n prompt: 'What is the base URL for the HTTP call?',\n type: 'string',\n required: true,\n })\n }\n })\n\n return missing\n}\n\n/**\n * Apply workspace defaults to raw spec.\n * Called after elicitation check to fill in defaults.\n * Pure function.\n */\nexport const applyWorkspaceDefaults = (raw: RawServiceSpec, workspaceConfig?: CapabilitiesConfig): RawServiceSpec => {\n if (!workspaceConfig || !raw.actions) return raw\n\n const updatedActions = raw.actions.map((action) => {\n if (action.type === 'notify' && !action.provider) {\n const channel = action.channel as NotifierChannel\n const defaultProvider = getDefaultProvider(channel, workspaceConfig)\n if (defaultProvider) {\n return { ...action, provider: defaultProvider }\n }\n }\n return action\n })\n\n return { ...raw, actions: updatedActions }\n}\n\n// ============================================================================\n// Validation (Pure) - Supports Workspace Config\n// ============================================================================\n\n/**\n * Validate raw spec with workspace config support.\n * Applies workspace defaults before validation.\n */\nexport const validateSpec = (raw: RawServiceSpec, workspaceConfig?: CapabilitiesConfig): ParseResult => {\n // Apply workspace defaults first (e.g., default providers)\n const withDefaults = applyWorkspaceDefaults(raw, workspaceConfig)\n\n // Check for missing fields (respects workspace defaults)\n const missingFields = findMissingFields(withDefaults, workspaceConfig)\n\n if (missingFields.length > 0) {\n return {\n complete: false,\n fields: missingFields,\n partialSpec: withDefaults as Partial<ServiceSpec>,\n }\n }\n\n const result = ServiceSpecSchema.safeParse(withDefaults)\n\n if (!result.success) {\n const fields: ElicitField[] = result.error.issues.map((issue) => ({\n path: issue.path.join('.'),\n prompt: issue.message,\n type: 'string',\n required: true,\n }))\n return { complete: false, fields, partialSpec: withDefaults as Partial<ServiceSpec> }\n }\n\n return { complete: true, spec: result.data }\n}\n\n// ============================================================================\n// Main Parser Function (Pure) - Supports Workspace Config\n// ============================================================================\n\nexport interface ParseOptions {\n interpreter?: PromptInterpreter\n workspaceConfig?: CapabilitiesConfig\n}\n\n/**\n * Parse natural language prompt to ServiceSpec.\n * Uses interpreter for extraction, with pattern matching fallback.\n * Supports workspace config for defaults and provider detection.\n */\nexport const parseServicePrompt = async (\n prompt: string,\n options?: ParseOptions | PromptInterpreter,\n): Promise<ParseResult> => {\n // Handle legacy signature (just interpreter)\n const opts: ParseOptions = options && 'extract' in options ? { interpreter: options } : (options ?? {})\n\n const { interpreter, workspaceConfig } = opts\n let raw: RawServiceSpec\n\n if (interpreter) {\n raw = await interpreter.extract(prompt)\n } else {\n // Pattern matching fallback - pass workspaceConfig for provider detection\n raw = {\n serviceName: inferServiceName(prompt),\n framework: /nest(?:js)?/i.test(prompt) ? 'nest' : 'hono',\n triggers: inferTriggers(prompt),\n actions: inferActions(prompt, workspaceConfig),\n }\n }\n\n return validateSpec(raw, workspaceConfig)\n}\n\n// ============================================================================\n// Merge Elicited Answers (Pure)\n// ============================================================================\n\nexport const mergeElicitedAnswers = (\n partial: Partial<ServiceSpec>,\n answers: Record<string, unknown>,\n): RawServiceSpec => {\n const merged = { ...partial } as RawServiceSpec\n\n for (const [path, value] of Object.entries(answers)) {\n const parts = path.split(/[.[\\]]/).filter(Boolean)\n let current: Record<string, unknown> = merged as Record<string, unknown>\n\n for (let i = 0; i < parts.length - 1; i++) {\n const key = parts[i]\n const nextKey = parts[i + 1]\n const isNextArray = /^\\d+$/.test(nextKey)\n\n if (current[key] === undefined) {\n current[key] = isNextArray ? [] : {}\n }\n current = current[key] as Record<string, unknown>\n }\n\n current[parts[parts.length - 1]] = value\n }\n\n return merged\n}\n\n// ============================================================================\n// Fixture Interpreter (For Testing)\n// ============================================================================\n\n/**\n * Create a fixture-based interpreter for testing.\n * Maps keywords in prompt to predefined specs.\n */\nexport const createFixtureInterpreter = (fixtures: Record<string, RawServiceSpec>): PromptInterpreter => ({\n extract: async (prompt: string): Promise<RawServiceSpec> => {\n const lowerPrompt = prompt.toLowerCase()\n for (const [keyword, spec] of Object.entries(fixtures)) {\n if (lowerPrompt.includes(keyword.toLowerCase())) {\n return spec\n }\n }\n // Fallback to pattern matching\n return {\n serviceName: inferServiceName(prompt),\n framework: /nest(?:js)?/i.test(prompt) ? 'nest' : 'hono',\n triggers: inferTriggers(prompt),\n actions: inferActions(prompt),\n }\n },\n})\n","/**\n * Change Aggregation Utilities\n *\n * For plan mode (dry-run) - aggregate and format change previews.\n *\n * Code organization: types → pure functions → higher-order functions\n */\n\nimport type { Change, EffectResult } from './handlers'\n\n/**\n * Group items by key (functional, immutable)\n */\nconst groupBy = <T>(items: T[], key: keyof T): Record<string, T[]> => {\n return items.reduce((acc, item) => {\n const group = String(item[key])\n const existing = acc[group]\n acc[group] = existing ? [...existing, item] : [item]\n return acc\n }, {} as Record<string, T[]>)\n}\n\n/**\n * Format a single change detail\n */\nconst formatChange = (change: Change, index: number): string[] => {\n const lines = [\n `${index + 1}. ${change.type.toUpperCase()}: ${change.path}`,\n ` ${change.description}`,\n ]\n\n if (change.preview) {\n const previewLines = change.preview.split('\\n').map((line) => ` ${line}`)\n lines.push(' Preview:', ' ```', ...previewLines, ' ```')\n }\n\n lines.push('')\n return lines\n}\n\n/**\n * Format file list for a group\n */\nconst formatFileList = (icon: string, label: string, items: Change[]): string[] => {\n if (!items?.length) return []\n return [\n `${icon} ${label}:`,\n ...items.map((c) => ` • ${c.path} - ${c.description}`),\n '',\n ]\n}\n\n/**\n * Aggregate all changes from effect results\n *\n * Filters successful results and flattens their changes arrays.\n */\nexport const aggregateChanges = (results: EffectResult[]): Change[] => {\n return results.filter((r) => r.success && r.changes).flatMap((r) => r.changes ?? [])\n}\n\n/**\n * Format change summary for display\n *\n * Groups by type and shows counts + file list.\n */\nexport const formatChangeSummary = (changes: Change[]): string => {\n if (changes.length === 0) {\n return '✓ No changes'\n }\n\n const groups = groupBy(changes, 'type')\n\n const summary = [\n '📝 Changes Summary:',\n `${groups.create?.length || 0} files to create`,\n `${groups.update?.length || 0} files to update`,\n `${groups.delete?.length || 0} files to delete`,\n '',\n ...formatFileList('📄', 'Create', groups.create),\n ...formatFileList('✏️ ', 'Update', groups.update),\n ...formatFileList('🗑️ ', 'Delete', groups.delete),\n ]\n\n return summary.join('\\n')\n}\n\n/**\n * Format detailed change preview (with code snippets)\n */\nexport const formatChangeDetails = (changes: Change[]): string => {\n if (changes.length === 0) {\n return '✓ No changes'\n }\n\n const header = ['📝 Detailed Changes:', '']\n const details = changes.flatMap((change, index) => formatChange(change, index))\n\n return [...header, ...details].join('\\n')\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { deriveEventNames } from '@crossdelta/cloudevents'\nimport { getContractsConfig } from '../packages/config'\n\n/**\n * Add export to a domain index (e.g., events/orders/index.ts)\n */\nconst addExportToDomainIndex = (domainIndexPath: string, eventFile: string): boolean => {\n const exportLine = `export * from './${eventFile}'`\n\n // Create domain index if it doesn't exist\n if (!existsSync(domainIndexPath)) {\n const domainDir = dirname(domainIndexPath)\n if (!existsSync(domainDir)) {\n mkdirSync(domainDir, { recursive: true })\n }\n\n const header = `/**\\n * ${dirname(domainIndexPath).split('/').pop()} Domain Events\\n */\\n\\n`\n writeFileSync(domainIndexPath, `${header + exportLine}\\n`, 'utf-8')\n return true\n }\n\n const content = readFileSync(domainIndexPath, 'utf-8')\n if (content.includes(`'./${eventFile}'`)) return false\n\n // Append export\n const updatedContent = `${content.trimEnd()}\\n${exportLine}\\n`\n writeFileSync(domainIndexPath, updatedContent, 'utf-8')\n return true\n}\n\n/**\n * Add export to events/index.ts (domain-level)\n */\nconst addDomainToEventsIndex = (eventsIndexPath: string, domain: string): boolean => {\n const exportLine = `export * from './${domain}'`\n\n if (!existsSync(eventsIndexPath)) {\n // Create events/index.ts with header\n const header = `/**\\n * Event Contracts Index\\n * \\n * Re-exports all event contracts for convenient importing.\\n */\\n\\n`\n writeFileSync(eventsIndexPath, header + exportLine + '\\n', 'utf-8')\n return true\n }\n\n const content = readFileSync(eventsIndexPath, 'utf-8')\n\n // Check if export line already exists (not just in comments)\n const lines = content.split('\\n')\n if (lines.some((line) => line.trim() === exportLine)) {\n return false\n }\n\n // Find last export line or append to end\n const lastExportIndex = lines.findLastIndex((line) => line.startsWith('export'))\n\n if (lastExportIndex >= 0) {\n // Insert after last export\n lines.splice(lastExportIndex + 1, 0, exportLine)\n } else {\n // No exports yet - append at end (after all comments)\n lines.push(exportLine)\n }\n\n writeFileSync(eventsIndexPath, lines.join('\\n'), 'utf-8')\n return true\n}\n\n/**\n * Ensure main index.ts has proper exports.\n * Fixes: commented exports, direct deep imports, missing exports.\n */\nconst enableMainExports = (mainIndexPath: string): boolean => {\n if (!existsSync(mainIndexPath)) return false\n\n const content = readFileSync(mainIndexPath, 'utf-8')\n const eventsExport = \"export * from './events'\"\n\n // Check if UNCOMMENTED export exists (not just in comments)\n const hasUncommentedExport = content.split('\\n').some(\n (line) => line.trim() === eventsExport || line.trim().startsWith(eventsExport)\n )\n if (hasUncommentedExport) return false\n\n let updated = content\n\n // Uncomment if commented\n updated = updated.replace(/\\/\\/\\s*export \\* from '\\.\\/events'/, eventsExport)\n updated = updated.replace(/\\/\\/\\s*export \\* from '\\.\\/stream-policies'/, \"export * from './stream-policies'\")\n\n // Remove direct deep imports (e.g., './events/orders/created')\n if (/export \\* from '\\.\\/events\\/\\w+\\/\\w+'/.test(updated)) {\n updated = updated.replace(/export \\* from '\\.\\/events\\/\\w+\\/\\w+'\\n?/g, '')\n }\n\n // Add if still missing\n if (!updated.includes(eventsExport)) {\n updated = `${updated.trimEnd()}\\n${eventsExport}\\n`\n }\n\n if (updated !== content) {\n writeFileSync(mainIndexPath, updated, 'utf-8')\n return true\n }\n\n return false\n}\n\n/**\n * Manages exports in packages/contracts/src/index.ts\n */\n/**\n * Add export for event type to contracts index.ts (now uses domain structure)\n */\nexport const addExportToIndex = (eventType: string, workspaceRoot?: string): boolean => {\n const { packagePath } = getContractsConfig(workspaceRoot)\n const { domain, action } = deriveEventNames(eventType)\n\n const eventsDir = join(packagePath, 'src', 'events')\n\n // Guard: contracts package doesn't exist (e.g. fake path in tests)\n if (!existsSync(eventsDir)) return false\n\n const domainDir = join(eventsDir, domain)\n const domainIndexPath = join(domainDir, 'index.ts')\n const eventsIndexPath = join(eventsDir, 'index.ts')\n const mainIndexPath = join(packagePath, 'src', 'index.ts')\n\n // Check for legacy singular folder (e.g., 'customer' when we're creating 'customers')\n const singularDomain = eventType.split('.')[0]\n const legacyDomainDir = join(eventsDir, singularDomain)\n if (singularDomain !== domain && existsSync(legacyDomainDir)) {\n console.warn(`⚠️ Warning: Legacy folder '${singularDomain}/' found. Please migrate to '${domain}/' to avoid conflicts.`)\n console.warn(` Run: mv ${legacyDomainDir} ${domainDir}`)\n }\n\n let updated = false\n\n // 1. Add export to domain index (e.g., events/orders/index.ts)\n if (addExportToDomainIndex(domainIndexPath, action)) {\n updated = true\n }\n\n // 2. Add domain export to events index (e.g., events/index.ts)\n if (addDomainToEventsIndex(eventsIndexPath, domain)) {\n updated = true\n }\n\n // 3. Enable main exports if commented (first event created)\n if (enableMainExports(mainIndexPath)) {\n updated = true\n }\n\n return updated\n}\n\nexport const addExportToIndexPath = (indexPath: string, eventName: string): boolean => {\n if (!existsSync(indexPath)) return false\n\n const exportLine = `export * from './events/${eventName}'`\n const content = readFileSync(indexPath, 'utf-8')\n\n if (content.includes(`'./events/${eventName}'`)) return false\n\n const lines = content.split('\\n')\n const lastExportIndex = lines.findLastIndex((line) => line.startsWith('export'))\n\n if (lastExportIndex >= 0) {\n lines.splice(lastExportIndex + 1, 0, exportLine)\n } else {\n lines.push('', exportLine)\n }\n\n writeFileSync(indexPath, lines.join('\\n'), 'utf-8')\n return true\n}\n\nexport const hasExportInIndex = (indexPath: string, eventName: string): boolean => {\n if (!existsSync(indexPath)) return false\n\n const content = readFileSync(indexPath, 'utf-8')\n return content.includes(`'./events/${eventName}'`)\n}\n","/**\n * Stream Effect Handler\n *\n * Executes stream.wired effects by modifying service entry points.\n * This is the RUNTIME EXECUTION for the stream.wired domain effect.\n *\n * Domain effects (cloudevents) → Effect handlers (platform-sdk)\n */\n\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { getStreamName } from '@crossdelta/cloudevents'\n\n/**\n * Checks if service index.ts already consumes events for the given stream\n * Handles variations like CUSTOMER/CUSTOMERS by checking subject patterns\n */\nexport const serviceConsumesStream = (servicePath: string, streamName: string): boolean => {\n const indexPath = join(servicePath, 'src', 'index.ts')\n if (!existsSync(indexPath)) return false\n\n const content = readFileSync(indexPath, 'utf-8')\n const namespace = streamName.toLowerCase()\n\n // Check new API: streams: ['STREAMNAME']\n const streamsArrayPattern = new RegExp(`streams:\\\\s*\\\\[[^\\\\]]*['\"]${streamName}['\"]`)\n if (streamsArrayPattern.test(content)) return true\n\n // Check exact stream name (old API)\n if (content.includes(`stream: '${streamName}'`)) return true\n\n // Check for subject patterns that would overlap (e.g., customer.* or customer.>)\n const subjectPattern = new RegExp(`subjects:\\\\s*\\\\[.*['\"]${namespace}\\\\.[*>]`)\n return subjectPattern.test(content)\n}\n\n/**\n * Adds cloudevents import to service index.ts if not present\n */\nconst addCloudEventsImport = (content: string): string => {\n if (content.includes('@crossdelta/cloudevents')) return content\n\n const cloudEventsImport = `import { consumeJetStreams } from '@crossdelta/cloudevents'\\n`\n\n // Try after telemetry import first\n const telemetryMatch = content.match(/import\\s+['\"]@crossdelta\\/telemetry['\"]\\s*\\n/)\n if (telemetryMatch) {\n const insertPos = (telemetryMatch.index ?? 0) + telemetryMatch[0].length\n return `${content.slice(0, insertPos)}\\n${cloudEventsImport}${content.slice(insertPos)}`\n }\n\n // Fallback: after first import\n const firstImportMatch = content.match(/import\\s+.*\\n/)\n if (firstImportMatch) {\n const insertPos = (firstImportMatch.index ?? 0) + firstImportMatch[0].length\n return content.slice(0, insertPos) + cloudEventsImport + content.slice(insertPos)\n }\n\n return content\n}\n\n/**\n * Generates stream consumption code block\n */\nconst generateStreamCode = (streamName: string, serviceName: string): string => `\n\n// Consume from ${streamName} stream\nconsumeJetStreams({\n streams: ['${streamName}'],\n consumer: '${serviceName}-service',\n discover: './src/events/**/*.handler.ts',\n})`\n\n/**\n * Result of adding stream to service\n */\nexport interface AddStreamResult {\n added: boolean\n streamName: string\n warning?: string\n}\n\n/**\n * Adds stream consumption to service index.ts (Hono services)\n * For NestJS services (main.ts), returns without modification (EventsModule handles it)\n *\n * This is the effect handler for stream.wired domain effect.\n */\nexport const addStreamToService = (\n servicePath: string,\n eventType: string,\n): AddStreamResult => {\n const streamName = getStreamName(eventType)\n const indexPath = join(servicePath, 'src', 'index.ts')\n const mainPath = join(servicePath, 'src', 'main.ts')\n\n // Check for NestJS service (main.ts instead of index.ts)\n // NestJS services have EventsModule set up during scaffolding\n if (!existsSync(indexPath) && existsSync(mainPath)) {\n return { added: false, streamName }\n }\n\n if (!existsSync(indexPath)) {\n return { added: false, streamName, warning: 'Entry point not found (index.ts or main.ts)' }\n }\n\n if (serviceConsumesStream(servicePath, streamName)) {\n return { added: false, streamName }\n }\n\n let content = readFileSync(indexPath, 'utf-8')\n const serviceName = servicePath.split('/').pop() || 'unknown'\n\n // Add import if service doesn't use JetStream yet\n if (!content.includes('consumeJetStreams')) {\n content = addCloudEventsImport(content)\n }\n\n const streamCode = generateStreamCode(streamName, serviceName)\n const updatedContent = `${content.trimEnd() + streamCode}\\n`\n writeFileSync(indexPath, updatedContent, 'utf-8')\n\n return { added: true, streamName }\n}\n","/**\n * Effect Handlers\n *\n * pf applies domain effects returned by plugin commands.\n * Handlers are keyed by effect kind - clean data-driven dispatch.\n */\n\nimport { addExportToIndex } from '../events/index-manager'\nimport type { PfEffect, PfWorkspaceContext } from '../plugins/types'\nimport { addStreamToService } from './stream.handler'\n\n/**\n * Runtime context for effect handlers\n */\nexport interface EffectRuntimeContext {\n workspace: PfWorkspaceContext\n logger: {\n debug: (message: string) => void\n info: (message: string) => void\n warn: (message: string) => void\n error: (message: string) => void\n }\n}\n\n/**\n * Represents a planned change (for dry-run mode)\n */\nexport interface Change {\n type: 'create' | 'update' | 'delete'\n path: string\n description: string\n preview?: string // Content preview (first 500 chars)\n}\n\n/**\n * Result of applying an effect\n */\nexport interface EffectResult {\n success: boolean\n message?: string\n changes?: Change[] // For plan mode (dry-run)\n}\n\n/**\n * Options for effect handlers\n */\nexport interface EffectHandlerOptions {\n dryRun?: boolean // If true, return changes without applying\n}\n\n/**\n * Effect handler function signature\n */\nexport type EffectHandler = (\n effect: PfEffect,\n context: EffectRuntimeContext,\n options?: EffectHandlerOptions,\n) => EffectResult\n\n/**\n * Handler for stream.wired effect\n *\n * Wires a JetStream stream to a service's entry point\n */\nconst handleStreamWired: EffectHandler = (effect, context, options) => {\n const { stream, servicePath } = effect as PfEffect & { stream: string; servicePath: string }\n\n // Build absolute path if relative\n const absolutePath = servicePath.startsWith('/') ? servicePath : `${context.workspace.workspaceRoot}/${servicePath}`\n\n // Plan mode: Return change preview without modifying files\n if (options?.dryRun) {\n return {\n success: true,\n message: `Would wire stream ${stream} to ${servicePath}`,\n changes: [\n {\n type: 'update',\n path: absolutePath,\n description: `Wire ${stream} stream to service`,\n preview: `consumeJetStreams({ streams: ['${stream.toUpperCase()}'], ... })`,\n },\n ],\n }\n }\n\n // Apply mode: Execute the wiring\n const result = addStreamToService(absolutePath, `${stream.toLowerCase()}.event`)\n\n if (result.warning) {\n context.logger.warn(result.warning)\n return { success: false, message: result.warning }\n }\n\n if (result.added) {\n context.logger.info(`Wired stream ${result.streamName} to service`)\n return { success: true, message: `Wired stream ${result.streamName}` }\n }\n\n context.logger.debug(`Stream ${result.streamName} already wired`)\n return { success: true, message: `Stream ${result.streamName} already configured` }\n}\n\n/**\n * Handler for contract.created effect\n *\n * In plan mode: Returns preview of contract file that would be created\n * In apply mode: Logs contract creation (actual file creation happens in command)\n */\nconst handleContractCreated: EffectHandler = (effect, context, options) => {\n const { path, eventType } = effect as PfEffect & { path: string; eventType: string }\n\n // Plan mode: Return change preview\n if (options?.dryRun) {\n // Generate preview of contract content (simplified)\n const preview = `\nimport { createContract } from '@crossdelta/cloudevents'\nimport { z } from 'zod'\n\nexport const ${toPascalCase(eventType)}Contract = createContract({\n type: '${eventType}',\n schema: z.object({ ... }),\n})\n `.trim()\n\n return {\n success: true,\n message: `Would create contract ${eventType}`,\n changes: [\n {\n type: 'create',\n path,\n description: `Create event contract for ${eventType}`,\n preview: preview.slice(0, 500),\n },\n ],\n }\n }\n\n // Apply mode: Update index.ts exports\n const updated = addExportToIndex(eventType, context.workspace.workspaceRoot)\n if (updated) {\n context.logger.debug(`Added export for ${eventType} to contracts index`)\n }\n\n context.logger.debug(`Contract created: ${eventType} at ${path}`)\n return {\n success: true,\n message: updated ? `Contract ${eventType} created with exports` : `Contract ${eventType} created`,\n }\n}\n\n/**\n * Helper: Convert event.type to PascalCase\n */\nconst toPascalCase = (eventType: string): string => {\n return eventType\n .split('.')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n}\n\n/**\n * Handler for handler.created effect\n *\n * In plan mode: Returns preview of event handler that would be created\n * In apply mode: Logs handler creation (actual file creation happens in command)\n */\nconst handleHandlerCreated: EffectHandler = (effect, context, options) => {\n const { path, eventType, servicePath } = effect as PfEffect & {\n path: string\n eventType: string\n servicePath: string\n }\n\n // Plan mode: Return change preview\n if (options?.dryRun) {\n const preview = `\nimport { handleEvent } from '@crossdelta/cloudevents'\nimport { ${toPascalCase(eventType)}Contract } from '@your-scope/contracts'\n\nexport default handleEvent(${toPascalCase(eventType)}Contract, async (data) => {\n console.log('Processing ${eventType}:', data)\n // TODO: Implement handler logic\n})\n `.trim()\n\n return {\n success: true,\n message: `Would create handler for ${eventType}`,\n changes: [\n {\n type: 'create',\n path,\n description: `Create event handler for ${eventType}`,\n preview: preview.slice(0, 500),\n },\n ],\n }\n }\n\n // Apply mode: Log (file already created by command)\n context.logger.debug(`Handler created: ${eventType} at ${path} (service: ${servicePath})`)\n return { success: true }\n}\n\n/**\n * Effect handlers registry\n *\n * Maps effect kinds to their handlers.\n * Add new handlers here as new effect types are introduced.\n */\nconst effectHandlers: Record<string, EffectHandler> = {\n 'stream.wired': handleStreamWired,\n 'contract.created': handleContractCreated,\n 'handler.created': handleHandlerCreated,\n}\n\n/**\n * Apply a list of effects\n *\n * Iterates through effects and dispatches to registered handlers.\n * Unknown effects are logged and skipped (not fatal).\n *\n * @param effects - List of effects to apply\n * @param context - Runtime context with workspace and logger\n * @param options - Optional settings (e.g., dryRun for plan mode)\n * @returns Array of effect results\n */\nexport const applyEffects = (\n effects: PfEffect[],\n context: EffectRuntimeContext,\n options?: EffectHandlerOptions,\n): EffectResult[] => {\n return effects.map((effect) => {\n const handler = effectHandlers[effect.kind]\n\n if (!handler) {\n context.logger.warn(`Unknown effect kind: ${effect.kind}`)\n return { success: false, message: `Unknown effect kind: ${effect.kind}` }\n }\n\n return handler(effect, context, options)\n })\n}\n","/**\n * Service Generation Flow\n *\n * Deterministic flow for generating microservices from templates.\n * Supports plan/apply separation for MCP integration.\n */\n\nimport { join } from 'node:path'\nimport { deriveEventNames } from '@crossdelta/cloudevents'\nimport type { Artifact, NextAction, OperationResult } from '../operations/types'\nimport { ok } from '../operations/types'\nimport { findWorkspaceRoot, getContractsConfig, getWorkspacePathsConfig } from '../packages/config'\nimport type { PfEffect } from '../plugins/types'\nimport { type EnvVarDef, selectTemplate, type TemplateType, type TemplateVars, toEnvKey } from '../templates'\nimport { buildServiceEffects, type FileSpec } from './effect-builder'\nimport { allocateNextPort, INTERNAL_PORT_START, scanUsedPorts } from './port-allocation'\n\n/**\n * Service generation inputs\n */\nexport interface ServiceGenerationInputs {\n /** Template type (hono-bun, hono-micro, nest, nest-micro) */\n type: TemplateType\n /** Service name (kebab-case) */\n name: string\n /** Optional: Custom service path (default: services/<name>) */\n path?: string\n /** Optional: Enable event consumers (auto-set if events provided) */\n hasEvents?: boolean\n /** Optional: NATS streams to consume from (auto-derived if events provided) */\n streams?: string[]\n /** Optional: Event types to consume (e.g., ['order.created']) */\n events?: string[]\n /** Optional: Workspace root (auto-detected if not provided) */\n workspaceRoot?: string\n /** Optional: Explicit port (for deterministic generation) */\n port?: number\n /** Optional: Environment variables from capability plan (for env.ts) */\n envVars?: EnvVarDef[]\n}\n\n/**\n * Service metadata\n */\nexport interface ServiceMeta {\n serviceName: string\n servicePath: string\n port: number\n vars: TemplateVars\n}\n\n/**\n * Legacy result format (for backward compatibility)\n */\nexport interface ServiceGenerationResult {\n serviceName: string\n servicePath: string\n port: number\n effects: PfEffect[]\n vars: TemplateVars\n}\n\n/**\n * Validate service name (pure)\n */\nconst validateServiceName = (name: string): void => {\n if (!name || name.trim().length === 0) {\n throw new Error('Service name cannot be empty')\n }\n\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {\n throw new Error(`Service name '${name}' must be kebab-case (lowercase, alphanumeric, hyphens only)`)\n }\n}\n\n/**\n * Resolve service path (pure)\n */\nconst resolveServicePath = (name: string, customPath: string | undefined, workspaceRoot: string): string => {\n if (customPath) {\n if (customPath.startsWith('/')) {\n return customPath\n }\n\n if (customPath.startsWith('.')) {\n return join(workspaceRoot, customPath)\n }\n\n if (customPath.includes('/')) {\n return join(workspaceRoot, customPath)\n }\n }\n\n const paths = getWorkspacePathsConfig(workspaceRoot)\n return join(workspaceRoot, paths.services, name)\n}\n\n/**\n * Derive unique streams from event types (pure)\n *\n * Uses deriveEventNames from @crossdelta/cloudevents for correct stream naming.\n *\n * @example deriveStreamsFromEvents(['order.created', 'order.updated']) => ['ORDERS']\n */\nconst deriveStreamsFromEvents = (events: readonly string[]): string[] => [\n ...new Set(events.map((e) => deriveEventNames(e).streamName)),\n]\n\n/**\n * Build template variables (pure)\n *\n * Derives hasEvents and streams from events array if provided.\n */\nconst buildTemplateVars = (\n inputs: ServiceGenerationInputs,\n workspaceRoot: string,\n servicePath: string,\n port: number,\n): TemplateVars => {\n const contractsConfig = getContractsConfig(workspaceRoot)\n const workspaceScope = contractsConfig.packageName.split('/')[0]\n\n // Derive hasEvents and streams from events array if provided\n const events = inputs.events ?? []\n const hasEvents = events.length > 0 || inputs.hasEvents || false\n const streams = events.length > 0 ? deriveStreamsFromEvents(events) : (inputs.streams ?? [])\n\n return {\n serviceName: inputs.name,\n packageName: `${workspaceScope}/${inputs.name}`,\n servicePath: servicePath.replace(`${workspaceRoot}/`, ''),\n port,\n envVarName: toEnvKey(inputs.name),\n hasEvents,\n streams,\n events,\n workspaceScope,\n envVars: inputs.envVars,\n }\n}\n\n/**\n * Generate files from template (pure)\n */\nconst generateFiles = (template: ReturnType<typeof selectTemplate>, vars: TemplateVars): FileSpec[] => {\n return template.files\n .filter((f) => !f.skip || !f.skip(vars))\n .map((f) => ({\n path: f.path,\n content: f.content(vars),\n }))\n}\n\n/**\n * Build artifacts list for operation result (pure)\n */\nconst buildArtifacts = (files: FileSpec[], serviceName: string, servicePath: string): Artifact[] => {\n const fileArtifacts: Artifact[] = files.map((f) => ({\n type: 'file' as const,\n path: join(servicePath, f.path),\n description: `Service file: ${f.path}`,\n }))\n\n return [\n ...fileArtifacts,\n {\n type: 'config',\n path: `infra/services/${serviceName}.ts`,\n description: 'Infrastructure configuration',\n },\n {\n type: 'env',\n path: '.env.local',\n description: 'Environment variables',\n },\n ]\n}\n\n/**\n * Build next actions for operation result (pure)\n */\nconst buildNextActions = (servicePath: string): NextAction[] => {\n return [\n {\n command: `cd ${servicePath} && bun dev`,\n description: 'Start this service',\n },\n {\n command: 'pf dev',\n description: 'Start all services',\n },\n ]\n}\n\n/**\n * Plan service generation (returns OperationResult)\n *\n * This is the MCP-ready interface that returns a structured result\n * with effects that can be inspected before execution.\n */\nexport const planServiceGeneration = (inputs: ServiceGenerationInputs): OperationResult<ServiceMeta> => {\n // 1. Validate\n validateServiceName(inputs.name)\n\n // 2. Resolve context\n const workspaceRoot = inputs.workspaceRoot ?? findWorkspaceRoot()\n const servicePath = resolveServicePath(inputs.name, inputs.path, workspaceRoot)\n\n // 3. Allocate port (deterministic if explicit, scans if auto)\n const port = inputs.port ?? allocateNextPort(scanUsedPorts(workspaceRoot), INTERNAL_PORT_START)\n\n // 4. Build vars\n const vars = buildTemplateVars(inputs, workspaceRoot, servicePath, port)\n\n // 5. Select template\n const template = selectTemplate(inputs.type)\n\n // 6. Generate files\n const files = generateFiles(template, vars)\n\n // 7. Build effects\n const effects = buildServiceEffects(servicePath, files, vars, template)\n\n // 8. Build artifacts\n const artifacts = buildArtifacts(files, inputs.name, servicePath)\n\n // 9. Build next actions\n const next = buildNextActions(servicePath)\n\n return ok<ServiceMeta>('service.generate', `Generated ${inputs.name} service (port ${port})`, {\n artifacts,\n changes: effects,\n next,\n data: {\n serviceName: inputs.name,\n servicePath,\n port,\n vars,\n },\n })\n}\n\n/**\n * Generate service (legacy interface for backward compatibility)\n *\n * Returns the old ServiceGenerationResult format.\n * Use planServiceGeneration() for new code.\n */\nexport const generateService = (inputs: ServiceGenerationInputs): ServiceGenerationResult => {\n const result = planServiceGeneration(inputs)\n\n if (!result.ok || !result.data) {\n throw new Error(result.summary)\n }\n\n return {\n serviceName: result.data.serviceName,\n servicePath: result.data.servicePath,\n port: result.data.port,\n effects: result.changes,\n vars: result.data.vars,\n }\n}\n","/**\n * Operation Result Types\n *\n * Standard result shape for all pf operations.\n * Enables consistent MCP tool responses and plan/apply workflows.\n */\n\nimport type { PfEffect } from '../plugins/types'\n\n/**\n * Artifact generated by an operation\n */\nexport interface Artifact {\n /** Artifact type (file, config, env, etc.) */\n type: 'file' | 'config' | 'env' | 'stream' | 'service'\n /** Path or identifier */\n path: string\n /** Human-readable description */\n description: string\n}\n\n/**\n * Diagnostic message from an operation\n */\nexport interface Diagnostic {\n /** Severity level */\n level: 'info' | 'warning' | 'error'\n /** Diagnostic message */\n message: string\n /** Optional: Location (file path, line number) */\n location?: string\n}\n\n/**\n * Suggested next action after operation\n */\nexport interface NextAction {\n /** Command to run */\n command: string\n /** Description of what the command does */\n description: string\n}\n\n/**\n * Standard operation result\n *\n * All pf operations return this shape for consistency.\n * Supports both plan mode (effects only) and apply mode (execution).\n */\nexport interface OperationResult<T = unknown> {\n /** Operation succeeded */\n ok: boolean\n /** Operation identifier (e.g., 'service.generate', 'event.add') */\n operation: string\n /** Human-readable summary */\n summary: string\n /** Generated artifacts */\n artifacts: Artifact[]\n /** Structured changes (effects) for plan/apply */\n changes: PfEffect[]\n /** Non-blocking diagnostics */\n diagnostics: Diagnostic[]\n /** Optional: Suggested next actions */\n next?: NextAction[]\n /** Optional: Operation-specific data */\n data?: T\n}\n\n/**\n * Create a successful operation result\n */\nexport const ok = <T>(\n operation: string,\n summary: string,\n options: {\n artifacts?: Artifact[]\n changes?: PfEffect[]\n diagnostics?: Diagnostic[]\n next?: NextAction[]\n data?: T\n } = {},\n): OperationResult<T> => ({\n ok: true,\n operation,\n summary,\n artifacts: options.artifacts ?? [],\n changes: options.changes ?? [],\n diagnostics: options.diagnostics ?? [],\n next: options.next,\n data: options.data,\n})\n\n/**\n * Create a failed operation result\n */\nexport const err = (\n operation: string,\n error: string,\n options: {\n diagnostics?: Diagnostic[]\n data?: unknown\n } = {},\n): OperationResult => ({\n ok: false,\n operation,\n summary: `Failed: ${error}`,\n artifacts: [],\n changes: [],\n diagnostics: options.diagnostics ?? [{ level: 'error', message: error }],\n data: options.data,\n})\n","/**\n * Templates for Hono microservice scaffolding using Handlebars.\n */\nimport { join } from 'node:path'\nimport { getDirname } from '../../../core/esm'\nimport { findPackageRoot } from '../../../core/filesystem'\nimport { createTemplateRenderer, findTemplatesDir } from '../../../core/templates/renderer'\nimport { toEnvKey } from '../../../core/templates/strings'\nimport type { EnvVarDef } from '../../../core/templates/types'\n\n// Re-export for backward compatibility\nexport { toEnvKey }\n\n/**\n * Gets module directory path.\n * Lazy evaluation to support both ESM and CJS bundles.\n */\nconst getModuleDir = (): string => {\n if (typeof import.meta?.url === 'string') {\n return getDirname(import.meta.url)\n }\n if (typeof __dirname === 'string') return __dirname\n return process.cwd()\n}\n\nconst getTemplatesDir = () => {\n const moduleDir = getModuleDir()\n const packageRoot = findPackageRoot()\n return findTemplatesDir(\n [\n join(moduleDir, 'templates', 'hono-microservice'),\n join(moduleDir, '..', 'hono-microservice', 'templates'),\n join(packageRoot, 'bin', 'templates', 'hono-microservice'), // Global install fallback\n ],\n 'Hono templates directory not found.',\n )\n}\n\nconst renderTemplate = (templateName: string, data: Record<string, unknown> = {}) =>\n createTemplateRenderer(getTemplatesDir())(templateName, data)\n\n/**\n * Generate the tsconfig.json content for a Hono microservice.\n */\nexport function generateHonoTsConfig(): string {\n return renderTemplate('tsconfig.json.hbs')\n}\n\n/**\n * Generate the Dockerfile content for a Hono microservice.\n */\nexport function generateHonoDockerfile(bunVersion = '1.2.23'): string {\n return renderTemplate('Dockerfile.hbs', { bunVersion })\n}\n\n/**\n * Generate biome.json for Hono services.\n */\nexport function generateHonoBiomeJson(): string {\n return renderTemplate('biome.json.hbs')\n}\n\n/**\n * Generate the src/index.ts content for a Hono microservice.\n */\nexport function generateHonoIndexTs(serviceName: string): string {\n return renderTemplate('src/index.ts.hbs', {\n envKey: toEnvKey(serviceName),\n })\n}\n\n/**\n * Generate the src/config/env.ts content for environment validation.\n * @param serviceName - Service name for PORT env var\n * @param envVars - Additional env vars to include (from capability plan)\n */\nexport function generateHonoEnvTs(serviceName: string, envVars: EnvVarDef[] = []): string {\n return renderTemplate('src/config/env.ts.hbs', {\n envKey: toEnvKey(serviceName),\n envVars,\n })\n}\n","/**\n * ESM Compatibility Utilities\n *\n * Provides ESM-compatible alternatives to CommonJS globals like __dirname and __filename.\n * These require the caller to pass import.meta.url from the calling module.\n *\n * Note: CLI is built as ESM (.mjs) so import.meta.url is always available.\n */\nimport { dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n/**\n * Get directory path from import.meta.url (ESM equivalent of __dirname)\n *\n * @param importMetaUrl - The import.meta.url from the calling module\n * @returns Absolute directory path\n *\n * @example\n * ```ts\n * import { getDirname } from '../core/esm'\n * const __dirname = getDirname(import.meta.url)\n * ```\n */\nexport const getDirname = (importMetaUrl: string): string =>\n dirname(fileURLToPath(importMetaUrl))\n\n/**\n * Get file path from import.meta.url (ESM equivalent of __filename)\n *\n * @param importMetaUrl - The import.meta.url from the calling module\n * @returns Absolute file path\n *\n * @example\n * ```ts\n * import { getFilename } from '../core/esm'\n * const __filename = getFilename(import.meta.url)\n * ```\n */\nexport const getFilename = (importMetaUrl: string): string =>\n fileURLToPath(importMetaUrl)\n","/**\n * File system utilities.\n */\nimport { existsSync, readdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { getDirname } from '../esm'\n\nexport * from './watcher'\n\n/**\n * Gets a safe default starting directory for findPackageRoot.\n * Works in both ESM and CJS bundled contexts.\n */\nconst getDefaultStartDir = (): string => {\n if (typeof import.meta?.url === 'string') {\n return getDirname(import.meta.url)\n }\n // Fallback for CJS bundles where import.meta.url is undefined\n if (typeof __dirname === 'string') return __dirname\n return process.cwd()\n}\n\n/**\n * Finds the package root by traversing up from a starting directory until package.json is found.\n * This works for both development and globally installed packages.\n *\n * @param startDir - Starting directory (defaults to current module directory)\n * @returns Absolute path to package root\n * @throws Error if package.json cannot be found\n */\nexport const findPackageRoot = (startDir?: string): string => {\n const dir = startDir ?? getDefaultStartDir()\n const hasPackageJson = (d: string) => existsSync(join(d, 'package.json'))\n const parent = dirname(dir)\n\n if (hasPackageJson(dir)) return dir\n if (dir === '/') throw new Error('Could not find package.json (package root)')\n\n return findPackageRoot(parent)\n}\n\n/**\n * Finds a directory by checking multiple possible paths.\n *\n * @param searchPaths - Array of possible paths to check\n * @param errorMessage - Custom error message if not found\n * @returns First existing path\n * @throws Error if no valid path is found\n */\nexport const findDirectory = (\n searchPaths: string[],\n errorMessage?: string,\n): string => {\n const found = searchPaths.find(existsSync)\n\n if (!found) {\n throw new Error(\n errorMessage ?? `Directory not found. Searched in: ${searchPaths.join(', ')}`,\n )\n }\n\n return found\n}\n\n/**\n * Discovers all services in services/ and apps/ directories.\n * Excludes packages/ (where contracts live) and other non-service directories.\n *\n * @param root - Workspace root directory\n * @returns Array of service paths relative to root (e.g., ['services/orders', 'apps/storefront'])\n */\nexport const discoverWorkspaceServices = async (root: string): Promise<string[]> => {\n const { getWorkspacePathsConfig } = await import('../packages/config')\n const paths = getWorkspacePathsConfig(root)\n\n // Only scan services and apps directories (not packages)\n const serviceDirs = [paths.services, paths.apps]\n\n return serviceDirs.flatMap(dir => {\n const fullPath = join(root, dir)\n if (!existsSync(fullPath)) return []\n\n try {\n return readdirSync(fullPath, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory() && dirent.name !== '.gitkeep')\n .map(dirent => `${dir}/${dirent.name}`)\n } catch {\n return []\n }\n })\n}\n","/**\n * Template rendering utilities using Handlebars.\n *\n * Shared across all generators (workspace, hono, nest).\n */\nimport { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport Handlebars from 'handlebars'\nimport { findDirectory } from '../filesystem'\n\nexport type TemplateData = Record<string, unknown>\n\n/**\n * Finds a templates directory by checking multiple possible paths.\n * Used for locating generator-specific templates in different execution contexts.\n *\n * @param searchPaths - Array of possible paths to check\n * @param errorMessage - Custom error message if not found\n * @throws Error if no valid path is found\n */\nexport const findTemplatesDir = (\n searchPaths: string[],\n errorMessage?: string,\n): string => {\n return findDirectory(\n searchPaths,\n errorMessage ?? `Templates directory not found. Searched in: ${searchPaths.join(', ')}`,\n )\n}\n\n/**\n * Renders a Handlebars template file with the given data.\n *\n * @param templatePath - Absolute path to the template file\n * @param data - Data object to pass to the template\n */\nexport const renderTemplate = (\n templatePath: string,\n data: TemplateData = {},\n): string => {\n const templateContent = readFileSync(templatePath, 'utf-8')\n const template = Handlebars.compile(templateContent)\n return template(data)\n}\n\n/**\n * Creates a template renderer bound to a specific templates directory.\n *\n * @param templatesDir - Base directory containing templates\n * @returns Function that renders templates by name\n *\n * @example\n * const render = createTemplateRenderer('/path/to/templates')\n * const content = render('main.ts.hbs', { serviceName: 'orders' })\n */\nexport const createTemplateRenderer = (templatesDir: string) =>\n (templateName: string, data: TemplateData = {}): string => {\n const templatePath = join(templatesDir, templateName)\n return renderTemplate(templatePath, data)\n }\n","/**\n * String transformation utilities for code generation.\n *\n * Shared across all generators (workspace, hono, nest).\n */\n\n/**\n * Converts a service name to an environment variable prefix.\n * @example 'my-service' -> 'MY_SERVICE'\n */\nexport const toEnvKey = (name: string): string =>\n name.toUpperCase().replace(/-/g, '_')\n\n/**\n * Converts a string to kebab-case.\n * @example 'orders.created' -> 'orders-created'\n * @example 'MyService' -> 'my-service'\n */\nexport const toKebabCase = (str: string): string =>\n str\n .replace(/\\./g, '-')\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .toLowerCase()\n\n/**\n * Converts a string to PascalCase.\n * @example 'orders.created' -> 'OrdersCreated'\n * @example 'my-service' -> 'MyService'\n */\nexport const toPascalCase = (str: string): string =>\n str\n .split(/[-.]/)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n\n/**\n * Converts a string to camelCase.\n * @example 'orders.created' -> 'ordersCreated'\n * @example 'my-service' -> 'myService'\n */\nexport const toCamelCase = (str: string): string => {\n const pascal = toPascalCase(str)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/**\n * Converts a service name to a human-readable display name.\n * @example 'my-service' -> 'My Service'\n */\nexport const toDisplayName = (name: string): string =>\n name\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ')\n\n","/**\n * Hono + Bun Template\n *\n * Service template for Hono framework with Bun runtime.\n * Supports optional event handling with consumeJetStreams.\n */\n\nimport {\n generateHonoBiomeJson,\n generateHonoDockerfile,\n generateHonoEnvTs,\n generateHonoTsConfig,\n} from '../../commands/create/hono-microservice/templates'\nimport { toEnvKey } from './strings'\nimport type { ServiceTemplate, TemplateVars } from './types'\n\n/**\n * Generate imports section for index.ts\n */\nconst generateImports = (hasEvents: boolean): string[] => {\n const imports = [\n \"import './config/env'\",\n \"import '@crossdelta/telemetry'\",\n '',\n ]\n\n if (hasEvents) {\n imports.push(\"import { consumeJetStreams } from '@crossdelta/cloudevents'\")\n }\n imports.push(\"import { Hono } from 'hono'\")\n\n return imports\n}\n\n/**\n * Generate server setup (pure)\n */\nconst generateServerSetup = (envKey: string): string[] => [\n `const port = Number(process.env.${envKey}_PORT) || 8080`,\n 'const app = new Hono()',\n '',\n \"app.get('/health', (c) => {\",\n \" return c.json({ status: 'ok' })\",\n '})',\n]\n\n/**\n * Generate JetStream consumer config (pure)\n */\nconst generateJetStreamConsumer = (serviceName: string, streams: readonly string[]): string[] => [\n '',\n '// Start NATS JetStream consumer',\n 'consumeJetStreams({',\n ` streams: [${streams.map((s) => `'${s}'`).join(', ')}],`,\n ` consumer: '${serviceName}',`,\n \" discover: './src/events/**/*.handler.ts',\",\n '})',\n]\n\n/**\n * Generate Bun server start (pure)\n */\nconst generateBunServe = (): string[] => [\n '',\n 'Bun.serve({',\n ' port,',\n ' fetch: app.fetch,',\n '})',\n '',\n 'console.log(`🚀 Service ready at http://localhost:$' + '{port}`)',\n]\n\n/**\n * Compose index.ts from parts (declarative composition)\n */\nconst generateIndexTs = (vars: TemplateVars): string => {\n const envKey = toEnvKey(vars.serviceName)\n\n const parts = [\n ...generateImports(vars.hasEvents),\n '',\n ...generateServerSetup(envKey),\n ...(vars.hasEvents ? generateJetStreamConsumer(vars.serviceName, vars.streams) : []),\n ...generateBunServe(),\n ]\n\n return `${parts.join('\\n')}\\n`\n}\n\n/**\n * Generate package.json content for Hono service\n */\nconst generatePackageJson = (vars: TemplateVars): string => {\n const dependencies: Record<string, string> = {\n hono: '^4.6.14',\n '@crossdelta/telemetry': 'workspace:*',\n zod: '^4.1.0',\n // Always include contracts - user may add events later via \"pf cloudevents add\"\n [`${vars.workspaceScope}/contracts`]: 'workspace:*',\n }\n\n if (vars.hasEvents) {\n dependencies['@crossdelta/cloudevents'] = 'workspace:*'\n }\n\n const pkg = {\n name: vars.packageName,\n version: '0.0.1',\n type: 'module',\n scripts: {\n 'start:dev': 'bun --watch src/index.ts',\n start: 'bun src/index.ts',\n test: 'bun test',\n },\n dependencies,\n devDependencies: {\n '@types/bun': '^1.2.23',\n },\n }\n\n return JSON.stringify(pkg, null, 2)\n}\n\n/**\n * Generate README.md content\n */\nconst generateReadme = (vars: TemplateVars): string => {\n return `# ${vars.serviceName}\n\n## Development\n\n\\`\\`\\`bash\nbun install\nbun dev\n\\`\\`\\`\n\nService runs on port: \\`${vars.port}\\`\n\n## Environment Variables\n\n- \\`${vars.envVarName}_PORT\\`: Service port (default: ${vars.port})\n${vars.hasEvents ? `\\n## Events\\n\\nThis service consumes from:\\n${vars.streams.map((s) => `- ${s}`).join('\\n')}` : ''}\n`\n}\n\n/**\n * Generate .gitkeep for events directory\n */\nconst generateEventsGitkeep = (): string => ''\n\n/**\n * Hono + Bun Service Template\n *\n * Generates a microservice with:\n * - Hono web framework\n * - Bun runtime\n * - Health check endpoint\n * - Optional: Event consumers\n */\nexport const HonoBunTemplate: ServiceTemplate = {\n name: 'hono-bun',\n runtime: 'bun',\n framework: 'hono',\n files: [\n {\n path: 'src/index.ts',\n content: generateIndexTs,\n },\n {\n path: 'src/config/env.ts',\n content: (vars) => generateHonoEnvTs(vars.serviceName, vars.envVars),\n },\n {\n path: 'package.json',\n content: generatePackageJson,\n },\n {\n path: 'tsconfig.json',\n content: () => generateHonoTsConfig(),\n },\n {\n path: 'Dockerfile',\n content: () => generateHonoDockerfile(),\n },\n {\n path: 'biome.json',\n content: () => generateHonoBiomeJson(),\n },\n {\n path: 'README.md',\n content: generateReadme,\n },\n {\n path: 'src/events/.gitkeep',\n content: generateEventsGitkeep,\n skip: (vars) => !vars.hasEvents,\n },\n ],\n}\n","/**\n * Templates for NestJS microservice scaffolding using Handlebars.\n */\nimport { join } from 'node:path'\nimport { getDirname } from '../../../core/esm'\nimport { findPackageRoot } from '../../../core/filesystem'\nimport { createTemplateRenderer, findTemplatesDir } from '../../../core/templates/renderer'\nimport { toDisplayName, toEnvKey } from '../../../core/templates/strings'\nimport type { EnvVarDef } from '../../../core/templates/types'\n\n/**\n * Gets module directory path.\n * Lazy evaluation to support both ESM and CJS bundles.\n */\nconst getModuleDir = (): string => {\n if (typeof import.meta?.url === 'string') {\n return getDirname(import.meta.url)\n }\n if (typeof __dirname === 'string') return __dirname\n return process.cwd()\n}\n\nconst getTemplatesDir = () => {\n const moduleDir = getModuleDir()\n const packageRoot = findPackageRoot()\n return findTemplatesDir(\n [\n join(moduleDir, 'templates', 'nest-microservice'),\n join(moduleDir, '..', 'nest-microservice', 'templates'),\n join(packageRoot, 'bin', 'templates', 'nest-microservice'), // Global install fallback\n ],\n 'NestJS templates directory not found.',\n )\n}\n\nconst renderTemplate = (templateName: string, data: Record<string, string | number> = {}) =>\n createTemplateRenderer(getTemplatesDir())(templateName, data)\n\n/**\n * Generate the main.ts content for a NestJS microservice.\n */\nexport function generateNestMainTs(serviceName: string, defaultPort = 3000): string {\n return renderTemplate('src/main.ts.hbs', {\n serviceName,\n envKey: toEnvKey(serviceName),\n displayName: toDisplayName(serviceName),\n defaultPort,\n })\n}\n\n/**\n * Generate the app.context.ts for NestJS DI bridge.\n */\nexport function generateAppContext(): string {\n return renderTemplate('src/app.context.ts.hbs', {})\n}\n\n/**\n * Generate the events.module.ts for NestJS event handling.\n */\nexport function generateEventsModule(): string {\n return renderTemplate('src/events/events.module.ts.hbs', {})\n}\n\n/**\n * Generate the events.service.ts for NATS consumer setup.\n */\nexport function generateEventsService(serviceName: string): string {\n return renderTemplate('src/events/events.service.ts.hbs', { serviceName })\n}\n\n/**\n * Generate the Dockerfile content for a NestJS microservice.\n */\nexport function generateNestDockerfile(nodeVersion = '24', bunVersion = '1.2.23'): string {\n return renderTemplate('Dockerfile.hbs', { nodeVersion, bunVersion })\n}\n\n/**\n * Generate biome.json for NestJS services.\n * Disables useImportType to prevent breaking NestJS dependency injection.\n */\nexport function generateNestBiomeJson(): string {\n return renderTemplate('biome.json.hbs', {})\n}\n\n/**\n * Generate the src/config/env.ts content for environment validation.\n * @param serviceName - Service name for PORT env var\n * @param envVars - Additional env vars to include (from capability plan)\n */\nexport function generateNestEnvTs(serviceName: string, envVars: EnvVarDef[] = []): string {\n return renderTemplate('src/config/env.ts.hbs', {\n envKey: toEnvKey(serviceName),\n envVars,\n })\n}\n","/**\n * NestJS Template\n *\n * Service template for NestJS framework with Node runtime.\n * Wraps existing Handlebars templates from commands/create/nest-microservice.\n */\n\nimport {\n generateAppContext,\n generateEventsModule,\n generateEventsService,\n generateNestBiomeJson,\n generateNestDockerfile,\n generateNestEnvTs,\n generateNestMainTs,\n} from '../../commands/create/nest-microservice/templates'\nimport type { ServiceTemplate, TemplateVars } from './types'\n\n/**\n * Generate package.json content for NestJS service\n */\nconst generatePackageJson = (vars: TemplateVars): string => {\n const dependencies: Record<string, string> = {\n '@nestjs/common': '^11.0.0',\n '@nestjs/core': '^11.0.0',\n '@nestjs/platform-express': '^11.0.0',\n '@crossdelta/telemetry': 'workspace:*',\n 'reflect-metadata': '^0.2.0',\n 'rxjs': '^7.8.0',\n 'zod': '^4.1.0',\n // Always include contracts - user may add events later via \"pf cloudevents add\"\n [`${vars.workspaceScope}/contracts`]: 'workspace:*',\n }\n\n if (vars.hasEvents) {\n dependencies['@crossdelta/cloudevents'] = 'workspace:*'\n }\n\n const pkg = {\n name: vars.packageName,\n version: '0.0.1',\n scripts: {\n 'start:dev': 'bun --watch src/main.ts',\n start: 'node dist/main.js',\n build: 'tsc',\n test: 'bun test',\n },\n dependencies,\n devDependencies: {\n '@nestjs/cli': '^11.0.0',\n '@types/node': '^24.0.0',\n typescript: '^5.7.0',\n },\n }\n\n return JSON.stringify(pkg, null, 2)\n}\n\n/**\n * Generate tsconfig.json for NestJS\n */\nconst generateTsConfig = (): string => {\n const config = {\n extends: '../../../../tsconfig.json',\n compilerOptions: {\n outDir: './dist',\n rootDir: './src',\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n },\n include: ['src/**/*'],\n exclude: ['node_modules', 'dist', '**/*.test.ts'],\n }\n\n return JSON.stringify(config, null, 2)\n}\n\n/**\n * Generate app.module.ts\n */\nconst generateAppModule = (vars: TemplateVars): string => {\n const imports = ['Module', 'HttpModule']\n const moduleImports = ['HttpModule']\n\n if (vars.hasEvents) {\n imports.push('OnModuleInit')\n moduleImports.push('EventsModule')\n }\n\n return `import { ${imports.join(', ')} } from '@nestjs/common'\n${vars.hasEvents ? \"import { EventsModule } from './events/events.module'\" : ''}\n\n@Module({\n imports: [${moduleImports.join(', ')}],\n controllers: [],\n providers: [],\n})\nexport class AppModule${vars.hasEvents ? ' implements OnModuleInit' : ''} {\n ${vars.hasEvents ? 'async onModuleInit() {\\n // Events module initializes NATS consumer\\n }' : ''}\n}\n`\n}\n\n/**\n * Generate app.controller.ts with health check\n */\nconst generateAppController = (): string => {\n return `import { Controller, Get } from '@nestjs/common'\n\n@Controller()\nexport class AppController {\n @Get('health')\n health() {\n return { status: 'ok' }\n }\n}\n`\n}\n\n/**\n * Generate README.md content\n */\nconst generateReadme = (vars: TemplateVars): string => {\n return `# ${vars.serviceName}\n\n## Development\n\n\\`\\`\\`bash\nbun install\nbun dev\n\\`\\`\\`\n\nService runs on port: \\`${vars.port}\\`\n\n## Environment Variables\n\n- \\`${vars.envVarName}_PORT\\`: Service port (default: ${vars.port})\n${vars.hasEvents ? `\\n## Events\\n\\nThis service consumes from:\\n${vars.streams.map((s) => `- ${s}`).join('\\n')}` : ''}\n`\n}\n\n/**\n * Generate .gitkeep for events directory\n */\nconst generateEventsGitkeep = (): string => ''\n\n/**\n * NestJS Service Template\n *\n * Generates a microservice with:\n * - NestJS framework\n * - Node runtime\n * - Health check endpoint\n * - Optional: Event consumers with EventsModule\n */\nexport const NestTemplate: ServiceTemplate = {\n name: 'nest',\n runtime: 'node',\n framework: 'nest',\n files: [\n {\n path: 'src/config/env.ts',\n content: (vars) => generateNestEnvTs(vars.serviceName, vars.envVars),\n },\n {\n path: 'src/main.ts',\n content: (vars) => generateNestMainTs(vars.serviceName, vars.port),\n },\n {\n path: 'src/app.module.ts',\n content: generateAppModule,\n },\n {\n path: 'src/app.controller.ts',\n content: () => generateAppController(),\n },\n {\n path: 'src/app.context.ts',\n content: () => generateAppContext(),\n },\n {\n path: 'package.json',\n content: generatePackageJson,\n },\n {\n path: 'tsconfig.json',\n content: () => generateTsConfig(),\n },\n {\n path: 'Dockerfile',\n content: () => generateNestDockerfile(),\n },\n {\n path: 'biome.json',\n content: () => generateNestBiomeJson(),\n },\n {\n path: 'README.md',\n content: generateReadme,\n },\n {\n path: 'src/events/events.module.ts',\n content: () => generateEventsModule(),\n skip: (vars) => !vars.hasEvents,\n },\n {\n path: 'src/events/events.service.ts',\n content: (vars) => generateEventsService(vars.serviceName),\n skip: (vars) => !vars.hasEvents,\n },\n {\n path: 'src/events/handlers/.gitkeep',\n content: generateEventsGitkeep,\n skip: (vars) => !vars.hasEvents,\n },\n ],\n}\n","/**\n * Template System\n *\n * Includes:\n * - Handlebars renderer (existing)\n * - String helpers (existing)\n * - Service templates (new)\n */\n\nexport * from './hono-bun.template'\nexport * from './nest.template'\nexport * from './renderer'\nexport * from './strings'\n// Service Templates\nexport * from './types'\n\nimport { HonoBunTemplate } from './hono-bun.template'\nimport { NestTemplate } from './nest.template'\nimport type { ServiceTemplate } from './types'\n\n/**\n * All available service templates\n */\nexport const templates: ServiceTemplate[] = [HonoBunTemplate, NestTemplate]\n\n/**\n * Template type for selection\n */\nexport type TemplateType = 'hono-bun' | 'hono-micro' | 'nest' | 'nest-micro'\n\n/**\n * Select template by type\n *\n * Normalizes template type aliases (hono-micro → hono-bun, nest-micro → nest)\n *\n * @param type - Template type or alias\n * @returns ServiceTemplate\n * @throws Error if template not found\n */\nexport const selectTemplate = (type: TemplateType): ServiceTemplate => {\n const normalized = normalizeTemplateType(type)\n\n const template = templates.find((t) => t.name === normalized)\n\n if (!template) {\n throw new Error(`Template '${type}' not found. Available: ${templates.map((t) => t.name).join(', ')}`)\n }\n\n return template\n}\n\n/**\n * Normalize template type aliases\n */\nconst normalizeTemplateType = (type: TemplateType): string => {\n const aliases: Record<string, string> = {\n 'hono-micro': 'hono-bun',\n 'nest-micro': 'nest',\n }\n\n return aliases[type] || type\n}\n\n/**\n * Get all available template types\n */\nexport const getAvailableTemplates = (): string[] => {\n return templates.map((t) => t.name)\n}\n","/**\n * Effect Builder Module\n *\n * Pure functions for building PfEffects from service generation data.\n * No I/O, no side effects - just data transformation.\n */\n\nimport { join } from 'node:path'\nimport { deriveEventNames } from '@crossdelta/cloudevents'\nimport type { EnvAddEffect, FileWriteEffect, InfraAddEffect, PfEffect } from '../plugins/types'\nimport { deriveUseCaseName, resolveEventLayout, resolveServiceLayout, type ServiceFramework } from '../policies'\nimport type { ServiceTemplate, TemplateVars } from '../templates/types'\n\n/**\n * File specification for effect generation\n */\nexport interface FileSpec {\n path: string\n content: string\n}\n\n/**\n * Build file write effects from file specifications (pure)\n */\nexport const buildFileEffects = (servicePath: string, files: FileSpec[]): FileWriteEffect[] => {\n return files.map((file) => ({\n kind: 'file:write',\n path: join(servicePath, file.path),\n content: file.content,\n }))\n}\n\n/**\n * Build infrastructure effect (pure)\n */\nexport const buildInfraEffect = (serviceName: string, port: number, template: ServiceTemplate): InfraAddEffect => ({\n kind: 'infra:add',\n serviceName,\n port,\n framework: template.framework,\n runtime: template.runtime,\n})\n\n/**\n * Build environment variable effect (pure)\n */\nexport const buildEnvEffect = (envVarName: string, port: number): EnvAddEffect => ({\n kind: 'env:add',\n key: `${envVarName}_PORT`,\n value: port.toString(),\n})\n\n/**\n * Generate use-case file content (pure)\n *\n * Creates a use-case stub for handling an event type.\n * Use-case contains business logic, handler delegates to it.\n */\nconst generateUseCaseContent = (eventType: string, workspaceScope: string): string => {\n const { typeName } = deriveEventNames(eventType)\n const useCaseName = deriveUseCaseName(eventType)\n const layout = resolveServiceLayout('hono', useCaseName)\n\n return `import type { ${typeName} } from '${workspaceScope}/contracts'\n\n/**\n * Handle ${eventType} event\n *\n * Business logic for processing the event.\n * Keep this pure where possible - side effects via returned data or adapters.\n */\nexport const ${layout.functionName} = async (data: ${typeName}): Promise<void> => {\n // TODO: Implement business logic\n // Example: validate data, transform, call external services\n}\n`\n}\n\n/**\n * Generate event handler file content with use-case delegation (pure)\n *\n * Creates a thin handler that delegates to the use-case.\n * Handler is responsible for: logging, calling use-case, error handling.\n *\n * All paths derived from serviceLayoutPolicy - no hardcoded paths.\n */\nconst generateEventHandlerContent = (\n eventType: string,\n workspaceScope: string,\n framework: ServiceFramework,\n): string => {\n const { contractName, typeName } = deriveEventNames(eventType)\n const useCaseName = deriveUseCaseName(eventType)\n const layout = resolveServiceLayout(framework, useCaseName)\n\n // For frameworks that delegate to business logic\n if (layout.delegateFromHandler) {\n // Import path derived from policy (importFromEvents)\n return `import { handleEvent } from '@crossdelta/cloudevents'\nimport { ${contractName}, type ${typeName} } from '${workspaceScope}/contracts'\nimport { ${layout.functionName} } from '${layout.importFromEvents}'\n\nexport default handleEvent(${contractName}, async (data: ${typeName}) => {\n console.log('📦 [${eventType}] Event received:', data)\n await ${layout.functionName}(data)\n})\n`\n }\n\n // For frameworks without delegation (e.g., NestJS uses services differently)\n return `import { handleEvent } from '@crossdelta/cloudevents'\nimport { ${contractName}, type ${typeName} } from '${workspaceScope}/contracts'\n\nexport default handleEvent(${contractName}, async (data: ${typeName}) => {\n console.log('📦 [${eventType}] Event received:', data)\n // TODO: Inject and call service\n})\n`\n}\n\n/**\n * Build use-case file effects (pure)\n *\n * Generates a use-case stub for each event (Hono only).\n */\nconst buildUseCaseEffects = (\n servicePath: string,\n vars: TemplateVars,\n framework: ServiceFramework,\n): FileWriteEffect[] => {\n if (!vars.hasEvents || vars.events.length === 0) {\n return []\n }\n\n const layout = resolveServiceLayout(framework, 'stub')\n if (!layout.delegateFromHandler) {\n return []\n }\n\n return vars.events.map((eventType) => {\n const useCaseName = deriveUseCaseName(eventType)\n const resolved = resolveServiceLayout(framework, useCaseName)\n return {\n kind: 'file:write' as const,\n path: join(servicePath, resolved.filePath),\n content: generateUseCaseContent(eventType, vars.workspaceScope),\n }\n })\n}\n\n/**\n * Build event handler file effects (pure)\n *\n * Generates a handler file for each event in the events array.\n * All paths derived from serviceLayoutPolicy via resolveEventLayout.\n */\nconst buildEventHandlerEffects = (\n servicePath: string,\n vars: TemplateVars,\n framework: ServiceFramework,\n): FileWriteEffect[] => {\n if (!vars.hasEvents || vars.events.length === 0) {\n return []\n }\n\n return vars.events.map((eventType) => {\n const { kebab } = deriveEventNames(eventType)\n const eventLayout = resolveEventLayout(framework, kebab)\n return {\n kind: 'file:write' as const,\n path: join(servicePath, eventLayout.filePath),\n content: generateEventHandlerContent(eventType, vars.workspaceScope, framework),\n }\n })\n}\n\n/**\n * Map template framework to policy framework\n */\nconst mapFramework = (templateFramework: string): ServiceFramework => {\n if (templateFramework === 'hono') return 'hono'\n if (templateFramework === 'nest') return 'nestjs'\n return 'hono' // default\n}\n\n/**\n * Build all service effects (pure composition)\n */\nexport const buildServiceEffects = (\n servicePath: string,\n files: FileSpec[],\n vars: TemplateVars,\n template: ServiceTemplate,\n): PfEffect[] => {\n const framework = mapFramework(template.framework)\n\n const fileEffects = buildFileEffects(servicePath, files)\n const useCaseEffects = buildUseCaseEffects(servicePath, vars, framework)\n const eventHandlerEffects = buildEventHandlerEffects(servicePath, vars, framework)\n const infraEffect = buildInfraEffect(vars.serviceName, vars.port, template)\n const envEffect = buildEnvEffect(vars.envVarName, vars.port)\n\n return [...fileEffects, ...useCaseEffects, ...eventHandlerEffects, infraEffect, envEffect]\n}\n","/**\n * Service Layout Policy (v1)\n *\n * Machine-readable policy for service file layouts and coding constraints.\n * Enforces consistent structure across generators (CLI + MCP).\n *\n * - Hono: Use-cases for business logic (src/use-cases/*.use-case.ts)\n * - NestJS: Services following NestJS conventions\n *\n * Features:\n * - PathGuards: Forbidden directories per framework\n * - CodingConstraints: Forbidden patterns in domain/use-case code\n */\n\n/** Policy version for backward compatibility */\nexport const SERVICE_LAYOUT_POLICY_VERSION = 1\n\n/**\n * Supported service frameworks\n */\nexport type ServiceFramework = 'hono' | 'nestjs'\n\n/**\n * Forbidden pattern for coding constraints\n */\nexport interface ForbiddenPattern {\n /** Pattern to match (string or regex source) */\n pattern: string\n /** Human-readable description */\n description: string\n /** Error code for structured reporting */\n code: string\n}\n\n/**\n * Coding constraints for business logic code\n */\nexport interface CodingConstraints {\n /** Directories where constraints apply (relative to service root) */\n appliesTo: readonly string[]\n /** Forbidden patterns in code */\n forbiddenPatterns: readonly ForbiddenPattern[]\n}\n\n/**\n * Path guards for framework\n */\nexport interface PathGuards {\n /** Directories that must not be used for business logic */\n forbidDirs: readonly string[]\n}\n\n/**\n * Framework-specific layout configuration\n */\nexport interface FrameworkLayout {\n /** Directory for business logic (relative to src/) */\n businessLogicDir: string\n /** Directory for event handlers (relative to src/) */\n eventsDir: string\n /** File naming pattern. Placeholders: {name} */\n filePattern: string\n /** File suffix (e.g., 'use-case', 'service') */\n suffix: string\n /** Whether event handlers should delegate to business logic */\n handlerDelegatesToBusinessLogic: boolean\n /** Path guards for this framework */\n pathGuards: PathGuards\n /** Coding constraints for business logic */\n codingConstraints: CodingConstraints\n}\n\n/**\n * Default coding constraints for business logic\n *\n * Applied to domain and use-case directories.\n * These are hard checks - violations block generation.\n */\nconst defaultCodingConstraints: CodingConstraints = {\n appliesTo: ['src/domain', 'src/use-cases'],\n forbiddenPatterns: [\n {\n pattern: 'console\\\\.(log|error|warn|info|debug)\\\\s*\\\\(',\n description: 'console.* is forbidden in business logic (use structured logging)',\n code: 'CONSOLE_IN_DOMAIN',\n },\n {\n pattern: 'process\\\\.env\\\\b',\n description: 'process.env is forbidden in business logic (use dependency injection)',\n code: 'PROCESS_ENV_IN_DOMAIN',\n },\n {\n pattern: '\\\\bfetch\\\\s*\\\\(',\n description: 'fetch() is forbidden in business logic (use adapters/services)',\n code: 'FETCH_IN_DOMAIN',\n },\n ],\n}\n\n/**\n * Service layout policy\n *\n * Defines where business logic files should be placed for each framework.\n * This is the single source of truth for service structure.\n */\nexport const serviceLayoutPolicy: Record<ServiceFramework, FrameworkLayout> = {\n hono: {\n businessLogicDir: 'use-cases',\n eventsDir: 'events',\n filePattern: '{name}.use-case.ts',\n suffix: 'use-case',\n handlerDelegatesToBusinessLogic: true,\n pathGuards: {\n forbidDirs: ['src/services'],\n },\n codingConstraints: defaultCodingConstraints,\n },\n nestjs: {\n businessLogicDir: '',\n eventsDir: 'events',\n filePattern: '{name}.service.ts',\n suffix: 'service',\n handlerDelegatesToBusinessLogic: false,\n pathGuards: {\n forbidDirs: [],\n },\n codingConstraints: {\n appliesTo: ['src/domain'],\n forbiddenPatterns: defaultCodingConstraints.forbiddenPatterns,\n },\n },\n} as const\n\n/**\n * Resolved layout paths for a specific use case\n */\nexport interface ResolvedLayout {\n /** Full relative path to business logic file (e.g., 'src/use-cases/process-order.use-case.ts') */\n filePath: string\n /** Directory path (e.g., 'src/use-cases') */\n dirPath: string\n /** File name without path (e.g., 'process-order.use-case.ts') */\n fileName: string\n /** Function name in PascalCase (e.g., 'processOrder') */\n functionName: string\n /** Whether handler should import and call this */\n delegateFromHandler: boolean\n /** Relative import path from events dir to this file (e.g., '../use-cases/process-order.use-case') */\n importFromEvents: string\n}\n\n/**\n * Resolved event handler layout\n */\nexport interface ResolvedEventLayout {\n /** Full relative path to handler file (e.g., 'src/events/order-created.handler.ts') */\n filePath: string\n /** Directory path (e.g., 'src/events') */\n dirPath: string\n /** File name without path (e.g., 'order-created.handler.ts') */\n fileName: string\n}\n\n/**\n * Convert kebab-case name to camelCase function name\n */\nconst toCamelCase = (name: string): string => {\n // For use-case names like 'handle-order-created', convert to 'handleOrderCreated'\n return name.replace(/-([a-z])/g, (_, char) => char.toUpperCase())\n}\n\n/**\n * Calculate relative import path from events dir to business logic dir\n */\nconst calculateImportPath = (businessLogicDir: string, fileNameWithoutExt: string): string => {\n // Both are relative to src/, so from src/events to src/use-cases is '../use-cases'\n return `../${businessLogicDir}/${fileNameWithoutExt}`\n}\n\n/**\n * Resolve service layout for a specific business logic unit\n *\n * @param framework - Target framework (hono, nestjs)\n * @param name - Business logic name in kebab-case (e.g., 'process-order', 'send-notification')\n * @returns Resolved paths and metadata\n *\n * @example\n * resolveServiceLayout('hono', 'process-order')\n * // => {\n * // filePath: 'src/use-cases/process-order.use-case.ts',\n * // dirPath: 'src/use-cases',\n * // fileName: 'process-order.use-case.ts',\n * // functionName: 'processOrder',\n * // delegateFromHandler: true,\n * // importFromEvents: '../use-cases/process-order.use-case',\n * // }\n */\nexport const resolveServiceLayout = (\n framework: ServiceFramework,\n name: string,\n): ResolvedLayout => {\n const layout = serviceLayoutPolicy[framework]\n const fileName = layout.filePattern.replace('{name}', name)\n const fileNameWithoutExt = fileName.replace(/\\.ts$/, '')\n const dirPath = layout.businessLogicDir\n ? `src/${layout.businessLogicDir}`\n : 'src'\n\n return {\n filePath: dirPath ? `${dirPath}/${fileName}` : `src/${fileName}`,\n dirPath,\n fileName,\n functionName: toCamelCase(name),\n delegateFromHandler: layout.handlerDelegatesToBusinessLogic,\n importFromEvents: layout.businessLogicDir\n ? calculateImportPath(layout.businessLogicDir, fileNameWithoutExt)\n : `./${fileNameWithoutExt}`,\n }\n}\n\n/**\n * Resolve event handler layout\n *\n * @param framework - Target framework (hono, nestjs)\n * @param eventName - Event name in kebab-case (e.g., 'order-created')\n * @returns Resolved paths for event handler\n */\nexport const resolveEventLayout = (\n framework: ServiceFramework,\n eventName: string,\n): ResolvedEventLayout => {\n const layout = serviceLayoutPolicy[framework]\n const dirPath = `src/${layout.eventsDir}`\n const fileName = `${eventName}.handler.ts`\n\n return {\n filePath: `${dirPath}/${fileName}`,\n dirPath,\n fileName,\n }\n}\n\n/**\n * Derive use-case name from event type\n *\n * @param eventType - Event type (e.g., 'order.created')\n * @returns Use-case name in kebab-case (e.g., 'handle-order-created')\n *\n * @example\n * deriveUseCaseName('order.created') // => 'handle-order-created'\n * deriveUseCaseName('customer.updated') // => 'handle-customer-updated'\n */\nexport const deriveUseCaseName = (eventType: string): string => {\n const normalized = eventType.replace(/\\./g, '-')\n return `handle-${normalized}`\n}\n\n// ============================================================================\n// Policy Validation\n// ============================================================================\n\n/**\n * Policy violation details\n */\nexport interface PolicyViolation {\n /** Error code for structured handling */\n code: string\n /** Human-readable message */\n message: string\n /** File path that caused the violation */\n path: string\n /** Line number (if applicable) */\n line?: number\n}\n\n/**\n * Validation result for generated files\n */\nexport interface PolicyValidationResult {\n /** Whether validation passed */\n valid: boolean\n /** List of violations (empty if valid) */\n violations: PolicyViolation[]\n}\n\n/**\n * Planned file for validation\n */\nexport interface PlannedFile {\n /** Relative path within service (e.g., 'src/services/foo.ts') */\n path: string\n /** File content */\n content: string\n}\n\n// ============================================================================\n// Path Normalization (Security)\n// ============================================================================\n\n/**\n * Normalize a file path for consistent policy checking\n *\n * - Converts backslashes to forward slashes (Windows compatibility)\n * - Removes leading ./ or /\n * - Resolves .. traversal segments\n * - Returns POSIX-style path\n *\n * @example\n * normalizePath('src\\\\services\\\\x.ts') => 'src/services/x.ts'\n * normalizePath('./src/services/x.ts') => 'src/services/x.ts'\n * normalizePath('src/use-cases/../services/x.ts') => 'src/services/x.ts'\n */\nconst normalizePath = (filePath: string): string => {\n // 1. Convert backslashes to forward slashes\n let normalized = filePath.replace(/\\\\/g, '/')\n\n // 2. Remove leading ./ or /\n normalized = normalized.replace(/^\\.\\//, '').replace(/^\\//, '')\n\n // 3. Resolve .. segments\n const segments = normalized.split('/')\n const resolved: string[] = []\n\n for (const segment of segments) {\n if (segment === '..') {\n resolved.pop() // Go up one directory\n } else if (segment !== '.' && segment !== '') {\n resolved.push(segment)\n }\n }\n\n return resolved.join('/')\n}\n\n/**\n * Check if a path matches any forbidden directory\n *\n * Path is normalized before checking to prevent bypass via:\n * - Backslashes: src\\\\services\\\\x.ts\n * - Traversal: src/use-cases/../services/x.ts\n * - Leading ./ or /\n */\nconst matchesForbiddenDir = (filePath: string, forbidDirs: readonly string[]): string | null => {\n const normalizedPath = normalizePath(filePath)\n\n for (const dir of forbidDirs) {\n const normalizedDir = normalizePath(dir)\n if (normalizedPath.startsWith(`${normalizedDir}/`) || normalizedPath === normalizedDir) {\n return dir\n }\n }\n return null\n}\n\n/**\n * Check if a path is within a constrained directory\n *\n * Path is normalized before checking (same as matchesForbiddenDir).\n */\nconst isInConstrainedDir = (filePath: string, appliesTo: readonly string[]): boolean => {\n const normalizedPath = normalizePath(filePath)\n\n return appliesTo.some((dir) => {\n const normalizedDir = normalizePath(dir)\n return normalizedPath.startsWith(`${normalizedDir}/`) || normalizedPath === normalizedDir\n })\n}\n\n/**\n * Find forbidden pattern violations in content\n */\nconst findPatternViolations = (\n content: string,\n patterns: readonly ForbiddenPattern[],\n filePath: string,\n): PolicyViolation[] => {\n const violations: PolicyViolation[] = []\n const lines = content.split('\\n')\n\n for (const { pattern, description, code } of patterns) {\n const regex = new RegExp(pattern, 'g')\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i])) {\n violations.push({\n code,\n message: description,\n path: filePath,\n line: i + 1,\n })\n }\n regex.lastIndex = 0 // Reset regex state\n }\n }\n\n return violations\n}\n\n/**\n * Validate a single planned file against policy\n */\nconst validateFile = (file: PlannedFile, layout: FrameworkLayout): PolicyViolation[] => {\n const violations: PolicyViolation[] = []\n\n // Check path guards (forbidden directories)\n const forbiddenDir = matchesForbiddenDir(file.path, layout.pathGuards.forbidDirs)\n if (forbiddenDir) {\n violations.push({\n code: 'FORBIDDEN_DIR',\n message: `Path '${file.path}' is in forbidden directory '${forbiddenDir}'`,\n path: file.path,\n })\n }\n\n // Check coding constraints if in constrained directory\n if (isInConstrainedDir(file.path, layout.codingConstraints.appliesTo)) {\n const patternViolations = findPatternViolations(\n file.content,\n layout.codingConstraints.forbiddenPatterns,\n file.path,\n )\n violations.push(...patternViolations)\n }\n\n return violations\n}\n\n/**\n * Validate generated files against service policy\n *\n * Call this before applying effects to ensure compliance.\n * Returns violations that MUST block generation.\n *\n * @param framework - Target framework\n * @param files - Planned files to validate\n * @returns Validation result with any violations\n *\n * @example\n * const result = validateGeneratedFiles('hono', [\n * { path: 'src/services/foo.ts', content: '...' }\n * ])\n * if (!result.valid) {\n * throw new PolicyViolationError(result.violations)\n * }\n */\nexport const validateGeneratedFiles = (\n framework: ServiceFramework,\n files: readonly PlannedFile[],\n): PolicyValidationResult => {\n const layout = serviceLayoutPolicy[framework]\n const violations: PolicyViolation[] = []\n\n for (const file of files) {\n violations.push(...validateFile(file, layout))\n }\n\n return {\n valid: violations.length === 0,\n violations,\n }\n}\n\n/**\n * Get policy for a specific framework\n *\n * Useful for MCP/CLI to pass policy data to templates.\n */\nexport const getFrameworkPolicy = (framework: ServiceFramework): FrameworkLayout =>\n serviceLayoutPolicy[framework]\n","/**\n * Port Allocation Module\n *\n * Handles port scanning and allocation for services.\n * Isolates I/O from main flow orchestration.\n */\n\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\n/**\n * Port assignment constants\n */\nexport const INTERNAL_PORT_START = 4001\n\n/**\n * Extract port from service config file content\n */\nconst extractPort = (content: string): number | null => {\n // Match ports().http(4000) or ports().primary(4222)\n const portsMatch = content.match(/ports\\(\\)\\.(?:http|https|grpc|primary)\\((\\d+)\\)/)\n if (portsMatch) {\n return Number.parseInt(portsMatch[1], 10)\n }\n\n // Match containerPort: 4001 (DEPRECATED)\n const containerMatch = content.match(/containerPort:\\s*(\\d+)/)\n if (containerMatch) {\n return Number.parseInt(containerMatch[1], 10)\n }\n\n return null\n}\n\n/**\n * Scan used ports from infra/services/*.ts files\n *\n * This is the ONLY I/O operation in port allocation.\n * Returns a set of used ports for deterministic allocation.\n */\nexport const scanUsedPorts = (workspaceRoot: string): Set<number> => {\n try {\n const infraServicesPath = join(workspaceRoot, 'infra', 'services')\n\n if (!existsSync(infraServicesPath)) {\n return new Set()\n }\n\n const files = readdirSync(infraServicesPath).filter((f: string) => f.endsWith('.ts'))\n\n return files.reduce((ports: Set<number>, file: string) => {\n const content = readFileSync(join(infraServicesPath, file), 'utf-8')\n const port = extractPort(content)\n if (port !== null) {\n ports.add(port) // Ephemeral mutation within reduce\n }\n return ports\n }, new Set<number>())\n } catch (error) {\n console.warn('Failed to scan ports:', error)\n return new Set()\n }\n}\n\n/**\n * Allocate next available port (pure function)\n *\n * Given a set of used ports, finds the next available port\n * starting from the given start port.\n */\nexport const allocateNextPort = (usedPorts: Set<number>, startPort: number): number => {\n return usedPorts.has(startPort) ? allocateNextPort(usedPorts, startPort + 1) : startPort\n}\n\n/**\n * Get next available port for service\n *\n * Convenience function that combines scanning and allocation.\n * For deterministic behavior, use scanUsedPorts + allocateNextPort separately.\n */\nexport const getNextAvailablePort = (workspaceRoot: string): number => {\n const usedPorts = scanUsedPorts(workspaceRoot)\n return allocateNextPort(usedPorts, INTERNAL_PORT_START)\n}\n","/**\n * Plugin System Types\n *\n * pf owns and defines these interfaces.\n * Plugins MUST adapt to these interfaces.\n * pf is strict and predictable - no duck-typing, no fallbacks.\n */\n\n/**\n * Base effect type - all domain effects must have a kind\n * pf handles effects generically via kind-based handler registry\n */\nexport interface PfEffect {\n readonly kind: string\n}\n\n/**\n * File write effect - write content to a file\n */\nexport interface FileWriteEffect extends PfEffect {\n readonly kind: 'file:write'\n readonly path: string\n readonly content: string\n}\n\n/**\n * Infrastructure service configuration effect\n */\nexport interface InfraAddEffect extends PfEffect {\n readonly kind: 'infra:add'\n readonly serviceName: string\n readonly port: number\n readonly framework: string\n readonly runtime: string\n}\n\n/**\n * Environment variable effect\n */\nexport interface EnvAddEffect extends PfEffect {\n readonly kind: 'env:add'\n readonly key: string\n readonly value: string\n}\n\n/**\n * Field definition for input elicitation\n *\n * Describes a single field that needs user input.\n * Host-agnostic - CLI and MCP interpret this differently.\n */\nexport interface ElicitInputField {\n /** Field name (used as key in response) */\n readonly name: string\n /** Human-readable prompt/question */\n readonly prompt: string\n /** Whether the field is required */\n readonly required?: boolean\n /** Detailed description (shown as help text) */\n readonly description?: string\n /** Default value if user provides nothing */\n readonly defaultValue?: unknown\n /** Allowed values (enum constraint) */\n readonly enum?: readonly string[]\n /** Field type hint */\n readonly type?: 'string' | 'number' | 'boolean'\n}\n\n/**\n * Input elicitation effect\n *\n * Returned by tools when required inputs are missing.\n * Pure data - no MCP SDK imports, no host-specific logic.\n *\n * Hosts interpret this effect differently:\n * - CLI: Interactive prompt\n * - MCP: server.elicitInput() or structured error\n */\nexport interface ElicitInputEffect extends PfEffect {\n readonly kind: 'elicit:input'\n /** Message explaining what's needed */\n readonly message: string\n /** Fields to collect from user */\n readonly fields: readonly ElicitInputField[]\n}\n\n/**\n * Type guard for ElicitInputEffect\n */\nexport const isElicitInputEffect = (effect: PfEffect): effect is ElicitInputEffect =>\n effect.kind === 'elicit:input'\n\n/**\n * Result of running a command\n */\nexport interface PfCommandResult {\n /** Domain effects to be applied by the runtime */\n effects: PfEffect[]\n /** Optional output to display (for read-only commands) */\n output?: string | string[]\n}\n\n/**\n * Command argument definition\n */\nexport interface PfCommandArg {\n name: string\n description: string\n required: boolean\n}\n\n/**\n * Command option definition\n */\nexport interface PfCommandOption {\n flags: string\n description: string\n default?: unknown\n}\n\n/**\n * A CLI command provided by a plugin\n *\n * Plugins MUST implement this exact interface.\n */\nexport interface PfCommand {\n name: string\n description: string\n args: PfCommandArg[]\n options: PfCommandOption[]\n run(args: Record<string, unknown>, options: Record<string, unknown>): Promise<PfCommandResult>\n}\n\n/**\n * An interactive flow provided by a plugin\n */\nexport interface PfFlow {\n name: string\n description: string\n getSteps(initialContext?: Record<string, unknown>): Promise<unknown[]>\n}\n\n/**\n * Workspace context with all discovered information\n * pf owns this - plugins receive it during setup\n */\nexport interface PfWorkspaceContext {\n /** Absolute path to workspace root */\n workspaceRoot: string\n /** Discovered services (relative paths like 'services/api-gateway') */\n availableServices: string[]\n /** Contracts package configuration */\n contracts: {\n /** Relative path to contracts source (e.g., 'packages/contracts/src') */\n path: string\n /** Package name (e.g., '@my-platform/contracts') */\n packageName?: string\n }\n}\n\n/**\n * Plugin context provided by pf during setup\n */\nexport interface PfPluginContext {\n workspace: PfWorkspaceContext\n logger: {\n debug: (message: string) => void\n info: (message: string) => void\n warn: (message: string) => void\n error: (message: string) => void\n }\n}\n\n/**\n * A plugin that can be loaded by pf\n *\n * Plugins MUST implement this exact interface.\n * If a plugin has a different internal API, it must provide an adapter.\n */\nexport interface PfPlugin {\n name: string\n version: string\n description?: string\n commands: PfCommand[]\n flows: PfFlow[]\n setup: (context: PfPluginContext) => Promise<void> | void\n}\n\n/**\n * Result of loading a plugin\n */\nexport interface LoadedPlugin {\n plugin: PfPlugin\n source: string\n}\n","/**\n * Context Factory\n *\n * Functions for creating plugin contexts from workspace configuration.\n */\n\nimport { discoverAvailableServices, findWorkspaceRoot, getContractsConfig } from '../packages/config'\nimport { createPluginContext } from '../plugins/loader'\nimport type { PfPluginContext, PfWorkspaceContext } from '../plugins/types'\n\n// ============================================================================\n// Context Creation\n// ============================================================================\n\n/**\n * Create plugin context by auto-discovering workspace configuration\n *\n * Reads workspace config from package.json (pf.* fields) and discovers\n * contracts path, services, etc. This is the recommended way to create context.\n *\n * @param workspaceRoot - Optional workspace root (defaults to auto-discovery from cwd)\n * @param logger - Optional logger (defaults to console)\n * @returns Plugin context ready for use\n *\n * @example\n * // Auto-discover workspace from current directory\n * const context = await createContextFromWorkspace()\n *\n * @example\n * // Specify workspace root explicitly\n * const context = await createContextFromWorkspace('/path/to/workspace')\n */\nexport const createContextFromWorkspace = async (\n workspaceRoot?: string,\n logger?: PfPluginContext['logger'],\n): Promise<PfPluginContext> => {\n const root = workspaceRoot ?? findWorkspaceRoot()\n const contractsConfig = getContractsConfig(root)\n const availableServices = discoverAvailableServices(root)\n\n const workspace: PfWorkspaceContext = {\n workspaceRoot: root,\n contracts: {\n path: contractsConfig.packagePath,\n packageName: contractsConfig.packageName,\n },\n availableServices,\n }\n\n return createPluginContext(workspace, logger)\n}\n\n/**\n * Create a plugin context from workspace information (manual)\n *\n * Use this when you need full control over workspace configuration.\n * For most cases, prefer `createContextFromWorkspace()` which auto-discovers config.\n *\n * @param workspace - Workspace context with paths and configuration\n * @param logger - Optional logger (defaults to console)\n * @returns Plugin context ready for use\n *\n * @example\n * const context = createContext({\n * workspaceRoot: '/path/to/workspace',\n * contracts: {\n * path: '/path/to/contracts',\n * packageName: '@my-org/contracts'\n * },\n * availableServices: ['orders', 'notifications']\n * })\n */\nexport const createContext = createPluginContext\n","/**\n * Tool Collection\n *\n * Functions for transforming plugin commands into tool specifications.\n * Shared schema building logic to avoid duplication.\n */\n\nimport type { LoadedPlugin, PfCommand, PfPlugin, PfPluginContext } from '../plugins/types'\nimport type { CommandLikeResult, ExecutableToolSpec, ToolInputSchema, ToolPropertySchema, ToolSpec } from './types'\n\n// ============================================================================\n// Schema Building (pure)\n// ============================================================================\n\n/**\n * Convert command arg to JSON Schema property\n */\nconst argToProperty = (arg: { name: string; description: string }): [string, ToolPropertySchema] => [\n arg.name,\n { type: 'string', description: arg.description },\n]\n\n/**\n * Parse option name from flags (e.g., '-s, --service <path>' -> 'service')\n */\nconst parseOptionName = (flags: string): string | null => {\n const match = flags.match(/--([a-zA-Z0-9-]+)/)\n return match ? match[1] : null\n}\n\n/**\n * Convert command option to JSON Schema property (if valid)\n */\nconst optionToProperty = (opt: {\n flags: string\n description: string\n default?: unknown\n}): [string, ToolPropertySchema] | null => {\n const name = parseOptionName(opt.flags)\n if (!name) return null\n\n return [\n name,\n {\n type: 'string',\n description: opt.description,\n ...(opt.default !== undefined && { default: opt.default }),\n },\n ]\n}\n\n/**\n * Build input schema from command definition\n */\nconst buildInputSchema = (command: PfCommand): ToolInputSchema => {\n const argProperties = Object.fromEntries(command.args.map(argToProperty))\n\n const optionProperties = Object.fromEntries(\n command.options.map(optionToProperty).filter((entry): entry is [string, ToolPropertySchema] => entry !== null),\n )\n\n const required = command.args.filter((arg) => arg.required !== false).map((arg) => arg.name)\n\n return {\n type: 'object',\n properties: { ...argProperties, ...optionProperties },\n ...(required.length > 0 && { required }),\n }\n}\n\n/**\n * Build tool name from plugin and command\n */\nconst buildToolName = (pluginName: string, commandName: string): string => `${pluginName}.${commandName}`\n\n// ============================================================================\n// Tool Spec Creation (pure)\n// ============================================================================\n\n/**\n * Convert a single command to a ToolSpec\n */\nconst commandToToolSpec = (plugin: PfPlugin, command: PfCommand): ToolSpec => ({\n name: buildToolName(plugin.name, command.name),\n description: command.description,\n inputSchema: buildInputSchema(command),\n})\n\n/**\n * Convert a single command to an ExecutableToolSpec\n */\nconst commandToExecutableToolSpec = (plugin: PfPlugin, command: PfCommand): ExecutableToolSpec => ({\n ...commandToToolSpec(plugin, command),\n execute: async (args: Record<string, unknown>): Promise<CommandLikeResult> => {\n const result = await command.run(args, {})\n\n return {\n ok: true,\n operation: buildToolName(plugin.name, command.name),\n summary: formatOutput(result.output) ?? `Executed ${buildToolName(plugin.name, command.name)}`,\n effects: result.effects ?? [],\n output: result.output,\n }\n },\n})\n\n/**\n * Format command output to summary string\n */\nconst formatOutput = (output: string | string[] | undefined): string | undefined => {\n if (!output) return undefined\n return Array.isArray(output) ? output.join('\\n') : output\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Collect tool specifications from loaded plugins\n *\n * Transforms plugin commands into a unified tool specification format.\n * This abstraction allows different consumers (MCP, VS Code) to use the same data.\n *\n * @param plugins - Array of loaded plugins\n * @returns Array of tool specifications with schema information\n *\n * @example\n * const tools = collectToolSpecs(plugins)\n * // Returns: [{ name: 'event.add', description: '...', inputSchema: {...} }]\n */\nexport const collectToolSpecs = (plugins: LoadedPlugin[]): ToolSpec[] =>\n plugins.flatMap(({ plugin }) => plugin.commands.map((cmd) => commandToToolSpec(plugin, cmd)))\n\n/**\n * Collect executable tool specifications from loaded plugins\n *\n * Transforms plugin commands into executable tool specs with dispatch functions.\n * Each tool's execute() returns a plan-like result without applying effects.\n *\n * @param plugins - Array of loaded plugins\n * @param context - Plugin context for command execution\n * @returns Array of executable tool specifications\n *\n * @example\n * const tools = collectExecutableToolSpecs(plugins, context)\n * const result = await tools[0].execute({ eventType: 'order.created' })\n */\nexport const collectExecutableToolSpecs = (\n plugins: LoadedPlugin[],\n _context: PfPluginContext,\n): ExecutableToolSpec[] =>\n plugins.flatMap(({ plugin }) => plugin.commands.map((cmd) => commandToExecutableToolSpec(plugin, cmd)))\n"],"mappings":"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","names":["import_chalk","import_chalk","import_node_fs","import_node_path","import_chalk","import_chalk","import_node_fs","import_node_path","import_node_path","import_node_url","import_cloudevents","getWorkspacePackageJson","import_zod","import_node_fs","import_node_path","import_node_fs","import_node_path","import_cloudevents","import_node_path","import_cloudevents","import_node_path","import_node_path","import_node_url","import_node_fs","import_node_path","import_meta","import_node_fs","import_node_path","Handlebars","import_meta","import_meta","renderTemplate","renderTemplate","import_node_path","import_meta","getModuleDir","getTemplatesDir","renderTemplate","generatePackageJson","generateReadme","generateEventsGitkeep","import_node_path","import_cloudevents","import_node_fs","import_node_path","import_meta","flowcoreRunFlow","__dirname"]}