motia 0.15.5-beta.174-650639 → 0.15.5-beta.174-096320

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.
@@ -1,7 +1,7 @@
1
1
  import { version } from "../version.mjs";
2
2
  import { executeCommand } from "../utils/execute-command.mjs";
3
3
  import { checkIfDirectoryExists, checkIfFileExists } from "./utils.mjs";
4
- import { getPackageManager } from "../utils/get-package-manager.mjs";
4
+ import { getPackageManager, getPackageManagerFromEnv } from "../utils/get-package-manager.mjs";
5
5
  import { generateTypes } from "../generate-types.mjs";
6
6
  import { pythonInstall } from "../install.mjs";
7
7
  import { pluginDependencies } from "../plugins/plugin-dependencies.mjs";
@@ -19,7 +19,8 @@ const installRequiredDependencies = async (packageManager, rootDir, context) =>
19
19
  const installCommand = {
20
20
  npm: "npm install --save",
21
21
  yarn: "yarn add",
22
- pnpm: "pnpm add"
22
+ pnpm: "pnpm add",
23
+ bun: "bun add"
23
24
  }[packageManager];
24
25
  const dependencies = [
25
26
  `motia@${version}`,
@@ -40,13 +41,12 @@ const installRequiredDependencies = async (packageManager, rootDir, context) =>
40
41
  console.error("❌ Failed to install dependencies:", error);
41
42
  }
42
43
  };
