@contentrail/cli 0.0.0-stage → 0.1.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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -2
  3. package/bin/contentrail.js +5 -0
  4. package/dist/cli.d.ts +7 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +203 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/collections/load.d.ts +6 -0
  9. package/dist/collections/load.d.ts.map +1 -0
  10. package/dist/collections/load.js +57 -0
  11. package/dist/collections/load.js.map +1 -0
  12. package/dist/commands/build.d.ts +5 -0
  13. package/dist/commands/build.d.ts.map +1 -0
  14. package/dist/commands/build.js +46 -0
  15. package/dist/commands/build.js.map +1 -0
  16. package/dist/commands/doctor.d.ts +4 -0
  17. package/dist/commands/doctor.d.ts.map +1 -0
  18. package/dist/commands/doctor.js +136 -0
  19. package/dist/commands/doctor.js.map +1 -0
  20. package/dist/commands/init.d.ts +11 -0
  21. package/dist/commands/init.d.ts.map +1 -0
  22. package/dist/commands/init.js +129 -0
  23. package/dist/commands/init.js.map +1 -0
  24. package/dist/commands/status.d.ts +4 -0
  25. package/dist/commands/status.d.ts.map +1 -0
  26. package/dist/commands/status.js +67 -0
  27. package/dist/commands/status.js.map +1 -0
  28. package/dist/commands/validate.d.ts +9 -0
  29. package/dist/commands/validate.d.ts.map +1 -0
  30. package/dist/commands/validate.js +84 -0
  31. package/dist/commands/validate.js.map +1 -0
  32. package/dist/config/load.d.ts +11 -0
  33. package/dist/config/load.d.ts.map +1 -0
  34. package/dist/config/load.js +33 -0
  35. package/dist/config/load.js.map +1 -0
  36. package/dist/config/schema.d.ts +3 -0
  37. package/dist/config/schema.d.ts.map +1 -0
  38. package/dist/config/schema.js +34 -0
  39. package/dist/config/schema.js.map +1 -0
  40. package/dist/config/types.d.ts +14 -0
  41. package/dist/config/types.d.ts.map +1 -0
  42. package/dist/config/types.js +8 -0
  43. package/dist/config/types.js.map +1 -0
  44. package/dist/detect/framework.d.ts +13 -0
  45. package/dist/detect/framework.d.ts.map +1 -0
  46. package/dist/detect/framework.js +52 -0
  47. package/dist/detect/framework.js.map +1 -0
  48. package/dist/editor/validate-config.d.ts +10 -0
  49. package/dist/editor/validate-config.d.ts.map +1 -0
  50. package/dist/editor/validate-config.js +135 -0
  51. package/dist/editor/validate-config.js.map +1 -0
  52. package/dist/exit-codes.d.ts +9 -0
  53. package/dist/exit-codes.d.ts.map +1 -0
  54. package/dist/exit-codes.js +8 -0
  55. package/dist/exit-codes.js.map +1 -0
  56. package/dist/index.d.ts +11 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +11 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/util/fs.d.ts +7 -0
  61. package/dist/util/fs.d.ts.map +1 -0
  62. package/dist/util/fs.js +27 -0
  63. package/dist/util/fs.js.map +1 -0
  64. package/dist/util/paths.d.ts +7 -0
  65. package/dist/util/paths.d.ts.map +1 -0
  66. package/dist/util/paths.js +23 -0
  67. package/dist/util/paths.js.map +1 -0
  68. package/dist/util/print.d.ts +7 -0
  69. package/dist/util/print.d.ts.map +1 -0
  70. package/dist/util/print.js +14 -0
  71. package/dist/util/print.js.map +1 -0
  72. package/dist/util/redact.d.ts +10 -0
  73. package/dist/util/redact.d.ts.map +1 -0
  74. package/dist/util/redact.js +19 -0
  75. package/dist/util/redact.js.map +1 -0
  76. package/dist/util/spawn.d.ts +11 -0
  77. package/dist/util/spawn.d.ts.map +1 -0
  78. package/dist/util/spawn.js +32 -0
  79. package/dist/util/spawn.js.map +1 -0
  80. package/package.json +52 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ContentRail contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,82 @@
