@open-mercato/cli 0.6.4-develop.4382.1.6b4f656b77 → 0.6.4

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 (109) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/agentic/guides/core.customers.md +1 -1
  3. package/dist/agentic/shared/AGENTS.md.template +56 -33
  4. package/dist/agentic/shared/ai/skills/{auto-continue-pr → om-auto-continue-pr}/SKILL.md +19 -19
  5. package/dist/agentic/shared/ai/skills/{auto-create-pr → om-auto-continue-pr}/STANDALONE.md +1 -1
  6. package/dist/agentic/shared/ai/skills/{auto-continue-pr-loop → om-auto-continue-pr-loop}/SKILL.md +32 -32
  7. package/dist/agentic/shared/ai/skills/{auto-create-pr → om-auto-create-pr}/SKILL.md +24 -24
  8. package/dist/agentic/shared/ai/skills/{auto-fix-github → om-auto-create-pr}/STANDALONE.md +1 -1
  9. package/dist/agentic/shared/ai/skills/{auto-create-pr-loop → om-auto-create-pr-loop}/SKILL.md +40 -40
  10. package/dist/agentic/shared/ai/skills/{auto-fix-github → om-auto-fix-github}/SKILL.md +3 -3
  11. package/dist/agentic/shared/ai/skills/{auto-continue-pr → om-auto-fix-github}/STANDALONE.md +1 -1
  12. package/dist/agentic/shared/ai/skills/{auto-review-pr → om-auto-review-pr}/SKILL.md +5 -5
  13. package/dist/agentic/shared/ai/skills/{auto-review-pr → om-auto-review-pr}/STANDALONE.md +1 -1
  14. package/dist/agentic/shared/ai/skills/{auto-upgrade-0.4.10-to-0.5.0 → om-auto-upgrade-0.4.10-to-0.5.0}/SKILL.md +1 -1
  15. package/dist/agentic/shared/ai/skills/{backend-ui-design → om-backend-ui-design}/SKILL.md +2 -2
  16. package/dist/agentic/shared/ai/skills/{code-review → om-code-review}/SKILL.md +1 -1
  17. package/dist/agentic/shared/ai/skills/{code-review → om-code-review}/references/review-checklist.md +3 -0
  18. package/dist/agentic/shared/ai/skills/{data-model-design → om-data-model-design}/SKILL.md +4 -2
  19. package/dist/agentic/shared/ai/skills/{eject-and-customize → om-eject-and-customize}/SKILL.md +2 -2
  20. package/dist/agentic/shared/ai/skills/{implement-spec → om-implement-spec}/SKILL.md +6 -6
  21. package/dist/agentic/shared/ai/skills/{integration-builder → om-integration-builder}/SKILL.md +1 -1
  22. package/dist/agentic/shared/ai/skills/{integration-tests → om-integration-tests}/SKILL.md +1 -1
  23. package/dist/agentic/shared/ai/skills/{module-scaffold → om-module-scaffold}/SKILL.md +5 -3
  24. package/dist/agentic/shared/ai/skills/{module-scaffold → om-module-scaffold}/references/naming-conventions.md +7 -8
  25. package/dist/agentic/shared/ai/skills/om-prepare-issue/SKILL.md +202 -0
  26. package/dist/agentic/shared/ai/skills/{spec-writing → om-spec-writing}/SKILL.md +6 -6
  27. package/dist/agentic/shared/ai/skills/{spec-writing → om-spec-writing}/references/spec-checklist.md +3 -3
  28. package/dist/agentic/shared/ai/skills/{system-extension → om-system-extension}/SKILL.md +1 -1
  29. package/dist/agentic/shared/ai/skills/{trim-unused-modules → om-trim-unused-modules}/SKILL.md +1 -1
  30. package/dist/agentic/shared/ai/skills/{troubleshooter → om-troubleshooter}/SKILL.md +1 -1
  31. package/dist/bin.js +1 -0
  32. package/dist/bin.js.map +2 -2
  33. package/dist/lib/__integration__/TC-INT-008.spec.js +1 -1
  34. package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
  35. package/dist/lib/agentic-setup.js +52 -51
  36. package/dist/lib/agentic-setup.js.map +2 -2
  37. package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.meta.js +7 -0
  38. package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.meta.js.map +7 -0
  39. package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.spec.js +63 -0
  40. package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.spec.js.map +7 -0
  41. package/dist/lib/deploy/railway/env.js +98 -0
  42. package/dist/lib/deploy/railway/env.js.map +7 -0
  43. package/dist/lib/deploy/railway/graphql-client.js +99 -0
  44. package/dist/lib/deploy/railway/graphql-client.js.map +7 -0
  45. package/dist/lib/deploy/railway/index.js +1115 -0
  46. package/dist/lib/deploy/railway/index.js.map +7 -0
  47. package/dist/lib/deploy/railway/operations.js +249 -0
  48. package/dist/lib/deploy/railway/operations.js.map +7 -0
  49. package/dist/lib/deploy/railway/options.js +155 -0
  50. package/dist/lib/deploy/railway/options.js.map +7 -0
  51. package/dist/lib/deploy/railway/railway-cli.js +61 -0
  52. package/dist/lib/deploy/railway/railway-cli.js.map +7 -0
  53. package/dist/lib/deploy/railway/redaction.js +88 -0
  54. package/dist/lib/deploy/railway/redaction.js.map +7 -0
  55. package/dist/lib/deploy/railway/source.js +128 -0
  56. package/dist/lib/deploy/railway/source.js.map +7 -0
  57. package/dist/lib/deploy/railway/state.js +41 -0
  58. package/dist/lib/deploy/railway/state.js.map +7 -0
  59. package/dist/lib/deploy/railway/token.js +46 -0
  60. package/dist/lib/deploy/railway/token.js.map +7 -0
  61. package/dist/lib/deploy/railway/types.js +1 -0
  62. package/dist/lib/deploy/railway/types.js.map +7 -0
  63. package/dist/lib/generators/openapi.js +4 -0
  64. package/dist/lib/generators/openapi.js.map +2 -2
  65. package/dist/lib/testing/integration.js +57 -26
  66. package/dist/lib/testing/integration.js.map +2 -2
  67. package/dist/lib/testing/runtime-utils.js +16 -8
  68. package/dist/lib/testing/runtime-utils.js.map +2 -2
  69. package/dist/mercato.js +23 -8
  70. package/dist/mercato.js.map +2 -2
  71. package/package.json +11 -12
  72. package/src/bin.ts +1 -0
  73. package/src/lib/__integration__/TC-INT-008.spec.ts +1 -1
  74. package/src/lib/agentic-setup.ts +52 -51
  75. package/src/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.meta.ts +3 -0
  76. package/src/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.spec.ts +71 -0
  77. package/src/lib/deploy/railway/__tests__/dry-run.test.ts +61 -0
  78. package/src/lib/deploy/railway/__tests__/env.test.ts +55 -0
  79. package/src/lib/deploy/railway/__tests__/graphql-client.test.ts +80 -0
  80. package/src/lib/deploy/railway/__tests__/operations.test.ts +21 -0
  81. package/src/lib/deploy/railway/__tests__/options.test.ts +78 -0
  82. package/src/lib/deploy/railway/__tests__/redaction.test.ts +62 -0
  83. package/src/lib/deploy/railway/__tests__/source.test.ts +130 -0
  84. package/src/lib/deploy/railway/__tests__/state.test.ts +24 -0
  85. package/src/lib/deploy/railway/__tests__/token.test.ts +39 -0
  86. package/src/lib/deploy/railway/env.ts +112 -0
  87. package/src/lib/deploy/railway/graphql-client.ts +128 -0
  88. package/src/lib/deploy/railway/index.ts +1454 -0
  89. package/src/lib/deploy/railway/operations.ts +248 -0
  90. package/src/lib/deploy/railway/options.ts +167 -0
  91. package/src/lib/deploy/railway/railway-cli.ts +65 -0
  92. package/src/lib/deploy/railway/redaction.ts +91 -0
  93. package/src/lib/deploy/railway/source.ts +143 -0
  94. package/src/lib/deploy/railway/state.ts +45 -0
  95. package/src/lib/deploy/railway/token.ts +49 -0
  96. package/src/lib/deploy/railway/types.ts +87 -0
  97. package/src/lib/generators/openapi.ts +3 -0
  98. package/src/lib/testing/__tests__/integration.test.ts +79 -0
  99. package/src/lib/testing/__tests__/runtime-utils.test.ts +45 -1
  100. package/src/lib/testing/integration.ts +74 -28
  101. package/src/lib/testing/runtime-utils.ts +17 -8
  102. package/src/mercato.ts +33 -8
  103. /package/dist/agentic/shared/ai/skills/{backend-ui-design → om-backend-ui-design}/references/ui-components.md +0 -0
  104. /package/dist/agentic/shared/ai/skills/{data-model-design → om-data-model-design}/references/mikro-orm-cheatsheet.md +0 -0
  105. /package/dist/agentic/shared/ai/skills/{integration-builder → om-integration-builder}/references/adapter-contracts.md +0 -0
  106. /package/dist/agentic/shared/ai/skills/{module-scaffold → om-module-scaffold}/references/navigation-patterns.md +0 -0
  107. /package/dist/agentic/shared/ai/skills/{spec-writing → om-spec-writing}/references/spec-template.md +0 -0
  108. /package/dist/agentic/shared/ai/skills/{system-extension → om-system-extension}/references/extension-contracts.md +0 -0
  109. /package/dist/agentic/shared/ai/skills/{troubleshooter → om-troubleshooter}/references/diagnostic-commands.md +0 -0
