@remix-run/cli 0.3.3 → 0.4.0

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 (121) hide show
  1. package/README.md +105 -1
  2. package/dist/index.js +1 -1
  3. package/dist/lib/app-root.d.ts +11 -0
  4. package/dist/lib/app-root.d.ts.map +1 -0
  5. package/dist/lib/app-root.js +38 -0
  6. package/dist/lib/bootstrap-project.js +2 -2
  7. package/dist/lib/cli-context.d.ts +6 -0
  8. package/dist/lib/cli-context.d.ts.map +1 -1
  9. package/dist/lib/cli-context.js +12 -1
  10. package/dist/lib/cli.d.ts +3 -2
  11. package/dist/lib/cli.d.ts.map +1 -1
  12. package/dist/lib/cli.js +42 -14
  13. package/dist/lib/commands/completion.js +4 -4
  14. package/dist/lib/commands/db.d.ts +4 -0
  15. package/dist/lib/commands/db.d.ts.map +1 -0
  16. package/dist/lib/commands/db.js +283 -0
  17. package/dist/lib/commands/doctor.d.ts +5 -0
  18. package/dist/lib/commands/doctor.d.ts.map +1 -1
  19. package/dist/lib/commands/doctor.js +26 -251
  20. package/dist/lib/commands/help.d.ts.map +1 -1
  21. package/dist/lib/commands/help.js +17 -9
  22. package/dist/lib/commands/new.js +6 -6
  23. package/dist/lib/commands/routes.js +6 -6
  24. package/dist/lib/commands/test.d.ts +20 -1
  25. package/dist/lib/commands/test.d.ts.map +1 -1
  26. package/dist/lib/commands/test.js +353 -10
  27. package/dist/lib/commands/version.js +3 -3
  28. package/dist/lib/completion.d.ts +1 -1
  29. package/dist/lib/completion.d.ts.map +1 -1
  30. package/dist/lib/completion.js +229 -6
  31. package/dist/lib/controller-files.d.ts +0 -8
  32. package/dist/lib/controller-files.d.ts.map +1 -1
  33. package/dist/lib/controller-files.js +0 -23
  34. package/dist/lib/controller-ownership.d.ts +4 -12
  35. package/dist/lib/controller-ownership.d.ts.map +1 -1
  36. package/dist/lib/controller-ownership.js +31 -127
  37. package/dist/lib/database-command.d.ts +20 -0
  38. package/dist/lib/database-command.d.ts.map +1 -0
  39. package/dist/lib/database-command.js +7 -0
  40. package/dist/lib/doctor/controller-findings.d.ts +2 -2
  41. package/dist/lib/doctor/controller-findings.d.ts.map +1 -1
  42. package/dist/lib/doctor/controller-findings.js +23 -39
  43. package/dist/lib/doctor/controllers.d.ts +1 -2
  44. package/dist/lib/doctor/controllers.d.ts.map +1 -1
  45. package/dist/lib/doctor/controllers.js +4 -7
  46. package/dist/lib/doctor/environment.js +2 -2
  47. package/dist/lib/doctor/fixes.d.ts.map +1 -1
  48. package/dist/lib/doctor/fixes.js +46 -7
  49. package/dist/lib/doctor/project.d.ts.map +1 -1
  50. package/dist/lib/doctor/project.js +3 -212
  51. package/dist/lib/doctor/run.d.ts +9 -0
  52. package/dist/lib/doctor/run.d.ts.map +1 -0
  53. package/dist/lib/doctor/run.js +237 -0
  54. package/dist/lib/doctor/types.d.ts +2 -1
  55. package/dist/lib/doctor/types.d.ts.map +1 -1
  56. package/dist/lib/doctor/types.js +4 -1
  57. package/dist/lib/errors.d.ts +30 -0
  58. package/dist/lib/errors.d.ts.map +1 -1
  59. package/dist/lib/errors.js +55 -0
  60. package/dist/lib/help-text.js +1 -1
  61. package/dist/lib/parse-args.d.ts.map +1 -1
  62. package/dist/lib/parse-args.js +17 -4
  63. package/dist/lib/remix-config.d.ts +75 -0
  64. package/dist/lib/remix-config.d.ts.map +1 -0
  65. package/dist/lib/remix-config.js +411 -0
  66. package/dist/lib/reporter.js +1 -1
  67. package/dist/lib/route-map.js +13 -33
  68. package/package.json +12 -6
  69. package/schema/remix.json +242 -0
  70. package/src/lib/app-root.ts +46 -0
  71. package/src/lib/cli-context.ts +17 -0
  72. package/src/lib/cli.ts +41 -6
  73. package/src/lib/commands/db.ts +377 -0
  74. package/src/lib/commands/doctor.ts +27 -329
  75. package/src/lib/commands/help.ts +10 -1
  76. package/src/lib/commands/test.ts +453 -12
  77. package/src/lib/completion.ts +321 -6
  78. package/src/lib/controller-files.ts +0 -38
  79. package/src/lib/controller-ownership.ts +50 -203
  80. package/src/lib/database-command.ts +31 -0
  81. package/src/lib/doctor/controller-findings.ts +30 -47
  82. package/src/lib/doctor/controllers.ts +2 -6
  83. package/src/lib/doctor/fixes.ts +55 -6
  84. package/src/lib/doctor/project.ts +0 -236
  85. package/src/lib/doctor/run.ts +311 -0
  86. package/src/lib/doctor/types.ts +6 -5
  87. package/src/lib/errors.ts +65 -0
  88. package/src/lib/parse-args.ts +19 -3
  89. package/src/lib/remix-config.ts +639 -0
  90. package/src/lib/route-map.ts +11 -48
  91. package/template/.agents/skills/remix/SKILL.md +39 -28
  92. package/template/.agents/skills/remix/references/assets-and-browser-modules.md +53 -10
  93. package/template/.agents/skills/remix/references/auth-and-sessions.md +5 -5
  94. package/template/.agents/skills/remix/references/data-and-validation.md +15 -15
  95. package/template/.agents/skills/remix/references/hydration-frames-navigation.md +54 -8
  96. package/template/.agents/skills/remix/references/middleware-and-server.md +68 -6
  97. package/template/.agents/skills/remix/references/mixins-styling-events.md +2 -0
  98. package/template/.agents/skills/remix/references/routing-and-controllers.md +8 -8
  99. package/template/.agents/skills/remix/references/testing-patterns.md +19 -18
  100. package/template/AGENTS.md +6 -3
  101. package/template/README.md +6 -3
  102. package/template/app/actions/controller.tsx +1 -1
  103. package/template/app/{ui → actions}/document.tsx +7 -5
  104. package/template/app/{ui/scaffold-home-page.tsx → actions/home-page.tsx} +2 -3
  105. package/template/app/actions/public/entry.ts +48 -0
  106. package/template/app/{assets → actions/public}/prompt-button.tsx +29 -25
  107. package/template/app/assets.ts +19 -8
  108. package/template/app/middleware/render.tsx +29 -1
  109. package/template/hmr.ts +46 -0
  110. package/template/package.json +4 -3
  111. package/template/server.ts +8 -1
  112. package/template/tsconfig.json +1 -1
  113. package/dist/lib/doctor/controller-fix-plans.d.ts +0 -4
  114. package/dist/lib/doctor/controller-fix-plans.d.ts.map +0 -1
  115. package/dist/lib/doctor/controller-fix-plans.js +0 -119
  116. package/dist/lib/doctor/controller-placeholders.d.ts +0 -3
  117. package/dist/lib/doctor/controller-placeholders.d.ts.map +0 -1
  118. package/dist/lib/doctor/controller-placeholders.js +0 -52
  119. package/src/lib/doctor/controller-fix-plans.ts +0 -168
  120. package/src/lib/doctor/controller-placeholders.ts +0 -70
  121. package/template/app/assets/entry.ts +0 -8
