motia 0.15.5-beta.174-720958 → 0.15.5-beta.174-093524

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 (33) hide show
  1. package/dist/cli.mjs +9 -1
  2. package/dist/cli.mjs.map +1 -1
  3. package/dist/cloud/config-utils.mjs +1 -1
  4. package/dist/cloud/config-utils.mjs.map +1 -1
  5. package/dist/cloud/new-deployment/build.mjs +11 -1
  6. package/dist/cloud/new-deployment/build.mjs.map +1 -1
  7. package/dist/create/index.mjs +28 -12
  8. package/dist/create/index.mjs.map +1 -1
  9. package/dist/cursor-rules/dot-files/.claude/agents/motia-developer.md +20 -11
  10. package/dist/cursor-rules/dot-files/.cursor/architecture/architecture.mdc +124 -28
  11. package/dist/cursor-rules/dot-files/.cursor/rules/motia/motia-config.mdc +66 -0
  12. package/dist/cursor-rules/dot-files/AGENTS.md +31 -16
  13. package/dist/cursor-rules/dot-files/CLAUDE.md +7 -2
  14. package/dist/cursor-rules/dot-files/opencode.json +1 -0
  15. package/dist/dev.mjs +8 -2
  16. package/dist/dev.mjs.map +1 -1
  17. package/dist/generate-locked-data.d.mts.map +1 -1
  18. package/dist/generate-locked-data.mjs +0 -2
  19. package/dist/generate-locked-data.mjs.map +1 -1
  20. package/dist/install.mjs +1 -1
  21. package/dist/plugins/install-plugin-dependencies.mjs +4 -3
  22. package/dist/plugins/install-plugin-dependencies.mjs.map +1 -1
  23. package/dist/start.mjs +8 -2
  24. package/dist/start.mjs.map +1 -1
  25. package/dist/utils/activate-python-env.mjs +9 -15
  26. package/dist/utils/activate-python-env.mjs.map +1 -1
  27. package/dist/utils/get-package-manager.mjs +42 -5
  28. package/dist/utils/get-package-manager.mjs.map +1 -1
  29. package/dist/utils/validate-python-environment.mjs +81 -0
  30. package/dist/utils/validate-python-environment.mjs.map +1 -0
  31. package/dist/watcher.mjs +1 -3
  32. package/dist/watcher.mjs.map +1 -1
  33. package/package.json +8 -8
@@ -0,0 +1,81 @@
1
+ import { internalLogger } from "./internal-logger.mjs";
2
+ import { getPythonCommand } from "./python-version-utils.mjs";
3
+ import { getPackageManager } from "./get-package-manager.mjs";
4
+ import fs from "fs";
5
+ import path from "path";
6
+
7
+ //#region src/utils/validate-python-environment.ts
8
+ function getInstallCommand(baseDir) {
9
+ switch (getPackageManager(baseDir)) {
10
+ case "yarn": return "yarn install";
11
+ case "pnpm": return "pnpm install";
12
+ case "bun": return "bun install";
13
+ case "npm":
14
+ default: return "npm install";
15
+ }
16
+ }
17
+ async function validatePythonEnvironment({ baseDir, hasPythonFiles, pythonVersion = "3.13" }) {
18
+ if (!hasPythonFiles) return {
19
+ success: true,
20
+ hasPythonFiles: false
21
+ };
22
+ const installCmd = getInstallCommand(baseDir);
23
+ try {
24
+ await getPythonCommand(pythonVersion, baseDir);
25
+ } catch {
26
+ internalLogger.error("Python is not installed");
27
+ internalLogger.info("Python files were detected in your project but Python 3 is not available");
28
+ internalLogger.info("Please install Python 3.10 or higher: https://www.python.org/downloads/");
29
+ return {
30
+ success: false,
31
+ hasPythonFiles: true
32
+ };
33
+ }
34
+ const venvPath = path.join(baseDir, "python_modules");
35
+ if (!fs.existsSync(venvPath)) {
36
+ internalLogger.error("Python environment not configured");
37
+ internalLogger.info("The python_modules directory was not found");
38
+ internalLogger.info(`Run '${installCmd}' to set up your Python environment`);
39
+ return {
40
+ success: false,
41
+ hasPythonFiles: true
42
+ };
43
+ }
44
+ const libPath = path.join(venvPath, "lib");
45
+ if (!fs.existsSync(libPath)) {
46
+ internalLogger.error("Python environment is incomplete");
47
+ internalLogger.info("The python_modules directory exists but appears to be corrupted");
48
+ internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
49
+ return {
50
+ success: false,
51
+ hasPythonFiles: true
52
+ };
53
+ }
54
+ try {
55
+ if (fs.readdirSync(libPath).filter((item) => item.startsWith("python3")).length === 0) {
56
+ internalLogger.error("Python environment is incomplete");
57
+ internalLogger.info("The python_modules/lib directory exists but contains no Python version directories");
58
+ internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
59
+ return {
60
+ success: false,
61
+ hasPythonFiles: true
62
+ };
63
+ }
64
+ } catch (error) {
65
+ internalLogger.error("Python environment is incomplete");
66
+ internalLogger.info("The python_modules/lib directory cannot be read");
67
+ internalLogger.info(`Run '${installCmd}' to recreate your Python environment`);
68
+ return {
69
+ success: false,
70
+ hasPythonFiles: true
71
+ };
72
+ }
73
+ return {
74
+ success: true,
75
+ hasPythonFiles: true
76
+ };
77
+ }
78
+
79
+ //#endregion
80
+ export { validatePythonEnvironment };
81
+ //# sourceMappingURL=validate-python-environment.mjs.map
@@ -0,0 +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 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/dist/watcher.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { getStepConfig, getStreamConfig, invalidate } from "@motiadev/core";
1
+ import { getStepConfig, getStreamConfig } from "@motiadev/core";
2
2
  import { randomUUID } from "crypto";
