motia 0.5.11-beta.120-391598 → 0.5.11-beta.120-207545

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 (63) hide show
  1. package/dist/cjs/cloud/build/builders/python/index.d.ts +11 -3
  2. package/dist/cjs/cloud/build/builders/python/index.js +215 -79
  3. package/dist/cjs/cloud/build/builders/python/uv-packager.d.ts +13 -0
  4. package/dist/cjs/cloud/build/builders/python/uv-packager.js +77 -0
  5. package/dist/cjs/cloud/cli/deploy.js +8 -4
  6. package/dist/cjs/cloud/new-deployment/cloud-api/create-deployment.d.ts +3 -1
  7. package/dist/cjs/cloud/new-deployment/cloud-api/index.d.ts +3 -1
  8. package/dist/cjs/create/templates/python/steps/state_audit_cron_step.py.txt +1 -1
  9. package/dist/cjs/create/templates/typescript/steps/state-audit-cron.step.ts.txt +1 -1
  10. package/dist/cjs/cursor-rules/index.js +32 -3
  11. package/dist/cjs/install.js +5 -0
  12. package/dist/cjs/utils/ensure-uv.d.ts +1 -0
  13. package/dist/cjs/utils/ensure-uv.js +81 -0
  14. package/dist/esm/cloud/build/builders/python/index.d.ts +11 -3
  15. package/dist/esm/cloud/build/builders/python/index.js +215 -79
  16. package/dist/esm/cloud/build/builders/python/uv-packager.d.ts +13 -0
  17. package/dist/esm/cloud/build/builders/python/uv-packager.js +70 -0
  18. package/dist/esm/cloud/cli/deploy.js +8 -4
  19. package/dist/esm/cloud/new-deployment/cloud-api/create-deployment.d.ts +3 -1
  20. package/dist/esm/cloud/new-deployment/cloud-api/index.d.ts +3 -1
  21. package/dist/esm/create/templates/python/steps/state_audit_cron_step.py.txt +1 -1
  22. package/dist/esm/create/templates/typescript/steps/state-audit-cron.step.ts.txt +1 -1
  23. package/dist/esm/cursor-rules/index.js +32 -3
  24. package/dist/esm/install.js +5 -0
  25. package/dist/esm/utils/ensure-uv.d.ts +1 -0
  26. package/dist/esm/utils/ensure-uv.js +77 -0
  27. package/dist/types/cloud/build/builders/python/index.d.ts +11 -3
  28. package/dist/types/cloud/build/builders/python/uv-packager.d.ts +13 -0
  29. package/dist/types/cloud/new-deployment/cloud-api/create-deployment.d.ts +3 -1
  30. package/dist/types/cloud/new-deployment/cloud-api/index.d.ts +3 -1
  31. package/dist/types/utils/ensure-uv.d.ts +1 -0
  32. package/package.json +4 -4
  33. package/dist/cjs/cloud/build/builders/python/add-package-to-archive.d.ts +0 -2
  34. package/dist/cjs/cloud/build/builders/python/add-package-to-archive.js +0 -56
  35. package/dist/cjs/cloud/build/builders/python/python-builder.py +0 -226
  36. package/dist/dot-files/.cursor/rules/ai-agent-patterns.mdc +0 -725
  37. package/dist/dot-files/.cursor/rules/api-design-patterns.mdc +0 -740
  38. package/dist/dot-files/.cursor/rules/api-steps.mdc +0 -230
  39. package/dist/dot-files/.cursor/rules/architecture.mdc +0 -189
  40. package/dist/dot-files/.cursor/rules/authentication-patterns.mdc +0 -620
  41. package/dist/dot-files/.cursor/rules/background-job-patterns.mdc +0 -628
  42. package/dist/dot-files/.cursor/rules/complete-application-patterns.mdc +0 -433
  43. package/dist/dot-files/.cursor/rules/complete-backend-generator.mdc +0 -415
  44. package/dist/dot-files/.cursor/rules/cron-steps.mdc +0 -257
  45. package/dist/dot-files/.cursor/rules/event-steps.mdc +0 -504
  46. package/dist/dot-files/.cursor/rules/instructions.mdc +0 -15
  47. package/dist/dot-files/.cursor/rules/multi-language-workflows.mdc +0 -1059
  48. package/dist/dot-files/.cursor/rules/noop-steps.mdc +0 -57
  49. package/dist/dot-files/.cursor/rules/production-deployment.mdc +0 -668
  50. package/dist/dot-files/.cursor/rules/realtime-streaming.mdc +0 -656
  51. package/dist/dot-files/.cursor/rules/state-management.mdc +0 -371
  52. package/dist/dot-files/.cursor/rules/steps.mdc +0 -373
  53. package/dist/dot-files/.cursor/rules/testing.mdc +0 -329
  54. package/dist/dot-files/.cursor/rules/typescript.mdc +0 -409
  55. package/dist/dot-files/.cursor/rules/ui-steps.mdc +0 -90
  56. package/dist/dot-files/.cursor/rules/workflow-patterns.mdc +0 -938
  57. package/dist/dot-files/AGENTS.md +0 -397
  58. package/dist/dot-files/CLAUDE.md +0 -1032
  59. package/dist/dot-files/README.md +0 -58
  60. package/dist/esm/cloud/build/builders/python/add-package-to-archive.d.ts +0 -2
  61. package/dist/esm/cloud/build/builders/python/add-package-to-archive.js +0 -49
  62. package/dist/esm/cloud/build/builders/python/python-builder.py +0 -226
  63. package/dist/types/cloud/build/builders/python/add-package-to-archive.d.ts +0 -2