@@ -14,10 +14,17 @@ function assertNode24Runtime(options) {
14
14
  );
15
15
  }
16
16
  async function getFreePort() {
17
- return new Promise((resolve, reject) => {
17
+ const tryListen = (host) => new Promise((resolve, reject) => {
18
18
  const server = createServer();
19
- server.on("error", reject);
20
- server.listen(0, "127.0.0.1", () => {
19
+ server.on("error", (error) => {
20
+ const errorCode = error.code;
21
+ if (errorCode === "EAFNOSUPPORT") {
22
+ resolve(null);
23
+ return;
24
+ }
25
+ reject(error);
26
+ });
27
+ server.listen(0, host, () => {
21
28
  const address = server.address();
22
29
  if (!address || typeof address === "string") {
23
30
  server.close();
@@ -34,6 +41,7 @@ async function getFreePort() {
34
41
  });
35
42
  });
36
43
  });
44
+ return await tryListen("::") ?? await tryListen("127.0.0.1") ?? Promise.reject(new Error("Unable to allocate free port"));
37
45
  }
38
46
  async function isPortAvailable(port) {
39
47
  const canBind = (host) => new Promise((resolve) => {
@@ -52,15 +60,15 @@ async function isPortAvailable(port) {
52
60
  });
53
61
  });
54
62
  });
55
- const ipv4Availability = await canBind("127.0.0.1");
56
- if (ipv4Availability === false) {
63
+ const wildcardIpv6Availability = await canBind("::");
64
+ if (wildcardIpv6Availability === false) {
57
65
  return false;
58
66
  }
59
- const ipv6Availability = await canBind("::1");
60
- if (ipv6Availability === false) {
67
+ const ipv4Availability = await canBind("127.0.0.1");
68
+ if (ipv4Availability === false) {
61
69
  return false;
62
70
  }
63
- return ipv4Availability === true || ipv6Availability === true;
71
+ return wildcardIpv6Availability === true || ipv4Availability === true;
64
72
  }
65
73
  async function getPreferredPort(preferredPort, logPrefix) {
66
74
  if (await isPortAvailable(preferredPort)) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/testing/runtime-utils.ts"],
4
- "sourcesContent": ["import { createServer } from 'node:net'\nimport { spawn } from 'node:child_process'\n\ntype Node24RuntimeGuardOptions = {\n context: string\n retryCommand: string\n}\n\nexport function assertNode24Runtime(options: Node24RuntimeGuardOptions): void {\n const major = Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10)\n if (major >= 24) {\n return\n }\n\n throw new Error(\n [\n `Unsupported Node.js runtime for ${options.context}.`,\n `Cause: Detected Node ${process.versions.node}, but this repository requires Node 24.x.`,\n `What to do: switch your shell to Node 24 (for example \\`nvm use 24\\`), reinstall dependencies (\\`yarn install\\`), then retry \\`${options.retryCommand}\\`.`,\n ].join(' '),\n )\n}\n\nexport async function getFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = createServer()\n server.on('error', reject)\n server.listen(0, '127.0.0.1', () => {\n const address = server.address()\n if (!address || typeof address === 'string') {\n server.close()\n reject(new Error('Unable to allocate free port'))\n return\n }\n const port = address.port\n server.close((closeError) => {\n if (closeError) {\n reject(closeError)\n return\n }\n resolve(port)\n })\n })\n })\n}\n\nexport async function isPortAvailable(port: number): Promise<boolean> {\n const canBind = (host: string): Promise<boolean | null> => new Promise((resolve) => {\n const server = createServer()\n server.once('error', (error) => {\n const errorCode = (error as NodeJS.ErrnoException).code\n if (errorCode === 'EAFNOSUPPORT') {\n resolve(null)\n return\n }\n resolve(false)\n })\n server.listen(port, host, () => {\n server.close(() => {\n resolve(true)\n })\n })\n })\n\n const ipv4Availability = await canBind('127.0.0.1')\n if (ipv4Availability === false) {\n return false\n }\n\n const ipv6Availability = await canBind('::1')\n if (ipv6Availability === false) {\n return false\n }\n\n return ipv4Availability === true || ipv6Availability === true\n}\n\nexport async function getPreferredPort(preferredPort: number, logPrefix: string): Promise<number> {\n if (await isPortAvailable(preferredPort)) {\n return preferredPort\n }\n\n const fallbackPort = await getFreePort()\n console.log(`[${logPrefix}] Port ${preferredPort} is busy, using fallback port ${fallbackPort}.`)\n return fallbackPort\n}\n\nexport async function isEndpointResponsive(url: string, timeoutMs = 1500): Promise<boolean> {\n try {\n const response = await fetch(url, {\n method: 'GET',\n redirect: 'manual',\n signal: AbortSignal.timeout(timeoutMs),\n })\n return response.status > 0\n } catch {\n return false\n }\n}\n\nexport function redactPostgresUrl(url: string): string {\n const trimmed = url.trim()\n if (!trimmed) {\n return trimmed\n }\n\n try {\n const parsed = new URL(trimmed)\n if (parsed.password) {\n parsed.password = '***'\n }\n if (!parsed.username && parsed.password) {\n parsed.username = '***'\n }\n return parsed.toString()\n } catch {\n return trimmed.replace(/(postgres(?:ql)?:\\/\\/[^:/?#\\s]+:)[^@/\\s]+@/i, '$1***@')\n }\n}\n\nexport type DockerHostConfig = {\n dockerHost: string\n socketOverride: string\n}\n\nexport function runCommandAndCapture(command: string, args: string[], options?: { cwd?: string }): Promise<{ code: number | null; stdout: string; stderr: string }> {\n return new Promise((resolve) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd ?? process.cwd(),\n env: process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n let stdout = ''\n let stderr = ''\n proc.stdout?.on('data', (chunk: Buffer | string) => {\n stdout += chunk.toString()\n })\n proc.stderr?.on('data', (chunk: Buffer | string) => {\n stderr += chunk.toString()\n })\n proc.on('error', () => {\n resolve({ code: -1, stdout, stderr })\n })\n proc.on('exit', (code) => {\n resolve({ code, stdout, stderr })\n })\n })\n}\n\n/**\n * Resolve Docker host configuration from the active Docker context.\n *\n * Testcontainers only checks hardcoded socket paths and doesn't respect Docker CLI contexts.\n * This function queries the active Docker context to get the correct socket path for\n * non-standard Docker setups like Colima.\n *\n * @returns Docker host configuration or null if auto-detection fails/not needed\n */\nexport async function resolveDockerHostFromContext(logPrefix: string): Promise<DockerHostConfig | null> {\n // Respect explicit user configuration\n if (process.env.DOCKER_HOST) {\n return null\n }\n\n const result = await runCommandAndCapture('docker', ['context', 'inspect', '--format', '{{.Endpoints.docker.Host}}'])\n if (result.code !== 0) {\n return null\n }\n\n const dockerHost = result.stdout.trim()\n if (!dockerHost) {\n return null\n }\n\n // Standard socket path - testcontainers handles this natively\n if (dockerHost === 'unix:///var/run/docker.sock') {\n return null\n }\n\n // For non-standard Docker setups (Colima, Podman, etc.), the socket override\n // tells testcontainers what path containers should use to reach the Docker daemon.\n // This is typically /var/run/docker.sock inside the VM, regardless of the host path.\n const socketOverride = '/var/run/docker.sock'\n\n console.log(`[${logPrefix}] Auto-detected Docker context: ${dockerHost}`)\n\n return {\n dockerHost,\n socketOverride,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createServer } from 'node:net'\nimport { spawn } from 'node:child_process'\n\ntype Node24RuntimeGuardOptions = {\n context: string\n retryCommand: string\n}\n\nexport function assertNode24Runtime(options: Node24RuntimeGuardOptions): void {\n const major = Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10)\n if (major >= 24) {\n return\n }\n\n throw new Error(\n [\n `Unsupported Node.js runtime for ${options.context}.`,\n `Cause: Detected Node ${process.versions.node}, but this repository requires Node 24.x.`,\n `What to do: switch your shell to Node 24 (for example \\`nvm use 24\\`), reinstall dependencies (\\`yarn install\\`), then retry \\`${options.retryCommand}\\`.`,\n ].join(' '),\n )\n}\n\nexport async function getFreePort(): Promise<number> {\n const tryListen = (host: string): Promise<number | null> => new Promise((resolve, reject) => {\n const server = createServer()\n server.on('error', (error) => {\n const errorCode = (error as NodeJS.ErrnoException).code\n if (errorCode === 'EAFNOSUPPORT') {\n resolve(null)\n return\n }\n reject(error)\n })\n server.listen(0, host, () => {\n const address = server.address()\n if (!address || typeof address === 'string') {\n server.close()\n reject(new Error('Unable to allocate free port'))\n return\n }\n const port = address.port\n server.close((closeError) => {\n if (closeError) {\n reject(closeError)\n return\n }\n resolve(port)\n })\n })\n })\n\n return (await tryListen('::')) ?? await tryListen('127.0.0.1') ?? Promise.reject(new Error('Unable to allocate free port'))\n}\n\nexport async function isPortAvailable(port: number): Promise<boolean> {\n const canBind = (host: string): Promise<boolean | null> => new Promise((resolve) => {\n const server = createServer()\n server.once('error', (error) => {\n const errorCode = (error as NodeJS.ErrnoException).code\n if (errorCode === 'EAFNOSUPPORT') {\n resolve(null)\n return\n }\n resolve(false)\n })\n server.listen(port, host, () => {\n server.close(() => {\n resolve(true)\n })\n })\n })\n\n const wildcardIpv6Availability = await canBind('::')\n if (wildcardIpv6Availability === false) {\n return false\n }\n\n const ipv4Availability = await canBind('127.0.0.1')\n if (ipv4Availability === false) {\n return false\n }\n\n return wildcardIpv6Availability === true || ipv4Availability === true\n}\n\nexport async function getPreferredPort(preferredPort: number, logPrefix: string): Promise<number> {\n if (await isPortAvailable(preferredPort)) {\n return preferredPort\n }\n\n const fallbackPort = await getFreePort()\n console.log(`[${logPrefix}] Port ${preferredPort} is busy, using fallback port ${fallbackPort}.`)\n return fallbackPort\n}\n\nexport async function isEndpointResponsive(url: string, timeoutMs = 1500): Promise<boolean> {\n try {\n const response = await fetch(url, {\n method: 'GET',\n redirect: 'manual',\n signal: AbortSignal.timeout(timeoutMs),\n })\n return response.status > 0\n } catch {\n return false\n }\n}\n\nexport function redactPostgresUrl(url: string): string {\n const trimmed = url.trim()\n if (!trimmed) {\n return trimmed\n }\n\n try {\n const parsed = new URL(trimmed)\n if (parsed.password) {\n parsed.password = '***'\n }\n if (!parsed.username && parsed.password) {\n parsed.username = '***'\n }\n return parsed.toString()\n } catch {\n return trimmed.replace(/(postgres(?:ql)?:\\/\\/[^:/?#\\s]+:)[^@/\\s]+@/i, '$1***@')\n }\n}\n\nexport type DockerHostConfig = {\n dockerHost: string\n socketOverride: string\n}\n\nexport function runCommandAndCapture(command: string, args: string[], options?: { cwd?: string }): Promise<{ code: number | null; stdout: string; stderr: string }> {\n return new Promise((resolve) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd ?? process.cwd(),\n env: process.env,\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n let stdout = ''\n let stderr = ''\n proc.stdout?.on('data', (chunk: Buffer | string) => {\n stdout += chunk.toString()\n })\n proc.stderr?.on('data', (chunk: Buffer | string) => {\n stderr += chunk.toString()\n })\n proc.on('error', () => {\n resolve({ code: -1, stdout, stderr })\n })\n proc.on('exit', (code) => {\n resolve({ code, stdout, stderr })\n })\n })\n}\n\n/**\n * Resolve Docker host configuration from the active Docker context.\n *\n * Testcontainers only checks hardcoded socket paths and doesn't respect Docker CLI contexts.\n * This function queries the active Docker context to get the correct socket path for\n * non-standard Docker setups like Colima.\n *\n * @returns Docker host configuration or null if auto-detection fails/not needed\n */\nexport async function resolveDockerHostFromContext(logPrefix: string): Promise<DockerHostConfig | null> {\n // Respect explicit user configuration\n if (process.env.DOCKER_HOST) {\n return null\n }\n\n const result = await runCommandAndCapture('docker', ['context', 'inspect', '--format', '{{.Endpoints.docker.Host}}'])\n if (result.code !== 0) {\n return null\n }\n\n const dockerHost = result.stdout.trim()\n if (!dockerHost) {\n return null\n }\n\n // Standard socket path - testcontainers handles this natively\n if (dockerHost === 'unix:///var/run/docker.sock') {\n return null\n }\n\n // For non-standard Docker setups (Colima, Podman, etc.), the socket override\n // tells testcontainers what path containers should use to reach the Docker daemon.\n // This is typically /var/run/docker.sock inside the VM, regardless of the host path.\n const socketOverride = '/var/run/docker.sock'\n\n console.log(`[${logPrefix}] Auto-detected Docker context: ${dockerHost}`)\n\n return {\n dockerHost,\n socketOverride,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/mercato.js CHANGED
@@ -60,7 +60,7 @@ const TURBOPACK_CORRUPTION_PATTERNS = [
60
60
  "Unable to open static sorted file",
61
61
  "TurbopackInternalError"
62
62
  ];
63
- const BUILTIN_CLI_MODULE_IDS = /* @__PURE__ */ new Set(["queue", "generate", "db", "server", "test"]);
63
+ const BUILTIN_CLI_MODULE_IDS = /* @__PURE__ */ new Set(["queue", "generate", "deploy", "db", "server", "test"]);
64
64
  function collectNestedErrors(error, seen = /* @__PURE__ */ new Set()) {
65
65
  if (!error || seen.has(error)) {
66
66
  return [];
@@ -192,16 +192,16 @@ function isTurbopackCacheCorruption(output) {
192
192
  function removeTurbopackDevCache(appDir) {
193
193
  fs.rmSync(path.join(appDir, ".mercato", "next", "dev"), { recursive: true, force: true });
194
194
  }
195
- async function ensureEnvLoaded() {
195
+ async function ensureEnvLoaded(options = {}) {
196
196
  if (envLoaded) return;
197
197
  envLoaded = true;
198
- const quietDotenv = process.env.DOTENV_CONFIG_QUIET === "1" || process.env.DOTENV_CONFIG_QUIET === "true";
198
+ const quietDotenv = options.quiet === true || process.env.DOTENV_CONFIG_QUIET === "1" || process.env.DOTENV_CONFIG_QUIET === "true";
199
199
  try {
200
200
  const { createResolver } = await import("./lib/resolver.js");
201
201
  const resolver = createResolver();
202
202
  const appDir = resolver.getAppDir();
203
203
  const envPath = path.join(appDir, ".env");
204
- if (!fs.existsSync(envPath) && process.env.NODE_ENV !== "production") {
204
+ if (options.createIfMissing !== false && !fs.existsSync(envPath) && process.env.NODE_ENV !== "production") {
205
205
  const examplePath = path.join(appDir, ".env.example");
206
206
  if (fs.existsSync(examplePath)) {
207
207
  fs.copyFileSync(examplePath, envPath);
@@ -568,9 +568,9 @@ async function buildAllModules() {
568
568
  return all;
569
569
  }
570
570
  async function run(argv = process.argv) {
571
- await ensureEnvLoaded();
572
571
  const [, , ...parts] = argv;
573
572
  const [first, second, ...remaining] = parts;
573
+ await ensureEnvLoaded({ createIfMissing: first !== "deploy", quiet: first === "deploy" });
574
574
  if (first === "init") {
575
575
  const { execSync } = await import("child_process");
576
576
  console.log("\u{1F680} Initializing Open Mercato app...\n");
@@ -1184,6 +1184,18 @@ async function run(argv = process.argv) {
1184
1184
  }
1185
1185
  }
1186
1186
  const all = modules.slice();
1187
+ all.push({
1188
+ id: "deploy",
1189
+ cli: [
1190
+ {
1191
+ command: "railway",
1192
+ run: async (args) => {
1193
+ const { runRailwayDeploy } = await import("./lib/deploy/railway/index.js");
1194
+ await runRailwayDeploy(args);
1195
+ }
1196
+ }
1197
+ ]
1198
+ });
1187
1199
  all.push({
1188
1200
  id: "queue",
1189
1201
  cli: [
@@ -1976,11 +1988,14 @@ async function run(argv = process.argv) {
1976
1988
  }
1977
1989
  console.log("");
1978
1990
  const started = Date.now();
1979
- console.log(`\u{1F680} Running ${modName}:${cmdName} ${rest.join(" ")}`);
1991
+ const loggedArgs = modName === "deploy" && cmdName === "railway" ? (await import("./lib/deploy/railway/options.js")).redactRailwayCliArgs(rest) : rest;
1992
+ console.log(`\u{1F680} Running ${modName}:${cmdName} ${loggedArgs.join(" ")}`);
1980
1993
  try {
1981
1994
  await cmd.run(rest);
1982
- const ms = Date.now() - started;
1983
- console.log(`\u23F1\uFE0F Done in ${ms}ms`);
1995
+ if (modName !== "deploy" || cmdName !== "railway") {
1996
+ const ms = Date.now() - started;
1997
+ console.log(`\u23F1\uFE0F Done in ${ms}ms`);
1998
+ }
1984
1999
  return 0;
1985
2000
  } catch (e) {
1986
2001
  console.error(`\u{1F4A5} Failed: ${formatCliFailureMessage(modName, cmdName, e)}`);