package/README.md CHANGED
@@ -7,9 +7,11 @@ Command-line interface for creating and managing Remix projects.
7
7
  - Create new Remix projects with `npx remix@next new` or installed `remix new`
8
8
  - Print shell completion scripts with `remix completion`
9
9
  - Check project environment and Remix app conventions with `remix doctor`
10
- - Create low-risk project and controller files with `remix doctor --fix`
10
+ - Apply available low-risk project fixes with `remix doctor --fix`
11
+ - Manage the current app database with `remix db`
11
12
  - Inspect the current app route tree with `remix routes`
12
13
  - Run project tests with `remix test`
14
+ - Configure commands with a static, commented `remix.json` file
13
15
  - Print the current Remix version with `remix version`
14
16
  - Use the same CLI through the `remix` package or the `remix/cli` API
15
17
  - Scaffold a starter app that matches the Remix project layout conventions
@@ -47,6 +49,9 @@ remix new my-remix-app
47
49
  remix completion bash >> ~/.bashrc
48
50
  remix doctor
49
51
  remix doctor --fix
52
+ remix db migrate
53
+ remix db status
54
+ remix db reset --force
50
55
  remix routes
51
56
  remix routes --table
52
57
  remix routes --table --no-headers
@@ -64,6 +69,9 @@ await runRemix(['new', 'my-remix-app'])
64
69
  await runRemix(['completion', 'bash'])