@@ -4,9 +4,17 @@ import { BuildListener } from '../../../new-deployment/listeners/listener.types'
4
4
  export declare class PythonBuilder implements StepBuilder {
5
5
  private readonly builder;
6
6
  private readonly listener;
7
+ private uvPackager;
7
8
  constructor(builder: Builder, listener: BuildListener);
8
- private buildStep;
9
- build(step: Step): Promise<void>;
10
9
  buildApiSteps(steps: Step<ApiRouteConfig>[]): Promise<RouterBuildResult>;
11
- private getPythonBuilderData;
10
+ build(step: Step): Promise<void>;
11
+ private addStepToArchive;
12
+ private addPackagesToArchive;
13
+ private shouldIgnoreFile;
14
+ private normalizeStepPath;
15
+ private createRouterTemplate;
16
+ private findInternalFiles;
17
+ private resolveModulePaths;
18
+ private getModuleName;
19
+ private waitForDirectoryReady;
12
20
  }
@@ -4,116 +4,252 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PythonBuilder = void 0;
7
- const child_process_1 = require("child_process");
8
7
  const fs_1 = __importDefault(require("fs"));
9
8
  const path_1 = __importDefault(require("path"));
10
- const activate_python_env_1 = require("../../../../utils/activate-python-env");
11
9
  const archiver_1 = require("../archiver");
12
10
  const include_static_files_1 = require("../include-static-files");
13
- const add_package_to_archive_1 = require("./add-package-to-archive");
14
11
  const constants_1 = require("../../../new-deployment/constants");