1
- # Temporary Holding Version
1
+ # `@contentrail/cli`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Node.js CLI for ContentRail local development (ADR 020).
4
+
5
+ Requires **Node.js ≥ 22**. Supported frameworks: **Astro** and **Vite**
6
+ (verified with Astro **7.3.8** and Vite **8.3.5**; `@contentrail/astro` needs
7
+ Node ≥ **22.12**).
8
+
9
+ ## Install
10
+
11
+ > **Not on the public npm registry yet.** Use the monorepo CLI until publication
12
+ > is authorized (`docs/PUBLISHING.md`).
13
+
14
+ ### Monorepo (current)
15
+
16
+ ```sh
17
+ pnpm install
18
+ pnpm --filter @contentrail/cli build
19
+ pnpm exec contentrail --help
20
+ ```
21
+
22
+ ### Intended after first public `0.1.0` release
23
+
24
+ ```sh
25
+ pnpm add -D @contentrail/cli
26
+ pnpm exec contentrail --help
27
+ ```
28
+
29
+ ## Commands
30
+
31
+ | Command | Purpose |
32
+ | ---------------------- | ----------------------------------------------- |
33
+ | `contentrail init` | Scaffold config, sample collection, sample JSON |
34
+ | `contentrail validate` | Validate config + local JSON content |
35
+ | `contentrail build` | Validate, then run `package.json` build script |
36
+ | `contentrail doctor` | Diagnose setup (no secret values printed) |
37
+ | `contentrail status` | Summarize local readiness |
38
+
39
+ `publish` / `rollback` are **deferred** — use the Worker API or editor.
40
+
41
+ ### Exit codes
42
+
43
+ | Code | Meaning |
44
+ | ---- | --------------------------------- |
45
+ | 0 | Success |
46
+ | 1 | Failure (validation/build/doctor) |
47
+ | 2 | Usage error |
48
+ | 3 | Configuration error |
49
+
50
+ ## Configuration (`contentrail.config.json`)
51
+
52
+ ```json
53
+ {
54
+ "contentRoot": "content",
55
+ "framework": "auto",
56
+ "collections": "content/config.ts",
57
+ "buildScript": "build",
58
+ "editorConfig": "contentrail.editor.json",
59
+ "publishApiUrl": "https://your-worker.example"
60
+ }
61
+ ```
62
+
63
+ - Paths are relative to the project root and cannot escape it.
64
+ - Do not put tokens or credentials in this file.
65
+ - `publishApiUrl` is optional and only checked structurally by doctor/status.
66
+
67
+ ## Typical workflow
68
+
69
+ 1. Create an Astro or Vite app (or use a monorepo `examples/*` app).
70
+ 2. Add `@contentrail/core` + `zod`, plus `@contentrail/astro` or `@contentrail/vite`
71
+ (workspace links today; `pnpm add` from npm only after public release).
72
+ 3. `pnpm exec contentrail init --framework vite` (or `astro`)
73
+ 4. Edit collections / JSON under `content/`
74
+ 5. `pnpm exec contentrail validate`
75
+ 6. Framework `dev` / `contentrail build`
76
+ 7. `contentrail doctor` when something fails
77
+
78
+ ## Limitations
79
+
80
+ - No live Access/Worker publish from the CLI yet (ADR 020).
81
+ - Collection TypeScript modules are loaded via **jiti**.
82
+ - Lint/format tooling remains a separate monorepo gap.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from "../dist/cli.js";
3
+
4
+ const code = await runCli(process.argv.slice(2));
5
+ process.exitCode = code;
package/dist/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { ExitCode } from "./exit-codes.js";
2
+ export declare function runCli(argv: readonly string[], options?: {
3
+ cwd?: string;
4
+ stdout?: NodeJS.WritableStream;
5
+ stderr?: NodeJS.WritableStream;
6
+ }): Promise<ExitCode>;
7
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAwE3C,wBAAsB,MAAM,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE;IACR,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC,GACA,OAAO,CAAC,QAAQ,CAAC,CAsFnB"}
package/dist/cli.js ADDED
@@ -0,0 +1,203 @@
1
+ import path from "node:path";
2
+ import { runBuild } from "./commands/build.js";
3
+ import { runDoctor } from "./commands/doctor.js";
4
+ import { runInit } from "./commands/init.js";
5
+ import { runStatus } from "./commands/status.js";
6
+ import { runValidate } from "./commands/validate.js";
7
+ import { loadProject } from "./config/load.js";
8
+ import { ExitCode } from "./exit-codes.js";
9
+ import { createLogger } from "./util/print.js";
10
+ import { findProjectRoot } from "./util/paths.js";
11
+ const VERSION = "0.1.0";
12
+ const HELP = `ContentRail CLI — local developer tooling
13
+
14
+ Usage:
15
+ contentrail <command> [options]
16
+
17
+ Commands:
18
+ init Initialize ContentRail files in an Astro or Vite project
19
+ validate Validate configuration and local JSON content
20
+ build Validate then run the project build script
21
+ doctor Diagnose common setup problems
22
+ status Summarize local project state
23
+
24
+ Global options:
25
+ -h, --help Show help
26
+ -V, --version Show version
27
+ -C, --cwd <dir> Project directory (default: current working directory)
28
+
29
+ init options:
30
+ --framework <astro|vite> Force framework (default: auto-detect)
31
+ --force Overwrite existing generated files
32
+ --with-editor Also write contentrail.editor.json
33
+ -y, --yes Non-interactive; accept defaults
34
+
35
+ Exit codes:
36
+ 0 success
37
+ 1 failure (validation/build/doctor)
38
+ 2 usage error
39
+ 3 configuration error
40
+
41
+ Notes:
42
+ publish / rollback are not implemented in the CLI (ADR 020).
43
+ Use the authenticated Worker API or editor for remote publishing.
44
+ `;
45
+ function printCommandHelp(command) {
46
+ switch (command) {
47
+ case "init":
48
+ return `Usage: contentrail init [--framework astro|vite] [--force] [--with-editor] [-y]
49
+
50
+ Creates contentrail.config.json, a sample collection module, and sample JSON.
51
+ Never overwrites existing files unless --force is set.
52
+ Does not require publishing credentials.`;
53
+ case "validate":
54
+ return `Usage: contentrail validate
55
+
56
+ Loads collections, validates local JSON via @contentrail/reader, checks
57
+ duplicate slugs when present, and validates optional editor metadata.`;
58
+ case "build":
59
+ return `Usage: contentrail build
60
+
61
+ Runs validate, then the package.json script named by buildScript (default: build).`;
62
+ case "doctor":
63
+ return `Usage: contentrail doctor
64
+
65
+ Checks Node version, framework deps, config, content, validation, and whether
66
+ remote env var *names* are set (values never printed).`;
67
+ case "status":
68
+ return `Usage: contentrail status
69
+
70
+ Reports framework, collections, validation, build readiness, and whether a
71
+ publishApiUrl is configured (does not probe live deployment health).`;
72
+ default:
73
+ return HELP;
74
+ }
75
+ }
76
+ export async function runCli(argv, options) {
77
+ const log = createLogger(options?.stdout, options?.stderr);
78
+ const baseCwd = options?.cwd ?? process.cwd();
79
+ try {
80
+ const { command, flags, cwd } = parseArgv(argv, baseCwd);
81
+ if (flags.version) {
82
+ log.info(VERSION);
83
+ return ExitCode.Success;
84
+ }
85
+ if (command === undefined || command === "help" || flags.help) {
86
+ log.info(command !== undefined && command !== "help"
87
+ ? printCommandHelp(command)
88
+ : HELP);
89
+ return ExitCode.Success;
90
+ }
91
+ const projectRoot = findProjectRoot(cwd);
92
+ switch (command) {
93
+ case "init": {
94
+ const framework = flags.framework;
95
+ if (framework !== undefined &&
96
+ framework !== "astro" &&
97
+ framework !== "vite") {
98
+ log.error('--framework must be "astro" or "vite".');
99
+ return ExitCode.Usage;
100
+ }
101
+ return runInit({
102
+ projectRoot,
103
+ ...(framework !== undefined ? { framework } : {}),
104
+ force: flags.force,
105
+ withEditor: flags.withEditor,
106
+ yes: flags.yes,
107
+ }, log);
108
+ }
109
+ case "validate": {
110
+ const project = await loadProject(projectRoot);
111
+ return (await runValidate(project, log)).code;
112
+ }
113
+ case "build": {
114
+ const project = await loadProject(projectRoot);
115
+ return runBuild(project, log);
116
+ }
117
+ case "doctor":
118
+ return runDoctor(projectRoot, log);
119
+ case "status":
120
+ return runStatus(projectRoot, log);
121
+ case "publish":
122
+ case "rollback":
123
+ log.error(`Command "${command}" is deferred (ADR 020). Use the Worker API or editor for authenticated publishing.`);
124
+ return ExitCode.Usage;
125
+ default:
126
+ log.error(`Unknown command "${command}". Run contentrail --help.`);
127
+ return ExitCode.Usage;
128
+ }
129
+ }
130
+ catch (error) {
131
+ const message = error instanceof Error ? error.message : String(error);
132
+ log.error(message);
133
+ if (/Unknown option|Unexpected argument|requires a directory|--framework requires/i.test(message)) {
134
+ return ExitCode.Usage;
135
+ }
136
+ if (/contentrail\.config\.json|Invalid contentrail|collections module|escapes the project/i.test(message)) {
137
+ return ExitCode.Config;
138
+ }
139
+ return ExitCode.Failure;
140
+ }
141
+ }
142
+ function parseArgv(argv, baseCwd) {
143
+ let command;
144
+ let cwd = baseCwd;
145
+ const flags = {
146
+ help: false,
147
+ version: false,
148
+ force: false,
149
+ withEditor: false,
150
+ yes: false,
151
+ };
152
+ for (let i = 0; i < argv.length; i += 1) {
153
+ const arg = argv[i];
154
+ if (arg === "--help" || arg === "-h") {
155
+ flags.help = true;
156
+ continue;
157
+ }
158
+ if (arg === "--version" || arg === "-V") {
159
+ flags.version = true;
160
+ continue;
161
+ }
162
+ if (arg === "--force") {
163
+ flags.force = true;
164
+ continue;
165
+ }
166
+ if (arg === "--with-editor") {
167
+ flags.withEditor = true;
168
+ continue;
169
+ }
170
+ if (arg === "--yes" || arg === "-y") {
171
+ flags.yes = true;
172
+ continue;
173
+ }
174
+ if (arg === "--framework") {
175
+ const value = argv[i + 1];
176
+ if (value === undefined || value.startsWith("-")) {
177
+ throw new Error("--framework requires astro or vite.");
178
+ }
179
+ flags.framework = value;
180
+ i += 1;
181
+ continue;
182
+ }
183
+ if (arg === "--cwd" || arg === "-C") {
184
+ const value = argv[i + 1];
185
+ if (value === undefined || value.startsWith("-")) {
186
+ throw new Error(`${arg} requires a directory path.`);
187
+ }
188
+ cwd = path.resolve(baseCwd, value);
189
+ i += 1;
190
+ continue;
191
+ }
192
+ if (arg.startsWith("-")) {
193
+ throw new Error(`Unknown option ${arg}`);
194
+ }
195
+ if (command === undefined) {
196
+ command = arg;
197
+ continue;
198
+ }
199
+ throw new Error(`Unexpected argument "${arg}"`);
200
+ }
201
+ return { command, cwd, flags };
202
+ }
203
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ContentCollection } from "@contentrail/core";
2
+ /**
3
+ * Dynamically load named ContentCollection exports from a JS/TS module.
4
+ */
5
+ export declare function loadCollectionsModule(absoluteModulePath: string): Promise<ContentCollection[]>;
6
+ //# sourceMappingURL=load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/collections/load.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAe3D;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA0D9B"}
@@ -0,0 +1,57 @@
1
+ import { createJiti } from "jiti";
2
+ import { pathExists } from "../util/fs.js";
3
+ function isContentCollection(value) {
4
+ return (value !== null &&
5
+ typeof value === "object" &&
6
+ "name" in value &&
7
+ "schema" in value &&
8
+ typeof value.name === "string" &&
9
+ typeof value.schema?.safeParse ===
10
+ "function");
11
+ }
12
+ /**
13
+ * Dynamically load named ContentCollection exports from a JS/TS module.
14
+ */
15
+ export async function loadCollectionsModule(absoluteModulePath) {
16
+ if (!(await pathExists(absoluteModulePath))) {
17
+ throw new Error(`Collections module not found: ${absoluteModulePath}`);
18
+ }
19
+ const jiti = createJiti(import.meta.url, {
20
+ interopDefault: true,
21
+ });
22
+ const mod = (await jiti.import(absoluteModulePath));
23
+ const collections = [];
24
+ for (const [exportName, value] of Object.entries(mod)) {
25
+ if (exportName === "default" &&
26
+ value !== null &&
27
+ typeof value === "object") {
28
+ for (const [key, nested] of Object.entries(value)) {
29
+ if (isContentCollection(nested)) {
30
+ collections.push(nested);
31
+ }
32
+ else if (nested !== null &&
33
+ typeof nested === "object" &&
34
+ "articles" in nested) {
35
+ // ignore unrelated default bags
36
+ void key;
37
+ }
38
+ }
39
+ continue;
40
+ }
41
+ if (isContentCollection(value)) {
42
+ collections.push(value);
43
+ }
44
+ }
45
+ if (collections.length === 0) {
46
+ throw new Error(`No ContentRail collections exported from ${absoluteModulePath}. Export defineCollection(...) results as named exports.`);
47
+ }
48
+ const names = new Set();
49
+ for (const collection of collections) {
50
+ if (names.has(collection.name)) {
51
+ throw new Error(`Duplicate collection name "${collection.name}" in ${absoluteModulePath}.`);
52
+ }
53
+ names.add(collection.name);
54
+ }
55
+ return collections;
56
+ }
57
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/collections/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,SAAS,mBAAmB,CAAC,KAAc;IACzC,OAAO,CACL,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,MAAM,IAAI,KAAK;QACf,QAAQ,IAAI,KAAK;QACjB,OAAQ,KAA2B,CAAC,IAAI,KAAK,QAAQ;QACrD,OAAQ,KAA6C,CAAC,MAAM,EAAE,SAAS;YACrE,UAAU,CACb,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,kBAA0B;IAE1B,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,iCAAiC,kBAAkB,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;QACvC,cAAc,EAAE,IAAI;KACrB,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAGjD,CAAC;IACF,MAAM,WAAW,GAAwB,EAAE,CAAC;IAE5C,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACtD,IACE,UAAU,KAAK,SAAS;YACxB,KAAK,KAAK,IAAI;YACd,OAAO,KAAK,KAAK,QAAQ,EACzB,CAAC;YACD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CACxC,KAAgC,CACjC,EAAE,CAAC;gBACF,IAAI,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;oBAChC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC3B,CAAC;qBAAM,IACL,MAAM,KAAK,IAAI;oBACf,OAAO,MAAM,KAAK,QAAQ;oBAC1B,UAAU,IAAK,MAAiB,EAChC,CAAC;oBACD,gCAAgC;oBAChC,KAAK,GAAG,CAAC;gBACX,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,4CAA4C,kBAAkB,0DAA0D,CACzH,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,8BAA8B,UAAU,CAAC,IAAI,QAAQ,kBAAkB,GAAG,CAC3E,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { LoadedProject } from "../config/load.js";
2
+ import { ExitCode } from "../exit-codes.js";
3
+ import type { Logger } from "../util/print.js";
4
+ export declare function runBuild(project: LoadedProject, log: Logger): Promise<ExitCode>;
5
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI/C,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,QAAQ,CAAC,CAkDnB"}
@@ -0,0 +1,46 @@
1
+ import { detectPackageManager, readPackageJson } from "../detect/framework.js";
2
+ import { ExitCode } from "../exit-codes.js";
3
+ import { runCommand } from "../util/spawn.js";
4
+ import { runValidate } from "./validate.js";
5
+ export async function runBuild(project, log) {
6
+ const validation = await runValidate(project, log);
7
+ if (validation.code !== ExitCode.Success) {
8
+ log.error("Build aborted because validation failed.");
9
+ return validation.code;
10
+ }
11
+ const pkg = await readPackageJson(project.projectRoot);
12
+ const script = project.config.buildScript;
13
+ if (pkg?.scripts?.[script] === undefined) {
14
+ log.error(`package.json has no "${script}" script. Set buildScript in contentrail.config.json or add the script.`);
15
+ return ExitCode.Config;
16
+ }
17
+ const pm = await detectPackageManager(project.projectRoot);
18
+ const command = pm === "pnpm" ? "pnpm" : pm === "yarn" ? "yarn" : "npm";
19
+ const args = pm === "pnpm" || pm === "yarn" ? ["run", script] : ["run", script];
20
+ log.info(`Running ${command} ${args.join(" ")} …`);
21
+ let result;
22
+ try {
23
+ result = await runCommand(command, args, { cwd: project.projectRoot });
24
+ }
25
+ catch (error) {
26
+ log.error(`Failed to start build command: ${error instanceof Error ? error.message : String(error)}`);
27
+ return ExitCode.Failure;
28
+ }
29
+ if (result.stdout.trim() !== "") {
30
+ log.info(result.stdout.trimEnd());
31
+ }
32
+ if (result.stderr.trim() !== "") {
33
+ log.warn(result.stderr.trimEnd());
34
+ }
35
+ if (result.signal !== null) {
36
+ log.error(`Build interrupted (${result.signal}).`);
37
+ return ExitCode.Failure;
38
+ }
39
+ if (result.code !== 0) {
40
+ log.error(`Build failed with exit code ${result.code ?? "unknown"}.`);
41
+ return ExitCode.Failure;
42
+ }
43
+ log.info("Build completed successfully.");
44
+ return ExitCode.Success;
45
+ }
46
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { ExitCode } from "../exit-codes.js";
2
+ import type { Logger } from "../util/print.js";
3
+ export declare function runDoctor(projectRoot: string, log: Logger): Promise<ExitCode>;
4
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAW/C,wBAAsB,SAAS,CAC7B,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,QAAQ,CAAC,CAwInB"}
@@ -0,0 +1,136 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { loadProject } from "../config/load.js";
4
+ import { detectFrameworkFromPackage, detectPackageManager, readPackageJson, resolveFramework, } from "../detect/framework.js";
5
+ import { ExitCode } from "../exit-codes.js";
6
+ import { pathExists } from "../util/fs.js";
7
+ import { formatEnvPresence } from "../util/redact.js";
8
+ import { runValidate } from "./validate.js";
9
+ const REMOTE_ENV_HINTS = [
10
+ "CONTENTRAIL_ACCESS_TEAM_DOMAIN",
11
+ "CONTENTRAIL_ACCESS_AUD",
12
+ "GITHUB_TOKEN",
13
+ "R2_ACCESS_KEY_ID",
14
+ "R2_SECRET_ACCESS_KEY",
15
+ ];
16
+ export async function runDoctor(projectRoot, log) {
17
+ let failed = false;
18
+ const recommendations = [];
19
+ const nodeMajor = Number(process.versions.node.split(".")[0]);
20
+ if (Number.isNaN(nodeMajor) || nodeMajor < 22) {
21
+ log.error(`FAIL Node.js >= 22 required (found ${process.versions.node}).`);
22
+ failed = true;
23
+ }
24
+ else {
25
+ log.info(`OK Node.js ${process.versions.node}`);
26
+ }
27
+ const pm = await detectPackageManager(projectRoot);
28
+ if (pm === "unknown") {
29
+ recommendations.push("No lockfile detected (pnpm-lock.yaml / package-lock.json / yarn.lock).");
30
+ }
31
+ else {
32
+ log.info(`OK package manager hint: ${pm}`);
33
+ }
34
+ const pkg = await readPackageJson(projectRoot);
35
+ if (pkg === null) {
36
+ log.error("FAIL package.json missing.");
37
+ return ExitCode.Failure;
38
+ }
39
+ log.info("OK package.json present");
40
+ const detected = detectFrameworkFromPackage(pkg);
41
+ if (detected === "unknown") {
42
+ log.error("FAIL neither Astro nor Vite dependency detected.");
43
+ failed = true;
44
+ }
45
+ else {
46
+ log.info(`OK framework dependency: ${detected}`);
47
+ }
48
+ let project;
49
+ try {
50
+ project = await loadProject(projectRoot);
51
+ log.info(`OK ${path.basename(project.configPath)}`);
52
+ }
53
+ catch (error) {
54
+ log.error(`FAIL config: ${error instanceof Error ? error.message : String(error)}`);
55
+ return ExitCode.Config;
56
+ }
57
+ const framework = resolveFramework(project.config.framework, detected);
58
+ log.info(`OK resolved framework: ${framework}`);
59
+ if (!(await pathExists(project.contentRootAbs))) {
60
+ log.error(`FAIL content root missing: ${project.config.contentRoot}`);
61
+ failed = true;
62
+ }
63
+ else {
64
+ const stat = await fs.stat(project.contentRootAbs);
65
+ if (!stat.isDirectory()) {
66
+ log.error(`FAIL content root is not a directory: ${project.config.contentRoot}`);
67
+ failed = true;
68
+ }
69
+ else {
70
+ log.info(`OK content root: ${project.config.contentRoot}`);
71
+ }
72
+ }
73
+ if (!(await pathExists(project.collectionsAbs))) {
74
+ log.error(`FAIL collections module missing: ${project.config.collections}`);
75
+ failed = true;
76
+ }
77
+ else {
78
+ log.info(`OK collections module: ${project.config.collections}`);
79
+ }
80
+ const validation = await runValidate(project, {
81
+ info: (message) => log.info(` ${message}`),
82
+ warn: log.warn,
83
+ error: (message) => {
84
+ failed = true;
85
+ log.error(`FAIL validation: ${message}`);
86
+ },
87
+ });
88
+ if (validation.code === ExitCode.Success) {
89
+ log.info("OK content validation");
90
+ }
91
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
92
+ if (framework === "astro" && deps["@contentrail/astro"] === undefined) {
93
+ recommendations.push("Add @contentrail/astro for Astro integration.");
94
+ }
95
+ if (framework === "vite" && deps["@contentrail/vite"] === undefined) {
96
+ recommendations.push("Add @contentrail/vite for Vite integration.");
97
+ }
98
+ if (deps["@contentrail/core"] === undefined) {
99
+ recommendations.push("Add @contentrail/core for collection schemas.");
100
+ }
101
+ if (project.config.publishApiUrl !== undefined) {
102
+ try {
103
+ const url = new URL(project.config.publishApiUrl);
104
+ if (url.protocol !== "https:" && url.hostname !== "localhost") {
105
+ recommendations.push("publishApiUrl should use https in non-local environments.");
106
+ }
107
+ log.info(`OK publishApiUrl structure: ${url.origin}`);
108
+ }
109
+ catch {
110
+ log.error("FAIL publishApiUrl is not a valid URL.");
111
+ failed = true;
112
+ }
113
+ }
114
+ else {
115
+ recommendations.push("publishApiUrl is unset — fine for local-only projects; set it when a Worker API exists.");
116
+ }
117
+ log.info("Remote env presence (names only, values never printed):");
118
+ for (const name of REMOTE_ENV_HINTS) {
119
+ const present = process.env[name] !== undefined && process.env[name] !== "";
120
+ log.info(` ${formatEnvPresence(name, present)}`);
121
+ }
122
+ recommendations.push("Missing remote publishing env vars is OK for local validate/build.");
123
+ if (recommendations.length > 0) {
124
+ log.info("Recommendations:");
125
+ for (const item of recommendations) {
126
+ log.info(` - ${item}`);
127
+ }
128
+ }
129
+ if (failed) {
130
+ log.error("Doctor found failures.");
131
+ return ExitCode.Failure;
132
+ }
133
+ log.info("Doctor completed with no failures.");
134
+ return ExitCode.Success;
135
+ }
136
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { ExitCode } from "../exit-codes.js";
2
+ import type { Logger } from "../util/print.js";
3
+ export interface InitOptions {
4
+ readonly projectRoot: string;
5
+ readonly framework?: "astro" | "vite" | "auto";
6
+ readonly force?: boolean;
7
+ readonly withEditor?: boolean;
8
+ readonly yes?: boolean;
9
+ }
10
+ export declare function runInit(options: InitOptions, log: Logger): Promise<ExitCode>;
11
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAsB,OAAO,CAC3B,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,QAAQ,CAAC,CAoKnB"}