43
- const preparePackageManager = async (rootDir, context) => {
44
- let packageManager = "npm";
45
- const detectedPackageManager = getPackageManager(rootDir);
46
- if (detectedPackageManager !== "unknown") {
47
- context.log("package-manager-detected", (message) => message.tag("info").append("Detected package manager").append(detectedPackageManager, "gray"));
48
- packageManager = detectedPackageManager;
49
- } else context.log("package-manager-using-default", (message) => message.tag("info").append("Using default package manager").append(packageManager, "gray"));
44
+ const preparePackageManager = async (rootDir, context, detectFromParent = false) => {
45
+ const detectionDir = detectFromParent ? process.cwd() : rootDir;
46
+ const envPackageManager = getPackageManagerFromEnv();
47
+ const packageManager = getPackageManager(detectionDir);
48
+ if (!envPackageManager && packageManager === "npm" && !checkIfFileExists(detectionDir, "package-lock.json")) context.log("package-manager-using-default", (message) => message.tag("info").append("Using default package manager").append(packageManager, "gray"));
49
+ else context.log("package-manager-detected", (message) => message.tag("info").append("Detected package manager").append(packageManager, "gray"));
50
50
  return packageManager;
51
51
  };
52
52
  const installNodeDependencies = async (rootDir, context) => {
@@ -162,7 +162,23 @@ const create = async ({ projectName, template, cursorEnabled, context, skipRedis
162
162
  packageManager = await installNodeDependencies(rootDir, context);
163
163
  if (template.includes("python") || template.includes("multilang")) await pythonInstall({ baseDir: rootDir });
164
164
  await generateTypes(rootDir);
165
- } else packageManager = await preparePackageManager(rootDir, context);
165
+ } else {
166
+ packageManager = await preparePackageManager(rootDir, context, true);
167
+ context.log("installing-plugin-dependencies", (message) => message.tag("info").append("Installing plugin dependencies..."));
168
+ const installCommand = {
169
+ npm: "npm install",
170
+ yarn: "yarn",
171
+ pnpm: "pnpm install",
172
+ bun: "bun install"
173
+ }[packageManager];
174
+ try {
175
+ await executeCommand(installCommand, rootDir);
176
+ context.log("plugin-dependencies-installed", (message) => message.tag("success").append("Plugin dependencies installed"));
177
+ } catch (error) {
178
+ context.log("failed-to-install-plugin-dependencies", (message) => message.tag("failed").append("Failed to install plugin dependencies"));
179
+ console.error(error);
180
+ }
181
+ }
166
182
  const projectDirName = path.basename(rootDir);
167
183
  const devCommand = `${packageManager} run dev`;
168
184
  const port = 3e3;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["packageManager: string"],"sources":["../../src/create/index.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport pc from 'picocolors'\nimport { fileURLToPath } from 'url'\nimport type { CliContext, Message } from '../cloud/config-utils'\nimport { generateTypes } from '../generate-types'\nimport { pythonInstall } from '../install'\nimport { pluginDependencies } from '../plugins/plugin-dependencies'\nimport { executeCommand } from '../utils/execute-command'\nimport { getPackageManager } from '../utils/get-package-manager'\nimport { version } from '../version'\nimport { pullRules } from './pull-rules'\nimport { setupTemplate } from './setup-template'\nimport { checkIfDirectoryExists, checkIfFileExists } from './utils'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nconst installRequiredDependencies = async (packageManager: string, rootDir: string, context: CliContext) => {\n context.log('installing-dependencies', (message: Message) => message.tag('info').append('Installing dependencies...'))\n\n const installCommand = {\n npm: 'npm install --save',\n yarn: 'yarn add',\n pnpm: 'pnpm add',\n }[packageManager]\n\n const dependencies = [\n `motia@${version}`,\n 'zod@4.1.12',\n `@motiadev/adapter-bullmq-events@${version}`,\n ...pluginDependencies.map((dep: string) => `${dep}@${version}`),\n ].join(' ')\n\n const devDependencies = ['ts-node@10.9.2', 'typescript@5.7.3', '@types/react@19.1.1'].join(' ')\n\n try {\n await executeCommand(`${installCommand} ${dependencies}`, rootDir)\n await executeCommand(`${installCommand} -D ${devDependencies}`, rootDir)\n\n context.log('dependencies-installed', (message: Message) => message.tag('success').append('Dependencies installed'))\n } catch (error) {\n console.error('❌ Failed to install dependencies:', error)\n }\n}\n\nconst preparePackageManager = async (rootDir: string, context: CliContext) => {\n let packageManager = 'npm'\n const detectedPackageManager = getPackageManager(rootDir)\n\n if (detectedPackageManager !== 'unknown') {\n context.log('package-manager-detected', (message: Message) =>\n message.tag('info').append('Detected package manager').append(detectedPackageManager, 'gray'),\n )\n packageManager = detectedPackageManager\n } else {\n context.log('package-manager-using-default', (message: Message) =>\n message.tag('info').append('Using default package manager').append(packageManager, 'gray'),\n )\n }\n\n return packageManager\n}\n\nconst installNodeDependencies = async (rootDir: string, context: CliContext) => {\n const packageManager = await preparePackageManager(rootDir, context)\n\n await installRequiredDependencies(packageManager, rootDir, context).catch((error: unknown) => {\n context.log('failed-to-install-dependencies', (message: Message) =>\n message.tag('failed').append('Failed to install dependencies'),\n )\n console.error(error)\n })\n\n return packageManager\n}\n\ntype Args = {\n projectName: string\n template: string\n cursorEnabled: boolean\n context: CliContext\n skipTutorialTemplates?: boolean\n skipRedis?: boolean\n}\n\nexport const create = async ({\n projectName,\n template,\n cursorEnabled,\n context,\n skipRedis = false,\n}: Args): Promise<void> => {\n console.log(\n '\\n\\n' +\n `\n _____ ______ ______ ______\n /'\\\\_/\\`\\\\/\\\\ __\\`\\\\/\\\\__ _\\\\/\\\\__ _\\\\ /\\\\ _ \\\\\n /\\\\ \\\\ \\\\ \\\\/\\\\ \\\\/_/\\\\ \\\\/\\\\/_/\\\\ \\\\/ \\\\ \\\\ \\\\L\\\\ \\\\\n \\\\ \\\\ \\\\__\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ __ \\\\\n \\\\ \\\\ \\\\_/\\\\ \\\\ \\\\ \\\\_\\\\ \\\\ \\\\ \\\\ \\\\ \\\\_\\\\ \\\\__\\\\ \\\\ \\\\/\\\\ \\\\\n \\\\ \\\\_\\\\\\\\ \\\\_\\\\ \\\\_____\\\\ \\\\ \\\\_\\\\ /\\\\_____\\\\\\\\ \\\\_\\\\ \\\\_\\\\\n \\\\/_/ \\\\/_/\\\\/_____/ \\\\/_/ \\\\/_____/ \\\\/_/\\\\/_/\n ` +\n '\\n\\n',\n )\n\n const isCurrentDir = projectName === '.' || projectName === './' || projectName === '.\\\\'\n const rootDir = isCurrentDir ? process.cwd() : path.join(process.cwd(), projectName)\n const isPluginTemplate = template === 'plugin'\n\n process.env.REDISMS_DISABLE_POSTINSTALL = '1'\n if (!isCurrentDir && !checkIfDirectoryExists(rootDir)) {\n fs.mkdirSync(path.join(rootDir))\n context.log('directory-created', (message: Message) =>\n message.tag('success').append('Directory created ').append(projectName, 'gray'),\n )\n } else {\n context.log('directory-using', (message: Message) => message.tag('info').append('Using current directory'))\n }\n\n // Plugin template handles package.json differently (via template)\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'package.json')) {\n const finalProjectName =\n !projectName || projectName === '.' || projectName === './' || projectName === '.\\\\'\n ? path.basename(process.cwd())\n : projectName.trim()\n\n const packageJsonContent = {\n name: finalProjectName,\n description: '',\n type: 'module',\n scripts: {\n postinstall: 'motia install',\n dev: 'motia dev',\n start: 'motia start',\n 'generate-types': 'motia generate-types',\n build: 'motia build',\n clean: 'rm -rf dist node_modules python_modules .motia .mermaid',\n //'generate:config': 'motia get-config --output ./', TODO: doesnt work at the moment\n },\n keywords: ['motia'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'package.json'), JSON.stringify(packageJsonContent, null, 2))\n\n context.log('package-json-created', (message: Message) =>\n message.tag('success').append('File').append('package.json', 'cyan').append('has been created.'),\n )\n } else if (!isPluginTemplate) {\n const packageJsonPath = path.join(rootDir, 'package.json')\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n\n if (!packageJson.scripts) {\n packageJson.scripts = {}\n }\n\n if (!packageJson.scripts.dev) {\n packageJson.scripts.dev = 'motia dev'\n } else {\n packageJson.scripts.olddev = packageJson.scripts.dev\n packageJson.scripts.dev = 'motia dev'\n context.log('dev-command-already-exists', (message: Message) =>\n message.tag('warning').append('dev command already exists in package.json'),\n )\n }\n\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))\n context.log('dev-command-updated', (message: Message) =>\n message\n .tag('success')\n .append('Updated')\n .append('dev', 'gray')\n .append('command to')\n .append('package.json', 'gray'),\n )\n }\n\n // Plugin template handles tsconfig.json via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'tsconfig.json')) {\n const tsconfigContent = {\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n noEmit: true,\n esModuleInterop: true,\n strict: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n resolveJsonModule: true,\n allowJs: true,\n outDir: 'dist',\n rootDir: '.',\n baseUrl: '.',\n jsx: 'react-jsx',\n },\n include: ['**/*.ts', 'motia.config.ts', '**/*.tsx', 'types.d.ts', '**/*.jsx'],\n exclude: ['node_modules', 'dist', 'tests'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'tsconfig.json'), JSON.stringify(tsconfigContent, null, 2))\n context.log('tsconfig-json-created', (message: Message) =>\n message.tag('success').append('File').append('tsconfig.json', 'cyan').append('has been created.'),\n )\n }\n\n // Plugin template handles .gitignore via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, '.gitignore')) {\n const gitignoreContent = [\n 'node_modules',\n 'python_modules',\n '.venv',\n 'venv',\n '.motia',\n '.mermaid',\n 'dist',\n '*.pyc',\n ].join('\\n')\n\n fs.writeFileSync(path.join(rootDir, '.gitignore'), gitignoreContent)\n context.log('gitignore-created', (message: Message) =>\n message.tag('success').append('File').append('.gitignore', 'cyan').append('has been created.'),\n )\n }\n\n // Skip cursor rules for plugin template\n if (!isPluginTemplate && cursorEnabled) {\n await pullRules({ force: true, rootDir }, context)\n }\n\n if (template) {\n await setupTemplate(template, rootDir, context)\n }\n\n if (!isPluginTemplate && skipRedis) {\n const motiaConfigPath = path.join(rootDir, 'motia.config.ts')\n\n const templatePath = path.join(__dirname, 'templates/motia.config.external-redis.ts.txt')\n const templateContent = fs.readFileSync(templatePath, 'utf-8')\n fs.writeFileSync(motiaConfigPath, templateContent)\n context.log('motia-config-created', (message: Message) =>\n message.tag('success').append('File').append('motia.config.ts', 'cyan').append('has been created.'),\n )\n }\n\n let packageManager: string\n if (!isPluginTemplate) {\n packageManager = await installNodeDependencies(rootDir, context)\n\n if (template.includes('python') || template.includes('multilang')) {\n await pythonInstall({ baseDir: rootDir })\n }\n\n await generateTypes(rootDir)\n } else {\n // For plugin template, just detect the package manager\n packageManager = await preparePackageManager(rootDir, context)\n }\n\n const projectDirName = path.basename(rootDir)\n const devCommand = `${packageManager} run dev`\n const port = 3000\n const cdCommand = isCurrentDir ? '' : `${pc.cyan(`cd ${projectDirName}`)}\\n `\n\n context.log('success-blank', (message) => message.text(''))\n context.log('success-header', (message) =>\n message.text(`${pc.green('✨')} ${pc.bold('All set! Your project is ready to go.')}`),\n )\n context.log('success-blank-2', (message) => message.text(''))\n context.log('success-get-started', (message) => message.text('Get started:'))\n context.log('success-blank-3', (message) => message.text(''))\n context.log('success-commands', (message) => message.text(` ${cdCommand}${pc.cyan(devCommand)}`))\n context.log('success-blank-4', (message) => message.text(''))\n context.log('success-open', (message) => message.text(`Then open ${pc.cyan(`http://localhost:${port}`)}`))\n context.log('success-blank-5', (message: Message) => message.text(''))\n context.log('success-docs', (message) => message.text(`Docs: ${pc.cyan('https://www.motia.dev/docs')}`))\n context.log('success-blank-6', (message) => message.text(''))\n if (skipRedis) {\n context.log('redis-skip-warning', (message: Message) =>\n message\n .tag('warning')\n .append(\n '⚠️ You skipped Redis binary installation. Make sure to provide a Redis connection before running Motia.',\n ),\n )\n context.log('success-blank-7', (message) => message.text(''))\n }\n context.log('success-signoff', (message) => message.text('Happy coding! 🚀'))\n context.log('success-blank-8', (message) => message.text(''))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["packageManager: string"],"sources":["../../src/create/index.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport pc from 'picocolors'\nimport { fileURLToPath } from 'url'\nimport type { CliContext, Message } from '../cloud/config-utils'\nimport { generateTypes } from '../generate-types'\nimport { pythonInstall } from '../install'\nimport { pluginDependencies } from '../plugins/plugin-dependencies'\nimport { executeCommand } from '../utils/execute-command'\nimport { getPackageManager, getPackageManagerFromEnv } from '../utils/get-package-manager'\nimport { version } from '../version'\nimport { pullRules } from './pull-rules'\nimport { setupTemplate } from './setup-template'\nimport { checkIfDirectoryExists, checkIfFileExists } from './utils'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nconst installRequiredDependencies = async (packageManager: string, rootDir: string, context: CliContext) => {\n context.log('installing-dependencies', (message: Message) => message.tag('info').append('Installing dependencies...'))\n\n const installCommand = {\n npm: 'npm install --save',\n yarn: 'yarn add',\n pnpm: 'pnpm add',\n bun: 'bun add',\n }[packageManager]\n\n const dependencies = [\n `motia@${version}`,\n 'zod@4.1.12',\n `@motiadev/adapter-bullmq-events@${version}`,\n ...pluginDependencies.map((dep: string) => `${dep}@${version}`),\n ].join(' ')\n\n const devDependencies = ['ts-node@10.9.2', 'typescript@5.7.3', '@types/react@19.1.1'].join(' ')\n\n try {\n await executeCommand(`${installCommand} ${dependencies}`, rootDir)\n await executeCommand(`${installCommand} -D ${devDependencies}`, rootDir)\n\n context.log('dependencies-installed', (message: Message) => message.tag('success').append('Dependencies installed'))\n } catch (error) {\n console.error('❌ Failed to install dependencies:', error)\n }\n}\n\nconst preparePackageManager = async (rootDir: string, context: CliContext, detectFromParent = false) => {\n const detectionDir = detectFromParent ? process.cwd() : rootDir\n const envPackageManager = getPackageManagerFromEnv()\n const packageManager = getPackageManager(detectionDir)\n\n const isFallback =\n !envPackageManager && packageManager === 'npm' && !checkIfFileExists(detectionDir, 'package-lock.json')\n\n if (isFallback) {\n context.log('package-manager-using-default', (message: Message) =>\n message.tag('info').append('Using default package manager').append(packageManager, 'gray'),\n )\n } else {\n context.log('package-manager-detected', (message: Message) =>\n message.tag('info').append('Detected package manager').append(packageManager, 'gray'),\n )\n }\n\n return packageManager\n}\n\nconst installNodeDependencies = async (rootDir: string, context: CliContext) => {\n const packageManager = await preparePackageManager(rootDir, context)\n\n await installRequiredDependencies(packageManager, rootDir, context).catch((error: unknown) => {\n context.log('failed-to-install-dependencies', (message: Message) =>\n message.tag('failed').append('Failed to install dependencies'),\n )\n console.error(error)\n })\n\n return packageManager\n}\n\ntype Args = {\n projectName: string\n template: string\n cursorEnabled: boolean\n context: CliContext\n skipTutorialTemplates?: boolean\n skipRedis?: boolean\n}\n\nexport const create = async ({\n projectName,\n template,\n cursorEnabled,\n context,\n skipRedis = false,\n}: Args): Promise<void> => {\n console.log(\n '\\n\\n' +\n `\n _____ ______ ______ ______\n /'\\\\_/\\`\\\\/\\\\ __\\`\\\\/\\\\__ _\\\\/\\\\__ _\\\\ /\\\\ _ \\\\\n /\\\\ \\\\ \\\\ \\\\/\\\\ \\\\/_/\\\\ \\\\/\\\\/_/\\\\ \\\\/ \\\\ \\\\ \\\\L\\\\ \\\\\n \\\\ \\\\ \\\\__\\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ \\\\ __ \\\\\n \\\\ \\\\ \\\\_/\\\\ \\\\ \\\\ \\\\_\\\\ \\\\ \\\\ \\\\ \\\\ \\\\_\\\\ \\\\__\\\\ \\\\ \\\\/\\\\ \\\\\n \\\\ \\\\_\\\\\\\\ \\\\_\\\\ \\\\_____\\\\ \\\\ \\\\_\\\\ /\\\\_____\\\\\\\\ \\\\_\\\\ \\\\_\\\\\n \\\\/_/ \\\\/_/\\\\/_____/ \\\\/_/ \\\\/_____/ \\\\/_/\\\\/_/\n ` +\n '\\n\\n',\n )\n\n const isCurrentDir = projectName === '.' || projectName === './' || projectName === '.\\\\'\n const rootDir = isCurrentDir ? process.cwd() : path.join(process.cwd(), projectName)\n const isPluginTemplate = template === 'plugin'\n\n process.env.REDISMS_DISABLE_POSTINSTALL = '1'\n if (!isCurrentDir && !checkIfDirectoryExists(rootDir)) {\n fs.mkdirSync(path.join(rootDir))\n context.log('directory-created', (message: Message) =>\n message.tag('success').append('Directory created ').append(projectName, 'gray'),\n )\n } else {\n context.log('directory-using', (message: Message) => message.tag('info').append('Using current directory'))\n }\n\n // Plugin template handles package.json differently (via template)\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'package.json')) {\n const finalProjectName =\n !projectName || projectName === '.' || projectName === './' || projectName === '.\\\\'\n ? path.basename(process.cwd())\n : projectName.trim()\n\n const packageJsonContent = {\n name: finalProjectName,\n description: '',\n type: 'module',\n scripts: {\n postinstall: 'motia install',\n dev: 'motia dev',\n start: 'motia start',\n 'generate-types': 'motia generate-types',\n build: 'motia build',\n clean: 'rm -rf dist node_modules python_modules .motia .mermaid',\n //'generate:config': 'motia get-config --output ./', TODO: doesnt work at the moment\n },\n keywords: ['motia'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'package.json'), JSON.stringify(packageJsonContent, null, 2))\n\n context.log('package-json-created', (message: Message) =>\n message.tag('success').append('File').append('package.json', 'cyan').append('has been created.'),\n )\n } else if (!isPluginTemplate) {\n const packageJsonPath = path.join(rootDir, 'package.json')\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n\n if (!packageJson.scripts) {\n packageJson.scripts = {}\n }\n\n if (!packageJson.scripts.dev) {\n packageJson.scripts.dev = 'motia dev'\n } else {\n packageJson.scripts.olddev = packageJson.scripts.dev\n packageJson.scripts.dev = 'motia dev'\n context.log('dev-command-already-exists', (message: Message) =>\n message.tag('warning').append('dev command already exists in package.json'),\n )\n }\n\n fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))\n context.log('dev-command-updated', (message: Message) =>\n message\n .tag('success')\n .append('Updated')\n .append('dev', 'gray')\n .append('command to')\n .append('package.json', 'gray'),\n )\n }\n\n // Plugin template handles tsconfig.json via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, 'tsconfig.json')) {\n const tsconfigContent = {\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n noEmit: true,\n esModuleInterop: true,\n strict: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n resolveJsonModule: true,\n allowJs: true,\n outDir: 'dist',\n rootDir: '.',\n baseUrl: '.',\n jsx: 'react-jsx',\n },\n include: ['**/*.ts', 'motia.config.ts', '**/*.tsx', 'types.d.ts', '**/*.jsx'],\n exclude: ['node_modules', 'dist', 'tests'],\n }\n\n fs.writeFileSync(path.join(rootDir, 'tsconfig.json'), JSON.stringify(tsconfigContent, null, 2))\n context.log('tsconfig-json-created', (message: Message) =>\n message.tag('success').append('File').append('tsconfig.json', 'cyan').append('has been created.'),\n )\n }\n\n // Plugin template handles .gitignore via template\n if (!isPluginTemplate && !checkIfFileExists(rootDir, '.gitignore')) {\n const gitignoreContent = [\n 'node_modules',\n 'python_modules',\n '.venv',\n 'venv',\n '.motia',\n '.mermaid',\n 'dist',\n '*.pyc',\n ].join('\\n')\n\n fs.writeFileSync(path.join(rootDir, '.gitignore'), gitignoreContent)\n context.log('gitignore-created', (message: Message) =>\n message.tag('success').append('File').append('.gitignore', 'cyan').append('has been created.'),\n )\n }\n\n // Skip cursor rules for plugin template\n if (!isPluginTemplate && cursorEnabled) {\n await pullRules({ force: true, rootDir }, context)\n }\n\n if (template) {\n await setupTemplate(template, rootDir, context)\n }\n\n if (!isPluginTemplate && skipRedis) {\n const motiaConfigPath = path.join(rootDir, 'motia.config.ts')\n\n const templatePath = path.join(__dirname, 'templates/motia.config.external-redis.ts.txt')\n const templateContent = fs.readFileSync(templatePath, 'utf-8')\n fs.writeFileSync(motiaConfigPath, templateContent)\n context.log('motia-config-created', (message: Message) =>\n message.tag('success').append('File').append('motia.config.ts', 'cyan').append('has been created.'),\n )\n }\n\n let packageManager: string\n if (!isPluginTemplate) {\n packageManager = await installNodeDependencies(rootDir, context)\n\n if (template.includes('python') || template.includes('multilang')) {\n await pythonInstall({ baseDir: rootDir })\n }\n\n await generateTypes(rootDir)\n } else {\n packageManager = await preparePackageManager(rootDir, context, true)\n\n context.log('installing-plugin-dependencies', (message: Message) =>\n message.tag('info').append('Installing plugin dependencies...'),\n )\n\n const installCommand = {\n npm: 'npm install',\n yarn: 'yarn',\n pnpm: 'pnpm install',\n bun: 'bun install',\n }[packageManager]\n\n try {\n await executeCommand(installCommand!, rootDir)\n context.log('plugin-dependencies-installed', (message: Message) =>\n message.tag('success').append('Plugin dependencies installed'),\n )\n } catch (error) {\n context.log('failed-to-install-plugin-dependencies', (message: Message) =>\n message.tag('failed').append('Failed to install plugin dependencies'),\n )\n console.error(error)\n }\n }\n\n const projectDirName = path.basename(rootDir)\n const devCommand = `${packageManager} run dev`\n const port = 3000\n const cdCommand = isCurrentDir ? '' : `${pc.cyan(`cd ${projectDirName}`)}\\n `\n\n context.log('success-blank', (message) => message.text(''))\n context.log('success-header', (message) =>\n message.text(`${pc.green('✨')} ${pc.bold('All set! Your project is ready to go.')}`),\n )\n context.log('success-blank-2', (message) => message.text(''))\n context.log('success-get-started', (message) => message.text('Get started:'))\n context.log('success-blank-3', (message) => message.text(''))\n context.log('success-commands', (message) => message.text(` ${cdCommand}${pc.cyan(devCommand)}`))\n context.log('success-blank-4', (message) => message.text(''))\n context.log('success-open', (message) => message.text(`Then open ${pc.cyan(`http://localhost:${port}`)}`))\n context.log('success-blank-5', (message: Message) => message.text(''))\n context.log('success-docs', (message) => message.text(`Docs: ${pc.cyan('https://www.motia.dev/docs')}`))\n context.log('success-blank-6', (message) => message.text(''))\n if (skipRedis) {\n context.log('redis-skip-warning', (message: Message) =>\n message\n .tag('warning')\n .append(\n '⚠️ You skipped Redis binary installation. Make sure to provide a Redis connection before running Motia.',\n ),\n )\n context.log('success-blank-7', (message) => message.text(''))\n }\n context.log('success-signoff', (message) => message.text('Happy coding! 🚀'))\n context.log('success-blank-8', (message) => message.text(''))\n}\n"],"mappings":"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"}
@@ -11,56 +11,64 @@ You are an expert Motia developer with comprehensive knowledge of all Motia patt
11
11
 
12
12
  Before writing ANY Motia code, you MUST read the relevant cursor rules from `.cursor/rules/`:
13
13
 
14
+ ### Configuration Guide (in `.cursor/rules/motia/`)
15
+
16
+ 1. **`motia-config.mdc`** - Project configuration
17
+ - Package.json requirements (`"type": "module"`)
18
+ - Plugin naming conventions and setup
19
+ - Adapter configuration, Redis setup
20
+ - Stream authentication patterns
21
+
14
22
  ### Step Type Guides (in `.cursor/rules/motia/`)
15
23
 
16
- 1. **`api-steps.mdc`** - HTTP endpoints
24
+ 2. **`api-steps.mdc`** - HTTP endpoints
17
25
  - Creating API Steps with TypeScript, JavaScript, or Python
18
26
  - Request/response schemas, validation, middleware
19
27
  - When to emit events vs process directly
20
28
 
21
- 2. **`event-steps.mdc`** - Background tasks
29
+ 3. **`event-steps.mdc`** - Background tasks
22
30
  - Creating Event Steps with TypeScript, JavaScript, or Python
23
31
  - Topic subscription, event chaining, retry mechanisms
24
32
  - Asynchronous workflow patterns
25
33
 
26
- 3. **`cron-steps.mdc`** - Scheduled tasks
34
+ 4. **`cron-steps.mdc`** - Scheduled tasks
27
35
  - Creating Cron Steps with TypeScript, JavaScript, or Python
28
36
  - Cron expression syntax, idempotent patterns
29
37
  - When to emit events from scheduled jobs
30
38
 
31
- 4. **`state-management.mdc`** - State/cache management
39
+ 5. **`state-management.mdc`** - State/cache management
32
40
  - Using state across steps with TypeScript, JavaScript, or Python
33
41
  - When to use state vs database
34
42
  - TTL configuration, caching strategies
35
43
 
36
- 5. **`middlewares.mdc`** - Request/response middleware
44
+ 6. **`middlewares.mdc`** - Request/response middleware
37
45
  - Creating middleware with TypeScript, JavaScript, or Python
38
46
  - Authentication, validation, error handling
39
47
  - Middleware composition patterns
40
48
 
41
- 6. **`realtime-streaming.mdc`** - Real-time data
49
+ 7. **`realtime-streaming.mdc`** - Real-time data
42
50
  - Server-Sent Events (SSE) patterns
43
51
  - WebSocket support
44
52
  - Stream configuration and usage
45
53
 
46
- 7. **`virtual-steps.mdc`** - Visual flow connections
54
+ 8. **`virtual-steps.mdc`** - Visual flow connections
47
55
  - Creating NOOP steps for Workbench
48
56
  - Virtual emits/subscribes for documentation
49
57
  - Workflow visualization
50
58
 
51
- 8. **`ui-steps.mdc`** - Custom Workbench components
59
+ 9. **`ui-steps.mdc`** - Custom Workbench components
52
60
  - Creating custom visual components (TypeScript/React)
53
61
  - EventNode, ApiNode, CronNode components
54
62
  - Styling with Tailwind
55
63
 
56
64
  ### Architecture Guides (in `.cursor/architecture/`)
57
65
 
58
- 9. **`architecture.mdc`** - Project structure
66
+ 10. **`architecture.mdc`** - Project structure
59
67
  - File organization, naming conventions
60
68
  - Domain-Driven Design patterns
61
69
  - Services, repositories, utilities structure
62
70
 
63
- 10. **`error-handling.mdc`** - Error handling
71
+ 11. **`error-handling.mdc`** - Error handling
64
72
  - Custom error classes
65
73
  - Middleware error handling
66
74
  - ZodError/Pydantic validation errors
@@ -78,6 +86,7 @@ Before writing ANY Motia code, you MUST read the relevant cursor rules from `.cu
78
86
  ## Key Principles
79
87
 
80
88
  - **All guides have TypeScript, JavaScript, and Python examples**
89
+ - **Steps can live in `/src` or `/steps`** - Motia discovers both (use `/src` for modern structure)
81
90
  - **Always export `config` and `handler`**
82
91
  - **List all emits in config before using them**
83
92
  - **Follow naming conventions**: `*.step.ts` (TS), `*.step.js` (JS), `*_step.py` (Python)
@@ -92,4 +101,4 @@ If you're unsure about any Motia pattern:
92
101
 
93
102
  ---
94
103
 
95
- Remember: The 10 cursor rules in `.cursor/rules/` are your source of truth. Always read them first.
104
+ Remember: The 11 cursor rules in `.cursor/rules/` are your source of truth. Always read them first.
@@ -8,13 +8,61 @@ alwaysApply: true
8
8
 
9
9
  ## Overview
10
10
 
11
- This guide covers the architecture of a Motia project.
11
+ This guide covers the architecture and best practices for structuring Motia projects.
12
+
13
+ **Key Takeaway**: Motia automatically discovers steps from anywhere in your project. Modern projects use `/src` for a familiar structure that works seamlessly with Domain-Driven Design.
12
14
 
13
15
  ## File Structure
14
16
 
15
- All step files should be underneath the `steps/` folder.
17
+ Motia automatically discovers step files from your project. You can organize steps in either:
18
+
19
+ - **`/src` folder** (recommended) - Familiar pattern for most developers
20
+ - **`/steps` folder** - Traditional Motia pattern
21
+ - Both folders simultaneously
22
+
23
+ ### Recommended Structure (using `/src`)
24
+
25
+ ```
26
+ project/
27
+ ├── src/
28
+ │ ├── api/ # API endpoints
29
+ │ │ ├── users.step.ts
30
+ │ │ └── orders.step.ts
31
+ │ ├── events/ # Event handlers
32
+ │ │ ├── order-processing.step.ts
33
+ │ │ └── notifications.step.ts
34
+ │ ├── cron/ # Scheduled tasks
35
+ │ │ └── cleanup.step.ts
36
+ │ ├── services/ # Business logic
37
+ │ ├── repositories/ # Data access
38
+ │ └── utils/ # Utilities
39
+ └── motia.config.ts
40
+ ```
16
41
 
17
- Underneath the `steps/` folder, create subfolders for Flows. Flows are used to group steps together.
42
+ ### Alternative Structure (using `/steps`)
43
+
44
+ ```
45
+ project/
46
+ ├── steps/
47
+ │ ├── api/
48
+ │ │ └── users.step.ts
49
+ │ ├── events/
50
+ │ │ └── order-processing.step.ts
51
+ │ └── cron/
52
+ │ └── cleanup.step.ts
53
+ ├── src/
54
+ │ ├── services/
55
+ │ └── utils/
56
+ └── motia.config.ts
57
+ ```
58
+
59
+ Create subfolders within your chosen directory to organize related steps into logical groups (domains, features, or flows).
60
+
61
+ **Why `/src` is recommended:**
62
+ - Familiar to developers from other frameworks (Next.js, NestJS, etc.)
63
+ - Natural co-location with services, repositories, and utilities
64
+ - Works seamlessly with Domain-Driven Design patterns
65
+ - Cleaner project root with fewer top-level folders
18
66
 
19
67
  ## Step Naming Conventions
20
68
 
@@ -40,49 +88,97 @@ Underneath the `steps/` folder, create subfolders for Flows. Flows are used to g
40
88
 
41
89
  ## Defining Middlewares
42
90
 
43
- Middleware is a powerful feature in Motia to help adding common validation, error
44
- handling and other common logic to your steps.
91
+ Middleware is a powerful feature in Motia for common validation, error handling, and shared logic.
92
+
93
+ ### Middleware Organization
45
94
 
46
- - Make sure to add all the middlewares in a single folder, called `middlewares/`.
47
- - Create a comprehensive file name for the middleware, like `auth.middleware.ts`.
48
- - Follow SOLID principles with separation of concerns in middlewares, create a middleware for each responsibility.
49
- - Use core middleware to handle ZodError gracefully (see [Error Handling Guide](./error-handling.mdc))
50
- - Rate limiting and CORS are not needed to be handled in middleware since they're an infrastructure concern.
95
+ Store middlewares in a dedicated folder:
96
+ - `/middlewares` at project root (recommended)
97
+ - `/src/middlewares` if using `/src` structure
98
+
99
+ ### Best Practices
100
+
101
+ - **One responsibility per middleware** - Follow SOLID principles
102
+ - **Descriptive naming** - Use names like `auth.middleware.ts`, `validation.middleware.ts`
103
+ - **Handle errors gracefully** - Use core middleware for ZodError (see [Error Handling Guide](./error-handling.mdc))
104
+ - **Avoid infrastructure concerns** - Rate limiting and CORS are handled by infrastructure, not middleware
51
105
 
52
106
  ## Domain Driven Design
53
107
 
54
- Make sure you follow Domain Driven Design principles in your project.
108
+ Motia encourages Domain-Driven Design (DDD) principles for maintainable, scalable applications.
55
109
 
56
- - Create `/src/services` folder to store your services, this is where it holds business logic.
57
- - Create `/src/repositories` folder to store your repositories, this is where it holds data access logic.
58
- - Create `/src/utils` folder to store your utility functions.
59
- - Models and DTOs are not quite necessary, we can rely on zod to create the models and DTOs from the steps.
60
- - Controller layer is the Steps, it should have mostly logic around validation and calling services.
61
- - Avoid having Service methods with just a call to the Repository, it should have some logic around it, if it doesn't have, then Steps can have access to repositories directly.
110
+ ### Folder Structure for DDD
62
111
 
63
- ### Services
112
+ When using `/src` for steps (recommended), your structure naturally supports DDD:
64
113
 
65
- Defining services can be done in the following way:
114
+ ```
115
+ src/
116
+ ├── api/ # API Steps (Controllers)
117
+ ├── events/ # Event Steps (Controllers)
118
+ ├── cron/ # Cron Steps (Controllers)
119
+ ├── services/ # Business logic layer
120
+ ├── repositories/ # Data access layer
121
+ ├── utils/ # Utility functions
122
+ └── types/ # Shared types (optional)
123
+ ```
124
+
125
+ ### Layer Responsibilities
126
+
127
+ - **Steps (Controller Layer)**: Handle validation, call services, emit events
128
+ - **Services**: Contain business logic, orchestrate repositories
129
+ - **Repositories**: Direct data access (database, external APIs)
130
+ - **Utils**: Pure utility functions with no side effects
66
131
 
67
- - Create a folder underneath `/src/services/` folder, like `/src/services/auth/`.
68
- - Create a file inside the folder called `index.ts`.
69
- - Inside `index.ts`, export a constant with the name of the service, with the methods as properties.
70
- - Methods should be defined as separate files, use export named functions.
71
- - Use the service in the Steps.
132
+ ### Best Practices
72
133
 
73
- #### Example
134
+ - Models and DTOs are not necessary - use Zod schemas from step configs
135
+ - Steps should focus on validation and calling services
136
+ - Avoid service methods that only call repositories - Steps can access repositories directly
137
+ - Keep business logic in services, not in steps
74
138
 
139
+ ### Services
140
+
141
+ Services contain your business logic and should be organized by domain.
142
+
143
+ **Structure:**
144
+ ```
145
+ src/
146
+ ├── services/
147
+ │ ├── auth/
148
+ │ │ ├── index.ts # Export service
149
+ │ │ ├── login.ts # Login method
150
+ │ │ └── register.ts # Register method
151
+ │ └── orders/
152
+ │ ├── index.ts
153
+ │ └── create-order.ts
154
+ └── api/
155
+ └── auth.step.ts # Uses authService
156
+ ```
157
+
158
+ **Service Definition (`/src/services/auth/index.ts`):**
75
159
  ```typescript
76
160
  /**
77
- * Business logic for authentication defined in a separate file in the same folder.
161
+ * Business logic methods imported from separate files
78
162
  */
79
163
  import { login } from './login'
164
+ import { register } from './register'
80
165
 
81
166
  /**
82
- * Constant with the name of the service, with the methods as properties.
167
+ * Export service with methods as properties
83
168
  */
84
169
  export const authService = {
85
- login
170
+ login,
171
+ register
172
+ }
173
+ ```
174
+
175
+ **Usage in Step (`/src/api/auth.step.ts`):**
176
+ ```typescript
177
+ import { authService } from '../services/auth'
178
+
179
+ export const handler = async (req, ctx) => {
180
+ const user = await authService.login(req.body.email, req.body.password)
181
+ return { status: 200, body: { user } }
86
182
  }
87
183
  ```
88
184
 
@@ -7,6 +7,43 @@ alwaysApply: false
7
7
 
8
8
  The `motia.config.ts` file is the central configuration file for your Motia application. It allows you to customize plugins, adapters, stream authentication, and Express app settings.
9
9
 
10
+ ## Critical Requirement: package.json Must Use ES Modules
11
+
12
+ **All Motia projects MUST have `"type": "module"` in their `package.json`.**
13
+
14
+ Motia uses ES modules internally and requires this setting to function correctly. Without it, you may encounter import/export errors during runtime.
15
+
16
+ ### Correct package.json Setup
17
+
18
+ ```json
19
+ {
20
+ "name": "my-motia-project",
21
+ "description": "My Motia application",
22
+ "type": "module",
23
+ "scripts": {
24
+ "postinstall": "motia install",
25
+ "dev": "motia dev",
26
+ "start": "motia start",
27
+ "build": "motia build",
28
+ "generate-types": "motia generate-types"
29
+ }
30
+ }
31
+ ```
32
+
33
+ ### Migration from Existing Projects
34
+
35
+ If you have an existing Motia project, ensure you add `"type": "module"` to your `package.json`:
36
+
37
+ ```json
38
+ {
39
+ "name": "my-project",
40
+ "type": "module", // ← Add this line
41
+ "scripts": {
42
+ "dev": "motia dev"
43
+ }
44
+ }
45
+ ```
46
+
10
47
  ## Creating the Configuration File
11
48
 
12
49
  Create a `motia.config.ts` file in the root of your project:
@@ -157,6 +194,21 @@ export default config({
157
194
 
158
195
  ### Creating a Local Plugin
159
196
 
197
+ **Project structure:**
198
+ ```
199
+ project/
200
+ ├── src/ # Steps can be in /src or /steps
201
+ │ └── api/
202
+ │ └── example.step.ts
203
+ ├── plugins/
204
+ │ └── my-plugin/
205
+ │ ├── components/
206
+ │ │ └── my-plugin-panel.tsx
207
+ │ └── index.ts
208
+ └── motia.config.ts
209
+ ```
210
+
211
+ **Plugin implementation (`plugins/my-plugin/index.ts`):**
160
212
  ```typescript
161
213
  import path from 'node:path'
162
214
  import { config, type MotiaPlugin, type MotiaPluginContext } from 'motia'
@@ -195,6 +247,20 @@ export default config({
195
247
  })
196
248
  ```
197
249
 
250
+ ### Common Plugin Errors
251
+
252
+ **Error: Component not found**
253
+ - **Cause**: `packageName` doesn't match the actual folder structure
254
+ - **Solution**: Ensure `packageName: '~/plugins/my-plugin'` matches `plugins/my-plugin/` folder
255
+
256
+ **Error: Plugin not loading in workbench**
257
+ - **Cause**: Plugin function not exported correctly
258
+ - **Solution**: Use `export default function` in plugin's `index.ts`
259
+
260
+ **Error: Module resolution failed**
261
+ - **Cause**: Using incorrect casing in folder/file names
262
+ - **Solution**: Use `kebab-case` for folders/files, `PascalCase` for React components
263
+
198
264
  ## Adapters
199
265
 
200
266
  Adapters allow you to customize the underlying infrastructure for state management, event handling, cron jobs, and streams. This is useful for horizontal scaling or using custom storage backends.
@@ -40,6 +40,7 @@ These guides are written in markdown and can be read by any AI coding tool. The
40
40
 
41
41
  Read these files in `.cursor/rules/motia/` for detailed patterns:
42
42
 
43
+ - **`motia-config.mdc`** - Essential project setup, package.json requirements, plugin naming
43
44
  - **`api-steps.mdc`** - Creating HTTP endpoints with schemas, validation, and middleware
44
45
  - **`event-steps.mdc`** - Background task processing and event-driven workflows
45
46
  - **`cron-steps.mdc`** - Scheduled tasks with cron expressions
@@ -62,31 +63,44 @@ Architecture guides in `.cursor/architecture/`:
62
63
 
63
64
  ### Project Structure
64
65
 
66
+ Motia discovers steps from both `/src` and `/steps` folders. Modern projects typically use `/src`:
67
+
68
+ **Recommended Structure (using `/src`):**
65
69
  ```
66
70
  project/
67
71
  ├── .cursor/rules/ # DETAILED GUIDES - Read these first!
68
- ├── steps/ # All step definitions
69
- │ ├── api/ # API endpoints
70
- │ │ └── api.step.ts
71
- │ │ └── api.step.js
72
- │ │ └── api_step.py
73
- │ ├── events/ # Events
74
- │ │ └── events.step.ts
75
- │ │ └── events.step.js
76
- │ │ └── events_step.py
77
- │ └── cron/ # Scheduled tasks
78
- │ │ └── cron.step.ts
79
- │ │ └── cron.step.js
80
- │ │ └── cron_step.py
81
- ├── middlewares/ # Reusable middleware
82
- │ └── middleware.middleware.ts
83
72
  ├── src/
73
+ │ ├── api/ # API endpoints
74
+ │ │ ├── users.step.ts
75
+ │ │ ├── orders.step.js
76
+ │ │ └── products_step.py
77
+ │ ├── events/ # Event handlers
78
+ │ │ ├── order-processing.step.ts
79
+ │ │ └── notifications_step.py
80
+ │ ├── cron/ # Scheduled tasks
81
+ │ │ └── cleanup.step.ts
84
82
  │ ├── services/ # Business logic
83
+ │ ├── repositories/ # Data access
85
84
  │ └── utils/ # Utilities
86
- ├── config.yml # Motia configuration
85
+ ├── middlewares/ # Reusable middleware
86
+ │ └── auth.middleware.ts
87
+ ├── motia.config.ts # Motia configuration
87
88
  └── types.d.ts # Auto-generated types
88
89
  ```
89
90
 
91
+ **Alternative Structure (using `/steps`):**
92
+ ```
93
+ project/
94
+ ├── steps/ # Step definitions
95
+ │ ├── api/
96
+ │ ├── events/
97
+ │ └── cron/
98
+ ├── src/
99
+ │ ├── services/
100
+ │ └── utils/
101
+ └── motia.config.ts
102
+ ```
103
+
90
104
  ### Step Naming Conventions
91
105
 
92
106
  **TypeScript/JavaScript:** `my-step.step.ts` (kebab-case)
@@ -194,6 +208,7 @@ When working on Motia projects, follow this pattern:
194
208
 
195
209
  ## Critical Rules
196
210
 
211
+ - **ALWAYS** ensure `package.json` has `"type": "module"` (read `motia-config.mdc` for details)
197
212
  - **ALWAYS** read `.cursor/rules/` guides before writing step code
198
213
  - **ALWAYS** run `npx motia generate-types` after modifying configs
199
214
  - **ALWAYS** list emits in config before using them in handlers
@@ -12,7 +12,7 @@ This project has detailed development guides in **`.cursor/rules/`** directory.
12
12
 
13
13
  **A pre-configured subagent is ready!**
14
14
 
15
- The `motia-developer` subagent in `.claude/agents/` automatically references all 10 cursor rules when coding.
15
+ The `motia-developer` subagent in `.claude/agents/` automatically references all 11 cursor rules when coding.
16
16
 
17
17
  Use it: `/agents` → select `motia-developer`
18
18
 
@@ -27,10 +27,13 @@ Read .cursor/rules/motia/api-steps.mdc and create an API endpoint
27
27
  for user registration following the patterns shown.
28
28
  ```
29
29
 
30
- ## Available Guides (10 Comprehensive Files)
30
+ ## Available Guides (11 Comprehensive Files)
31
31
 
32
32
  All guides in `.cursor/rules/` with **TypeScript, JavaScript, and Python** examples:
33
33
 
34
+ **Configuration** (`.cursor/rules/motia/`):
35
+ - `motia-config.mdc` - Essential project setup, package.json requirements, plugin naming
36
+
34
37
  **Step Types** (`.cursor/rules/motia/`):
35
38
  - `api-steps.mdc`, `event-steps.mdc`, `cron-steps.mdc`
36
39
 
@@ -45,6 +48,8 @@ All guides in `.cursor/rules/` with **TypeScript, JavaScript, and Python** examp
45
48
 
46
49
  See `AGENTS.md` in this directory for a quick overview and links to specific guides.
47
50
 
51
+ **Important**: Motia discovers steps from both `/src` and `/steps` folders. Modern projects use `/src` for a familiar structure.
52
+
48
53
  ## Key Commands
49
54
 
50
55
  ```bash
@@ -3,6 +3,7 @@
3
3
  "description": "Motia event-driven backend framework project",
4
4
  "rules": ["AGENTS.md"],
5
5
  "context": [
6
+ ".cursor/rules/motia/motia-config.mdc",
6
7
  ".cursor/rules/motia/api-steps.mdc",
7
8
  ".cursor/rules/motia/event-steps.mdc",
8
9
  ".cursor/rules/motia/cron-steps.mdc",
@@ -38,7 +38,8 @@ const installPluginDependencies = async (baseDir, printer) => {
38
38
  const installCommand = {
39
39
  npm: "npm install",
40
40
  yarn: "yarn install",
41
- pnpm: "pnpm install"
41
+ pnpm: "pnpm install",
42
+ bun: "bun install"
42
43
  }[packageManager] || "npm install";
43
44
  try {
44
45
  await executeCommand(installCommand, baseDir, { silent: false });
@@ -1 +1 @@
1
- {"version":3,"file":"install-plugin-dependencies.mjs","names":["missingDependencies: string[]"],"sources":["../../src/plugins/install-plugin-dependencies.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Printer } from '@motiadev/core'\nimport { executeCommand } from '../utils/execute-command'\nimport { getPackageManager } from '../utils/get-package-manager'\nimport { version } from '../version'\nimport { pluginDependencies } from './plugin-dependencies'\n\nexport const installPluginDependencies = async (baseDir: string, printer: Printer): Promise<void> => {\n const packageJsonPath = path.join(baseDir, 'package.json')\n\n if (!fs.existsSync(packageJsonPath)) {\n printer.printPluginWarn('No package.json found, skipping plugin dependency installation')\n return\n }\n\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n\n if (!packageJson.dependencies) {\n packageJson.dependencies = {}\n }\n\n const missingDependencies: string[] = []\n\n for (const dep of pluginDependencies) {\n if (packageJson.devDependencies?.[dep]) {\n delete packageJson.devDependencies[dep]\n }\n\n if (!packageJson.dependencies[dep]) {\n packageJson.dependencies[dep] = version\n missingDependencies.push(dep)\n }\n }\n\n if (missingDependencies.length === 0) {\n printer.printPluginLog('All plugin dependencies already installed')\n return\n }\n\n printer.printPluginLog(`Adding missing plugin dependencies: ${missingDependencies.join(', ')}`)\n\n fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\\n`)\n printer.printPluginLog('Updated package.json with plugin dependencies')\n\n let packageManager = getPackageManager(baseDir)\n if (packageManager === 'unknown') {\n printer.printPluginError('No package manager found, using npm as default')\n packageManager = 'npm'\n }\n printer.printPluginLog(`Installing dependencies using ${packageManager}...`)\n\n const installCommands: Record<string, string> = {\n npm: 'npm install',\n yarn: 'yarn install',\n pnpm: 'pnpm install',\n }\n\n const installCommand = installCommands[packageManager] || 'npm install'\n\n try {\n await executeCommand(installCommand, baseDir, { silent: false })\n printer.printPluginLog('Plugin dependencies installed successfully')\n } catch (error) {\n printer.printPluginError('Failed to install plugin dependencies:', error)\n printer.printPluginWarn(`Please run '${installCommand}' manually to install the dependencies`)\n }\n}\n"],"mappings":";;;;;;;;AAQA,MAAa,4BAA4B,OAAO,SAAiB,YAAoC;CACnG,MAAM,kBAAkB,KAAK,KAAK,SAAS,eAAe;AAE1D,KAAI,CAAC,GAAG,WAAW,gBAAgB,EAAE;AACnC,UAAQ,gBAAgB,iEAAiE;AACzF;;CAGF,MAAM,cAAc,KAAK,MAAM,GAAG,aAAa,iBAAiB,QAAQ,CAAC;AAEzE,KAAI,CAAC,YAAY,aACf,aAAY,eAAe,EAAE;CAG/B,MAAMA,sBAAgC,EAAE;AAExC,MAAK,MAAM,OAAO,oBAAoB;AACpC,MAAI,YAAY,kBAAkB,KAChC,QAAO,YAAY,gBAAgB;AAGrC,MAAI,CAAC,YAAY,aAAa,MAAM;AAClC,eAAY,aAAa,OAAO;AAChC,uBAAoB,KAAK,IAAI;;;AAIjC,KAAI,oBAAoB,WAAW,GAAG;AACpC,UAAQ,eAAe,4CAA4C;AACnE;;AAGF,SAAQ,eAAe,uCAAuC,oBAAoB,KAAK,KAAK,GAAG;AAE/F,IAAG,cAAc,iBAAiB,GAAG,KAAK,UAAU,aAAa,MAAM,EAAE,CAAC,IAAI;AAC9E,SAAQ,eAAe,gDAAgD;CAEvE,IAAI,iBAAiB,kBAAkB,QAAQ;AAC/C,KAAI,mBAAmB,WAAW;AAChC,UAAQ,iBAAiB,iDAAiD;AAC1E,mBAAiB;;AAEnB,SAAQ,eAAe,iCAAiC,eAAe,KAAK;CAQ5E,MAAM,iBAN0C;EAC9C,KAAK;EACL,MAAM;EACN,MAAM;EACP,CAEsC,mBAAmB;AAE1D,KAAI;AACF,QAAM,eAAe,gBAAgB,SAAS,EAAE,QAAQ,OAAO,CAAC;AAChE,UAAQ,eAAe,6CAA6C;UAC7D,OAAO;AACd,UAAQ,iBAAiB,0CAA0C,MAAM;AACzE,UAAQ,gBAAgB,eAAe,eAAe,wCAAwC"}
1
+ {"version":3,"file":"install-plugin-dependencies.mjs","names":["missingDependencies: string[]"],"sources":["../../src/plugins/install-plugin-dependencies.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Printer } from '@motiadev/core'\nimport { executeCommand } from '../utils/execute-command'\nimport { getPackageManager } from '../utils/get-package-manager'\nimport { version } from '../version'\nimport { pluginDependencies } from './plugin-dependencies'\n\nexport const installPluginDependencies = async (baseDir: string, printer: Printer): Promise<void> => {\n const packageJsonPath = path.join(baseDir, 'package.json')\n\n if (!fs.existsSync(packageJsonPath)) {\n printer.printPluginWarn('No package.json found, skipping plugin dependency installation')\n return\n }\n\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n\n if (!packageJson.dependencies) {\n packageJson.dependencies = {}\n }\n\n const missingDependencies: string[] = []\n\n for (const dep of pluginDependencies) {\n if (packageJson.devDependencies?.[dep]) {\n delete packageJson.devDependencies[dep]\n }\n\n if (!packageJson.dependencies[dep]) {\n packageJson.dependencies[dep] = version\n missingDependencies.push(dep)\n }\n }\n\n if (missingDependencies.length === 0) {\n printer.printPluginLog('All plugin dependencies already installed')\n return\n }\n\n printer.printPluginLog(`Adding missing plugin dependencies: ${missingDependencies.join(', ')}`)\n\n fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\\n`)\n printer.printPluginLog('Updated package.json with plugin dependencies')\n\n let packageManager = getPackageManager(baseDir)\n if (packageManager === 'unknown') {\n printer.printPluginError('No package manager found, using npm as default')\n packageManager = 'npm'\n }\n printer.printPluginLog(`Installing dependencies using ${packageManager}...`)\n\n const installCommands: Record<string, string> = {\n npm: 'npm install',\n yarn: 'yarn install',\n pnpm: 'pnpm install',\n bun: 'bun install',\n }\n\n const installCommand = installCommands[packageManager] || 'npm install'\n\n try {\n await executeCommand(installCommand, baseDir, { silent: false })\n printer.printPluginLog('Plugin dependencies installed successfully')\n } catch (error) {\n printer.printPluginError('Failed to install plugin dependencies:', error)\n printer.printPluginWarn(`Please run '${installCommand}' manually to install the dependencies`)\n }\n}\n"],"mappings":";;;;;;;;AAQA,MAAa,4BAA4B,OAAO,SAAiB,YAAoC;CACnG,MAAM,kBAAkB,KAAK,KAAK,SAAS,eAAe;AAE1D,KAAI,CAAC,GAAG,WAAW,gBAAgB,EAAE;AACnC,UAAQ,gBAAgB,iEAAiE;AACzF;;CAGF,MAAM,cAAc,KAAK,MAAM,GAAG,aAAa,iBAAiB,QAAQ,CAAC;AAEzE,KAAI,CAAC,YAAY,aACf,aAAY,eAAe,EAAE;CAG/B,MAAMA,sBAAgC,EAAE;AAExC,MAAK,MAAM,OAAO,oBAAoB;AACpC,MAAI,YAAY,kBAAkB,KAChC,QAAO,YAAY,gBAAgB;AAGrC,MAAI,CAAC,YAAY,aAAa,MAAM;AAClC,eAAY,aAAa,OAAO;AAChC,uBAAoB,KAAK,IAAI;;;AAIjC,KAAI,oBAAoB,WAAW,GAAG;AACpC,UAAQ,eAAe,4CAA4C;AACnE;;AAGF,SAAQ,eAAe,uCAAuC,oBAAoB,KAAK,KAAK,GAAG;AAE/F,IAAG,cAAc,iBAAiB,GAAG,KAAK,UAAU,aAAa,MAAM,EAAE,CAAC,IAAI;AAC9E,SAAQ,eAAe,gDAAgD;CAEvE,IAAI,iBAAiB,kBAAkB,QAAQ;AAC/C,KAAI,mBAAmB,WAAW;AAChC,UAAQ,iBAAiB,iDAAiD;AAC1E,mBAAiB;;AAEnB,SAAQ,eAAe,iCAAiC,eAAe,KAAK;CAS5E,MAAM,iBAP0C;EAC9C,KAAK;EACL,MAAM;EACN,MAAM;EACN,KAAK;EACN,CAEsC,mBAAmB;AAE1D,KAAI;AACF,QAAM,eAAe,gBAAgB,SAAS,EAAE,QAAQ,OAAO,CAAC;AAChE,UAAQ,eAAe,6CAA6C;UAC7D,OAAO;AACd,UAAQ,iBAAiB,0CAA0C,MAAM;AACzE,UAAQ,gBAAgB,eAAe,eAAe,wCAAwC"}
@@ -1,19 +1,50 @@
1
1
  import { checkIfFileExists } from "../create/utils.mjs";
2
+ import fs from "fs";
2
3
  import path from "path";
3
4
 
4
5
  //#region src/utils/get-package-manager.ts
6
+ const getPackageManagerFromEnv = () => {
7
+ const userAgent = process.env.npm_config_user_agent;
8
+ if (!userAgent) return null;
9
+ const match = userAgent.match(/^(npm|pnpm|yarn|bun)\//);
10
+ if (match) return match[1];
11
+ return null;
12
+ };
13
+ const readPackageManagerFromPackageJson = (dir) => {
14
+ const packageJsonPath = path.join(dir, "package.json");
15
+ if (!checkIfFileExists(dir, "package.json")) return null;
16
+ try {
17
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
18
+ if (packageJson.packageManager) {
19
+ const pm = packageJson.packageManager.split("@")[0];
20
+ if ([
21
+ "npm",
22
+ "yarn",
23
+ "pnpm",
24
+ "bun"
25
+ ].includes(pm)) return pm;
26
+ }
27
+ } catch {
28
+ return null;
29
+ }
30
+ return null;
31
+ };
5
32
  const getPackageManager = (dir) => {
33
+ const envPackageManager = getPackageManagerFromEnv();
34
+ if (envPackageManager) return envPackageManager;
6
35
  let currentDir = dir;
7
36
  while (currentDir !== path.dirname(currentDir)) {
8
37
  if (checkIfFileExists(currentDir, "yarn.lock")) return "yarn";
9
38
  else if (checkIfFileExists(currentDir, "pnpm-lock.yaml")) return "pnpm";
10
39
  else if (checkIfFileExists(currentDir, "package-lock.json")) return "npm";
11
40
  else if (checkIfFileExists(currentDir, "bun.lockb") || checkIfFileExists(currentDir, "bun.lock")) return "bun";
41
+ const packageManagerFromJson = readPackageManagerFromPackageJson(currentDir);
42
+ if (packageManagerFromJson) return packageManagerFromJson;
12
43
  currentDir = path.dirname(currentDir);
13
44
  }
14
45
  return "npm";
15
46
  };
16
47
 
17
48
  //#endregion
18
- export { getPackageManager };
49
+ export { getPackageManager, getPackageManagerFromEnv };
19
50
  //# sourceMappingURL=get-package-manager.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-package-manager.mjs","names":[],"sources":["../../src/utils/get-package-manager.ts"],"sourcesContent":["import path from 'path'\nimport { checkIfFileExists } from '../create/utils'\n\nexport const getPackageManager = (dir: string): string => {\n let currentDir = dir\n\n while (currentDir !== path.dirname(currentDir)) {\n if (checkIfFileExists(currentDir, 'yarn.lock')) {\n return 'yarn'\n } else if (checkIfFileExists(currentDir, 'pnpm-lock.yaml')) {\n return 'pnpm'\n } else if (checkIfFileExists(currentDir, 'package-lock.json')) {\n return 'npm'\n } else if (checkIfFileExists(currentDir, 'bun.lockb') || checkIfFileExists(currentDir, 'bun.lock')) {\n return 'bun'\n }\n currentDir = path.dirname(currentDir)\n }\n\n return 'npm'\n}\n"],"mappings":";;;;AAGA,MAAa,qBAAqB,QAAwB;CACxD,IAAI,aAAa;AAEjB,QAAO,eAAe,KAAK,QAAQ,WAAW,EAAE;AAC9C,MAAI,kBAAkB,YAAY,YAAY,CAC5C,QAAO;WACE,kBAAkB,YAAY,iBAAiB,CACxD,QAAO;WACE,kBAAkB,YAAY,oBAAoB,CAC3D,QAAO;WACE,kBAAkB,YAAY,YAAY,IAAI,kBAAkB,YAAY,WAAW,CAChG,QAAO;AAET,eAAa,KAAK,QAAQ,WAAW;;AAGvC,QAAO"}
1
+ {"version":3,"file":"get-package-manager.mjs","names":[],"sources":["../../src/utils/get-package-manager.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { checkIfFileExists } from '../create/utils'\n\nexport const getPackageManagerFromEnv = (): string | null => {\n const userAgent = process.env.npm_config_user_agent\n if (!userAgent) {\n return null\n }\n\n const match = userAgent.match(/^(npm|pnpm|yarn|bun)\\//)\n if (match) {\n return match[1]\n }\n\n return null\n}\n\nconst readPackageManagerFromPackageJson = (dir: string): string | null => {\n const packageJsonPath = path.join(dir, 'package.json')\n if (!checkIfFileExists(dir, 'package.json')) {\n return null\n }\n\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))\n if (packageJson.packageManager) {\n const pm = packageJson.packageManager.split('@')[0]\n if (['npm', 'yarn', 'pnpm', 'bun'].includes(pm)) {\n return pm\n }\n }\n } catch {\n return null\n }\n\n return null\n}\n\nexport const getPackageManager = (dir: string): string => {\n const envPackageManager = getPackageManagerFromEnv()\n if (envPackageManager) {\n return envPackageManager\n }\n\n let currentDir = dir\n\n while (currentDir !== path.dirname(currentDir)) {\n if (checkIfFileExists(currentDir, 'yarn.lock')) {\n return 'yarn'\n } else if (checkIfFileExists(currentDir, 'pnpm-lock.yaml')) {\n return 'pnpm'\n } else if (checkIfFileExists(currentDir, 'package-lock.json')) {\n return 'npm'\n } else if (checkIfFileExists(currentDir, 'bun.lockb') || checkIfFileExists(currentDir, 'bun.lock')) {\n return 'bun'\n }\n\n const packageManagerFromJson = readPackageManagerFromPackageJson(currentDir)\n if (packageManagerFromJson) {\n return packageManagerFromJson\n }\n\n currentDir = path.dirname(currentDir)\n }\n\n return 'npm'\n}\n"],"mappings":";;;;;AAIA,MAAa,iCAAgD;CAC3D,MAAM,YAAY,QAAQ,IAAI;AAC9B,KAAI,CAAC,UACH,QAAO;CAGT,MAAM,QAAQ,UAAU,MAAM,yBAAyB;AACvD,KAAI,MACF,QAAO,MAAM;AAGf,QAAO;;AAGT,MAAM,qCAAqC,QAA+B;CACxE,MAAM,kBAAkB,KAAK,KAAK,KAAK,eAAe;AACtD,KAAI,CAAC,kBAAkB,KAAK,eAAe,CACzC,QAAO;AAGT,KAAI;EACF,MAAM,cAAc,KAAK,MAAM,GAAG,aAAa,iBAAiB,QAAQ,CAAC;AACzE,MAAI,YAAY,gBAAgB;GAC9B,MAAM,KAAK,YAAY,eAAe,MAAM,IAAI,CAAC;AACjD,OAAI;IAAC;IAAO;IAAQ;IAAQ;IAAM,CAAC,SAAS,GAAG,CAC7C,QAAO;;SAGL;AACN,SAAO;;AAGT,QAAO;;AAGT,MAAa,qBAAqB,QAAwB;CACxD,MAAM,oBAAoB,0BAA0B;AACpD,KAAI,kBACF,QAAO;CAGT,IAAI,aAAa;AAEjB,QAAO,eAAe,KAAK,QAAQ,WAAW,EAAE;AAC9C,MAAI,kBAAkB,YAAY,YAAY,CAC5C,QAAO;WACE,kBAAkB,YAAY,iBAAiB,CACxD,QAAO;WACE,kBAAkB,YAAY,oBAAoB,CAC3D,QAAO;WACE,kBAAkB,YAAY,YAAY,IAAI,kBAAkB,YAAY,WAAW,CAChG,QAAO;EAGT,MAAM,yBAAyB,kCAAkC,WAAW;AAC5E,MAAI,uBACF,QAAO;AAGT,eAAa,KAAK,QAAQ,WAAW;;AAGvC,QAAO"}
@@ -19,6 +19,7 @@ async function validatePythonEnvironment({ baseDir, hasPythonFiles, pythonVersio
19
19
  success: true,
20
20
  hasPythonFiles: false
21
21
  };
22
+ const installCmd = getInstallCommand(baseDir);
22
23
  try {
23
24
  await getPythonCommand(pythonVersion, baseDir);
24
25
  } catch {
@@ -32,7 +33,6 @@ async function validatePythonEnvironment({ baseDir, hasPythonFiles, pythonVersio
32
33
  }
33
34
  const venvPath = path.join(baseDir, "python_modules");
34
35
  if (!fs.existsSync(venvPath)) {
35
- const installCmd = getInstallCommand(baseDir);
36
36
  internalLogger.error("Python environment not configured");
37
37
  internalLogger.info("The python_modules directory was not found");
38
38
  internalLogger.info(`Run '${installCmd}' to set up your Python environment`);
@@ -43,7 +43,6 @@ async function validatePythonEnvironment({ baseDir, hasPythonFiles, pythonVersio
43
43
  }
44
44
  const libPath = path.join(venvPath, "lib");
45
45
  if (!fs.existsSync(libPath)) {
46
- const installCmd = getInstallCommand(baseDir);
47
46
  internalLogger.error("Python environment is incomplete");
48
47
  internalLogger.info("The python_modules directory exists but appears to be corrupted");
49
48
  internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
@@ -54,7 +53,6 @@ async function validatePythonEnvironment({ baseDir, hasPythonFiles, pythonVersio
54
53
  }
55
54
  try {
56
55
  if (fs.readdirSync(libPath).filter((item) => item.startsWith("python3")).length === 0) {
57
- const installCmd = getInstallCommand(baseDir);
58
56
  internalLogger.error("Python environment is incomplete");
59
57
  internalLogger.info("The python_modules/lib directory exists but contains no Python version directories");
60
58
  internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
@@ -64,7 +62,6 @@ async function validatePythonEnvironment({ baseDir, hasPythonFiles, pythonVersio
64
62
  };
65
63
  }
66
64
  } catch (error) {
67
- const installCmd = getInstallCommand(baseDir);
68
65
  internalLogger.error("Python environment is incomplete");
69
66
  internalLogger.info("The python_modules/lib directory cannot be read");
70
67
  internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
@@ -1 +1 @@
1
- {"version":3,"file":"validate-python-environment.mjs","names":["error: any"],"sources":["../../src/utils/validate-python-environment.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { getPackageManager } from './get-package-manager'\nimport { internalLogger } from './internal-logger'\nimport { getPythonCommand } from './python-version-utils'\n\nexport interface ValidationResult {\n success: boolean\n hasPythonFiles: boolean\n}\n\ninterface ValidateConfig {\n baseDir: string\n hasPythonFiles: boolean\n pythonVersion?: string\n}\n\nfunction getInstallCommand(baseDir: string): string {\n const pm = getPackageManager(baseDir)\n switch (pm) {\n case 'yarn':\n return 'yarn install'\n case 'pnpm':\n return 'pnpm install'\n case 'bun':\n return 'bun install'\n case 'npm':\n default:\n return 'npm install'\n }\n}\n\nexport async function validatePythonEnvironment({\n baseDir,\n hasPythonFiles,\n pythonVersion = '3.13',\n}: ValidateConfig): Promise<ValidationResult> {\n if (!hasPythonFiles) {\n return { success: true, hasPythonFiles: false }\n }\n\n try {\n await getPythonCommand(pythonVersion, baseDir)\n } catch {\n internalLogger.error('Python is not installed')\n internalLogger.info('Python files were detected in your project but Python 3 is not available')\n internalLogger.info('Please install Python 3.10 or higher: https://www.python.org/downloads/')\n return { success: false, hasPythonFiles: true }\n }\n\n const venvPath = path.join(baseDir, 'python_modules')\n if (!fs.existsSync(venvPath)) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment not configured')\n internalLogger.info('The python_modules directory was not found')\n internalLogger.info(`Run '${installCmd}' to set up your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n const libPath = path.join(venvPath, 'lib')\n if (!fs.existsSync(libPath)) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules directory exists but appears to be corrupted')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n try {\n const libContents = fs.readdirSync(libPath)\n const pythonDirs = libContents.filter((item) => item.startsWith('python3'))\n\n if (pythonDirs.length === 0) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules/lib directory exists but contains no Python version directories')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n } catch (error: any) {\n const installCmd = getInstallCommand(baseDir)\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules/lib directory cannot be read')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n return { success: true, hasPythonFiles: true }\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,kBAAkB,SAAyB;AAElD,SADW,kBAAkB,QAAQ,EACrC;EACE,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK;EACL,QACE,QAAO;;;AAIb,eAAsB,0BAA0B,EAC9C,SACA,gBACA,gBAAgB,UAC4B;AAC5C,KAAI,CAAC,eACH,QAAO;EAAE,SAAS;EAAM,gBAAgB;EAAO;AAGjD,KAAI;AACF,QAAM,iBAAiB,eAAe,QAAQ;SACxC;AACN,iBAAe,MAAM,0BAA0B;AAC/C,iBAAe,KAAK,2EAA2E;AAC/F,iBAAe,KAAK,0EAA0E;AAC9F,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;CAGjD,MAAM,WAAW,KAAK,KAAK,SAAS,iBAAiB;AACrD,KAAI,CAAC,GAAG,WAAW,SAAS,EAAE;EAC5B,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,iBAAe,MAAM,oCAAoC;AACzD,iBAAe,KAAK,6CAA6C;AACjE,iBAAe,KAAK,QAAQ,WAAW,qCAAqC;AAC5E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;CAGjD,MAAM,UAAU,KAAK,KAAK,UAAU,MAAM;AAC1C,KAAI,CAAC,GAAG,WAAW,QAAQ,EAAE;EAC3B,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,iBAAe,MAAM,mCAAmC;AACxD,iBAAe,KAAK,kEAAkE;AACtF,iBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;AAGjD,KAAI;AAIF,MAHoB,GAAG,YAAY,QAAQ,CACZ,QAAQ,SAAS,KAAK,WAAW,UAAU,CAAC,CAE5D,WAAW,GAAG;GAC3B,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,kBAAe,MAAM,mCAAmC;AACxD,kBAAe,KAAK,qFAAqF;AACzG,kBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,UAAO;IAAE,SAAS;IAAO,gBAAgB;IAAM;;UAE1CA,OAAY;EACnB,MAAM,aAAa,kBAAkB,QAAQ;AAC7C,iBAAe,MAAM,mCAAmC;AACxD,iBAAe,KAAK,kDAAkD;AACtE,iBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;AAGjD,QAAO;EAAE,SAAS;EAAM,gBAAgB;EAAM"}
1
+ {"version":3,"file":"validate-python-environment.mjs","names":["error: any"],"sources":["../../src/utils/validate-python-environment.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { getPackageManager } from './get-package-manager'\nimport { internalLogger } from './internal-logger'\nimport { getPythonCommand } from './python-version-utils'\n\nexport interface ValidationResult {\n success: boolean\n hasPythonFiles: boolean\n}\n\ninterface ValidateConfig {\n baseDir: string\n hasPythonFiles: boolean\n pythonVersion?: string\n}\n\nfunction getInstallCommand(baseDir: string): string {\n const pm = getPackageManager(baseDir)\n switch (pm) {\n case 'yarn':\n return 'yarn install'\n case 'pnpm':\n return 'pnpm install'\n case 'bun':\n return 'bun install'\n case 'npm':\n default:\n return 'npm install'\n }\n}\n\nexport async function validatePythonEnvironment({\n baseDir,\n hasPythonFiles,\n pythonVersion = '3.13',\n}: ValidateConfig): Promise<ValidationResult> {\n if (!hasPythonFiles) {\n return { success: true, hasPythonFiles: false }\n }\n\n const installCmd = getInstallCommand(baseDir)\n\n try {\n await getPythonCommand(pythonVersion, baseDir)\n } catch {\n internalLogger.error('Python is not installed')\n internalLogger.info('Python files were detected in your project but Python 3 is not available')\n internalLogger.info('Please install Python 3.10 or higher: https://www.python.org/downloads/')\n return { success: false, hasPythonFiles: true }\n }\n\n const venvPath = path.join(baseDir, 'python_modules')\n if (!fs.existsSync(venvPath)) {\n internalLogger.error('Python environment not configured')\n internalLogger.info('The python_modules directory was not found')\n internalLogger.info(`Run '${installCmd}' to set up your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n const libPath = path.join(venvPath, 'lib')\n if (!fs.existsSync(libPath)) {\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules directory exists but appears to be corrupted')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n try {\n const libContents = fs.readdirSync(libPath)\n const pythonDirs = libContents.filter((item) => item.startsWith('python3'))\n\n if (pythonDirs.length === 0) {\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules/lib directory exists but contains no Python version directories')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n } catch (error: any) {\n internalLogger.error('Python environment is incomplete')\n internalLogger.info('The python_modules/lib directory cannot be read')\n internalLogger.info(`Run '${installCmd}' to recreate your Python environment`)\n return { success: false, hasPythonFiles: true }\n }\n\n return { success: true, hasPythonFiles: true }\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,kBAAkB,SAAyB;AAElD,SADW,kBAAkB,QAAQ,EACrC;EACE,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,KAAK;EACL,QACE,QAAO;;;AAIb,eAAsB,0BAA0B,EAC9C,SACA,gBACA,gBAAgB,UAC4B;AAC5C,KAAI,CAAC,eACH,QAAO;EAAE,SAAS;EAAM,gBAAgB;EAAO;CAGjD,MAAM,aAAa,kBAAkB,QAAQ;AAE7C,KAAI;AACF,QAAM,iBAAiB,eAAe,QAAQ;SACxC;AACN,iBAAe,MAAM,0BAA0B;AAC/C,iBAAe,KAAK,2EAA2E;AAC/F,iBAAe,KAAK,0EAA0E;AAC9F,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;CAGjD,MAAM,WAAW,KAAK,KAAK,SAAS,iBAAiB;AACrD,KAAI,CAAC,GAAG,WAAW,SAAS,EAAE;AAC5B,iBAAe,MAAM,oCAAoC;AACzD,iBAAe,KAAK,6CAA6C;AACjE,iBAAe,KAAK,QAAQ,WAAW,qCAAqC;AAC5E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;CAGjD,MAAM,UAAU,KAAK,KAAK,UAAU,MAAM;AAC1C,KAAI,CAAC,GAAG,WAAW,QAAQ,EAAE;AAC3B,iBAAe,MAAM,mCAAmC;AACxD,iBAAe,KAAK,kEAAkE;AACtF,iBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;AAGjD,KAAI;AAIF,MAHoB,GAAG,YAAY,QAAQ,CACZ,QAAQ,SAAS,KAAK,WAAW,UAAU,CAAC,CAE5D,WAAW,GAAG;AAC3B,kBAAe,MAAM,mCAAmC;AACxD,kBAAe,KAAK,qFAAqF;AACzG,kBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,UAAO;IAAE,SAAS;IAAO,gBAAgB;IAAM;;UAE1CA,OAAY;AACnB,iBAAe,MAAM,mCAAmC;AACxD,iBAAe,KAAK,kDAAkD;AACtE,iBAAe,KAAK,QAAQ,WAAW,uCAAuC;AAC9E,SAAO;GAAE,SAAS;GAAO,gBAAgB;GAAM;;AAGjD,QAAO;EAAE,SAAS;EAAM,gBAAgB;EAAM"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "motia",
3
3
  "description": "Build production-grade backends with a single primitive. APIs, background jobs, Queues, Workflows, and AI agents - unified in one system with built-in State management, Streaming, and Observability.",
4
- "version": "0.15.5-beta.174-650639",
4
+ "version": "0.15.5-beta.174-096320",
5
5
  "license": "Elastic-2.0",
6
6
  "type": "module",
7
7
  "repository": {
@@ -46,13 +46,13 @@
46
46
  "table": "^6.9.0",
47
47
  "ts-node": "^10.9.2",
48
48
  "zod": "^4.1.12",
49
- "@motiadev/adapter-bullmq-events": "0.15.5-beta.174-650639",
50
- "@motiadev/adapter-redis-cron": "0.15.5-beta.174-650639",
51
- "@motiadev/stream-client-node": "0.15.5-beta.174-650639",
52
- "@motiadev/core": "0.15.5-beta.174-650639",
53
- "@motiadev/adapter-redis-streams": "0.15.5-beta.174-650639",
54
- "@motiadev/workbench": "0.15.5-beta.174-650639",
55
- "@motiadev/adapter-redis-state": "0.15.5-beta.174-650639"
49
+ "@motiadev/adapter-bullmq-events": "0.15.5-beta.174-096320",
50
+ "@motiadev/adapter-redis-cron": "0.15.5-beta.174-096320",
51
+ "@motiadev/adapter-redis-state": "0.15.5-beta.174-096320",
52
+ "@motiadev/core": "0.15.5-beta.174-096320",
53
+ "@motiadev/stream-client-node": "0.15.5-beta.174-096320",
54
+ "@motiadev/adapter-redis-streams": "0.15.5-beta.174-096320",
55
+ "@motiadev/workbench": "0.15.5-beta.174-096320"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@amplitude/analytics-types": "^2.9.2",