12
+ const uv_packager_1 = require("./uv-packager");
13
+ const activate_python_env_1 = require("../../../../utils/activate-python-env");
15
14
  class PythonBuilder {
16
15
  constructor(builder, listener) {
17
16
  this.builder = builder;
18
17
  this.listener = listener;
19
18
  (0, activate_python_env_1.activatePythonVenv)({ baseDir: this.builder.projectDir });
19
+ this.uvPackager = new uv_packager_1.UvPackager(this.builder.projectDir);
20
20
  }
21
- async buildStep(step, archive) {
22
- const entrypointPath = step.filePath.replace(this.builder.projectDir, '');
23
- const normalizedEntrypointPath = entrypointPath.replace(/[.]step.py$/, '_step.py');
24
- const sitePackagesDir = `${process.env.PYTHON_SITE_PACKAGES}-lambda`;
25
- // Get Python builder response
26
- const { packages } = await this.getPythonBuilderData(step);
27
- // Add main file to archive
28
- if (!fs_1.default.existsSync(step.filePath)) {
29
- throw new Error(`Source file not found: ${step.filePath}`);
21
+ async buildApiSteps(steps) {
22
+ const zipName = 'router-python.zip';
23
+ const archive = new archiver_1.Archiver(path_1.default.join(constants_1.distDir, zipName));
24
+ const tempSitePackages = path_1.default.join(constants_1.distDir, `temp-python-packages-${Date.now()}`);
25
+ try {
26
+ await this.uvPackager.packageDependencies(tempSitePackages);
27
+ // Wait for directory to be ready with proper access checks
28
+ await this.waitForDirectoryReady(tempSitePackages);
29
+ await this.addPackagesToArchive(archive, tempSitePackages);
30
+ for (const step of steps) {
31
+ await this.addStepToArchive(step, archive);
32
+ }
33
+ const routerTemplate = this.createRouterTemplate(steps);
34
+ archive.append(routerTemplate, 'router.py');
35
+ (0, include_static_files_1.includeStaticFiles)(steps, this.builder, archive);
36
+ const size = await archive.finalize();
37
+ return { size, path: zipName };
38
+ }
39
+ catch (error) {
40
+ throw new Error(`Failed to build Python API router: ${error}`);
41
+ }
42
+ finally {
43
+ if (fs_1.default.existsSync(tempSitePackages)) {
44
+ fs_1.default.rmSync(tempSitePackages, { recursive: true, force: true });
45
+ }
30
46
  }
31
- archive.append(fs_1.default.createReadStream(step.filePath), path_1.default.relative(this.builder.projectDir, normalizedEntrypointPath));
32
- await Promise.all(packages.map(async (packageName) => (0, add_package_to_archive_1.addPackageToArchive)(archive, sitePackagesDir, packageName)));
33
- return normalizedEntrypointPath;
34
47
  }
35
48
  async build(step) {
36
49
  const entrypointPath = step.filePath.replace(this.builder.projectDir, '');
37
50
  const bundlePath = path_1.default.join('python', entrypointPath.replace(/(.*)\.py$/, '$1.zip'));
38
- const normalizedEntrypointPath = entrypointPath.replace(/[.]step.py$/, '_step.py');
39
51
  const outfile = path_1.default.join(constants_1.distDir, bundlePath);
52
+ this.builder.registerStep({ entrypointPath, bundlePath, step, type: 'python' });
53
+ this.listener.onBuildStart(step);
40
54
  try {
41
- // Create output directory
42
55
  fs_1.default.mkdirSync(path_1.default.dirname(outfile), { recursive: true });
43
- this.listener.onBuildStart(step);
44
- // Get Python builder response
45
- const { packages } = await this.getPythonBuilderData(step);
46
- const stepArchiver = new archiver_1.Archiver(outfile);
47
- const stepPath = await this.buildStep(step, stepArchiver);
48
- // Add main file to archive
49
- if (!fs_1.default.existsSync(step.filePath)) {
50
- throw new Error(`Source file not found: ${step.filePath}`);
56
+ const archive = new archiver_1.Archiver(outfile);
57
+ const tempSitePackages = path_1.default.join(constants_1.distDir, `temp-python-packages-${Date.now()}`);
58
+ try {
59
+ await this.uvPackager.packageDependencies(tempSitePackages);
60
+ await this.waitForDirectoryReady(tempSitePackages);
61
+ await this.addStepToArchive(step, archive);
62
+ await this.addPackagesToArchive(archive, tempSitePackages);
63
+ (0, include_static_files_1.includeStaticFiles)([step], this.builder, archive);
64
+ const size = await archive.finalize();
65
+ this.listener.onBuildEnd(step, size);
51
66
  }
52
- stepArchiver.append(fs_1.default.createReadStream(step.filePath), path_1.default.relative(this.builder.projectDir, normalizedEntrypointPath));
53
- // Add all imported files to archive
54
- this.listener.onBuildProgress(step, 'Adding imported files to archive...');
55
- const sitePackagesDir = `${process.env.PYTHON_SITE_PACKAGES}-lambda`;
56
- (0, include_static_files_1.includeStaticFiles)([step], this.builder, stepArchiver);
57
- if (packages.length > 0) {
58
- await Promise.all(packages.map(async (packageName) => (0, add_package_to_archive_1.addPackageToArchive)(stepArchiver, sitePackagesDir, packageName)));
59
- this.listener.onBuildProgress(step, `Added ${packages.length} packages to archive`);
67
+ finally {
68
+ if (fs_1.default.existsSync(tempSitePackages)) {
69
+ fs_1.default.rmSync(tempSitePackages, { recursive: true, force: true });
70
+ }
60
71
  }
61
- // Finalize the archive and wait for completion
62
- const size = await stepArchiver.finalize();
63
- this.builder.registerStep({ entrypointPath: stepPath, bundlePath, step, type: 'python' });
64
- this.listener.onBuildEnd(step, size);
65
72
  }
66
73
  catch (err) {
67
74
  this.listener.onBuildError(step, err);
68
75
  throw err;
69
76
  }
70
77
  }
71
- async buildApiSteps(steps) {
72
- const getStepPath = (step) => {
73
- const normalizedEntrypointPath = step.filePath.replace(/[.]step.py$/, '_step.py');
74
- return normalizedEntrypointPath
75
- .replace(`${this.builder.projectDir}/`, '')
76
- .replace(/(.*)\.py$/, '$1')
77
- .replace(/\\/g, '.')
78
- .replace(/\//g, '.');
79
- };
80
- const zipName = 'router-python.zip';
81
- const archive = new archiver_1.Archiver(path_1.default.join(constants_1.distDir, zipName));
82
- const dependencies = ['uvicorn', 'pydantic', 'pydantic_core', 'uvloop', 'starlette', 'typing_inspection'];
83
- const lambdaSitePackages = `${process.env.PYTHON_SITE_PACKAGES}-lambda`;
84
- await Promise.all(dependencies.map(async (packageName) => (0, add_package_to_archive_1.addPackageToArchive)(archive, lambdaSitePackages, packageName)));
85
- for (const step of steps) {
86
- await this.buildStep(step, archive);
78
+ async addStepToArchive(step, archive) {
79
+ const normalizedPath = this.normalizeStepPath(step, false);
80
+ archive.append(fs_1.default.createReadStream(step.filePath), normalizedPath);
81
+ const internalFiles = await this.findInternalFiles(step.filePath);
82
+ for (const file of internalFiles) {
83
+ const fullPath = path_1.default.join(this.builder.projectDir, file);
84
+ if (fs_1.default.existsSync(fullPath) && fullPath !== step.filePath) {
85
+ const archivePath = file.replace(/\.step\.py$/, '_step.py');
86
+ archive.append(fs_1.default.createReadStream(fullPath), archivePath);
87
+ }
88
+ }
89
+ }
90
+ async addPackagesToArchive(archive, sitePackagesDir) {
91
+ if (!fs_1.default.existsSync(sitePackagesDir)) {
92
+ console.warn(`Warning: Site packages directory not found: ${sitePackagesDir}`);
93
+ return;
94
+ }
95
+ try {
96
+ fs_1.default.accessSync(sitePackagesDir, fs_1.default.constants.R_OK);
87
97
  }
88
- const file = fs_1.default
98
+ catch (error) {
99
+ console.warn(`Warning: Cannot access site packages directory: ${sitePackagesDir}`);
100
+ return;
101
+ }
102
+ const addDirectory = (dirPath, basePath = sitePackagesDir) => {
103
+ try {
104
+ const items = fs_1.default.readdirSync(dirPath);
105
+ for (const item of items) {
106
+ const fullPath = path_1.default.join(dirPath, item);
107
+ const relativePath = path_1.default.relative(basePath, fullPath);
108
+ if (this.shouldIgnoreFile(relativePath)) {
109
+ continue;
110
+ }
111
+ try {
112
+ const stat = fs_1.default.statSync(fullPath);
113
+ if (stat.isDirectory()) {
114
+ addDirectory(fullPath, basePath);
115
+ }
116
+ else {
117
+ archive.append(fs_1.default.createReadStream(fullPath), relativePath);
118
+ }
119
+ }
120
+ catch (error) {
121
+ console.warn(`Warning: Could not process file ${fullPath}: ${error}`);
122
+ }
123
+ }
124
+ }
125
+ catch (error) {
126
+ console.warn(`Warning: Could not read directory ${dirPath}: ${error}`);
127
+ }
128
+ };
129
+ addDirectory(sitePackagesDir);
130
+ }
131
+ shouldIgnoreFile(filePath) {
132
+ const ignorePatterns = [
133
+ /\.pyc$/,
134
+ /\.pyo$/,
135
+ /\.egg$/,
136
+ /\.egg-info$/,
137
+ /__pycache__/,
138
+ /\.dist-info$/,
139
+ /^tests?\//,
140
+ /^docs?\//,
141
+ /^examples?\//,
142
+ /\.pytest_cache/,
143
+ ];
144
+ return ignorePatterns.some((pattern) => pattern.test(filePath));
145
+ }
146
+ normalizeStepPath(step, normalizePythonModulePath) {
147
+ let normalizedStepPath = step.filePath
148
+ .replace(/[.]step.py$/, '_step.py') // Replace .step.py with _step.py
149
+ .replace(`${this.builder.projectDir}/`, ''); // Remove the project directory from the path
150
+ const pathParts = normalizedStepPath.split(path_1.default.sep).map((part) => part
151
+ .replace(/^[0-9]+/g, '') // Remove numeric prefixes
152
+ .replace(/[^a-zA-Z0-9._]/g, '_') // Replace any non-alphanumeric characters (except dots) with underscores
153
+ .replace(/^_/, '')); // Remove leading underscore
154
+ normalizedStepPath = normalizePythonModulePath
155
+ ? pathParts.join('.') // Convert path delimiter to dot (python module separator)
156
+ : '/' + pathParts.join(path_1.default.sep);
157
+ return normalizedStepPath;
158
+ }
159
+ createRouterTemplate(steps) {
160
+ const imports = steps
161
+ .map((step, index) => {
162
+ const moduleName = this.getModuleName(step);
163
+ return `from ${moduleName} import handler as route${index}_handler, config as route${index}_config`;
164
+ })
165
+ .join('\n');
166
+ const routerPaths = steps
167
+ .map((step, index) => {
168
+ const method = step.config.method.toUpperCase();
169
+ const path = step.config.path;
170
+ return ` '${method} ${path}': RouterPath('${step.config.name}', '${step.config.method.toLowerCase()}', route${index}_handler, route${index}_config)`;
171
+ })
172
+ .join(',\n');
173
+ return fs_1.default
89
174
  .readFileSync(path_1.default.join(__dirname, 'router_template.py'), 'utf-8')
90
- .replace('# {{imports}}', steps
91
- .map((step, index) => `from ${getStepPath(step)} import handler as route${index}_handler, config as route${index}_config`)
92
- .join('\n'))
93
- .replace('# {{router paths}}', steps
94
- .map((step, index) => `'${step.config.method} ${step.config.path}': RouterPath('${step.config.name}', '${step.config.method.toLowerCase()}', route${index}_handler, route${index}_config)`)
95
- .join(',\n '));
96
- archive.append(file, 'router.py');
97
- (0, include_static_files_1.includeStaticFiles)(steps, this.builder, archive);
98
- // Finalize the archive and wait for completion
99
- const size = await archive.finalize();
100
- return { size, path: zipName };
175
+ .replace('# {{imports}}', imports)
176
+ .replace('# {{router paths}}', routerPaths);
101
177
  }
102
- async getPythonBuilderData(step) {
103
- return new Promise((resolve, reject) => {
104
- const child = (0, child_process_1.spawn)('python', [path_1.default.join(__dirname, 'python-builder.py'), step.filePath], {
105
- cwd: this.builder.projectDir,
106
- stdio: [undefined, undefined, 'pipe', 'ipc'],
107
- });
108
- const err = [];
109
- child.on('stderr', (data) => err.push(data.toString()));
110
- child.on('message', resolve);
111
- child.on('close', (code) => {
112
- if (code !== 0) {
113
- reject(new Error(err.join('')));
178
+ async findInternalFiles(entryFile) {
179
+ const files = [];
180
+ const visited = new Set();
181
+ const analyzeFile = (filePath) => {
182
+ if (visited.has(filePath) || !fs_1.default.existsSync(filePath)) {
183
+ return;
184
+ }
185
+ visited.add(filePath);
186
+ files.push(path_1.default.relative(this.builder.projectDir, filePath));
187
+ try {
188
+ const content = fs_1.default.readFileSync(filePath, 'utf-8');
189
+ const importRegex = /^(?:from\s+([a-zA-Z_][a-zA-Z0-9_.]*)\s+import|import\s+([a-zA-Z_][a-zA-Z0-9_.]*))/gm;
190
+ let match;
191
+ while ((match = importRegex.exec(content)) !== null) {
192
+ const moduleName = match[1] || match[2]; // from X import Y ou import X
193
+ this.resolveModulePaths(moduleName, path_1.default.dirname(filePath)).forEach((possiblePath) => {
194
+ if (fs_1.default.existsSync(possiblePath)) {
195
+ analyzeFile(possiblePath);
196
+ }
197
+ });
114
198
  }
115
- });
116
- });
199
+ }
200
+ catch (error) {
201
+ console.warn(`Could not analyze file: ${filePath}`);
202
+ }
203
+ };
204
+ analyzeFile(entryFile);
205
+ return files;
206
+ }
207
+ resolveModulePaths(moduleName, currentDir) {
208
+ const parts = moduleName.split('.');
209
+ const baseName = parts[0];
210
+ const subPath = parts.length > 1 ? path_1.default.join(...parts) : baseName;
211
+ return [
212
+ path_1.default.join(currentDir, `${baseName}.py`),
213
+ path_1.default.join(currentDir, baseName, '__init__.py'),
214
+ path_1.default.join(currentDir, `${subPath}.py`),
215
+ path_1.default.join(this.builder.projectDir, `${baseName}.py`),
216
+ path_1.default.join(this.builder.projectDir, baseName, '__init__.py'),
217
+ path_1.default.join(this.builder.projectDir, `${subPath}.py`),
218
+ path_1.default.join(this.builder.projectDir, subPath + '.py'),
219
+ path_1.default.join(this.builder.projectDir, subPath, '__init__.py'),
220
+ ];
221
+ }
222
+ getModuleName(step) {
223
+ return this.normalizeStepPath(step, true).replace(/\.py$/, '').replace(/\//g, '.');
224
+ }
225
+ async waitForDirectoryReady(dirPath, maxRetries = 10, initialDelayMs = 10) {
226
+ let lastError = null;
227
+ for (let i = 0; i < maxRetries; i++) {
228
+ try {
229
+ const exists = await fs_1.default.promises
230
+ .access(dirPath, fs_1.default.constants.F_OK)
231
+ .then(() => true)
232
+ .catch(() => false);
233
+ if (!exists) {
234
+ // Directory doesn't exist yet, wait
235
+ lastError = new Error(`Directory ${dirPath} does not exist yet`);
236
+ }
237
+ else {
238
+ await fs_1.default.promises.access(dirPath, fs_1.default.constants.R_OK);
239
+ return;
240
+ }
241
+ }
242
+ catch (error) {
243
+ lastError = error;
244
+ }
245
+ if (i === maxRetries - 1) {
246
+ throw new Error(`Directory ${dirPath} is not accessible after ${maxRetries} attempts. ` +
247
+ `Last error: ${lastError?.message || 'Unknown error'}`);
248
+ }
249
+ // Exponential backoff: 10ms, 20ms, 40ms, 80ms, etc.
250
+ const delay = initialDelayMs * Math.pow(2, i);
251
+ await new Promise((resolve) => setTimeout(resolve, Math.min(delay, 1000))); // Cap at 1 second
252
+ }
117
253
  }
118
254
  }
119
255
  exports.PythonBuilder = PythonBuilder;
@@ -0,0 +1,13 @@
1
+ export interface UvPackageConfig {
2
+ pythonVersion?: string;
3
+ platform?: string;
4
+ onlyBinary?: boolean;
5
+ }
6
+ export declare const defaultUvConfig: UvPackageConfig;
7
+ export declare class UvPackager {
8
+ private readonly projectDir;
9
+ private readonly config;
10
+ constructor(projectDir: string, config?: UvPackageConfig);
11
+ private runCommand;
12
+ packageDependencies(targetDir: string): Promise<void>;
13
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.UvPackager = exports.defaultUvConfig = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ exports.defaultUvConfig = {
11
+ pythonVersion: process.env.MOTIA_PYTHON_VERSION || '3.13',
12
+ platform: process.env.MOTIA_PLATFORM || 'x86_64-manylinux2014',
13
+ onlyBinary: process.env.MOTIA_ONLY_BINARY !== 'false',
14
+ };
15
+ class UvPackager {
16
+ constructor(projectDir, config = exports.defaultUvConfig) {
17
+ this.projectDir = projectDir;
18
+ this.config = config;
19
+ }
20
+ async runCommand(command, args, options) {
21
+ return new Promise((resolve, reject) => {
22
+ const child = (0, child_process_1.spawn)(command, args, {
23
+ cwd: options?.cwd,
24
+ stdio: ['pipe', 'pipe', 'pipe'],
25
+ });
26
+ let stdout = '';
27
+ let stderr = '';
28
+ child.stdout?.on('data', (data) => {
29
+ stdout += data.toString();
30
+ if (options?.showOutput) {
31
+ process.stdout.write(data);
32
+ }
33
+ });
34
+ child.stderr?.on('data', (data) => {
35
+ stderr += data.toString();
36
+ });
37
+ child.on('close', (code) => {
38
+ if (code === 0) {
39
+ resolve(stdout);
40
+ }
41
+ else {
42
+ const errorPrefix = `Command '${command}'`;
43
+ reject(new Error(`${errorPrefix} failed: ${stderr || stdout}`));
44
+ }
45
+ });
46
+ child.on('error', (error) => {
47
+ reject(new Error(`Failed to spawn ${command}: ${error.message}`));
48
+ });
49
+ });
50
+ }
51
+ async packageDependencies(targetDir) {
52
+ if (!fs_1.default.existsSync(targetDir)) {
53
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
54
+ }
55
+ const requirementsFile = path_1.default.join(this.projectDir, 'requirements.txt');
56
+ if (!fs_1.default.existsSync(requirementsFile)) {
57
+ return;
58
+ }
59
+ const args = [
60
+ 'pip',
61
+ 'install',
62
+ '--target',
63
+ targetDir,
64
+ '--requirement',
65
+ requirementsFile,
66
+ '--python-version',
67
+ this.config.pythonVersion || '3.13',
68
+ '--python-platform',
69
+ this.config.platform || 'x86_64-manylinux2014',
70
+ ];
71
+ if (this.config.onlyBinary) {
72
+ args.push('--only-binary=:all:');
73
+ }
74
+ await this.runCommand('uv', args, { cwd: this.projectDir });
75
+ }
76
+ }
77
+ exports.UvPackager = UvPackager;
@@ -13,11 +13,13 @@ cli_1.cloudCli
13
13
  .command('deploy')
14
14
  .description('Deploy a new version to Motia Cloud')
15
15
  .requiredOption('-k, --api-key <key>', 'The API key for authentication', process.env.MOTIA_API_KEY)
16
- .requiredOption('-v, --version-name <version>', 'The version to deploy')
17
16
  .option('-p, --project-id <id>', 'Project ID (Deprecated)')
17
+ .option('-n, --project-name <name>', 'Project name (used when creating a new project)')
18
18
  .option('-s, --environment-id <id>', 'Environment ID', process.env.MOTIA_ENVIRONMENT_ID)
19
+ .option('--environment-name <name>', 'Environment name')
19
20
  .option('-e, --env-file <path>', 'Path to environment file')
20
- .option('-n, --project-name <name>', 'Project name (used when creating a new project)', '')
21
+ .requiredOption('-v, --version-name <version>', 'The version to deploy')
22
+ .option('-d, --version-description <description>', 'The description of the version')
21
23
  .action((0, config_utils_1.handler)(async (arg, context) => {
22
24
  const listener = new cli_listener_1.CliListener(context);
23
25
  const builder = await (0, build_1.build)(listener);
@@ -30,9 +32,11 @@ cli_1.cloudCli
30
32
  const deployment = await cloud_api_1.cloudApi
31
33
  .createDeployment({
32
34
  apiKey: arg.apiKey,
33
- versionName: arg.versionName,
34
- environmentId: arg.environmentId,
35
35
  projectName: arg.projectName,
36
+ environmentId: arg.environmentId,
37
+ environmentName: arg.environmentName,
38
+ versionName: arg.versionName,
39
+ versionDescription: arg.versionDescription,
36
40
  })
37
41
  .catch((error) => {
38
42
  context.log('creating-deployment', (message) => message.tag('failed').append('Failed to create deployment'));
@@ -1,8 +1,10 @@
1
1
  type CreateDeploymentRequest = {
2
2
  apiKey: string;
3
+ projectName?: string;
3
4
  environmentId?: string;
5
+ environmentName?: string;
4
6
  versionName: string;
5
- projectName?: string;
7
+ versionDescription?: string;
6
8
  };
7
9
  type CreateDeploymentResult = {
8
10
  deploymentId: string;
@@ -11,9 +11,11 @@ export declare const cloudApi: {
11
11
  }>;
12
12
  createDeployment: (request: {
13
13
  apiKey: string;
14
+ projectName?: string;
14
15
  environmentId?: string;
16
+ environmentName?: string;
15
17
  versionName: string;
16
- projectName?: string;
18
+ versionDescription?: string;
17
19
  }) => Promise<{
18
20
  deploymentId: string;
19
21
  deploymentToken: string;
@@ -2,7 +2,7 @@ from datetime import datetime, timezone
2
2
 
3
3
  config = {
4
4
  "type": "cron",
5
- "cron": "*/5 * * * *", # run every 5 minutes
5
+ "cron": "0 0 * * 1", # run once every Monday at midnight
6
6
  "name": "StateAuditJob",
7
7
  "description": "Checks the state for orders that are not complete and have a ship date in the past",
8
8
  "emits": ["notification"],
@@ -2,7 +2,7 @@ import { CronConfig, Handlers } from 'motia'
2
2
 
3
3
  export const config: CronConfig = {
4
4
  type: 'cron',
5
- cron: '*/5 * * * *', // run every 5 minutes
5
+ cron: '0 0 * * 1', // run once every Monday at midnight
6
6
  name: 'StateAuditJob',
7
7
  description: 'Checks the state for orders that are not complete and have a ship date in the past',
8
8
  emits: ['notification'],
@@ -9,7 +9,9 @@ const path_1 = __importDefault(require("path"));
9
9
  const colors_1 = __importDefault(require("colors"));
10
10
  const AI_GUIDES_VERSION = '1.0.0';
11
11
  const CURSOR_RULES_SOURCE = path_1.default.join(__dirname, '../../dot-files/.cursor/rules');
12
+ const CLAUDE_SOURCE = path_1.default.join(__dirname, '../../dot-files/.claude');
12
13
  const TARGET_DIR = '.cursor/rules';
14
+ const CLAUDE_TARGET_DIR = '.claude';
13
15
  async function handleAIGuides(options) {
14
16
  if (options.version) {
15
17
  console.log(colors_1.default.blue(`Motia AI Development Guides v${AI_GUIDES_VERSION}`));
@@ -50,11 +52,11 @@ async function pullAIGuides(force) {
50
52
  }
51
53
  // First, copy the essential AI development guides
52
54
  console.log(colors_1.default.blue('🤖 Installing AI Development Guides...'));
53
- let claudePath = path_1.default.join(__dirname, '../../dot-files/CLAUDE.md');
55
+ let claudePath = path_1.default.join(__dirname, '../../dot-files/.claude/CLAUDE.md');
54
56
  let agentsPath = path_1.default.join(__dirname, '../../dot-files/AGENTS.md');
55
57
  // Try node_modules paths if local paths don't exist
56
58
  if (!fs_1.default.existsSync(claudePath)) {
57
- claudePath = path_1.default.join('node_modules', '@motiadev/snap', 'dist', 'dot-files', 'CLAUDE.md');
59
+ claudePath = path_1.default.join('node_modules', '@motiadev/snap', 'dist', 'dot-files', '.claude', 'CLAUDE.md');
58
60
  }
59
61
  if (!fs_1.default.existsSync(agentsPath)) {
60
62
  agentsPath = path_1.default.join('node_modules', '@motiadev/snap', 'dist', 'dot-files', 'AGENTS.md');
@@ -89,18 +91,38 @@ async function pullAIGuides(force) {
89
91
  }
90
92
  }
91
93
  await copyDirectory(sourcePath, TARGET_DIR);
94
+ // Copy Claude IDE configurations
92
95
  console.log('');
93
- console.log(colors_1.default.green('🎉 AI Development Guides & Cursor Rules installed successfully!'));
96
+ console.log(colors_1.default.blue('🧠 Installing Claude IDE Configurations...'));
97
+ if (!fs_1.default.existsSync(CLAUDE_TARGET_DIR) || force) {
98
+ if (fs_1.default.existsSync(CLAUDE_TARGET_DIR) && force) {
99
+ fs_1.default.rmSync(CLAUDE_TARGET_DIR, { recursive: true, force: true });
100
+ }
101
+ if (fs_1.default.existsSync(CLAUDE_SOURCE)) {
102
+ await copyDirectory(CLAUDE_SOURCE, CLAUDE_TARGET_DIR);
103
+ console.log(colors_1.default.green('✅ Claude IDE configurations installed'));
104
+ }
105
+ else {
106
+ console.log(colors_1.default.yellow('⚠️ Claude configurations not found - this is optional'));
107
+ }
108
+ }
109
+ else {
110
+ console.log(colors_1.default.yellow('⚠️ Claude configurations already exist. Use --force to overwrite.'));
111
+ }
112
+ console.log('');
113
+ console.log(colors_1.default.green('🎉 AI Development Guides, Cursor Rules & Claude Configs installed successfully!'));
94
114
  console.log('');
95
115
  console.log(colors_1.default.blue('📋 What you got:'));
96
116
  console.log(colors_1.default.gray(' • AGENTS.md - Universal guide for ANY AI tool (project root)'));
97
117
  console.log(colors_1.default.gray(' • CLAUDE.md - Specific guide for Claude AI assistant (project root)'));
98
118
  console.log(colors_1.default.gray(` • Cursor Rules - IDE-specific patterns (${TARGET_DIR})`));
119
+ console.log(colors_1.default.gray(` • Claude Configs - Claude IDE configurations (${CLAUDE_TARGET_DIR})`));
99
120
  console.log('');
100
121
  console.log(colors_1.default.blue('📁 File locations:'));
101
122
  console.log(colors_1.default.gray(` ./AGENTS.md`));
102
123
  console.log(colors_1.default.gray(` ./CLAUDE.md`));
103
124
  console.log(colors_1.default.gray(` ${path_1.default.resolve(TARGET_DIR)}/`));
125
+ console.log(colors_1.default.gray(` ${path_1.default.resolve(CLAUDE_TARGET_DIR)}/`));
104
126
  console.log('');
105
127
  console.log(colors_1.default.blue('🚀 Next steps:'));
106
128
  console.log(colors_1.default.gray(' 1. Open AGENTS.md to understand Motia development patterns'));
@@ -214,6 +236,13 @@ async function removeAIGuides() {
214
236
  console.log(colors_1.default.yellow('🗑️ Removed .cursor/rules/'));
215
237
  removed = true;
216
238
  }
239
+ // Remove Claude configurations directory
240
+ if (fs_1.default.existsSync(CLAUDE_TARGET_DIR)) {
241
+ console.log(colors_1.default.yellow('🗑️ Removing Claude configurations...'));
242
+ fs_1.default.rmSync(CLAUDE_TARGET_DIR, { recursive: true, force: true });
243
+ console.log(colors_1.default.yellow('🗑️ Removed .claude/'));
244
+ removed = true;
245
+ }
217
246
  if (removed) {
218
247
  console.log(colors_1.default.green('✅ AI development guides and cursor rules removed successfully!'));
219
248
  }
@@ -11,6 +11,7 @@ const activate_python_env_1 = require("./utils/activate-python-env");
11
11
  const install_lambda_python_packages_1 = require("./utils/install-lambda-python-packages");
12
12
  const generate_locked_data_1 = require("./generate-locked-data");
13
13
  const python_version_utils_1 = require("./utils/python-version-utils");
14
+ const ensure_uv_1 = require("./utils/ensure-uv");
14
15
  const pythonInstall = async ({ baseDir, isVerbose = false, pythonVersion = '3.13', }) => {
15
16
  const venvPath = path_1.default.join(baseDir, 'python_modules');
16
17
  console.log('📦 Installing Python dependencies...', venvPath);
@@ -30,6 +31,10 @@ const pythonInstall = async ({ baseDir, isVerbose = false, pythonVersion = '3.13
30
31
  await (0, execute_command_1.executeCommand)(`${pythonCmd} -m venv python_modules`, baseDir);
31
32
  }
32
33
  (0, activate_python_env_1.activatePythonVenv)({ baseDir, isVerbose, pythonVersion });
34
+ // Ensure UV is installed
35
+ console.log('🔧 Checking UV installation...');
36
+ await (0, ensure_uv_1.ensureUvInstalled)();
37
+ console.log('✅ UV is available');
33
38
  (0, install_lambda_python_packages_1.installLambdaPythonPackages)({ isVerbose, requirementsList });
34
39
  // Install requirements
35
40
  console.log('📥 Installing Python dependencies...');
@@ -0,0 +1 @@
1
+ export declare const ensureUvInstalled: () => Promise<void>;