3
3
  import chokidar from "chokidar";
4
4
 
@@ -44,7 +44,6 @@ var Watcher = class {
44
44
  this.stepCreateHandler?.(step);
45
45
  }
46
46
  async onStepFileChange(path) {
47
- if (path.endsWith(".ts")) invalidate(path);
48
47
  const config = await getStepConfig(path, this.dir).catch((err) => {
49
48
  console.error(err);
50
49
  });
@@ -68,7 +67,6 @@ var Watcher = class {
68
67
  if (step && !config) this.stepDeleteHandler?.(step);
69
68
  }
70
69
  async onStepFileDelete(path) {
71
- if (path.endsWith(".ts")) invalidate(path);
72
70
  const step = this.findStep(path);
73
71
  if (!step) {
74
72
  console.warn(`Step ${path} not found, step skipped`);
@@ -1 +1 @@
1
- {"version":3,"file":"watcher.mjs","names":["dir: string","lockedData: LockedData","step: Step","step","newStep: Step"],"sources":["../src/watcher.ts"],"sourcesContent":["import type { Stream } from '@motiadev/core'\nimport { getStepConfig, getStreamConfig, invalidate, type LockedData, type Step } from '@motiadev/core'\nimport chokidar, { type FSWatcher } from 'chokidar'\nimport { randomUUID } from 'crypto'\n\ntype StepChangeHandler = (oldStep: Step, newStep: Step) => void\ntype StepCreateHandler = (step: Step) => void\ntype StepDeleteHandler = (step: Step) => void\n\ntype StreamChangeHandler = (oldStream: Stream, newStream: Stream) => void\ntype StreamCreateHandler = (stream: Stream) => void\ntype StreamDeleteHandler = (stream: Stream) => void\n\nexport class Watcher {\n private watcher?: FSWatcher\n private stepChangeHandler?: StepChangeHandler\n private stepCreateHandler?: StepCreateHandler\n private stepDeleteHandler?: StepDeleteHandler\n private streamChangeHandler?: StreamChangeHandler\n private streamCreateHandler?: StreamCreateHandler\n private streamDeleteHandler?: StreamDeleteHandler\n\n constructor(\n private readonly dir: string,\n private lockedData: LockedData,\n ) {}\n\n onStepChange(handler: StepChangeHandler) {\n this.stepChangeHandler = handler\n }\n\n onStepCreate(handler: StepCreateHandler) {\n this.stepCreateHandler = handler\n }\n\n onStepDelete(handler: StepDeleteHandler) {\n this.stepDeleteHandler = handler\n }\n\n onStreamChange(handler: StreamChangeHandler) {\n this.streamChangeHandler = handler\n }\n\n onStreamCreate(handler: StreamCreateHandler) {\n this.streamCreateHandler = handler\n }\n\n onStreamDelete(handler: StreamDeleteHandler) {\n this.streamDeleteHandler = handler\n }\n\n private findStep(path: string): Step | undefined {\n return (\n this.lockedData.activeSteps.find((step) => step.filePath === path) ||\n this.lockedData.devSteps.find((step) => step.filePath === path)\n )\n }\n\n private async onStepFileAdd(path: string): Promise<void> {\n if (!this.stepCreateHandler) {\n console.warn(`No step create handler, step skipped`)\n return\n }\n\n const config = await getStepConfig(path, this.dir).catch((err) => console.error(err))\n\n if (!config) {\n return\n }\n\n const version = `${randomUUID()}:${Math.floor(Date.now() / 1000)}`\n const step: Step = { filePath: path, version, config }\n\n this.stepCreateHandler?.(step)\n }\n\n private async onStepFileChange(path: string): Promise<void> {\n if (path.endsWith('.ts')) {\n invalidate(path)\n }\n\n const config = await getStepConfig(path, this.dir).catch((err) => {\n console.error(err)\n })\n\n const step = this.findStep(path)\n\n if (!step && !config) {\n return\n }\n\n // didn't have a step, but now we have a config\n if (!step && config) {\n const version = `${randomUUID()}:${Math.floor(Date.now() / 1000)}`\n const step: Step = { filePath: path, version, config }\n\n this.stepCreateHandler?.(step)\n }\n\n // had a step, and now we have a config\n if (step && config) {\n const newStep: Step = { ...step, config }\n this.stepChangeHandler?.(step, newStep)\n }\n\n // had a step, but no config\n if (step && !config) {\n this.stepDeleteHandler?.(step)\n }\n }\n\n private async onStepFileDelete(path: string): Promise<void> {\n if (path.endsWith('.ts')) {\n invalidate(path)\n }\n\n const step = this.findStep(path)\n\n if (!step) {\n console.warn(`Step ${path} not found, step skipped`)\n return\n }\n\n this.stepDeleteHandler?.(step)\n }\n\n private async onStreamFileAdd(path: string): Promise<void> {\n const config = await getStreamConfig(path).catch((err) => console.error(err))\n\n if (!config) {\n return\n }\n\n this.streamCreateHandler?.({ filePath: path, config, factory: null as never })\n }\n\n private async onStreamFileChange(path: string): Promise<void> {\n const stream = this.lockedData.findStream(path)\n const config = await getStreamConfig(path).catch((err) => console.error(err))\n\n if (!stream && config) {\n this.streamCreateHandler?.({ filePath: path, config, factory: null as never })\n } else if (stream && config) {\n this.streamChangeHandler?.(stream, { filePath: path, config, factory: null as never })\n } else if (stream && !config) {\n this.streamDeleteHandler?.(stream)\n }\n }\n\n private async onStreamFileDelete(path: string): Promise<void> {\n const stream = this.lockedData.findStream(path)\n\n if (this.streamDeleteHandler && stream) {\n this.streamDeleteHandler(stream)\n }\n }\n\n private async onFileAdd(path: string): Promise<void> {\n if (this.isStepFile(path)) {\n this.onStepFileAdd(path)\n } else if (this.isStreamFile(path)) {\n this.onStreamFileAdd(path)\n }\n }\n\n private async onFileChange(path: string): Promise<void> {\n if (this.isStepFile(path)) {\n this.onStepFileChange(path)\n } else if (this.isStreamFile(path)) {\n this.onStreamFileChange(path)\n }\n }\n\n private async onFileDelete(path: string): Promise<void> {\n if (this.isStepFile(path)) {\n this.onStepFileDelete(path)\n } else if (this.isStreamFile(path)) {\n this.onStreamFileDelete(path)\n }\n }\n\n init() {\n this.watcher = chokidar\n .watch(this.dir, { persistent: true, ignoreInitial: true })\n .on('add', (path) => this.onFileAdd(path))\n .on('change', (path) => this.onFileChange(path))\n .on('unlink', (path) => this.onFileDelete(path))\n }\n\n private isStepFile(path: string): boolean {\n const isUiNode = /\\.(tsx|jsx)$/.test(path)\n const isDeprecatedPythonStep = /\\.step\\.py$/.test(path)\n\n return /[._]step\\.((ts)|(js)|(rb)|(py))$/.test(path) && !isUiNode && !isDeprecatedPythonStep\n }\n\n private isStreamFile(path: string): boolean {\n const isUiNode = /\\.(tsx|jsx)$/.test(path)\n const isDeprecatedPythonStream = /\\.stream\\.py$/.test(path)\n\n return /[._]stream\\.((ts)|(js)|(rb)|(py))$/.test(path) && !isUiNode && !isDeprecatedPythonStream\n }\n\n async stop(): Promise<void> {\n if (this.watcher) {\n await this.watcher.close()\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"watcher.mjs","names":["dir: string","lockedData: LockedData","step: Step","step","newStep: Step"],"sources":["../src/watcher.ts"],"sourcesContent":["import type { Stream } from '@motiadev/core'\nimport { getStepConfig, getStreamConfig, type LockedData, type Step } from '@motiadev/core'\nimport chokidar, { type FSWatcher } from 'chokidar'\nimport { randomUUID } from 'crypto'\n\ntype StepChangeHandler = (oldStep: Step, newStep: Step) => void\ntype StepCreateHandler = (step: Step) => void\ntype StepDeleteHandler = (step: Step) => void\n\ntype StreamChangeHandler = (oldStream: Stream, newStream: Stream) => void\ntype StreamCreateHandler = (stream: Stream) => void\ntype StreamDeleteHandler = (stream: Stream) => void\n\nexport class Watcher {\n private watcher?: FSWatcher\n private stepChangeHandler?: StepChangeHandler\n private stepCreateHandler?: StepCreateHandler\n private stepDeleteHandler?: StepDeleteHandler\n private streamChangeHandler?: StreamChangeHandler\n private streamCreateHandler?: StreamCreateHandler\n private streamDeleteHandler?: StreamDeleteHandler\n\n constructor(\n private readonly dir: string,\n private lockedData: LockedData,\n ) {}\n\n onStepChange(handler: StepChangeHandler) {\n this.stepChangeHandler = handler\n }\n\n onStepCreate(handler: StepCreateHandler) {\n this.stepCreateHandler = handler\n }\n\n onStepDelete(handler: StepDeleteHandler) {\n this.stepDeleteHandler = handler\n }\n\n onStreamChange(handler: StreamChangeHandler) {\n this.streamChangeHandler = handler\n }\n\n onStreamCreate(handler: StreamCreateHandler) {\n this.streamCreateHandler = handler\n }\n\n onStreamDelete(handler: StreamDeleteHandler) {\n this.streamDeleteHandler = handler\n }\n\n private findStep(path: string): Step | undefined {\n return (\n this.lockedData.activeSteps.find((step) => step.filePath === path) ||\n this.lockedData.devSteps.find((step) => step.filePath === path)\n )\n }\n\n private async onStepFileAdd(path: string): Promise<void> {\n if (!this.stepCreateHandler) {\n console.warn(`No step create handler, step skipped`)\n return\n }\n\n const config = await getStepConfig(path, this.dir).catch((err) => console.error(err))\n\n if (!config) {\n return\n }\n\n const version = `${randomUUID()}:${Math.floor(Date.now() / 1000)}`\n const step: Step = { filePath: path, version, config }\n\n this.stepCreateHandler?.(step)\n }\n\n private async onStepFileChange(path: string): Promise<void> {\n const config = await getStepConfig(path, this.dir).catch((err) => {\n console.error(err)\n })\n\n const step = this.findStep(path)\n\n if (!step && !config) {\n return\n }\n\n // didn't have a step, but now we have a config\n if (!step && config) {\n const version = `${randomUUID()}:${Math.floor(Date.now() / 1000)}`\n const step: Step = { filePath: path, version, config }\n\n this.stepCreateHandler?.(step)\n }\n\n // had a step, and now we have a config\n if (step && config) {\n const newStep: Step = { ...step, config }\n this.stepChangeHandler?.(step, newStep)\n }\n\n // had a step, but no config\n if (step && !config) {\n this.stepDeleteHandler?.(step)\n }\n }\n\n private async onStepFileDelete(path: string): Promise<void> {\n const step = this.findStep(path)\n\n if (!step) {\n console.warn(`Step ${path} not found, step skipped`)\n return\n }\n\n this.stepDeleteHandler?.(step)\n }\n\n private async onStreamFileAdd(path: string): Promise<void> {\n const config = await getStreamConfig(path).catch((err) => console.error(err))\n\n if (!config) {\n return\n }\n\n this.streamCreateHandler?.({ filePath: path, config, factory: null as never })\n }\n\n private async onStreamFileChange(path: string): Promise<void> {\n const stream = this.lockedData.findStream(path)\n const config = await getStreamConfig(path).catch((err) => console.error(err))\n\n if (!stream && config) {\n this.streamCreateHandler?.({ filePath: path, config, factory: null as never })\n } else if (stream && config) {\n this.streamChangeHandler?.(stream, { filePath: path, config, factory: null as never })\n } else if (stream && !config) {\n this.streamDeleteHandler?.(stream)\n }\n }\n\n private async onStreamFileDelete(path: string): Promise<void> {\n const stream = this.lockedData.findStream(path)\n\n if (this.streamDeleteHandler && stream) {\n this.streamDeleteHandler(stream)\n }\n }\n\n private async onFileAdd(path: string): Promise<void> {\n if (this.isStepFile(path)) {\n this.onStepFileAdd(path)\n } else if (this.isStreamFile(path)) {\n this.onStreamFileAdd(path)\n }\n }\n\n private async onFileChange(path: string): Promise<void> {\n if (this.isStepFile(path)) {\n this.onStepFileChange(path)\n } else if (this.isStreamFile(path)) {\n this.onStreamFileChange(path)\n }\n }\n\n private async onFileDelete(path: string): Promise<void> {\n if (this.isStepFile(path)) {\n this.onStepFileDelete(path)\n } else if (this.isStreamFile(path)) {\n this.onStreamFileDelete(path)\n }\n }\n\n init() {\n this.watcher = chokidar\n .watch(this.dir, { persistent: true, ignoreInitial: true })\n .on('add', (path) => this.onFileAdd(path))\n .on('change', (path) => this.onFileChange(path))\n .on('unlink', (path) => this.onFileDelete(path))\n }\n\n private isStepFile(path: string): boolean {\n const isUiNode = /\\.(tsx|jsx)$/.test(path)\n const isDeprecatedPythonStep = /\\.step\\.py$/.test(path)\n\n return /[._]step\\.((ts)|(js)|(rb)|(py))$/.test(path) && !isUiNode && !isDeprecatedPythonStep\n }\n\n private isStreamFile(path: string): boolean {\n const isUiNode = /\\.(tsx|jsx)$/.test(path)\n const isDeprecatedPythonStream = /\\.stream\\.py$/.test(path)\n\n return /[._]stream\\.((ts)|(js)|(rb)|(py))$/.test(path) && !isUiNode && !isDeprecatedPythonStream\n }\n\n async stop(): Promise<void> {\n if (this.watcher) {\n await this.watcher.close()\n }\n }\n}\n"],"mappings":"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"}
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-720958",
4
+ "version": "0.15.5-beta.174-093524",
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-720958",
50
- "@motiadev/adapter-redis-cron": "0.15.5-beta.174-720958",
51
- "@motiadev/adapter-redis-state": "0.15.5-beta.174-720958",
52
- "@motiadev/adapter-redis-streams": "0.15.5-beta.174-720958",
53
- "@motiadev/core": "0.15.5-beta.174-720958",
54
- "@motiadev/stream-client-node": "0.15.5-beta.174-720958",
55
- "@motiadev/workbench": "0.15.5-beta.174-720958"
49
+ "@motiadev/adapter-bullmq-events": "0.15.5-beta.174-093524",
50
+ "@motiadev/adapter-redis-cron": "0.15.5-beta.174-093524",
51
+ "@motiadev/adapter-redis-streams": "0.15.5-beta.174-093524",
52
+ "@motiadev/core": "0.15.5-beta.174-093524",
53
+ "@motiadev/adapter-redis-state": "0.15.5-beta.174-093524",
54
+ "@motiadev/stream-client-node": "0.15.5-beta.174-093524",
55
+ "@motiadev/workbench": "0.15.5-beta.174-093524"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@amplitude/analytics-types": "^2.9.2",