65
70
  await runRemix(['doctor'])
66
71
  await runRemix(['doctor', '--fix'])
72
+ await runRemix(['db', 'migrate'])
73
+ await runRemix(['db', 'status'])
74
+ await runRemix(['db', 'reset', '--force'])
67
75
  await runRemix(['routes'])
68
76
  await runRemix(['routes', '--table'])
69
77
  await runRemix(['routes', '--table', '--no-headers'])
@@ -71,8 +79,104 @@ await runRemix(['test'])
71
79
  await runRemix(['version'])
72
80
  ```
73
81
 
82
+ Destructive database commands (`remix db wipe` and `remix db reset`) refuse to run without `--force`.
83
+
74
84
  `runRemix()` returns the CLI exit code as a promise.
75
85
 
86
+ ## Configuration
87
+
88
+ The CLI loads an optional `remix.json`. The file is parsed as JSONC, so it may contain comments and
89
+ trailing commas. Every top-level field is optional:
90
+
91
+ ```jsonc
92
+ {
93
+ "$schema": "https://remix.run/schemas/remix.json",
94
+
95
+ "db": {
96
+ "adapter": {
97
+ "type": "sqlite",
98
+ "filename": { "env": "DATABASE_URL", "default": "./db/app.sqlite" },
99
+ "foreignKeys": true,
100
+ "busyTimeout": 5000,
101
+ },
102
+ "migrations": {
103
+ "directory": "./db/migrations",
104
+ "journalTable": "data_table_migrations",
105
+ },
106
+ "seed": "./db/seed.sql",
107
+ },
108
+
109
+ "doctor": {
110
+ "strict": true,
111
+ },
112
+
113
+ "test": {
114
+ // Test discovery
115
+ "files": ["**/*.test{,.browser,.e2e}.{ts,tsx}"],
116
+ "browserFiles": ["**/*.test.browser.{ts,tsx}"],
117
+ "e2eFiles": ["**/*.test.e2e.{ts,tsx}"],
118
+ "exclude": ["node_modules/**", "dist/**"],
119
+ "type": ["server", "browser", "e2e"],
120
+ "only": ["/checkout/i"],
121
+
122
+ // Test execution
123
+ "concurrency": 4,
124
+ "pool": "forks",
125
+ "setup": "./test/setup.ts",
126
+ "watch": false,
127
+
128
+ // Playwright
129
+ "playwright": {
130
+ "echo": false,
131
+ "open": false,
132
+ "configFile": "./playwright.config.ts",
133
+ "projects": ["chromium", "firefox"],
134
+ },
135
+
136
+ // Output
137
+ "reporter": "spec",
138
+ "quiet": false,
139
+
140
+ // Coverage
141
+ "coverage": {
142
+ "enabled": true,
143
+ "dir": ".coverage",
144
+ "include": ["app/**"],
145
+ "exclude": ["**/*.test.*"],
146
+ "branches": 80,
147
+ "functions": 80,
148
+ "lines": 80,
149
+ "statements": 80,
150
+ },
151
+ },
152
+ }
153
+ ```
154
+
155
+ Explicit command flags and positional arguments override configured values. Repeated flags replace
156
+ configured arrays, while nested Playwright and coverage settings merge by field. Relative paths and
157
+ globs are resolved from the directory containing the config file. Use `remix doctor --no-strict` to
158
+ disable configured strict mode for one run.
159
+
160
+ `remix db` requires `db.adapter`. Adapters use `type: "sqlite"`, `type: "postgres"`, or
161
+ `type: "mysql"`; PostgreSQL uses `connectionString` and MySQL uses `uri`. A connection value may be
162
+ a string or an object naming an environment variable with an optional default. `db.seed` names a
163
+ SQL file that `remix db seed` and `remix db reset` run against the database. Database flags such as
164
+ `--migrations`, `--seed`, `--journal-table`, and `--connection-env` override the corresponding
165
+ config for one invocation. When no global `--config` is provided, database commands find the
166
+ nearest `remix.json` by walking up from the working directory.
167
+
168
+ Use the global `--config` option to select another JSONC file. The option itself is resolved from the
169
+ CLI working directory and may appear before or after the command:
170
+
171
+ ```sh
172
+ remix --config ./config/remix.ci.json test
173
+ remix test --config ./config/remix.ci.json
174
+ ```
175
+
176
+ A missing default `remix.json` is ignored. A missing explicitly selected file, malformed JSONC,
177
+ unknown property, or invalid value is reported as a CLI error. The optional `$schema` field enables
178
+ editor completion and validation; it has no runtime effect.
179
+
76
180
  ## License
77
181
 
78
182
  See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { runRemix } from "./lib/cli.js";
1
+ export { runRemix } from './lib/cli.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Walks up from `startDir` looking for the closest directory that contains
3
+ * `relativeFilePath`.
4
+ *
5
+ * @param startDir Directory the walk starts from.
6
+ * @param relativeFilePath Slash-separated app file path, for example `app/routes.ts`.
7
+ * @returns The closest ancestor directory that contains the file, or `null`
8
+ * when no ancestor contains it.
9
+ */
10
+ export declare function findAppRoot(startDir: string, relativeFilePath: string): Promise<string | null>;
11
+ //# sourceMappingURL=app-root.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-root.d.ts","sourceRoot":"","sources":["../../src/lib/app-root.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgBxB"}
@@ -0,0 +1,38 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ /**
4
+ * Walks up from `startDir` looking for the closest directory that contains
5
+ * `relativeFilePath`.
6
+ *
7
+ * @param startDir Directory the walk starts from.
8
+ * @param relativeFilePath Slash-separated app file path, for example `app/routes.ts`.
9
+ * @returns The closest ancestor directory that contains the file, or `null`
10
+ * when no ancestor contains it.
11
+ */
12
+ export async function findAppRoot(startDir, relativeFilePath) {
13
+ let relativeSegments = relativeFilePath.split('/');
14
+ let currentDir = path.resolve(startDir);
15
+ while (true) {
16
+ if (await pathExists(path.join(currentDir, ...relativeSegments))) {
17
+ return currentDir;
18
+ }
19
+ let parentDir = path.dirname(currentDir);
20
+ if (parentDir === currentDir) {
21
+ return null;
22
+ }
23
+ currentDir = parentDir;
24
+ }
25
+ }
26
+ async function pathExists(filePath) {
27
+ try {
28
+ await fs.access(filePath);
29
+ return true;
30
+ }
31
+ catch (error) {
32
+ let nodeError = error;
33
+ if (nodeError.code === 'ENOENT') {
34
+ return false;
35
+ }
36
+ throw error;
37
+ }
38
+ }
@@ -3,8 +3,8 @@ import * as path from 'node:path';
3
3
  import * as process from 'node:process';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import semver from 'semver';
6
- import { appNameUnavailable, invalidPackageName, targetDirectoryNotEmpty, targetPathNotDirectory, } from "./errors.js";
7
- import { runProgressStep } from "./reporter.js";
6
+ import { appNameUnavailable, invalidPackageName, targetDirectoryNotEmpty, targetPathNotDirectory, } from './errors.js';
7
+ import { runProgressStep } from './reporter.js';
8
8
  const MODULE_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
9
9
  const PACKAGE_TEMPLATE_DIRECTORY = path.resolve(MODULE_DIRECTORY, '../../template');
10
10
  const IS_RUNNING_FROM_SRC = path.extname(new URL(import.meta.url).pathname) === '.ts';
@@ -1,9 +1,15 @@
1
+ import { type RemixConfig } from './remix-config.ts';
1
2
  interface ResolveCliContextOptions {
3
+ configPath?: string;
2
4
  cwd?: string;
3
5
  remixVersion?: string;
4
6
  }
5
7
  export interface CliContext {
8
+ /** Explicit Remix configuration path selected by the caller. */
9
+ configPath?: string;
6
10
  cwd: string;
11
+ /** Loads and validates the Remix config file, memoizing the result. */
12
+ loadConfig(): Promise<RemixConfig>;
7
13
  remixVersion?: string;
8
14
  }
9
15
  export declare function resolveCliContext(options?: ResolveCliContextOptions): Promise<CliContext>;
@@ -1 +1 @@
1
- {"version":3,"file":"cli-context.d.ts","sourceRoot":"","sources":["../../src/lib/cli-context.ts"],"names":[],"mappings":"AAKA,UAAU,wBAAwB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,iBAAiB,CACrC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,UAAU,CAAC,CAQrB"}
1
+ {"version":3,"file":"cli-context.d.ts","sourceRoot":"","sources":["../../src/lib/cli-context.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAErE,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,uEAAuE;IACvE,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC,CAAA;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,iBAAiB,CACrC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,UAAU,CAAC,CAmBrB"}
@@ -1,11 +1,22 @@
1
1
  import * as path from 'node:path';
2
2
  import * as process from 'node:process';
3
- import { resolveDefaultRemixVersion } from "./remix-version.js";
3
+ import { resolveDefaultRemixVersion } from './remix-version.js';
4
+ import { loadRemixConfig } from './remix-config.js';
4
5
  export async function resolveCliContext(options = {}) {
5
6
  let cwd = resolveCwd(options.cwd);
6
7
  let remixVersion = normalizeRemixVersion(options.remixVersion);
8
+ let configPromise;
9
+ let loadConfig = () => (configPromise ??= loadRemixConfig(cwd, options.configPath));
10
+ // Validate an explicitly selected config file up front so every command
11
+ // fails fast on a bad --config path. The default remix.json is loaded
12
+ // lazily by the commands that read it, so an invalid file doesn't break
13
+ // unrelated commands like help, version, or shell completion.
14
+ if (options.configPath !== undefined)
15
+ await loadConfig();
7
16
  return {
17
+ configPath: options.configPath,
8
18
  cwd,
19
+ loadConfig,
9
20
  remixVersion: remixVersion ?? (await resolveDefaultRemixVersion(cwd)),
10
21
  };
11
22
  }
package/dist/lib/cli.d.ts CHANGED
@@ -15,8 +15,9 @@ export interface RunRemixOptions {
15
15
  }
16
16
  /**
17
17
  * Entry point for the `remix` CLI. Parses `argv`, dispatches to the matching
18
- * subcommand (`new`, `doctor`, `routes`, `test`, `version`, `completion`,
19
- * `help`), and resolves with the exit code the process should use.
18
+ * subcommand (`new`, `db`, `doctor`, `routes`, `test`, `version`,
19
+ * `completion`, `help`), and resolves with the exit code the process should
20
+ * use.
20
21
  *
21
22
  * @param argv Argument vector to parse, excluding the node and script paths
22
23
  * (default `process.argv.slice(2)`).
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/lib/cli.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,GAAE,MAAM,EAA0B,EACtC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CA0BjB"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/lib/cli.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,GAAE,MAAM,EAA0B,EACtC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CA8BjB"}
package/dist/lib/cli.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import * as process from 'node:process';
2
- import { getCliHelpText, runHelpCommand } from "./commands/help.js";
3
- import { resolveCliContext } from "./cli-context.js";
4
- import { renderCliError, unknownCommand } from "./errors.js";
5
- import { configureColors, restoreTerminalFormatting } from "./terminal.js";
2
+ import { getCliHelpText, runHelpCommand } from './commands/help.js';
3
+ import { resolveCliContext } from './cli-context.js';
4
+ import { missingOptionValue, renderCliError, toCliError, unknownCommand } from './errors.js';
5
+ import { configureColors, restoreTerminalFormatting } from './terminal.js';
6
6
  /**
7
7
  * Entry point for the `remix` CLI. Parses `argv`, dispatches to the matching
8
- * subcommand (`new`, `doctor`, `routes`, `test`, `version`, `completion`,
9
- * `help`), and resolves with the exit code the process should use.
8
+ * subcommand (`new`, `db`, `doctor`, `routes`, `test`, `version`,
9
+ * `completion`, `help`), and resolves with the exit code the process should
10
+ * use.
10
11
  *
11
12
  * @param argv Argument vector to parse, excluding the node and script paths
12
13
  * (default `process.argv.slice(2)`).
@@ -22,12 +23,12 @@ import { configureColors, restoreTerminalFormatting } from "./terminal.js";
22
23
  * ```
23
24
  */
24
25
  export async function runRemix(argv = process.argv.slice(2), options = {}) {
25
- let context = await resolveCliContext(options);
26
26
  try {
27
27
  argv = stripLeadingSeparators(argv);
28
28
  let globalOptions = extractGlobalOptions(argv);
29
29
  argv = stripLeadingSeparators(globalOptions.argv);
30
30
  configureColors({ disabled: globalOptions.noColor });
31
+ let context = await resolveCliContext({ ...options, configPath: globalOptions.configPath });
31
32
  if (argv.length === 0) {
32
33
  process.stdout.write(getCliHelpText());
33
34
  return 0;
@@ -39,6 +40,10 @@ export async function runRemix(argv = process.argv.slice(2), options = {}) {
39
40
  }
40
41
  return await runCommand(command, rest, context);
41
42
  }
43
+ catch (error) {
44
+ process.stderr.write(renderCliError(toCliError(error), { helpText: getCliHelpText(process.stderr) }));
45
+ return 1;
46
+ }
42
47
  finally {
43
48
  restoreTerminalFormatting();
44
49
  }
@@ -54,31 +59,35 @@ async function runCommand(command, argv, context) {
54
59
  return runHelpCommand(argv);
55
60
  }
56
61
  if (command === '-v' || command === '--version') {
57
- let { runVersionCommand } = await import("./commands/version.js");
62
+ let { runVersionCommand } = await import('./commands/version.js');
58
63
  return runVersionCommand([], context);
59
64
  }
60
65
  if (command === 'new') {
61
- let { runNewCommand } = await import("./commands/new.js");
66
+ let { runNewCommand } = await import('./commands/new.js');
62
67
  return runNewCommand(argv, context);
63
68
  }
64
69
  if (command === 'completion') {
65
- let { runCompletionCommand } = await import("./commands/completion.js");
70
+ let { runCompletionCommand } = await import('./commands/completion.js');
66
71
  return runCompletionCommand(argv);
67
72
  }
68
73
  if (command === 'doctor') {
69
- let { runDoctorCommand } = await import("./commands/doctor.js");
74
+ let { runDoctorCommand } = await import('./commands/doctor.js');
70
75
  return runDoctorCommand(argv, context);
71
76
  }
77
+ if (command === 'db') {
78
+ let { runDbCommand } = await import('./commands/db.js');
79
+ return runDbCommand(argv, context);
80
+ }
72
81
  if (command === 'routes') {
73
- let { runRoutesCommand } = await import("./commands/routes.js");
82
+ let { runRoutesCommand } = await import('./commands/routes.js');
74
83
  return runRoutesCommand(argv, context);
75
84
  }
76
85
  if (command === 'test') {
77
- let { runTestCommand } = await import("./commands/test.js");
86
+ let { runTestCommand } = await import('./commands/test.js');
78
87
  return runTestCommand(argv, context);
79
88
  }
80
89
  if (command === 'version') {
81
- let { runVersionCommand } = await import("./commands/version.js");
90
+ let { runVersionCommand } = await import('./commands/version.js');
82
91
  return runVersionCommand(argv, context);
83
92
  }
84
93
  process.stderr.write(renderCliError(unknownCommand(command), { helpText: getCliHelpText(process.stderr) }));
@@ -86,6 +95,7 @@ async function runCommand(command, argv, context) {
86
95
  }
87
96
  function extractGlobalOptions(argv) {
88
97
  let filteredArgv = [];
98
+ let configPath;
89
99
  let noColor = false;
90
100
  for (let index = 0; index < argv.length; index++) {
91
101
  let arg = argv[index];
@@ -97,10 +107,28 @@ function extractGlobalOptions(argv) {
97
107
  noColor = true;
98
108
  continue;
99
109
  }
110
+ if (arg === '--config') {
111
+ let value = argv[index + 1];
112
+ if (value == null || value.length === 0 || value.startsWith('-')) {
113
+ throw missingOptionValue('--config');
114
+ }
115
+ configPath = value;
116
+ index++;
117
+ continue;
118
+ }
119
+ if (arg.startsWith('--config=')) {
120
+ let value = arg.slice('--config='.length);
121
+ if (value.length === 0) {
122
+ throw missingOptionValue('--config');
123
+ }
124
+ configPath = value;
125
+ continue;
126
+ }
100
127
  filteredArgv.push(arg);
101
128
  }
102
129
  return {
103
130
  argv: filteredArgv,
131
+ configPath,
104
132
  noColor,
105
133
  };
106
134
  }
@@ -1,8 +1,8 @@
1
1
  import * as process from 'node:process';
2
- import { getCompletionResult, getCompletionScript, isCompletionShell, renderCompletionResult, } from "../completion.js";
3
- import { invalidCompletionRequest, renderCliError, toCliError, unknownCompletionShell, } from "../errors.js";
4
- import { formatHelpText } from "../help-text.js";
5
- import { parseArgs } from "../parse-args.js";
2
+ import { getCompletionResult, getCompletionScript, isCompletionShell, renderCompletionResult, } from '../completion.js';
3
+ import { invalidCompletionRequest, renderCliError, toCliError, unknownCompletionShell, } from '../errors.js';
4
+ import { formatHelpText } from '../help-text.js';
5
+ import { parseArgs } from '../parse-args.js';
6
6
  export async function runCompletionCommand(argv) {
7
7
  if (argv.length === 0) {
8
8
  process.stdout.write(getCompletionCommandHelpText());
@@ -0,0 +1,4 @@
1
+ import type { CliContext } from '../cli-context.ts';
2
+ export declare function runDbCommand(argv: string[], context: CliContext): Promise<number>;
3
+ export declare function getDbCommandHelpText(target?: NodeJS.WriteStream): string;
4
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/lib/commands/db.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AA6BnD,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBvF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,MAAM,CAAC,WAA4B,GAAG,MAAM,CA0CxF"}