octocms 0.1.2 → 0.1.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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  agentsMdSection,
3
3
  agentsMdTemplate
4
- } from "./chunk-I7KNSICQ.js";
4
+ } from "./chunk-VL7NZ3J2.js";
5
5
  import {
6
6
  log
7
7
  } from "./chunk-6PHFHGTZ.js";
@@ -35,4 +35,4 @@ async function agentDocsCommand(projectRoot) {
35
35
  export {
36
36
  agentDocsCommand
37
37
  };
38
- //# sourceMappingURL=agentDocs-Z5BI2Y2G.js.map
38
+ //# sourceMappingURL=agentDocs-GRGCRZBL.js.map
@@ -1,5 +1,5 @@
1
1
  // cli/lib/templates.ts
2
- var adminLayoutTemplate = `import '../../../cms/__generated__/configInit';
2
+ var adminLayoutTemplate = `import '../../cms/__generated__/configInit';
3
3
  import 'octocms/globals.css';
4
4
  import '@mdxeditor/editor/style.css';
5
5
 
@@ -22,14 +22,11 @@ ${gitBlock}
22
22
  mediaFolder: 'public/media',
23
23
  mediaAllowedFormats: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'avif'],
24
24
  collections: {
25
- post: {
26
- label: 'Posts',
27
- hasMany: true,
25
+ helloPage: {
26
+ label: 'Hello Page',
28
27
  fields: {
29
28
  title: { label: 'Title', format: 'string', entryTitle: true, required: true },
30
- slug: { label: 'Slug', format: 'slug', slugSource: 'title', required: true },
31
- body: { label: 'Body', format: 'markdown' },
32
- publishedAt: { label: 'Published At', format: 'datetime', defaultNow: true },
29
+ description: { label: 'Description', format: 'text' },
33
30
  },
34
31
  },
35
32
  },
@@ -52,27 +49,91 @@ const nextConfig: NextConfig = {};
52
49
  export default withOctoCMS(nextConfig, configOctoCMS);
53
50
  `;
54
51
  }
55
- function demoPostJson(id) {
56
- const now = (/* @__PURE__ */ new Date()).toISOString();
52
+ function demoHelloPageJson() {
57
53
  return JSON.stringify(
58
54
  {
59
- sys: { id, type: "post", status: "merged" },
55
+ sys: { id: "0000", type: "helloPage", status: "merged" },
60
56
  fields: {
61
57
  title: "Hello World",
62
- slug: "hello-world",
63
- publishedAt: now
58
+ description: "Welcome to your new OctoCMS site! Edit this content in the CMS admin panel."
64
59
  }
65
60
  },
66
61
  null,
67
62
  2
68
63
  );
69
64
  }
70
- var demoPostMarkdown = `# Hello World
65
+ var helloPageTemplate = `import { query } from 'cms/__generated__/query';
71
66
 
72
- Welcome to your new OctoCMS site! This is a demo post.
67
+ export default async function HelloPage() {
68
+ const page = await query('helloPage').first();
69
+ if (!page) return null;
70
+ return (
71
+ <main>
72
+ <h1>{page.fields.title}</h1>
73
+ <p>{page.fields.description}</p>
74
+ </main>
75
+ );
76
+ }
77
+ `;
78
+ function readmeTemplate(projectName) {
79
+ return `# ${projectName}
80
+
81
+ Built with [OctoCMS](https://octocms.com) \u2014 a file-based CMS on Next.js.
82
+
83
+ ## Setup
84
+
85
+ ### 1. Create a GitHub App
86
+
87
+ Follow the [OctoCMS GitHub App setup guide](https://octocms.com/docs/github-app) to create a GitHub App for authentication.
88
+
89
+ ### 2. Configure environment variables
90
+
91
+ Copy the values from your GitHub App into \`.env.local\`:
92
+
93
+ \`\`\`bash
94
+ # GitHub App credentials (required for CMS auth)
95
+ GITHUB_ID=your_github_app_client_id
96
+ GITHUB_SECRET=your_github_app_client_secret
97
+
98
+ # NextAuth (generate secret: openssl rand -base64 32)
99
+ NEXTAUTH_SECRET=your_nextauth_secret
100
+ NEXTAUTH_URL=http://localhost:3000
73
101
 
74
- Edit this content in the CMS admin panel at \`/cms\`.
102
+ # GitHub repo for content storage (required in production)
103
+ GITHUB_REPO_OWNER=your_github_username_or_org
104
+ GITHUB_REPO_NAME=your_repo_name
105
+
106
+ # Optional: static GitHub token for private repos / higher API rate limits
107
+ # CMS_GITHUB_TOKEN=your_github_pat
108
+ \`\`\`
109
+
110
+ ### 3. Run the dev server
111
+
112
+ \`\`\`bash
113
+ npm run dev
114
+ \`\`\`
115
+
116
+ Open [http://localhost:3000/cms](http://localhost:3000/cms) to access the CMS admin.
117
+ `;
118
+ }
119
+ function envLocalTemplate() {
120
+ return `# GitHub App credentials (required for CMS auth)
121
+ # Create a GitHub App at: https://github.com/settings/apps/new
122
+ GITHUB_ID=
123
+ GITHUB_SECRET=
124
+
125
+ # NextAuth secret \u2014 generate with: openssl rand -base64 32
126
+ NEXTAUTH_SECRET=
127
+ NEXTAUTH_URL=http://localhost:3000
128
+
129
+ # GitHub repo for content storage (required in production)
130
+ GITHUB_REPO_OWNER=
131
+ GITHUB_REPO_NAME=
132
+
133
+ # Optional: static GitHub token for private repos or higher API rate limits
134
+ # CMS_GITHUB_TOKEN=
75
135
  `;
136
+ }
76
137
  var AGENT_DOCS_MARKER = "<!-- octocms:agent-docs -->";
77
138
  function agentsMdSection() {
78
139
  return `${AGENT_DOCS_MARKER}
@@ -95,7 +156,6 @@ function tsconfigPaths() {
95
156
  return {
96
157
  "cms/__generated__": ["./cms/__generated__/index.ts"],
97
158
  "cms/__generated__/*": ["./cms/__generated__/*"],
98
- "octocms/*": ["./octocms/*"],
99
159
  "@/*": ["./src/*"]
100
160
  };
101
161
  }
@@ -105,10 +165,12 @@ export {
105
165
  adminPageTemplate,
106
166
  octoConfigTemplate,
107
167
  nextConfigTemplate,
108
- demoPostJson,
109
- demoPostMarkdown,
168
+ demoHelloPageJson,
169
+ helloPageTemplate,
170
+ readmeTemplate,
171
+ envLocalTemplate,
110
172
  agentsMdSection,
111
173
  agentsMdTemplate,
112
174
  tsconfigPaths
113
175
  };
114
- //# sourceMappingURL=chunk-I7KNSICQ.js.map
176
+ //# sourceMappingURL=chunk-VL7NZ3J2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/lib/templates.ts"],"sourcesContent":["/**\n * File templates used by `octocms init` and `octocms update`.\n */\n\nexport const adminLayoutTemplate = `import '../../cms/__generated__/configInit';\nimport 'octocms/globals.css';\nimport '@mdxeditor/editor/style.css';\n\nexport { AdminLayout as default, metadata } from 'octocms/admin/pages/AdminLayout';\n`;\n\nexport const adminPageTemplate = `export { AdminApp as default } from 'octocms/admin/AdminApp';\n`;\n\nexport function octoConfigTemplate(opts: { projectName: string; baseBranch: string; pointerBranch?: string }): string {\n const gitBlock = opts.pointerBranch\n ? ` git: {\\n baseBranch: '${opts.baseBranch}',\\n publishedPointerBranch: '${opts.pointerBranch}',\\n },`\n : ` git: { baseBranch: '${opts.baseBranch}' },`;\n\n return `import type { Config } from 'octocms/types';\nimport { defineConfig } from 'octocms/config';\n\nconst _typedConfigOctoCMS = defineConfig({\n projectName: '${opts.projectName}',\n${gitBlock}\n contentFolder: 'cms/content',\n mediaFolder: 'public/media',\n mediaAllowedFormats: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'avif'],\n collections: {\n helloPage: {\n label: 'Hello Page',\n fields: {\n title: { label: 'Title', format: 'string', entryTitle: true, required: true },\n description: { label: 'Description', format: 'text' },\n },\n },\n },\n});\n\nexport const configOctoCMS: Config = _typedConfigOctoCMS;\nexport type OctoConfig = typeof _typedConfigOctoCMS;\n`;\n}\n\nexport function nextConfigTemplate(): string {\n return `import type { NextConfig } from 'next';\nimport { withOctoCMS } from 'octocms/config';\nimport { configOctoCMS } from './cms/octocms.config';\n\nexport { configOctoCMS } from './cms/octocms.config';\nexport type { OctoConfig } from './cms/octocms.config';\n\nconst nextConfig: NextConfig = {};\n\nexport default withOctoCMS(nextConfig, configOctoCMS);\n`;\n}\n\nexport function demoHelloPageJson(): string {\n return JSON.stringify(\n {\n sys: { id: '0000', type: 'helloPage', status: 'merged' },\n fields: {\n title: 'Hello World',\n description: 'Welcome to your new OctoCMS site! Edit this content in the CMS admin panel.',\n },\n },\n null,\n 2,\n );\n}\n\nexport const helloPageTemplate = `import { query } from 'cms/__generated__/query';\n\nexport default async function HelloPage() {\n const page = await query('helloPage').first();\n if (!page) return null;\n return (\n <main>\n <h1>{page.fields.title}</h1>\n <p>{page.fields.description}</p>\n </main>\n );\n}\n`;\n\nexport function readmeTemplate(projectName: string): string {\n return `# ${projectName}\n\nBuilt with [OctoCMS](https://octocms.com) — a file-based CMS on Next.js.\n\n## Setup\n\n### 1. Create a GitHub App\n\nFollow the [OctoCMS GitHub App setup guide](https://octocms.com/docs/github-app) to create a GitHub App for authentication.\n\n### 2. Configure environment variables\n\nCopy the values from your GitHub App into \\`.env.local\\`:\n\n\\`\\`\\`bash\n# GitHub App credentials (required for CMS auth)\nGITHUB_ID=your_github_app_client_id\nGITHUB_SECRET=your_github_app_client_secret\n\n# NextAuth (generate secret: openssl rand -base64 32)\nNEXTAUTH_SECRET=your_nextauth_secret\nNEXTAUTH_URL=http://localhost:3000\n\n# GitHub repo for content storage (required in production)\nGITHUB_REPO_OWNER=your_github_username_or_org\nGITHUB_REPO_NAME=your_repo_name\n\n# Optional: static GitHub token for private repos / higher API rate limits\n# CMS_GITHUB_TOKEN=your_github_pat\n\\`\\`\\`\n\n### 3. Run the dev server\n\n\\`\\`\\`bash\nnpm run dev\n\\`\\`\\`\n\nOpen [http://localhost:3000/cms](http://localhost:3000/cms) to access the CMS admin.\n`;\n}\n\nexport function envLocalTemplate(): string {\n return `# GitHub App credentials (required for CMS auth)\n# Create a GitHub App at: https://github.com/settings/apps/new\nGITHUB_ID=\nGITHUB_SECRET=\n\n# NextAuth secret — generate with: openssl rand -base64 32\nNEXTAUTH_SECRET=\nNEXTAUTH_URL=http://localhost:3000\n\n# GitHub repo for content storage (required in production)\nGITHUB_REPO_OWNER=\nGITHUB_REPO_NAME=\n\n# Optional: static GitHub token for private repos or higher API rate limits\n# CMS_GITHUB_TOKEN=\n`;\n}\n\nconst AGENT_DOCS_MARKER = '<!-- octocms:agent-docs -->';\n\nexport function agentsMdSection(): string {\n return `${AGENT_DOCS_MARKER}\n## OctoCMS — AI Content Management\n\nFor tasks that involve creating, editing, or deleting CMS content directly (without the admin UI), read the auto-generated agent docs:\n\n- **\\`octocms/docs/overview.md\\`** — How to find, create, update, and delete content entries via file operations\n- **\\`octocms/docs/schema.md\\`** — Per-collection field definitions, example JSON, and file path conventions\n\nThese docs are generated from \\`cms/octocms.config.ts\\`. Regenerate after schema changes: \\`npm run agent-docs:gen\\`.`;\n}\n\nexport function agentsMdTemplate(): string {\n return `# Project Guidelines\n\n${agentsMdSection()}\n`;\n}\n\nexport function tsconfigPaths(): Record<string, string[]> {\n return {\n 'cms/__generated__': ['./cms/__generated__/index.ts'],\n 'cms/__generated__/*': ['./cms/__generated__/*'],\n '@/*': ['./src/*'],\n };\n}\n"],"mappings":";AAIO,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAO5B,IAAM,oBAAoB;AAAA;AAG1B,SAAS,mBAAmB,MAAmF;AACpH,QAAM,WAAW,KAAK,gBAClB;AAAA,mBAA8B,KAAK,UAAU;AAAA,+BAAoC,KAAK,aAAa;AAAA,QACnG,yBAAyB,KAAK,UAAU;AAE5C,SAAO;AAAA;AAAA;AAAA;AAAA,kBAIS,KAAK,WAAW;AAAA,EAChC,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBV;AAEO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWT;AAEO,SAAS,oBAA4B;AAC1C,SAAO,KAAK;AAAA,IACV;AAAA,MACE,KAAK,EAAE,IAAI,QAAQ,MAAM,aAAa,QAAQ,SAAS;AAAA,MACvD,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc1B,SAAS,eAAe,aAA6B;AAC1D,SAAO,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuCzB;AAEO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBT;AAEA,IAAM,oBAAoB;AAEnB,SAAS,kBAA0B;AACxC,SAAO,GAAG,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS7B;AAEO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA,EAEP,gBAAgB,CAAC;AAAA;AAEnB;AAEO,SAAS,gBAA0C;AACxD,SAAO;AAAA,IACL,qBAAqB,CAAC,8BAA8B;AAAA,IACpD,uBAAuB,CAAC,uBAAuB;AAAA,IAC/C,OAAO,CAAC,SAAS;AAAA,EACnB;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  // cli/lib/project.ts
2
2
  import { existsSync, readFileSync } from "fs";
3
- import { dirname, join } from "path";
3
+ import { dirname, join, resolve } from "path";
4
4
  function resolveProjectRoot(startDir) {
5
5
  let dir = startDir != null ? startDir : process.cwd();
6
6
  for (; ; ) {
@@ -17,12 +17,15 @@ function resolveProjectRoot(startDir) {
17
17
  }
18
18
  async function loadProjectConfig(projectRoot) {
19
19
  const { createJiti } = await import("./jiti-VYEW7A6R.js");
20
+ const alias = {};
21
+ const localOctocms = resolve(projectRoot, "octocms");
22
+ if (existsSync(localOctocms)) {
23
+ alias["octocms/"] = localOctocms + "/";
24
+ }
20
25
  const jiti = createJiti(join(projectRoot, "__cli_loader__.ts"), {
21
26
  fsCache: false,
22
27
  moduleCache: false,
23
- alias: {
24
- "octocms/": join(projectRoot, "octocms/")
25
- }
28
+ alias
26
29
  });
27
30
  const mod = await jiti.import(join(projectRoot, "cms", "octocms.config.ts"), {
28
31
  default: true,
@@ -35,12 +38,15 @@ async function loadProjectConfig(projectRoot) {
35
38
  }
36
39
  async function loadCollections(projectRoot) {
37
40
  const { createJiti } = await import("./jiti-VYEW7A6R.js");
41
+ const alias = {};
42
+ const localOctocms = resolve(projectRoot, "octocms");
43
+ if (existsSync(localOctocms)) {
44
+ alias["octocms/"] = localOctocms + "/";
45
+ }
38
46
  const jiti = createJiti(join(projectRoot, "__cli_loader__.ts"), {
39
47
  fsCache: false,
40
48
  moduleCache: false,
41
- alias: {
42
- "octocms/": join(projectRoot, "octocms/")
43
- }
49
+ alias
44
50
  });
45
51
  const mod = await jiti.import(join(projectRoot, "octocms/admin/consts.ts"), {
46
52
  default: true,
@@ -53,12 +59,15 @@ async function loadCollections(projectRoot) {
53
59
  }
54
60
  async function loadFieldTypes(projectRoot) {
55
61
  const { createJiti } = await import("./jiti-VYEW7A6R.js");
62
+ const alias = {};
63
+ const localOctocms = resolve(projectRoot, "octocms");
64
+ if (existsSync(localOctocms)) {
65
+ alias["octocms/"] = localOctocms + "/";
66
+ }
56
67
  const jiti = createJiti(join(projectRoot, "__cli_loader__.ts"), {
57
68
  fsCache: false,
58
69
  moduleCache: false,
59
- alias: {
60
- "octocms/": join(projectRoot, "octocms/")
61
- }
70
+ alias
62
71
  });
63
72
  const mod = await jiti.import(join(projectRoot, "octocms/admin/consts.ts"), {
64
73
  default: true,
@@ -76,4 +85,4 @@ export {
76
85
  loadCollections,
77
86
  loadFieldTypes
78
87
  };
79
- //# sourceMappingURL=chunk-C62C776U.js.map
88
+ //# sourceMappingURL=chunk-VN27V5NE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/lib/project.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'fs';\nimport { dirname, join, resolve } from 'path';\n\n/**\n * Walk up from `startDir` until we find a directory containing a\n * `next.config.ts` that includes `withOctoCMS`.\n * Returns the absolute path to the project root.\n */\nexport function resolveProjectRoot(startDir?: string): string {\n let dir = startDir ?? process.cwd();\n for (;;) {\n const nextConfigPath = join(dir, 'next.config.ts');\n if (existsSync(nextConfigPath) && readFileSync(nextConfigPath, 'utf8').includes('withOctoCMS')) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n throw new Error('Could not find next.config.ts with withOctoCMS — are you inside an OctoCMS project?');\n }\n dir = parent;\n }\n}\n\n/**\n * Load the CMS config from a project root. Uses `jiti` to handle TypeScript\n * files and tsconfig path aliases at runtime.\n */\nexport async function loadProjectConfig(projectRoot: string) {\n // Dynamic import so jiti stays an optional peer when published\n const { createJiti } = await import('jiti');\n // In this monorepo, octocms/ lives at the project root. When installed as an npm\n // package it lives in node_modules/octocms — jiti resolves it normally in that case.\n const alias: Record<string, string> = {};\n const localOctocms = resolve(projectRoot, 'octocms');\n if (existsSync(localOctocms)) {\n alias['octocms/'] = localOctocms + '/';\n }\n const jiti = createJiti(join(projectRoot, '__cli_loader__.ts'), {\n fsCache: false,\n moduleCache: false,\n alias,\n });\n const mod = (await jiti.import(join(projectRoot, 'cms', 'octocms.config.ts'), {\n default: true,\n try: true,\n })) as Record<string, unknown> | undefined;\n if (!mod || !mod.configOctoCMS) {\n throw new Error('cms/octocms.config.ts must export a `configOctoCMS` object (use defineConfig())');\n }\n return mod.configOctoCMS as import('../../types').Config;\n}\n\n/**\n * Load the COLLECTIONS array from `octocms/admin/consts.ts`.\n */\nexport async function loadCollections(projectRoot: string): Promise<readonly string[]> {\n const { createJiti } = await import('jiti');\n const alias: Record<string, string> = {};\n const localOctocms = resolve(projectRoot, 'octocms');\n if (existsSync(localOctocms)) {\n alias['octocms/'] = localOctocms + '/';\n }\n const jiti = createJiti(join(projectRoot, '__cli_loader__.ts'), {\n fsCache: false,\n moduleCache: false,\n alias,\n });\n const mod = (await jiti.import(join(projectRoot, 'octocms/admin/consts.ts'), {\n default: true,\n try: true,\n })) as Record<string, unknown> | undefined;\n if (!mod || !Array.isArray(mod.COLLECTIONS)) {\n throw new Error('Could not load COLLECTIONS from octocms/admin/consts.ts');\n }\n return mod.COLLECTIONS as readonly string[];\n}\n\n/**\n * Load FIELD_TYPES from `octocms/admin/consts.ts`.\n */\nexport async function loadFieldTypes(projectRoot: string): Promise<readonly string[]> {\n const { createJiti } = await import('jiti');\n const alias: Record<string, string> = {};\n const localOctocms = resolve(projectRoot, 'octocms');\n if (existsSync(localOctocms)) {\n alias['octocms/'] = localOctocms + '/';\n }\n const jiti = createJiti(join(projectRoot, '__cli_loader__.ts'), {\n fsCache: false,\n moduleCache: false,\n alias,\n });\n const mod = (await jiti.import(join(projectRoot, 'octocms/admin/consts.ts'), {\n default: true,\n try: true,\n })) as Record<string, unknown> | undefined;\n if (!mod || !Array.isArray(mod.FIELD_TYPES)) {\n throw new Error('Could not load FIELD_TYPES from octocms/admin/consts.ts');\n }\n return mod.FIELD_TYPES as readonly string[];\n}\n"],"mappings":";AAAA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,MAAM,eAAe;AAOhC,SAAS,mBAAmB,UAA2B;AAC5D,MAAI,MAAM,8BAAY,QAAQ,IAAI;AAClC,aAAS;AACP,UAAM,iBAAiB,KAAK,KAAK,gBAAgB;AACjD,QAAI,WAAW,cAAc,KAAK,aAAa,gBAAgB,MAAM,EAAE,SAAS,aAAa,GAAG;AAC9F,aAAO;AAAA,IACT;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,KAAK;AAClB,YAAM,IAAI,MAAM,0FAAqF;AAAA,IACvG;AACA,UAAM;AAAA,EACR;AACF;AAMA,eAAsB,kBAAkB,aAAqB;AAE3D,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAM;AAG1C,QAAM,QAAgC,CAAC;AACvC,QAAM,eAAe,QAAQ,aAAa,SAAS;AACnD,MAAI,WAAW,YAAY,GAAG;AAC5B,UAAM,UAAU,IAAI,eAAe;AAAA,EACrC;AACA,QAAM,OAAO,WAAW,KAAK,aAAa,mBAAmB,GAAG;AAAA,IAC9D,SAAS;AAAA,IACT,aAAa;AAAA,IACb;AAAA,EACF,CAAC;AACD,QAAM,MAAO,MAAM,KAAK,OAAO,KAAK,aAAa,OAAO,mBAAmB,GAAG;AAAA,IAC5E,SAAS;AAAA,IACT,KAAK;AAAA,EACP,CAAC;AACD,MAAI,CAAC,OAAO,CAAC,IAAI,eAAe;AAC9B,UAAM,IAAI,MAAM,iFAAiF;AAAA,EACnG;AACA,SAAO,IAAI;AACb;AAKA,eAAsB,gBAAgB,aAAiD;AACrF,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAM;AAC1C,QAAM,QAAgC,CAAC;AACvC,QAAM,eAAe,QAAQ,aAAa,SAAS;AACnD,MAAI,WAAW,YAAY,GAAG;AAC5B,UAAM,UAAU,IAAI,eAAe;AAAA,EACrC;AACA,QAAM,OAAO,WAAW,KAAK,aAAa,mBAAmB,GAAG;AAAA,IAC9D,SAAS;AAAA,IACT,aAAa;AAAA,IACb;AAAA,EACF,CAAC;AACD,QAAM,MAAO,MAAM,KAAK,OAAO,KAAK,aAAa,yBAAyB,GAAG;AAAA,IAC3E,SAAS;AAAA,IACT,KAAK;AAAA,EACP,CAAC;AACD,MAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAC3C,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO,IAAI;AACb;AAKA,eAAsB,eAAe,aAAiD;AACpF,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAM;AAC1C,QAAM,QAAgC,CAAC;AACvC,QAAM,eAAe,QAAQ,aAAa,SAAS;AACnD,MAAI,WAAW,YAAY,GAAG;AAC5B,UAAM,UAAU,IAAI,eAAe;AAAA,EACrC;AACA,QAAM,OAAO,WAAW,KAAK,aAAa,mBAAmB,GAAG;AAAA,IAC9D,SAAS;AAAA,IACT,aAAa;AAAA,IACb;AAAA,EACF,CAAC;AACD,QAAM,MAAO,MAAM,KAAK,OAAO,KAAK,aAAa,yBAAyB,GAAG;AAAA,IAC3E,SAAS;AAAA,IACT,KAAK;AAAA,EACP,CAAC;AACD,MAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAC3C,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO,IAAI;AACb;","names":[]}
package/dist/cli/index.js CHANGED
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveProjectRoot
4
- } from "../chunk-C62C776U.js";
4
+ } from "../chunk-VN27V5NE.js";
5
5
  import {
6
6
  fmt,
7
7
  log
8
8
  } from "../chunk-6PHFHGTZ.js";
9
9
  import "../chunk-W6QJTGBC.js";
10
10
 
11
+ // package.json
12
+ var version = "0.1.4";
13
+
11
14
  // cli/index.ts
12
- var VERSION = "0.0.0";
13
15
  var HELP = `
14
- ${fmt.bold("OctoCMS CLI")} v${VERSION}
16
+ ${fmt.bold("OctoCMS CLI")} v${version}
15
17
 
16
18
  Usage: octocms <command> [options]
17
19
 
@@ -51,7 +53,7 @@ var COMMAND_HELP = {
51
53
  ${fmt.bold("Usage:")} octocms dev [options]
52
54
 
53
55
  ${fmt.bold("Options:")}
54
- --port <n> Port number (default: 3001)
56
+ --port <n> Port number (default: 3000)
55
57
  --help Show this help message
56
58
  `,
57
59
  "types:gen": `
@@ -129,7 +131,7 @@ function parseArgs(argv) {
129
131
  async function main() {
130
132
  const { command, flags } = parseArgs(process.argv);
131
133
  if (flags.version) {
132
- console.log(VERSION);
134
+ console.log(version);
133
135
  return;
134
136
  }
135
137
  if (!command || flags.help) {
@@ -147,38 +149,38 @@ async function main() {
147
149
  try {
148
150
  switch (command) {
149
151
  case "init": {
150
- const { initCommand } = await import("../init-UGUTJFFI.js");
152
+ const { initCommand } = await import("../init-XLCXOUQB.js");
151
153
  await initCommand(process.cwd(), { yes: flags.yes === true });
152
154
  break;
153
155
  }
154
156
  case "dev": {
155
157
  const projectRoot = resolveProjectRoot();
156
- const { devCommand } = await import("../dev-QY534GEH.js");
158
+ const { devCommand } = await import("../dev-MZYDFX7K.js");
157
159
  const port = flags.port ? Number(flags.port) : void 0;
158
160
  await devCommand(projectRoot, { port });
159
161
  break;
160
162
  }
161
163
  case "types:gen": {
162
164
  const projectRoot = resolveProjectRoot();
163
- const { typesGenCommand } = await import("../typesGen-WBC6CNBG.js");
165
+ const { typesGenCommand } = await import("../typesGen-RGHGMI34.js");
164
166
  await typesGenCommand(projectRoot);
165
167
  break;
166
168
  }
167
169
  case "validate": {
168
170
  const projectRoot = resolveProjectRoot();
169
- const { validateCommand } = await import("../validate-OTJ6ULMP.js");
171
+ const { validateCommand } = await import("../validate-X6ALTVGH.js");
170
172
  await validateCommand(projectRoot);
171
173
  break;
172
174
  }
173
175
  case "update": {
174
176
  const projectRoot = resolveProjectRoot();
175
- const { updateCommand } = await import("../update-RMGZMS56.js");
177
+ const { updateCommand } = await import("../update-VXVCXDEE.js");
176
178
  await updateCommand(projectRoot);
177
179
  break;
178
180
  }
179
181
  case "agent-docs": {
180
182
  const projectRoot = resolveProjectRoot();
181
- const { agentDocsCommand } = await import("../agentDocs-Z5BI2Y2G.js");
183
+ const { agentDocsCommand } = await import("../agentDocs-GRGCRZBL.js");
182
184
  await agentDocsCommand(projectRoot);
183
185
  break;
184
186
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n/* eslint-disable no-console */\n\n/**\n * OctoCMS CLI — command-line tools for managing an OctoCMS project.\n *\n * Commands:\n * init Initialize OctoCMS in a Next.js project\n * dev Start development server with config watching\n * types:gen Generate TypeScript types from next.config.ts\n * validate Validate all content entries against the schema\n * update Regenerate admin route files\n * agent-docs Inject AI agent doc links into AGENTS.md\n *\n * Usage:\n * octocms <command> [options]\n * octocms --help\n * octocms --version\n */\n\nimport { fmt, log } from './lib/logger';\nimport { resolveProjectRoot } from './lib/project';\n\nconst VERSION = '0.0.0';\n\nconst HELP = `\n ${fmt.bold('OctoCMS CLI')} v${VERSION}\n\n Usage: octocms <command> [options]\n\n ${fmt.bold('Commands:')}\n init Initialize OctoCMS in a Next.js project\n dev Start development server with config watching\n types:gen Generate TypeScript types from next.config.ts\n validate Validate all content entries against the schema\n update Regenerate admin route files\n agent-docs Inject AI agent doc links into AGENTS.md\n\n ${fmt.bold('Options:')}\n --help Show this help message\n --version Show version number\n\n Run ${fmt.cyan('octocms <command> --help')} for command-specific help.\n`;\n\nconst COMMAND_HELP: Record<string, string> = {\n init: `\n ${fmt.bold('octocms init')} — Initialize OctoCMS in a Next.js project\n\n Creates next.config.ts, admin route files, demo content, and updates\n next.config.ts and tsconfig.json with required configuration.\n\n ${fmt.bold('Usage:')} octocms init [options]\n\n ${fmt.bold('Options:')}\n --yes, -y Accept all defaults (non-interactive)\n --help Show this help message\n`,\n dev: `\n ${fmt.bold('octocms dev')} — Start development server with config watching\n\n Spawns Next.js dev server and watches next.config.ts. When the config\n changes, types are automatically regenerated.\n\n ${fmt.bold('Usage:')} octocms dev [options]\n\n ${fmt.bold('Options:')}\n --port <n> Port number (default: 3001)\n --help Show this help message\n`,\n 'types:gen': `\n ${fmt.bold('octocms types:gen')} — Generate TypeScript types from next.config.ts\n\n Produces cms/__generated__/types.ts, enums.ts, content.d.ts, and index.ts.\n Validates the config before generating.\n\n ${fmt.bold('Usage:')} octocms types:gen\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n validate: `\n ${fmt.bold('octocms validate')} — Validate all content entries against the schema\n\n Reads every JSON file in cms/content/, validates structure, field types,\n required fields, select option values, reference targets, and companion files.\n\n ${fmt.bold('Usage:')} octocms validate\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n 'agent-docs': `\n ${fmt.bold('octocms agent-docs')} — Inject AI agent doc links into AGENTS.md\n\n Creates AGENTS.md if it doesn't exist, or appends the OctoCMS section\n if the file exists but doesn't reference the agent docs yet.\n\n ${fmt.bold('Usage:')} octocms agent-docs\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n update: `\n ${fmt.bold('octocms update')} — Regenerate admin route files\n\n Ensures src/app/cms/layout.tsx and the catch-all page re-export are\n up-to-date with the latest OctoCMS version.\n\n ${fmt.bold('Usage:')} octocms update\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n};\n\nfunction parseArgs(argv: string[]): { command: string | null; flags: Record<string, string | boolean> } {\n const args = argv.slice(2); // skip node + script path\n const flags: Record<string, string | boolean> = {};\n let command: string | null = null;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help' || arg === '-h') {\n flags.help = true;\n } else if (arg === '--version' || arg === '-v') {\n flags.version = true;\n } else if (arg === '--yes' || arg === '-y') {\n flags.yes = true;\n } else if (arg === '--port') {\n flags.port = args[++i] ?? '';\n } else if (arg.startsWith('--port=')) {\n flags.port = arg.slice(7);\n } else if (!arg.startsWith('-') && !command) {\n // Handle compound commands as single tokens\n if (arg === 'types:gen' || arg === 'agent-docs') {\n command = arg;\n } else {\n command = arg;\n }\n }\n }\n\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv);\n\n if (flags.version) {\n console.log(VERSION);\n return;\n }\n\n if (!command || flags.help) {\n if (command && COMMAND_HELP[command]) {\n console.log(COMMAND_HELP[command]);\n } else {\n console.log(HELP);\n }\n return;\n }\n\n if (COMMAND_HELP[command] && flags.help) {\n console.log(COMMAND_HELP[command]);\n return;\n }\n\n try {\n switch (command) {\n case 'init': {\n // init doesn't need an existing project root — use cwd\n const { initCommand } = await import('./commands/init');\n await initCommand(process.cwd(), { yes: flags.yes === true });\n break;\n }\n case 'dev': {\n const projectRoot = resolveProjectRoot();\n const { devCommand } = await import('./commands/dev');\n const port = flags.port ? Number(flags.port) : undefined;\n await devCommand(projectRoot, { port });\n break;\n }\n case 'types:gen': {\n const projectRoot = resolveProjectRoot();\n const { typesGenCommand } = await import('./commands/typesGen');\n await typesGenCommand(projectRoot);\n break;\n }\n case 'validate': {\n const projectRoot = resolveProjectRoot();\n const { validateCommand } = await import('./commands/validate');\n await validateCommand(projectRoot);\n break;\n }\n case 'update': {\n const projectRoot = resolveProjectRoot();\n const { updateCommand } = await import('./commands/update');\n await updateCommand(projectRoot);\n break;\n }\n case 'agent-docs': {\n const projectRoot = resolveProjectRoot();\n const { agentDocsCommand } = await import('./commands/agentDocs');\n await agentDocsCommand(projectRoot);\n break;\n }\n default:\n log.error(`Unknown command: ${command}`);\n console.log(HELP);\n process.exitCode = 1;\n }\n } catch (e) {\n log.error((e as Error).message);\n process.exitCode = 1;\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../package.json","../../cli/index.ts"],"sourcesContent":["{\n \"name\": \"octocms\",\n \"version\": \"0.1.4\",\n \"description\": \"A file-based CMS for Next.js — schema-driven, Git-backed, no database\",\n \"license\": \"MIT\",\n \"keywords\": [\n \"cms\",\n \"nextjs\",\n \"headless-cms\",\n \"git-cms\",\n \"content-management\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/octocms/octocms.git\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.mts\",\n \"import\": \"./dist/index.js\"\n },\n \"./query\": {\n \"types\": \"./dist/query.d.mts\",\n \"import\": \"./dist/query.js\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.mts\",\n \"import\": \"./dist/config.js\"\n },\n \"./defineConfig\": {\n \"types\": \"./dist/defineConfig.d.mts\",\n \"import\": \"./dist/defineConfig.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.mts\",\n \"import\": \"./dist/types.js\"\n },\n \"./withOctoCMS\": {\n \"types\": \"./dist/withOctoCMS.d.mts\",\n \"import\": \"./dist/withOctoCMS.js\"\n },\n \"./components/public\": {\n \"types\": \"./dist/components/public/index.d.mts\",\n \"import\": \"./dist/components/public/index.js\"\n },\n \"./globals.css\": \"./globals.css\",\n \"./docs/*\": \"./docs/*\"\n },\n \"bin\": {\n \"octocms\": \"dist/cli/index.js\"\n },\n \"files\": [\n \"dist\",\n \"docs\",\n \"globals.css\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"prepublishOnly\": \"npm run checks && npm run build\",\n \"lint\": \"oxlint .\",\n \"lint:fix\": \"oxlint --fix .\",\n \"fmt\": \"oxfmt .\",\n \"fmt:check\": \"oxfmt --check .\",\n \"test\": \"vitest\",\n \"test:run\": \"vitest run\",\n \"ts-check\": \"tsc --noEmit --incremental false\",\n \"checks\": \"npm run lint && npm run ts-check && npm run fmt:check && npm run test:run\",\n \"checks:fix\": \"npm run lint:fix && npm run fmt && npm run test:run\"\n },\n \"peerDependencies\": {\n \"next\": \">=15\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\"\n },\n \"dependencies\": {\n \"@mdxeditor/editor\": \"^3.11.4\",\n \"@radix-ui/react-avatar\": \"^1.1.11\",\n \"@radix-ui/react-dialog\": \"^1.1.15\",\n \"@radix-ui/react-dropdown-menu\": \"^2.1.16\",\n \"@radix-ui/react-label\": \"^2.1.8\",\n \"@radix-ui/react-select\": \"^2.2.6\",\n \"@radix-ui/react-slot\": \"^1.2.4\",\n \"@radix-ui/react-tabs\": \"^1.1.13\",\n \"@radix-ui/react-toast\": \"^1.2.15\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"glob\": \"^11.0.0\",\n \"lucide-react\": \"^1.7.0\",\n \"minisearch\": \"^7.2.0\",\n \"next-auth\": \"^4.24.13\",\n \"octokit\": \"^4.1.4\",\n \"react-markdown\": \"^10.1.0\",\n \"rehype-sanitize\": \"^6.0.0\",\n \"remark-gfm\": \"^4.0.1\",\n \"remark-mdx\": \"^3.1.1\",\n \"sharp\": \"^0.34.5\",\n \"slugify\": \"^1.6.9\",\n \"sonner\": \"^2.0.7\",\n \"tailwind-merge\": \"^3.5.0\",\n \"zod\": \"^4.3.6\"\n },\n \"devDependencies\": {\n \"@testing-library/dom\": \"^10.4.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19.2.14\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@vitejs/plugin-react\": \"^6.0.1\",\n \"jsdom\": \"^29.0.1\",\n \"oxfmt\": \"^0.11.0\",\n \"oxlint\": \"^0.17.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.9.3\",\n \"vite-tsconfig-paths\": \"^6.1.1\",\n \"vitest\": \"^4.1.2\"\n }\n}\n","#!/usr/bin/env node\n/* eslint-disable no-console */\n\n/**\n * OctoCMS CLI — command-line tools for managing an OctoCMS project.\n *\n * Commands:\n * init Initialize OctoCMS in a Next.js project\n * dev Start development server with config watching\n * types:gen Generate TypeScript types from next.config.ts\n * validate Validate all content entries against the schema\n * update Regenerate admin route files\n * agent-docs Inject AI agent doc links into AGENTS.md\n *\n * Usage:\n * octocms <command> [options]\n * octocms --help\n * octocms --version\n */\n\nimport { fmt, log } from './lib/logger';\nimport { resolveProjectRoot } from './lib/project';\nimport { version as VERSION } from '../package.json';\n\nconst HELP = `\n ${fmt.bold('OctoCMS CLI')} v${VERSION}\n\n Usage: octocms <command> [options]\n\n ${fmt.bold('Commands:')}\n init Initialize OctoCMS in a Next.js project\n dev Start development server with config watching\n types:gen Generate TypeScript types from next.config.ts\n validate Validate all content entries against the schema\n update Regenerate admin route files\n agent-docs Inject AI agent doc links into AGENTS.md\n\n ${fmt.bold('Options:')}\n --help Show this help message\n --version Show version number\n\n Run ${fmt.cyan('octocms <command> --help')} for command-specific help.\n`;\n\nconst COMMAND_HELP: Record<string, string> = {\n init: `\n ${fmt.bold('octocms init')} — Initialize OctoCMS in a Next.js project\n\n Creates next.config.ts, admin route files, demo content, and updates\n next.config.ts and tsconfig.json with required configuration.\n\n ${fmt.bold('Usage:')} octocms init [options]\n\n ${fmt.bold('Options:')}\n --yes, -y Accept all defaults (non-interactive)\n --help Show this help message\n`,\n dev: `\n ${fmt.bold('octocms dev')} — Start development server with config watching\n\n Spawns Next.js dev server and watches next.config.ts. When the config\n changes, types are automatically regenerated.\n\n ${fmt.bold('Usage:')} octocms dev [options]\n\n ${fmt.bold('Options:')}\n --port <n> Port number (default: 3000)\n --help Show this help message\n`,\n 'types:gen': `\n ${fmt.bold('octocms types:gen')} — Generate TypeScript types from next.config.ts\n\n Produces cms/__generated__/types.ts, enums.ts, content.d.ts, and index.ts.\n Validates the config before generating.\n\n ${fmt.bold('Usage:')} octocms types:gen\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n validate: `\n ${fmt.bold('octocms validate')} — Validate all content entries against the schema\n\n Reads every JSON file in cms/content/, validates structure, field types,\n required fields, select option values, reference targets, and companion files.\n\n ${fmt.bold('Usage:')} octocms validate\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n 'agent-docs': `\n ${fmt.bold('octocms agent-docs')} — Inject AI agent doc links into AGENTS.md\n\n Creates AGENTS.md if it doesn't exist, or appends the OctoCMS section\n if the file exists but doesn't reference the agent docs yet.\n\n ${fmt.bold('Usage:')} octocms agent-docs\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n update: `\n ${fmt.bold('octocms update')} — Regenerate admin route files\n\n Ensures src/app/cms/layout.tsx and the catch-all page re-export are\n up-to-date with the latest OctoCMS version.\n\n ${fmt.bold('Usage:')} octocms update\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n};\n\nfunction parseArgs(argv: string[]): { command: string | null; flags: Record<string, string | boolean> } {\n const args = argv.slice(2); // skip node + script path\n const flags: Record<string, string | boolean> = {};\n let command: string | null = null;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help' || arg === '-h') {\n flags.help = true;\n } else if (arg === '--version' || arg === '-v') {\n flags.version = true;\n } else if (arg === '--yes' || arg === '-y') {\n flags.yes = true;\n } else if (arg === '--port') {\n flags.port = args[++i] ?? '';\n } else if (arg.startsWith('--port=')) {\n flags.port = arg.slice(7);\n } else if (!arg.startsWith('-') && !command) {\n // Handle compound commands as single tokens\n if (arg === 'types:gen' || arg === 'agent-docs') {\n command = arg;\n } else {\n command = arg;\n }\n }\n }\n\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv);\n\n if (flags.version) {\n console.log(VERSION);\n return;\n }\n\n if (!command || flags.help) {\n if (command && COMMAND_HELP[command]) {\n console.log(COMMAND_HELP[command]);\n } else {\n console.log(HELP);\n }\n return;\n }\n\n if (COMMAND_HELP[command] && flags.help) {\n console.log(COMMAND_HELP[command]);\n return;\n }\n\n try {\n switch (command) {\n case 'init': {\n // init doesn't need an existing project root — use cwd\n const { initCommand } = await import('./commands/init');\n await initCommand(process.cwd(), { yes: flags.yes === true });\n break;\n }\n case 'dev': {\n const projectRoot = resolveProjectRoot();\n const { devCommand } = await import('./commands/dev');\n const port = flags.port ? Number(flags.port) : undefined;\n await devCommand(projectRoot, { port });\n break;\n }\n case 'types:gen': {\n const projectRoot = resolveProjectRoot();\n const { typesGenCommand } = await import('./commands/typesGen');\n await typesGenCommand(projectRoot);\n break;\n }\n case 'validate': {\n const projectRoot = resolveProjectRoot();\n const { validateCommand } = await import('./commands/validate');\n await validateCommand(projectRoot);\n break;\n }\n case 'update': {\n const projectRoot = resolveProjectRoot();\n const { updateCommand } = await import('./commands/update');\n await updateCommand(projectRoot);\n break;\n }\n case 'agent-docs': {\n const projectRoot = resolveProjectRoot();\n const { agentDocsCommand } = await import('./commands/agentDocs');\n await agentDocsCommand(projectRoot);\n break;\n }\n default:\n log.error(`Unknown command: ${command}`);\n console.log(HELP);\n process.exitCode = 1;\n }\n } catch (e) {\n log.error((e as Error).message);\n process.exitCode = 1;\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
@@ -11,7 +11,7 @@ import { existsSync, watch } from "fs";
11
11
  import { join } from "path";
12
12
  async function devCommand(projectRoot, options = {}) {
13
13
  var _a;
14
- const port = (_a = options.port) != null ? _a : 3001;
14
+ const port = (_a = options.port) != null ? _a : 3e3;
15
15
  log.header("Development server");
16
16
  const nextConfigPath = join(projectRoot, "next.config.ts");
17
17
  const octoConfigPath = join(projectRoot, "cms", "octocms.config.ts");
@@ -84,4 +84,4 @@ function regenerateTypes(projectRoot) {
84
84
  export {
85
85
  devCommand
86
86
  };
87
- //# sourceMappingURL=dev-QY534GEH.js.map
87
+ //# sourceMappingURL=dev-MZYDFX7K.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../cli/commands/dev.ts"],"sourcesContent":["/**\n * `octocms dev` — Start Next.js dev server with next.config.ts watching.\n *\n * Spawns `next dev` and watches the config file for changes. When the\n * config changes, types are automatically regenerated.\n */\n\nimport { spawn } from 'child_process';\nimport { existsSync, watch } from 'fs';\nimport { join } from 'path';\n\nimport { log } from '../lib/logger';\n\nexport type DevOptions = {\n port?: number;\n};\n\nexport async function devCommand(projectRoot: string, options: DevOptions = {}): Promise<void> {\n const port = options.port ?? 3001;\n\n log.header('Development server');\n\n const nextConfigPath = join(projectRoot, 'next.config.ts');\n const octoConfigPath = join(projectRoot, 'cms', 'octocms.config.ts');\n if (!existsSync(nextConfigPath)) {\n log.error('next.config.ts not found — run `octocms init` first.');\n process.exitCode = 1;\n return;\n }\n\n log.info(`Starting Next.js dev server on port ${port}...`);\n log.info('Watching next.config.ts and cms/octocms.config.ts for changes...');\n log.blank();\n\n // Spawn next dev\n const nextBin = join(projectRoot, 'node_modules', '.bin', 'next');\n const child = spawn(nextBin, ['dev', '-p', String(port)], {\n cwd: projectRoot,\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n // Watch both config files for changes and regenerate types\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const onConfigChange = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n regenerateTypes(projectRoot);\n }, 300);\n };\n\n const nextWatcher = watch(nextConfigPath, onConfigChange);\n const octoWatcher = existsSync(octoConfigPath) ? watch(octoConfigPath, onConfigChange) : null;\n\n // Forward signals to child\n const cleanup = () => {\n nextWatcher.close();\n octoWatcher?.close();\n if (debounceTimer) clearTimeout(debounceTimer);\n child.kill();\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n\n child.on('exit', (code) => {\n nextWatcher.close();\n octoWatcher?.close();\n if (debounceTimer) clearTimeout(debounceTimer);\n process.exitCode = code ?? 0;\n });\n}\n\nfunction regenerateTypes(projectRoot: string): void {\n log.blank();\n log.step('Config changed — regenerating types...');\n\n const jitiBin = join(projectRoot, 'node_modules', '.bin', 'jiti');\n const scriptPath = join(projectRoot, 'scripts', 'generate-types.ts');\n\n const child = spawn(jitiBin, [scriptPath], {\n cwd: projectRoot,\n stdio: 'pipe',\n });\n\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('exit', (code) => {\n if (code === 0) {\n log.success('Types regenerated');\n } else {\n log.error('Type generation failed:');\n if (stderr.trim()) {\n for (const line of stderr.trim().split('\\n')) {\n log.info(` ${line}`);\n }\n }\n }\n log.blank();\n });\n}\n"],"mappings":";;;;;;;;AAOA,SAAS,aAAa;AACtB,SAAS,YAAY,aAAa;AAClC,SAAS,YAAY;AAQrB,eAAsB,WAAW,aAAqB,UAAsB,CAAC,GAAkB;AAjB/F;AAkBE,QAAM,QAAO,aAAQ,SAAR,YAAgB;AAE7B,MAAI,OAAO,oBAAoB;AAE/B,QAAM,iBAAiB,KAAK,aAAa,gBAAgB;AACzD,QAAM,iBAAiB,KAAK,aAAa,OAAO,mBAAmB;AACnE,MAAI,CAAC,WAAW,cAAc,GAAG;AAC/B,QAAI,MAAM,2DAAsD;AAChE,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,MAAI,KAAK,uCAAuC,IAAI,KAAK;AACzD,MAAI,KAAK,kEAAkE;AAC3E,MAAI,MAAM;AAGV,QAAM,UAAU,KAAK,aAAa,gBAAgB,QAAQ,MAAM;AAChE,QAAM,QAAQ,MAAM,SAAS,CAAC,OAAO,MAAM,OAAO,IAAI,CAAC,GAAG;AAAA,IACxD,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK,mBAAK,QAAQ;AAAA,EACpB,CAAC;AAGD,MAAI,gBAAsD;AAE1D,QAAM,iBAAiB,MAAM;AAC3B,QAAI,cAAe,cAAa,aAAa;AAC7C,oBAAgB,WAAW,MAAM;AAC/B,sBAAgB,WAAW;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR;AAEA,QAAM,cAAc,MAAM,gBAAgB,cAAc;AACxD,QAAM,cAAc,WAAW,cAAc,IAAI,MAAM,gBAAgB,cAAc,IAAI;AAGzF,QAAM,UAAU,MAAM;AACpB,gBAAY,MAAM;AAClB,+CAAa;AACb,QAAI,cAAe,cAAa,aAAa;AAC7C,UAAM,KAAK;AAAA,EACb;AAEA,UAAQ,GAAG,UAAU,OAAO;AAC5B,UAAQ,GAAG,WAAW,OAAO;AAE7B,QAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,gBAAY,MAAM;AAClB,+CAAa;AACb,QAAI,cAAe,cAAa,aAAa;AAC7C,YAAQ,WAAW,sBAAQ;AAAA,EAC7B,CAAC;AACH;AAEA,SAAS,gBAAgB,aAA2B;AA1EpD;AA2EE,MAAI,MAAM;AACV,MAAI,KAAK,6CAAwC;AAEjD,QAAM,UAAU,KAAK,aAAa,gBAAgB,QAAQ,MAAM;AAChE,QAAM,aAAa,KAAK,aAAa,WAAW,mBAAmB;AAEnE,QAAM,QAAQ,MAAM,SAAS,CAAC,UAAU,GAAG;AAAA,IACzC,KAAK;AAAA,IACL,OAAO;AAAA,EACT,CAAC;AAED,MAAI,SAAS;AACb,cAAM,WAAN,mBAAc,GAAG,QAAQ,CAAC,SAAiB;AACzC,cAAU,KAAK,SAAS;AAAA,EAC1B;AAEA,QAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,QAAI,SAAS,GAAG;AACd,UAAI,QAAQ,mBAAmB;AAAA,IACjC,OAAO;AACL,UAAI,MAAM,yBAAyB;AACnC,UAAI,OAAO,KAAK,GAAG;AACjB,mBAAW,QAAQ,OAAO,KAAK,EAAE,MAAM,IAAI,GAAG;AAC5C,cAAI,KAAK,KAAK,IAAI,EAAE;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AACA,QAAI,MAAM;AAAA,EACZ,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../cli/commands/dev.ts"],"sourcesContent":["/**\n * `octocms dev` — Start Next.js dev server with next.config.ts watching.\n *\n * Spawns `next dev` and watches the config file for changes. When the\n * config changes, types are automatically regenerated.\n */\n\nimport { spawn } from 'child_process';\nimport { existsSync, watch } from 'fs';\nimport { join } from 'path';\n\nimport { log } from '../lib/logger';\n\nexport type DevOptions = {\n port?: number;\n};\n\nexport async function devCommand(projectRoot: string, options: DevOptions = {}): Promise<void> {\n const port = options.port ?? 3000;\n\n log.header('Development server');\n\n const nextConfigPath = join(projectRoot, 'next.config.ts');\n const octoConfigPath = join(projectRoot, 'cms', 'octocms.config.ts');\n if (!existsSync(nextConfigPath)) {\n log.error('next.config.ts not found — run `octocms init` first.');\n process.exitCode = 1;\n return;\n }\n\n log.info(`Starting Next.js dev server on port ${port}...`);\n log.info('Watching next.config.ts and cms/octocms.config.ts for changes...');\n log.blank();\n\n // Spawn next dev\n const nextBin = join(projectRoot, 'node_modules', '.bin', 'next');\n const child = spawn(nextBin, ['dev', '-p', String(port)], {\n cwd: projectRoot,\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n // Watch both config files for changes and regenerate types\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const onConfigChange = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n regenerateTypes(projectRoot);\n }, 300);\n };\n\n const nextWatcher = watch(nextConfigPath, onConfigChange);\n const octoWatcher = existsSync(octoConfigPath) ? watch(octoConfigPath, onConfigChange) : null;\n\n // Forward signals to child\n const cleanup = () => {\n nextWatcher.close();\n octoWatcher?.close();\n if (debounceTimer) clearTimeout(debounceTimer);\n child.kill();\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n\n child.on('exit', (code) => {\n nextWatcher.close();\n octoWatcher?.close();\n if (debounceTimer) clearTimeout(debounceTimer);\n process.exitCode = code ?? 0;\n });\n}\n\nfunction regenerateTypes(projectRoot: string): void {\n log.blank();\n log.step('Config changed — regenerating types...');\n\n const jitiBin = join(projectRoot, 'node_modules', '.bin', 'jiti');\n const scriptPath = join(projectRoot, 'scripts', 'generate-types.ts');\n\n const child = spawn(jitiBin, [scriptPath], {\n cwd: projectRoot,\n stdio: 'pipe',\n });\n\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('exit', (code) => {\n if (code === 0) {\n log.success('Types regenerated');\n } else {\n log.error('Type generation failed:');\n if (stderr.trim()) {\n for (const line of stderr.trim().split('\\n')) {\n log.info(` ${line}`);\n }\n }\n }\n log.blank();\n });\n}\n"],"mappings":";;;;;;;;AAOA,SAAS,aAAa;AACtB,SAAS,YAAY,aAAa;AAClC,SAAS,YAAY;AAQrB,eAAsB,WAAW,aAAqB,UAAsB,CAAC,GAAkB;AAjB/F;AAkBE,QAAM,QAAO,aAAQ,SAAR,YAAgB;AAE7B,MAAI,OAAO,oBAAoB;AAE/B,QAAM,iBAAiB,KAAK,aAAa,gBAAgB;AACzD,QAAM,iBAAiB,KAAK,aAAa,OAAO,mBAAmB;AACnE,MAAI,CAAC,WAAW,cAAc,GAAG;AAC/B,QAAI,MAAM,2DAAsD;AAChE,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,MAAI,KAAK,uCAAuC,IAAI,KAAK;AACzD,MAAI,KAAK,kEAAkE;AAC3E,MAAI,MAAM;AAGV,QAAM,UAAU,KAAK,aAAa,gBAAgB,QAAQ,MAAM;AAChE,QAAM,QAAQ,MAAM,SAAS,CAAC,OAAO,MAAM,OAAO,IAAI,CAAC,GAAG;AAAA,IACxD,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK,mBAAK,QAAQ;AAAA,EACpB,CAAC;AAGD,MAAI,gBAAsD;AAE1D,QAAM,iBAAiB,MAAM;AAC3B,QAAI,cAAe,cAAa,aAAa;AAC7C,oBAAgB,WAAW,MAAM;AAC/B,sBAAgB,WAAW;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR;AAEA,QAAM,cAAc,MAAM,gBAAgB,cAAc;AACxD,QAAM,cAAc,WAAW,cAAc,IAAI,MAAM,gBAAgB,cAAc,IAAI;AAGzF,QAAM,UAAU,MAAM;AACpB,gBAAY,MAAM;AAClB,+CAAa;AACb,QAAI,cAAe,cAAa,aAAa;AAC7C,UAAM,KAAK;AAAA,EACb;AAEA,UAAQ,GAAG,UAAU,OAAO;AAC5B,UAAQ,GAAG,WAAW,OAAO;AAE7B,QAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,gBAAY,MAAM;AAClB,+CAAa;AACb,QAAI,cAAe,cAAa,aAAa;AAC7C,YAAQ,WAAW,sBAAQ;AAAA,EAC7B,CAAC;AACH;AAEA,SAAS,gBAAgB,aAA2B;AA1EpD;AA2EE,MAAI,MAAM;AACV,MAAI,KAAK,6CAAwC;AAEjD,QAAM,UAAU,KAAK,aAAa,gBAAgB,QAAQ,MAAM;AAChE,QAAM,aAAa,KAAK,aAAa,WAAW,mBAAmB;AAEnE,QAAM,QAAQ,MAAM,SAAS,CAAC,UAAU,GAAG;AAAA,IACzC,KAAK;AAAA,IACL,OAAO;AAAA,EACT,CAAC;AAED,MAAI,SAAS;AACb,cAAM,WAAN,mBAAc,GAAG,QAAQ,CAAC,SAAiB;AACzC,cAAU,KAAK,SAAS;AAAA,EAC1B;AAEA,QAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,QAAI,SAAS,GAAG;AACd,UAAI,QAAQ,mBAAmB;AAAA,IACjC,OAAO;AACL,UAAI,MAAM,yBAAyB;AACnC,UAAI,OAAO,KAAK,GAAG;AACjB,mBAAW,QAAQ,OAAO,KAAK,EAAE,MAAM,IAAI,GAAG;AAC5C,cAAI,KAAK,KAAK,IAAI,EAAE;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AACA,QAAI,MAAM;AAAA,EACZ,CAAC;AACH;","names":[]}
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  adminLayoutTemplate,
3
3
  adminPageTemplate,
4
- demoPostJson,
5
- demoPostMarkdown,
4
+ demoHelloPageJson,
5
+ envLocalTemplate,
6
+ helloPageTemplate,
6
7
  nextConfigTemplate,
7
8
  octoConfigTemplate,
9
+ readmeTemplate,
8
10
  tsconfigPaths
9
- } from "./chunk-I7KNSICQ.js";
11
+ } from "./chunk-VL7NZ3J2.js";
10
12
  import {
11
13
  log
12
14
  } from "./chunk-6PHFHGTZ.js";
@@ -56,6 +58,17 @@ async function gatherAnswers(options) {
56
58
  rl.close();
57
59
  }
58
60
  }
61
+ function detectDevPort(projectRoot) {
62
+ var _a, _b;
63
+ try {
64
+ const pkg = JSON.parse(readFileSync(join(projectRoot, "package.json"), "utf8"));
65
+ const devScript = (_b = (_a = pkg.scripts) == null ? void 0 : _a.dev) != null ? _b : "";
66
+ const match = /(?:-p|--port)[= ](\d+)/.exec(devScript);
67
+ if (match) return parseInt(match[1], 10);
68
+ } catch (e) {
69
+ }
70
+ return 3e3;
71
+ }
59
72
  async function initCommand(projectRoot, options = {}) {
60
73
  log.header("Initialize a new project");
61
74
  const octoConfigPath = join(projectRoot, "cms", "octocms.config.ts");
@@ -74,19 +87,19 @@ async function initCommand(projectRoot, options = {}) {
74
87
  const answers = await gatherAnswers(options);
75
88
  log.blank();
76
89
  log.info("Creating files...");
77
- const cmsRouteDir = join(projectRoot, "src", "app", "cms");
90
+ const cmsRouteDir = join(projectRoot, "app", "cms");
78
91
  mkdirSync(join(cmsRouteDir, "[[...path]]"), { recursive: true });
79
92
  writeFileSync(join(cmsRouteDir, "layout.tsx"), adminLayoutTemplate, "utf8");
80
- log.success("src/app/cms/layout.tsx");
93
+ log.success("app/cms/layout.tsx");
81
94
  writeFileSync(join(cmsRouteDir, "[[...path]]", "page.tsx"), adminPageTemplate, "utf8");
82
- log.success("src/app/cms/[[...path]]/page.tsx");
83
- const demoId = "001";
84
- const contentDir = join(projectRoot, "cms", "content", "post");
95
+ log.success("app/cms/[[...path]]/page.tsx");
96
+ mkdirSync(join(projectRoot, "app", "hello"), { recursive: true });
97
+ writeFileSync(join(projectRoot, "app", "hello", "page.tsx"), helloPageTemplate, "utf8");
98
+ log.success("app/hello/page.tsx");
99
+ const contentDir = join(projectRoot, "cms", "content", "helloPage");
85
100
  mkdirSync(contentDir, { recursive: true });
86
- writeFileSync(join(contentDir, `post-${demoId}.json`), demoPostJson(demoId), "utf8");
87
- log.success(`cms/content/post/post-${demoId}.json`);
88
- writeFileSync(join(contentDir, `post-${demoId}.body.md`), demoPostMarkdown, "utf8");
89
- log.success(`cms/content/post/post-${demoId}.body.md`);
101
+ writeFileSync(join(contentDir, "helloPage-0000.json"), demoHelloPageJson(), "utf8");
102
+ log.success("cms/content/helloPage/helloPage-0000.json");
90
103
  mkdirSync(join(projectRoot, "cms", "__generated__"), { recursive: true });
91
104
  mkdirSync(join(projectRoot, "public", "media"), { recursive: true });
92
105
  log.blank();
@@ -121,25 +134,48 @@ async function initCommand(projectRoot, options = {}) {
121
134
  }
122
135
  if (changed) {
123
136
  writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n", "utf8");
124
- log.success("tsconfig.json \u2014 added octocms/* path aliases");
137
+ log.success("tsconfig.json \u2014 added path aliases");
125
138
  } else {
126
139
  log.success("tsconfig.json \u2014 path aliases already present");
127
140
  }
128
141
  } catch (e) {
129
- log.warn("tsconfig.json \u2014 could not parse; add octocms/* paths manually");
142
+ log.warn("tsconfig.json \u2014 could not parse; add path aliases manually");
130
143
  }
131
144
  } else {
132
- log.warn("tsconfig.json not found \u2014 create one with octocms/* path aliases");
145
+ log.warn("tsconfig.json not found \u2014 create one with the required path aliases");
146
+ }
147
+ const envLocalPath = join(projectRoot, ".env.local");
148
+ if (!existsSync(envLocalPath)) {
149
+ writeFileSync(envLocalPath, envLocalTemplate(), "utf8");
150
+ log.success(".env.local \u2014 environment variable stubs");
151
+ } else {
152
+ log.success(".env.local \u2014 already exists, skipped");
153
+ }
154
+ const readmePath = join(projectRoot, "README.md");
155
+ if (!existsSync(readmePath)) {
156
+ writeFileSync(readmePath, readmeTemplate(answers.projectName), "utf8");
157
+ log.success("README.md \u2014 setup guide");
158
+ } else {
159
+ log.success("README.md \u2014 already exists, skipped");
133
160
  }
134
161
  log.blank();
162
+ log.info("Generating types...");
163
+ try {
164
+ const { typesGenCommand } = await import("./typesGen-RGHGMI34.js");
165
+ await typesGenCommand(projectRoot);
166
+ } catch (e) {
167
+ log.warn(`Type generation failed: ${String(e.message)}`);
168
+ log.warn("Run `npx octocms types:gen` after installing dependencies.");
169
+ }
170
+ const port = detectDevPort(projectRoot);
135
171
  log.info("Next steps:");
136
- log.info(" 1. Add GitHub App credentials to .env.local (see README.md)");
137
- log.info(" 2. Run: npm run octocms types:gen");
138
- log.info(" 3. Run: npm run dev");
139
- log.info(" 4. Visit: http://localhost:3001/cms");
172
+ log.info(" 1. Fill in GitHub App credentials in .env.local (see README.md)");
173
+ log.info(" 2. Run: npm run dev");
174
+ log.info(` 3. Visit demo page: http://localhost:${port}/hello`);
175
+ log.info(` 4. Visit CMS admin: http://localhost:${port}/cms`);
140
176
  log.blank();
141
177
  }
142
178
  export {
143
179
  initCommand
144
180
  };
145
- //# sourceMappingURL=init-UGUTJFFI.js.map
181
+ //# sourceMappingURL=init-XLCXOUQB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/commands/init.ts"],"sourcesContent":["/**\n * `octocms init` — Initialize OctoCMS in a Next.js project.\n *\n * Writes the full CMS config inline into `next.config.ts`, creates admin\n * route files, demo content, and updates `tsconfig.json` with required\n * path aliases.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport readline from 'readline';\n\nimport { log } from '../lib/logger';\nimport {\n adminLayoutTemplate,\n adminPageTemplate,\n demoHelloPageJson,\n envLocalTemplate,\n helloPageTemplate,\n nextConfigTemplate,\n octoConfigTemplate,\n readmeTemplate,\n tsconfigPaths,\n} from '../lib/templates';\n\nexport type InitOptions = {\n /** Accept all defaults without prompting. */\n yes?: boolean;\n};\n\ntype InitAnswers = {\n projectName: string;\n baseBranch: string;\n usePointerBranch: boolean;\n pointerBranch: string;\n};\n\nasync function prompt(rl: readline.Interface, question: string, defaultValue?: string): Promise<string> {\n const suffix = defaultValue ? ` (${defaultValue})` : '';\n return new Promise((resolve) => {\n rl.question(` ? ${question}${suffix}: `, (answer) => {\n resolve(answer.trim() || defaultValue || '');\n });\n });\n}\n\nasync function confirm(rl: readline.Interface, question: string, defaultYes = false): Promise<boolean> {\n const hint = defaultYes ? 'Y/n' : 'y/N';\n const answer = await prompt(rl, `${question} (${hint})`);\n if (!answer) return defaultYes;\n return answer.toLowerCase().startsWith('y');\n}\n\nasync function gatherAnswers(options: InitOptions): Promise<InitAnswers> {\n if (options.yes) {\n return {\n projectName: 'My CMS',\n baseBranch: 'main',\n usePointerBranch: false,\n pointerBranch: '',\n };\n }\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const projectName = await prompt(rl, 'Project name', 'My CMS');\n const baseBranch = await prompt(rl, 'Git base branch', 'main');\n const usePointerBranch = await confirm(rl, 'Use a separate published pointer branch?');\n let pointerBranch = '';\n if (usePointerBranch) {\n pointerBranch = await prompt(rl, 'Pointer branch name', 'cms/publish-pointer');\n }\n\n return { projectName, baseBranch, usePointerBranch, pointerBranch };\n } finally {\n rl.close();\n }\n}\n\n/** Detect the dev port from the project's package.json dev script. Defaults to 3000. */\nfunction detectDevPort(projectRoot: string): number {\n try {\n const pkg = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8')) as {\n scripts?: Record<string, string>;\n };\n const devScript = pkg.scripts?.dev ?? '';\n const match = /(?:-p|--port)[= ](\\d+)/.exec(devScript);\n if (match) return parseInt(match[1], 10);\n } catch {\n // ignore\n }\n return 3000;\n}\n\nexport async function initCommand(projectRoot: string, options: InitOptions = {}): Promise<void> {\n log.header('Initialize a new project');\n\n // Already initialized if cms/octocms.config.ts already contains defineConfig\n const octoConfigPath = join(projectRoot, 'cms', 'octocms.config.ts');\n if (existsSync(octoConfigPath) && readFileSync(octoConfigPath, 'utf8').includes('defineConfig')) {\n log.error('cms/octocms.config.ts already contains defineConfig — this project is already initialized.');\n log.info('Use `octocms update` to regenerate admin route files.');\n process.exitCode = 1;\n return;\n }\n const nextConfigPath = join(projectRoot, 'next.config.ts');\n\n if (!existsSync(join(projectRoot, 'package.json'))) {\n log.error('No package.json found — run this inside a Next.js project.');\n process.exitCode = 1;\n return;\n }\n\n const answers = await gatherAnswers(options);\n\n log.blank();\n log.info('Creating files...');\n\n // Admin route files\n const cmsRouteDir = join(projectRoot, 'app', 'cms');\n mkdirSync(join(cmsRouteDir, '[[...path]]'), { recursive: true });\n\n writeFileSync(join(cmsRouteDir, 'layout.tsx'), adminLayoutTemplate, 'utf8');\n log.success('app/cms/layout.tsx');\n\n writeFileSync(join(cmsRouteDir, '[[...path]]', 'page.tsx'), adminPageTemplate, 'utf8');\n log.success('app/cms/[[...path]]/page.tsx');\n\n // Hello page demo route\n mkdirSync(join(projectRoot, 'app', 'hello'), { recursive: true });\n writeFileSync(join(projectRoot, 'app', 'hello', 'page.tsx'), helloPageTemplate, 'utf8');\n log.success('app/hello/page.tsx');\n\n // Demo content\n const contentDir = join(projectRoot, 'cms', 'content', 'helloPage');\n mkdirSync(contentDir, { recursive: true });\n writeFileSync(join(contentDir, 'helloPage-0000.json'), demoHelloPageJson(), 'utf8');\n log.success('cms/content/helloPage/helloPage-0000.json');\n\n // Generated types directory\n mkdirSync(join(projectRoot, 'cms', '__generated__'), { recursive: true });\n\n // Media directory\n mkdirSync(join(projectRoot, 'public', 'media'), { recursive: true });\n\n // cms/octocms.config.ts — write the OctoCMS schema\n log.blank();\n log.info('Updating configuration...');\n mkdirSync(join(projectRoot, 'cms'), { recursive: true });\n writeFileSync(\n octoConfigPath,\n octoConfigTemplate({\n projectName: answers.projectName,\n baseBranch: answers.baseBranch,\n pointerBranch: answers.usePointerBranch ? answers.pointerBranch : undefined,\n }),\n 'utf8',\n );\n log.success('cms/octocms.config.ts — OctoCMS schema');\n\n // next.config.ts — write the thin Next.js wrapper\n writeFileSync(nextConfigPath, nextConfigTemplate(), 'utf8');\n log.success('next.config.ts — Next.js wrapper');\n\n // tsconfig.json\n const tsconfigPath = join(projectRoot, 'tsconfig.json');\n if (existsSync(tsconfigPath)) {\n try {\n const raw = readFileSync(tsconfigPath, 'utf8');\n const tsconfig = JSON.parse(raw);\n if (!tsconfig.compilerOptions) tsconfig.compilerOptions = {};\n if (!tsconfig.compilerOptions.paths) tsconfig.compilerOptions.paths = {};\n const requiredPaths = tsconfigPaths();\n let changed = false;\n for (const [alias, targets] of Object.entries(requiredPaths)) {\n if (!tsconfig.compilerOptions.paths[alias]) {\n tsconfig.compilerOptions.paths[alias] = targets;\n changed = true;\n }\n }\n if (changed) {\n writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + '\\n', 'utf8');\n log.success('tsconfig.json — added path aliases');\n } else {\n log.success('tsconfig.json — path aliases already present');\n }\n } catch {\n log.warn('tsconfig.json — could not parse; add path aliases manually');\n }\n } else {\n log.warn('tsconfig.json not found — create one with the required path aliases');\n }\n\n // .env.local — write stub only if it doesn't already exist\n const envLocalPath = join(projectRoot, '.env.local');\n if (!existsSync(envLocalPath)) {\n writeFileSync(envLocalPath, envLocalTemplate(), 'utf8');\n log.success('.env.local — environment variable stubs');\n } else {\n log.success('.env.local — already exists, skipped');\n }\n\n // README.md — write only if it doesn't already exist\n const readmePath = join(projectRoot, 'README.md');\n if (!existsSync(readmePath)) {\n writeFileSync(readmePath, readmeTemplate(answers.projectName), 'utf8');\n log.success('README.md — setup guide');\n } else {\n log.success('README.md — already exists, skipped');\n }\n\n // Generate types (best-effort — may fail if octocms is not yet installed)\n log.blank();\n log.info('Generating types...');\n try {\n const { typesGenCommand } = await import('./typesGen');\n await typesGenCommand(projectRoot);\n } catch (e) {\n log.warn(`Type generation failed: ${String((e as Error).message)}`);\n log.warn('Run `npx octocms types:gen` after installing dependencies.');\n }\n\n const port = detectDevPort(projectRoot);\n log.info('Next steps:');\n log.info(' 1. Fill in GitHub App credentials in .env.local (see README.md)');\n log.info(' 2. Run: npm run dev');\n log.info(` 3. Visit demo page: http://localhost:${port}/hello`);\n log.info(` 4. Visit CMS admin: http://localhost:${port}/cms`);\n log.blank();\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import {
5
5
  loadCollections,
6
6
  loadFieldTypes,
7
7
  loadProjectConfig
8
- } from "./chunk-C62C776U.js";
8
+ } from "./chunk-VN27V5NE.js";
9
9
  import {
10
10
  log
11
11
  } from "./chunk-6PHFHGTZ.js";
@@ -18,8 +18,8 @@ import { join } from "path";
18
18
  // cli/lib/codegen.ts
19
19
  var CODEGEN_BANNER = `/*
20
20
  * AUTO-GENERATED \u2014 DO NOT EDIT.
21
- * Generated by scripts/generate-types.ts from cms/octocms.config.ts.
22
- * Run \`npm run types:gen\` to regenerate.
21
+ * Generated from cms/octocms.config.ts.
22
+ * Run \`npx octocms types:gen\` to regenerate.
23
23
  */
24
24
 
25
25
  `;
@@ -203,6 +203,23 @@ function generateContentDecls(cfg, collectionNames) {
203
203
  function generateIndex() {
204
204
  return CODEGEN_BANNER + "export * from './types';\nexport * from './enums';\nexport * from './query';\n";
205
205
  }
206
+ function generateQuery() {
207
+ return CODEGEN_BANNER + `import { createQuery } from 'octocms/query';
208
+ import { configOctoCMS, type OctoConfig } from '../octocms.config';
209
+ import type { EntryMap } from './types';
210
+
211
+ // configOctoCMS is widened to Config for admin internals; cast back to OctoConfig so
212
+ // createQuery preserves literal collection/field names for type-safe queries.
213
+ export const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);
214
+ `;
215
+ }
216
+ function generateConfigInit() {
217
+ return CODEGEN_BANNER + `import { configOctoCMS } from '../octocms.config';
218
+ import { setConfig } from 'octocms/lib/configStore';
219
+
220
+ setConfig(configOctoCMS);
221
+ `;
222
+ }
206
223
 
207
224
  // cli/commands/typesGen.ts
208
225
  async function typesGenCommand(projectRoot) {
@@ -227,7 +244,9 @@ async function typesGenCommand(projectRoot) {
227
244
  { name: "types.ts", content: generateTypes(config, collections) },
228
245
  { name: "enums.ts", content: generateEnums(config, collections, fieldTypes) },
229
246
  { name: "content.d.ts", content: generateContentDecls(config, collections) },
230
- { name: "index.ts", content: generateIndex() }
247
+ { name: "index.ts", content: generateIndex() },
248
+ { name: "query.ts", content: generateQuery() },
249
+ { name: "configInit.ts", content: generateConfigInit() }
231
250
  ];
232
251
  for (const file of files) {
233
252
  writeFileSync(join(generatedDir, file.name), file.content, "utf8");
@@ -238,4 +257,4 @@ async function typesGenCommand(projectRoot) {
238
257
  export {
239
258
  typesGenCommand
240
259
  };
241
- //# sourceMappingURL=typesGen-WBC6CNBG.js.map
260
+ //# sourceMappingURL=typesGen-RGHGMI34.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/commands/typesGen.ts","../cli/lib/codegen.ts"],"sourcesContent":["/**\n * `octocms types:gen` — Generate TypeScript types from next.config.ts.\n *\n * Produces `cms/__generated__/types.ts`, `enums.ts`, `content.d.ts`, and `index.ts`.\n * This is the CLI equivalent of `npm run types:gen`.\n */\n\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport {\n generateConfigInit,\n generateContentDecls,\n generateEnums,\n generateIndex,\n generateQuery,\n generateTypes,\n} from '../lib/codegen';\nimport { log } from '../lib/logger';\nimport { loadCollections, loadFieldTypes, loadProjectConfig } from '../lib/project';\nimport { validateConfig } from '../lib/validateConfig';\n\nexport async function typesGenCommand(projectRoot: string): Promise<void> {\n log.header('Generate types');\n\n const config = await loadProjectConfig(projectRoot);\n const collections = await loadCollections(projectRoot);\n const fieldTypes = await loadFieldTypes(projectRoot);\n\n log.info('Validating config...');\n try {\n validateConfig(config, collections);\n } catch (e) {\n log.error(String((e as Error).message));\n process.exitCode = 1;\n return;\n }\n log.success(`${collections.length} collections validated`);\n\n log.blank();\n log.info('Generating types...');\n\n const generatedDir = join(projectRoot, 'cms', '__generated__');\n mkdirSync(generatedDir, { recursive: true });\n\n const files = [\n { name: 'types.ts', content: generateTypes(config, collections) },\n { name: 'enums.ts', content: generateEnums(config, collections, fieldTypes) },\n { name: 'content.d.ts', content: generateContentDecls(config, collections) },\n { name: 'index.ts', content: generateIndex() },\n { name: 'query.ts', content: generateQuery() },\n { name: 'configInit.ts', content: generateConfigInit() },\n ];\n\n for (const file of files) {\n writeFileSync(join(generatedDir, file.name), file.content, 'utf8');\n log.success(`cms/__generated__/${file.name}`);\n }\n\n log.blank();\n}\n","/**\n * Type generation functions — pure functions that produce TypeScript source strings.\n *\n * Moved here from `scripts/generate-types.ts` as part of Phase 4 (CLI).\n * The script now imports these functions; the CLI `types:gen` command calls them directly.\n */\n\nimport type { CollectionField, Config, ConditionalBranchConfig } from '../../types';\n\nexport const CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated from cms/octocms.config.ts.\n * Run \\`npx octocms types:gen\\` to regenerate.\n */\n\n`;\n\n/** Capitalize the first letter of a string: `post` → `Post`, `homePage` → `HomePage`. */\nexport function pascalCase(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/** Build the TypeScript type string for a single field definition. */\nexport function fieldToTSType(\n field: CollectionField,\n collectionNames: readonly string[],\n mode: 'resolved' | 'raw' = 'resolved',\n): string {\n switch (field.format) {\n case 'string':\n return field.list ? 'string[]' : 'string';\n case 'text':\n case 'markdown':\n case 'slug':\n case 'url':\n case 'color':\n return 'string';\n case 'richtext':\n return 'RichTextDocument';\n case 'boolean':\n return \"'true' | 'false'\";\n case 'number':\n return 'number | null';\n case 'datetime':\n return 'string | null';\n case 'image':\n return mode === 'raw' ? 'string' : 'ResolvedImageField';\n case 'json':\n return 'unknown';\n case 'select': {\n const union = field.options.map((o) => `'${o.value}'`).join(' | ');\n if (field.multiple) {\n return field.options.length > 1 ? `(${union})[]` : `${union}[]`;\n }\n return union;\n }\n case 'reference': {\n if (mode === 'raw') {\n const cardinality = field.reference?.cardinality ?? 'many';\n return cardinality === 'one' ? 'string' : 'string';\n }\n return referenceFieldType(field, collectionNames);\n }\n case 'conditional': {\n if (mode === 'raw') {\n return 'unknown';\n }\n return conditionalFieldType(field, collectionNames);\n }\n default:\n return 'unknown';\n }\n}\n\nfunction referenceFieldType(\n field: Extract<CollectionField, { format: 'reference' }>,\n collectionNames: readonly string[],\n): string {\n const cols = field.reference?.collections ?? (field.collection ? [field.collection] : [...collectionNames]);\n const entryTypes = cols.map((c) => `${pascalCase(c)}Entry`);\n const union = entryTypes.length > 1 ? entryTypes.join(' | ') : entryTypes[0];\n const cardinality = field.reference?.cardinality ?? 'many';\n if (cardinality === 'one') {\n return entryTypes.length > 1 ? `(${union}) | null` : `${union} | null`;\n }\n return entryTypes.length > 1 ? `(${union})[]` : `${union}[]`;\n}\n\nfunction conditionalFieldType(\n field: Extract<CollectionField, { format: 'conditional' }>,\n collectionNames: readonly string[],\n): string {\n const branchTypes = field.conditional.branches.map((branch) => branchValueType(branch, collectionNames));\n return branchTypes.join(' | ');\n}\n\nfunction branchValueType(branch: ConditionalBranchConfig, collectionNames: readonly string[]): string {\n if ('collection' in branch && typeof branch.collection === 'string') {\n return `${pascalCase(branch.collection)}Entry`;\n }\n if (branch.fields) {\n const entries = Object.entries(branch.fields);\n if (entries.length === 0) return '{}';\n const props = entries.map(([name, f]) => ` ${name}: ${fieldToTSType(f, collectionNames)};`);\n return `{\\n${props.join('\\n')}\\n}`;\n }\n return 'unknown';\n}\n\n// ---------------------------------------------------------------------------\n// Generators\n// ---------------------------------------------------------------------------\n\nexport function generateTypes(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER + \"import type { EntryStatus, ResolvedImageField } from 'octocms/types';\",\n '',\n ];\n\n // Emit Fields interfaces\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n const tsType = fieldToTSType(field, collectionNames);\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n }\n\n // Emit Entry interfaces\n for (const key of collectionNames) {\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: ${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // AnyEntry union\n const entryNames = collectionNames.map((k) => `${pascalCase(k)}Entry`);\n lines.push(`export type AnyEntry = ${entryNames.join(' | ')};`);\n lines.push('');\n\n // EntryMap\n lines.push('export type EntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: ${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateEnums(cfg: Config, collectionNames: readonly string[], fieldTypes: readonly string[]): string {\n const lines: string[] = [];\n\n // CollectionName const object\n lines.push('export const CollectionName = {');\n for (const key of collectionNames) {\n lines.push(` ${pascalCase(key)}: '${key}',`);\n }\n lines.push('} as const;');\n lines.push('export type CollectionName = (typeof CollectionName)[keyof typeof CollectionName];');\n lines.push('');\n\n // COLLECTION_NAMES array\n lines.push(`export const COLLECTION_NAMES = [${collectionNames.map((k) => `'${k}'`).join(', ')}] as const;`);\n lines.push('');\n\n // Select option enums per collection\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format !== 'select') continue;\n const enumName = `${pascalCase(key)}${pascalCase(fieldName)}Option`;\n lines.push(`export const ${enumName} = {`);\n for (const opt of field.options) {\n lines.push(` ${pascalCase(opt.value)}: '${opt.value}',`);\n }\n lines.push('} as const;');\n lines.push(`export type ${enumName} = (typeof ${enumName})[keyof typeof ${enumName}];`);\n lines.push('');\n }\n }\n\n // FieldFormat const object\n lines.push('export const FieldFormat = {');\n for (const ft of fieldTypes) {\n lines.push(` ${pascalCase(ft)}: '${ft}',`);\n }\n lines.push('} as const;');\n lines.push('export type FieldFormat = (typeof FieldFormat)[keyof typeof FieldFormat];');\n lines.push('');\n\n return CODEGEN_BANNER + lines.join('\\n');\n}\n\nexport function generateContentDecls(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER +\n \"import type { EntryStatus } from 'octocms/types';\\n\\n\" +\n '// Raw on-disk types (before query() processing).\\n' +\n '// Image fields are UUID strings, reference fields are key strings,\\n' +\n '// markdown fields are omitted (stored in companion .md files),\\n' +\n '// richtext fields are omitted (stored in companion .mdx files).\\n',\n ];\n\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n\n lines.push(`export interface Raw${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format === 'markdown' || field.format === 'richtext') continue; // companion files, not in JSON\n const tsType = fieldToTSType(field, collectionNames, 'raw');\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n\n lines.push(`export interface Raw${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: Raw${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // RawEntryMap\n lines.push('export type RawEntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: Raw${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateIndex(): string {\n return CODEGEN_BANNER + \"export * from './types';\\nexport * from './enums';\\nexport * from './query';\\n\";\n}\n\n/**\n * Generate the app-specific `query.ts` file that binds `createQuery` from `octocms/query`\n * to the app's config and generated `EntryMap` type.\n *\n * This file is emitted to `cms/__generated__/query.ts` by `npm run types:gen`.\n * Consumers import the typed `query` function from `cms/__generated__/query`.\n */\nexport function generateQuery(): string {\n return (\n CODEGEN_BANNER +\n `import { createQuery } from 'octocms/query';\nimport { configOctoCMS, type OctoConfig } from '../octocms.config';\nimport type { EntryMap } from './types';\n\n// configOctoCMS is widened to Config for admin internals; cast back to OctoConfig so\n// createQuery preserves literal collection/field names for type-safe queries.\nexport const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);\n`\n );\n}\n\n/**\n * Generate `configInit.ts` — a side-effect module that imports the app config\n * and registers it with the `octocms` config store.\n *\n * Importing this file ensures the singleton is populated even in serverless\n * cold starts where `cms/octocms.config.ts` (and therefore `withOctoCMS`) has not run.\n *\n * Emitted to `cms/__generated__/configInit.ts` by `npm run types:gen`.\n */\nexport function generateConfigInit(): string {\n return (\n CODEGEN_BANNER +\n `import { configOctoCMS } from '../octocms.config';\nimport { setConfig } from 'octocms/lib/configStore';\n\nsetConfig(configOctoCMS);\n`\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  adminLayoutTemplate,
3
3
  adminPageTemplate
4
- } from "./chunk-I7KNSICQ.js";
4
+ } from "./chunk-VL7NZ3J2.js";
5
5
  import {
6
6
  log
7
7
  } from "./chunk-6PHFHGTZ.js";
@@ -54,4 +54,4 @@ async function updateCommand(projectRoot) {
54
54
  export {
55
55
  updateCommand
56
56
  };
57
- //# sourceMappingURL=update-RMGZMS56.js.map
57
+ //# sourceMappingURL=update-VXVCXDEE.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  loadCollections,
6
6
  loadProjectConfig
7
- } from "./chunk-C62C776U.js";
7
+ } from "./chunk-VN27V5NE.js";
8
8
  import {
9
9
  fmt,
10
10
  log
@@ -294,4 +294,4 @@ async function validateCommand(projectRoot) {
294
294
  export {
295
295
  validateCommand
296
296
  };
297
- //# sourceMappingURL=validate-OTJ6ULMP.js.map
297
+ //# sourceMappingURL=validate-X6ALTVGH.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "octocms",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "A file-based CMS for Next.js — schema-driven, Git-backed, no database",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -56,6 +56,7 @@
56
56
  ],
57
57
  "scripts": {
58
58
  "build": "tsup",
59
+ "prepublishOnly": "npm run checks && npm run build",
59
60
  "lint": "oxlint .",
60
61
  "lint:fix": "oxlint --fix .",
61
62
  "fmt": "oxfmt .",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../cli/lib/project.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'fs';\nimport { dirname, join } from 'path';\n\n/**\n * Walk up from `startDir` until we find a directory containing a\n * `next.config.ts` that includes `withOctoCMS`.\n * Returns the absolute path to the project root.\n */\nexport function resolveProjectRoot(startDir?: string): string {\n let dir = startDir ?? process.cwd();\n for (;;) {\n const nextConfigPath = join(dir, 'next.config.ts');\n if (existsSync(nextConfigPath) && readFileSync(nextConfigPath, 'utf8').includes('withOctoCMS')) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n throw new Error('Could not find next.config.ts with withOctoCMS — are you inside an OctoCMS project?');\n }\n dir = parent;\n }\n}\n\n/**\n * Load the CMS config from a project root. Uses `jiti` to handle TypeScript\n * files and tsconfig path aliases at runtime.\n */\nexport async function loadProjectConfig(projectRoot: string) {\n // Dynamic import so jiti stays an optional peer when published\n const { createJiti } = await import('jiti');\n const jiti = createJiti(join(projectRoot, '__cli_loader__.ts'), {\n fsCache: false,\n moduleCache: false,\n alias: {\n 'octocms/': join(projectRoot, 'octocms/'),\n },\n });\n const mod = (await jiti.import(join(projectRoot, 'cms', 'octocms.config.ts'), {\n default: true,\n try: true,\n })) as Record<string, unknown> | undefined;\n if (!mod || !mod.configOctoCMS) {\n throw new Error('cms/octocms.config.ts must export a `configOctoCMS` object (use defineConfig())');\n }\n return mod.configOctoCMS as import('../../types').Config;\n}\n\n/**\n * Load the COLLECTIONS array from `octocms/admin/consts.ts`.\n */\nexport async function loadCollections(projectRoot: string): Promise<readonly string[]> {\n const { createJiti } = await import('jiti');\n const jiti = createJiti(join(projectRoot, '__cli_loader__.ts'), {\n fsCache: false,\n moduleCache: false,\n alias: {\n 'octocms/': join(projectRoot, 'octocms/'),\n },\n });\n const mod = (await jiti.import(join(projectRoot, 'octocms/admin/consts.ts'), {\n default: true,\n try: true,\n })) as Record<string, unknown> | undefined;\n if (!mod || !Array.isArray(mod.COLLECTIONS)) {\n throw new Error('Could not load COLLECTIONS from octocms/admin/consts.ts');\n }\n return mod.COLLECTIONS as readonly string[];\n}\n\n/**\n * Load FIELD_TYPES from `octocms/admin/consts.ts`.\n */\nexport async function loadFieldTypes(projectRoot: string): Promise<readonly string[]> {\n const { createJiti } = await import('jiti');\n const jiti = createJiti(join(projectRoot, '__cli_loader__.ts'), {\n fsCache: false,\n moduleCache: false,\n alias: {\n 'octocms/': join(projectRoot, 'octocms/'),\n },\n });\n const mod = (await jiti.import(join(projectRoot, 'octocms/admin/consts.ts'), {\n default: true,\n try: true,\n })) as Record<string, unknown> | undefined;\n if (!mod || !Array.isArray(mod.FIELD_TYPES)) {\n throw new Error('Could not load FIELD_TYPES from octocms/admin/consts.ts');\n }\n return mod.FIELD_TYPES as readonly string[];\n}\n"],"mappings":";AAAA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,YAAY;AAOvB,SAAS,mBAAmB,UAA2B;AAC5D,MAAI,MAAM,8BAAY,QAAQ,IAAI;AAClC,aAAS;AACP,UAAM,iBAAiB,KAAK,KAAK,gBAAgB;AACjD,QAAI,WAAW,cAAc,KAAK,aAAa,gBAAgB,MAAM,EAAE,SAAS,aAAa,GAAG;AAC9F,aAAO;AAAA,IACT;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,KAAK;AAClB,YAAM,IAAI,MAAM,0FAAqF;AAAA,IACvG;AACA,UAAM;AAAA,EACR;AACF;AAMA,eAAsB,kBAAkB,aAAqB;AAE3D,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAM;AAC1C,QAAM,OAAO,WAAW,KAAK,aAAa,mBAAmB,GAAG;AAAA,IAC9D,SAAS;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,MACL,YAAY,KAAK,aAAa,UAAU;AAAA,IAC1C;AAAA,EACF,CAAC;AACD,QAAM,MAAO,MAAM,KAAK,OAAO,KAAK,aAAa,OAAO,mBAAmB,GAAG;AAAA,IAC5E,SAAS;AAAA,IACT,KAAK;AAAA,EACP,CAAC;AACD,MAAI,CAAC,OAAO,CAAC,IAAI,eAAe;AAC9B,UAAM,IAAI,MAAM,iFAAiF;AAAA,EACnG;AACA,SAAO,IAAI;AACb;AAKA,eAAsB,gBAAgB,aAAiD;AACrF,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAM;AAC1C,QAAM,OAAO,WAAW,KAAK,aAAa,mBAAmB,GAAG;AAAA,IAC9D,SAAS;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,MACL,YAAY,KAAK,aAAa,UAAU;AAAA,IAC1C;AAAA,EACF,CAAC;AACD,QAAM,MAAO,MAAM,KAAK,OAAO,KAAK,aAAa,yBAAyB,GAAG;AAAA,IAC3E,SAAS;AAAA,IACT,KAAK;AAAA,EACP,CAAC;AACD,MAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAC3C,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO,IAAI;AACb;AAKA,eAAsB,eAAe,aAAiD;AACpF,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAM;AAC1C,QAAM,OAAO,WAAW,KAAK,aAAa,mBAAmB,GAAG;AAAA,IAC9D,SAAS;AAAA,IACT,aAAa;AAAA,IACb,OAAO;AAAA,MACL,YAAY,KAAK,aAAa,UAAU;AAAA,IAC1C;AAAA,EACF,CAAC;AACD,QAAM,MAAO,MAAM,KAAK,OAAO,KAAK,aAAa,yBAAyB,GAAG;AAAA,IAC3E,SAAS;AAAA,IACT,KAAK;AAAA,EACP,CAAC;AACD,MAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,IAAI,WAAW,GAAG;AAC3C,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO,IAAI;AACb;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../cli/lib/templates.ts"],"sourcesContent":["/**\n * File templates used by `octocms init` and `octocms update`.\n */\n\nexport const adminLayoutTemplate = `import '../../../cms/__generated__/configInit';\nimport 'octocms/globals.css';\nimport '@mdxeditor/editor/style.css';\n\nexport { AdminLayout as default, metadata } from 'octocms/admin/pages/AdminLayout';\n`;\n\nexport const adminPageTemplate = `export { AdminApp as default } from 'octocms/admin/AdminApp';\n`;\n\nexport function octoConfigTemplate(opts: { projectName: string; baseBranch: string; pointerBranch?: string }): string {\n const gitBlock = opts.pointerBranch\n ? ` git: {\\n baseBranch: '${opts.baseBranch}',\\n publishedPointerBranch: '${opts.pointerBranch}',\\n },`\n : ` git: { baseBranch: '${opts.baseBranch}' },`;\n\n return `import type { Config } from 'octocms/types';\nimport { defineConfig } from 'octocms/config';\n\nconst _typedConfigOctoCMS = defineConfig({\n projectName: '${opts.projectName}',\n${gitBlock}\n contentFolder: 'cms/content',\n mediaFolder: 'public/media',\n mediaAllowedFormats: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'avif'],\n collections: {\n post: {\n label: 'Posts',\n hasMany: true,\n fields: {\n title: { label: 'Title', format: 'string', entryTitle: true, required: true },\n slug: { label: 'Slug', format: 'slug', slugSource: 'title', required: true },\n body: { label: 'Body', format: 'markdown' },\n publishedAt: { label: 'Published At', format: 'datetime', defaultNow: true },\n },\n },\n },\n});\n\nexport const configOctoCMS: Config = _typedConfigOctoCMS;\nexport type OctoConfig = typeof _typedConfigOctoCMS;\n`;\n}\n\nexport function nextConfigTemplate(): string {\n return `import type { NextConfig } from 'next';\nimport { withOctoCMS } from 'octocms/config';\nimport { configOctoCMS } from './cms/octocms.config';\n\nexport { configOctoCMS } from './cms/octocms.config';\nexport type { OctoConfig } from './cms/octocms.config';\n\nconst nextConfig: NextConfig = {};\n\nexport default withOctoCMS(nextConfig, configOctoCMS);\n`;\n}\n\nexport function demoPostJson(id: string): string {\n const now = new Date().toISOString();\n return JSON.stringify(\n {\n sys: { id, type: 'post', status: 'merged' },\n fields: {\n title: 'Hello World',\n slug: 'hello-world',\n publishedAt: now,\n },\n },\n null,\n 2,\n );\n}\n\nexport const demoPostMarkdown = `# Hello World\n\nWelcome to your new OctoCMS site! This is a demo post.\n\nEdit this content in the CMS admin panel at \\`/cms\\`.\n`;\n\nconst AGENT_DOCS_MARKER = '<!-- octocms:agent-docs -->';\n\nexport function agentsMdSection(): string {\n return `${AGENT_DOCS_MARKER}\n## OctoCMS — AI Content Management\n\nFor tasks that involve creating, editing, or deleting CMS content directly (without the admin UI), read the auto-generated agent docs:\n\n- **\\`octocms/docs/overview.md\\`** — How to find, create, update, and delete content entries via file operations\n- **\\`octocms/docs/schema.md\\`** — Per-collection field definitions, example JSON, and file path conventions\n\nThese docs are generated from \\`cms/octocms.config.ts\\`. Regenerate after schema changes: \\`npm run agent-docs:gen\\`.`;\n}\n\nexport function agentsMdTemplate(): string {\n return `# Project Guidelines\n\n${agentsMdSection()}\n`;\n}\n\nexport function tsconfigPaths(): Record<string, string[]> {\n return {\n 'cms/__generated__': ['./cms/__generated__/index.ts'],\n 'cms/__generated__/*': ['./cms/__generated__/*'],\n 'octocms/*': ['./octocms/*'],\n '@/*': ['./src/*'],\n };\n}\n"],"mappings":";AAIO,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAO5B,IAAM,oBAAoB;AAAA;AAG1B,SAAS,mBAAmB,MAAmF;AACpH,QAAM,WAAW,KAAK,gBAClB;AAAA,mBAA8B,KAAK,UAAU;AAAA,+BAAoC,KAAK,aAAa;AAAA,QACnG,yBAAyB,KAAK,UAAU;AAE5C,SAAO;AAAA;AAAA;AAAA;AAAA,kBAIS,KAAK,WAAW;AAAA,EAChC,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBV;AAEO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWT;AAEO,SAAS,aAAa,IAAoB;AAC/C,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,SAAO,KAAK;AAAA,IACV;AAAA,MACE,KAAK,EAAE,IAAI,MAAM,QAAQ,QAAQ,SAAS;AAAA,MAC1C,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAOhC,IAAM,oBAAoB;AAEnB,SAAS,kBAA0B;AACxC,SAAO,GAAG,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS7B;AAEO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA,EAEP,gBAAgB,CAAC;AAAA;AAEnB;AAEO,SAAS,gBAA0C;AACxD,SAAO;AAAA,IACL,qBAAqB,CAAC,8BAA8B;AAAA,IACpD,uBAAuB,CAAC,uBAAuB;AAAA,IAC/C,aAAa,CAAC,aAAa;AAAA,IAC3B,OAAO,CAAC,SAAS;AAAA,EACnB;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../cli/commands/init.ts"],"sourcesContent":["/**\n * `octocms init` — Initialize OctoCMS in a Next.js project.\n *\n * Writes the full CMS config inline into `next.config.ts`, creates admin\n * route files, demo content, and updates `tsconfig.json` with required\n * path aliases.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport readline from 'readline';\n\nimport { log } from '../lib/logger';\nimport {\n adminLayoutTemplate,\n adminPageTemplate,\n demoPostJson,\n demoPostMarkdown,\n nextConfigTemplate,\n octoConfigTemplate,\n tsconfigPaths,\n} from '../lib/templates';\n\nexport type InitOptions = {\n /** Accept all defaults without prompting. */\n yes?: boolean;\n};\n\ntype InitAnswers = {\n projectName: string;\n baseBranch: string;\n usePointerBranch: boolean;\n pointerBranch: string;\n};\n\nasync function prompt(rl: readline.Interface, question: string, defaultValue?: string): Promise<string> {\n const suffix = defaultValue ? ` (${defaultValue})` : '';\n return new Promise((resolve) => {\n rl.question(` ? ${question}${suffix}: `, (answer) => {\n resolve(answer.trim() || defaultValue || '');\n });\n });\n}\n\nasync function confirm(rl: readline.Interface, question: string, defaultYes = false): Promise<boolean> {\n const hint = defaultYes ? 'Y/n' : 'y/N';\n const answer = await prompt(rl, `${question} (${hint})`);\n if (!answer) return defaultYes;\n return answer.toLowerCase().startsWith('y');\n}\n\nasync function gatherAnswers(options: InitOptions): Promise<InitAnswers> {\n if (options.yes) {\n return {\n projectName: 'My CMS',\n baseBranch: 'main',\n usePointerBranch: false,\n pointerBranch: '',\n };\n }\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const projectName = await prompt(rl, 'Project name', 'My CMS');\n const baseBranch = await prompt(rl, 'Git base branch', 'main');\n const usePointerBranch = await confirm(rl, 'Use a separate published pointer branch?');\n let pointerBranch = '';\n if (usePointerBranch) {\n pointerBranch = await prompt(rl, 'Pointer branch name', 'cms/publish-pointer');\n }\n\n return { projectName, baseBranch, usePointerBranch, pointerBranch };\n } finally {\n rl.close();\n }\n}\n\nexport async function initCommand(projectRoot: string, options: InitOptions = {}): Promise<void> {\n log.header('Initialize a new project');\n\n // Already initialized if cms/octocms.config.ts already contains defineConfig\n const octoConfigPath = join(projectRoot, 'cms', 'octocms.config.ts');\n if (existsSync(octoConfigPath) && readFileSync(octoConfigPath, 'utf8').includes('defineConfig')) {\n log.error('cms/octocms.config.ts already contains defineConfig — this project is already initialized.');\n log.info('Use `octocms update` to regenerate admin route files.');\n process.exitCode = 1;\n return;\n }\n const nextConfigPath = join(projectRoot, 'next.config.ts');\n\n if (!existsSync(join(projectRoot, 'package.json'))) {\n log.error('No package.json found — run this inside a Next.js project.');\n process.exitCode = 1;\n return;\n }\n\n const answers = await gatherAnswers(options);\n\n log.blank();\n log.info('Creating files...');\n\n // Admin route files\n const cmsRouteDir = join(projectRoot, 'src', 'app', 'cms');\n mkdirSync(join(cmsRouteDir, '[[...path]]'), { recursive: true });\n\n writeFileSync(join(cmsRouteDir, 'layout.tsx'), adminLayoutTemplate, 'utf8');\n log.success('src/app/cms/layout.tsx');\n\n writeFileSync(join(cmsRouteDir, '[[...path]]', 'page.tsx'), adminPageTemplate, 'utf8');\n log.success('src/app/cms/[[...path]]/page.tsx');\n\n // Demo content\n const demoId = '001';\n const contentDir = join(projectRoot, 'cms', 'content', 'post');\n mkdirSync(contentDir, { recursive: true });\n\n writeFileSync(join(contentDir, `post-${demoId}.json`), demoPostJson(demoId), 'utf8');\n log.success(`cms/content/post/post-${demoId}.json`);\n\n writeFileSync(join(contentDir, `post-${demoId}.body.md`), demoPostMarkdown, 'utf8');\n log.success(`cms/content/post/post-${demoId}.body.md`);\n\n // Generated types directory\n mkdirSync(join(projectRoot, 'cms', '__generated__'), { recursive: true });\n\n // Media directory\n mkdirSync(join(projectRoot, 'public', 'media'), { recursive: true });\n\n // cms/octocms.config.ts — write the OctoCMS schema\n log.blank();\n log.info('Updating configuration...');\n mkdirSync(join(projectRoot, 'cms'), { recursive: true });\n writeFileSync(\n octoConfigPath,\n octoConfigTemplate({\n projectName: answers.projectName,\n baseBranch: answers.baseBranch,\n pointerBranch: answers.usePointerBranch ? answers.pointerBranch : undefined,\n }),\n 'utf8',\n );\n log.success('cms/octocms.config.ts — OctoCMS schema');\n\n // next.config.ts — write the thin Next.js wrapper\n writeFileSync(nextConfigPath, nextConfigTemplate(), 'utf8');\n log.success('next.config.ts — Next.js wrapper');\n\n // tsconfig.json\n const tsconfigPath = join(projectRoot, 'tsconfig.json');\n if (existsSync(tsconfigPath)) {\n try {\n const raw = readFileSync(tsconfigPath, 'utf8');\n const tsconfig = JSON.parse(raw);\n if (!tsconfig.compilerOptions) tsconfig.compilerOptions = {};\n if (!tsconfig.compilerOptions.paths) tsconfig.compilerOptions.paths = {};\n const requiredPaths = tsconfigPaths();\n let changed = false;\n for (const [alias, targets] of Object.entries(requiredPaths)) {\n if (!tsconfig.compilerOptions.paths[alias]) {\n tsconfig.compilerOptions.paths[alias] = targets;\n changed = true;\n }\n }\n if (changed) {\n writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + '\\n', 'utf8');\n log.success('tsconfig.json — added octocms/* path aliases');\n } else {\n log.success('tsconfig.json — path aliases already present');\n }\n } catch {\n log.warn('tsconfig.json — could not parse; add octocms/* paths manually');\n }\n } else {\n log.warn('tsconfig.json not found — create one with octocms/* path aliases');\n }\n\n log.blank();\n log.info('Next steps:');\n log.info(' 1. Add GitHub App credentials to .env.local (see README.md)');\n log.info(' 2. Run: npm run octocms types:gen');\n log.info(' 3. Run: npm run dev');\n log.info(' 4. Visit: http://localhost:3001/cms');\n log.blank();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../cli/commands/typesGen.ts","../cli/lib/codegen.ts"],"sourcesContent":["/**\n * `octocms types:gen` — Generate TypeScript types from next.config.ts.\n *\n * Produces `cms/__generated__/types.ts`, `enums.ts`, `content.d.ts`, and `index.ts`.\n * This is the CLI equivalent of `npm run types:gen`.\n */\n\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport { generateContentDecls, generateEnums, generateIndex, generateTypes } from '../lib/codegen';\nimport { log } from '../lib/logger';\nimport { loadCollections, loadFieldTypes, loadProjectConfig } from '../lib/project';\nimport { validateConfig } from '../lib/validateConfig';\n\nexport async function typesGenCommand(projectRoot: string): Promise<void> {\n log.header('Generate types');\n\n const config = await loadProjectConfig(projectRoot);\n const collections = await loadCollections(projectRoot);\n const fieldTypes = await loadFieldTypes(projectRoot);\n\n log.info('Validating config...');\n try {\n validateConfig(config, collections);\n } catch (e) {\n log.error(String((e as Error).message));\n process.exitCode = 1;\n return;\n }\n log.success(`${collections.length} collections validated`);\n\n log.blank();\n log.info('Generating types...');\n\n const generatedDir = join(projectRoot, 'cms', '__generated__');\n mkdirSync(generatedDir, { recursive: true });\n\n const files = [\n { name: 'types.ts', content: generateTypes(config, collections) },\n { name: 'enums.ts', content: generateEnums(config, collections, fieldTypes) },\n { name: 'content.d.ts', content: generateContentDecls(config, collections) },\n { name: 'index.ts', content: generateIndex() },\n ];\n\n for (const file of files) {\n writeFileSync(join(generatedDir, file.name), file.content, 'utf8');\n log.success(`cms/__generated__/${file.name}`);\n }\n\n log.blank();\n}\n","/**\n * Type generation functions — pure functions that produce TypeScript source strings.\n *\n * Moved here from `scripts/generate-types.ts` as part of Phase 4 (CLI).\n * The script now imports these functions; the CLI `types:gen` command calls them directly.\n */\n\nimport type { CollectionField, Config, ConditionalBranchConfig } from '../../types';\n\nexport const CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated by scripts/generate-types.ts from cms/octocms.config.ts.\n * Run \\`npm run types:gen\\` to regenerate.\n */\n\n`;\n\n/** Capitalize the first letter of a string: `post` → `Post`, `homePage` → `HomePage`. */\nexport function pascalCase(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/** Build the TypeScript type string for a single field definition. */\nexport function fieldToTSType(\n field: CollectionField,\n collectionNames: readonly string[],\n mode: 'resolved' | 'raw' = 'resolved',\n): string {\n switch (field.format) {\n case 'string':\n return field.list ? 'string[]' : 'string';\n case 'text':\n case 'markdown':\n case 'slug':\n case 'url':\n case 'color':\n return 'string';\n case 'richtext':\n return 'RichTextDocument';\n case 'boolean':\n return \"'true' | 'false'\";\n case 'number':\n return 'number | null';\n case 'datetime':\n return 'string | null';\n case 'image':\n return mode === 'raw' ? 'string' : 'ResolvedImageField';\n case 'json':\n return 'unknown';\n case 'select': {\n const union = field.options.map((o) => `'${o.value}'`).join(' | ');\n if (field.multiple) {\n return field.options.length > 1 ? `(${union})[]` : `${union}[]`;\n }\n return union;\n }\n case 'reference': {\n if (mode === 'raw') {\n const cardinality = field.reference?.cardinality ?? 'many';\n return cardinality === 'one' ? 'string' : 'string';\n }\n return referenceFieldType(field, collectionNames);\n }\n case 'conditional': {\n if (mode === 'raw') {\n return 'unknown';\n }\n return conditionalFieldType(field, collectionNames);\n }\n default:\n return 'unknown';\n }\n}\n\nfunction referenceFieldType(\n field: Extract<CollectionField, { format: 'reference' }>,\n collectionNames: readonly string[],\n): string {\n const cols = field.reference?.collections ?? (field.collection ? [field.collection] : [...collectionNames]);\n const entryTypes = cols.map((c) => `${pascalCase(c)}Entry`);\n const union = entryTypes.length > 1 ? entryTypes.join(' | ') : entryTypes[0];\n const cardinality = field.reference?.cardinality ?? 'many';\n if (cardinality === 'one') {\n return entryTypes.length > 1 ? `(${union}) | null` : `${union} | null`;\n }\n return entryTypes.length > 1 ? `(${union})[]` : `${union}[]`;\n}\n\nfunction conditionalFieldType(\n field: Extract<CollectionField, { format: 'conditional' }>,\n collectionNames: readonly string[],\n): string {\n const branchTypes = field.conditional.branches.map((branch) => branchValueType(branch, collectionNames));\n return branchTypes.join(' | ');\n}\n\nfunction branchValueType(branch: ConditionalBranchConfig, collectionNames: readonly string[]): string {\n if ('collection' in branch && typeof branch.collection === 'string') {\n return `${pascalCase(branch.collection)}Entry`;\n }\n if (branch.fields) {\n const entries = Object.entries(branch.fields);\n if (entries.length === 0) return '{}';\n const props = entries.map(([name, f]) => ` ${name}: ${fieldToTSType(f, collectionNames)};`);\n return `{\\n${props.join('\\n')}\\n}`;\n }\n return 'unknown';\n}\n\n// ---------------------------------------------------------------------------\n// Generators\n// ---------------------------------------------------------------------------\n\nexport function generateTypes(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER + \"import type { EntryStatus, ResolvedImageField } from 'octocms/types';\",\n '',\n ];\n\n // Emit Fields interfaces\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n const tsType = fieldToTSType(field, collectionNames);\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n }\n\n // Emit Entry interfaces\n for (const key of collectionNames) {\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: ${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // AnyEntry union\n const entryNames = collectionNames.map((k) => `${pascalCase(k)}Entry`);\n lines.push(`export type AnyEntry = ${entryNames.join(' | ')};`);\n lines.push('');\n\n // EntryMap\n lines.push('export type EntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: ${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateEnums(cfg: Config, collectionNames: readonly string[], fieldTypes: readonly string[]): string {\n const lines: string[] = [];\n\n // CollectionName const object\n lines.push('export const CollectionName = {');\n for (const key of collectionNames) {\n lines.push(` ${pascalCase(key)}: '${key}',`);\n }\n lines.push('} as const;');\n lines.push('export type CollectionName = (typeof CollectionName)[keyof typeof CollectionName];');\n lines.push('');\n\n // COLLECTION_NAMES array\n lines.push(`export const COLLECTION_NAMES = [${collectionNames.map((k) => `'${k}'`).join(', ')}] as const;`);\n lines.push('');\n\n // Select option enums per collection\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format !== 'select') continue;\n const enumName = `${pascalCase(key)}${pascalCase(fieldName)}Option`;\n lines.push(`export const ${enumName} = {`);\n for (const opt of field.options) {\n lines.push(` ${pascalCase(opt.value)}: '${opt.value}',`);\n }\n lines.push('} as const;');\n lines.push(`export type ${enumName} = (typeof ${enumName})[keyof typeof ${enumName}];`);\n lines.push('');\n }\n }\n\n // FieldFormat const object\n lines.push('export const FieldFormat = {');\n for (const ft of fieldTypes) {\n lines.push(` ${pascalCase(ft)}: '${ft}',`);\n }\n lines.push('} as const;');\n lines.push('export type FieldFormat = (typeof FieldFormat)[keyof typeof FieldFormat];');\n lines.push('');\n\n return CODEGEN_BANNER + lines.join('\\n');\n}\n\nexport function generateContentDecls(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER +\n \"import type { EntryStatus } from 'octocms/types';\\n\\n\" +\n '// Raw on-disk types (before query() processing).\\n' +\n '// Image fields are UUID strings, reference fields are key strings,\\n' +\n '// markdown fields are omitted (stored in companion .md files),\\n' +\n '// richtext fields are omitted (stored in companion .mdx files).\\n',\n ];\n\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n\n lines.push(`export interface Raw${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format === 'markdown' || field.format === 'richtext') continue; // companion files, not in JSON\n const tsType = fieldToTSType(field, collectionNames, 'raw');\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n\n lines.push(`export interface Raw${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: Raw${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // RawEntryMap\n lines.push('export type RawEntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: Raw${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateIndex(): string {\n return CODEGEN_BANNER + \"export * from './types';\\nexport * from './enums';\\nexport * from './query';\\n\";\n}\n\n/**\n * Generate the app-specific `query.ts` file that binds `createQuery` from `octocms/query`\n * to the app's config and generated `EntryMap` type.\n *\n * This file is emitted to `cms/__generated__/query.ts` by `npm run types:gen`.\n * Consumers import the typed `query` function from `cms/__generated__/query`.\n */\nexport function generateQuery(): string {\n return (\n CODEGEN_BANNER +\n `import { createQuery } from 'octocms/query';\nimport { configOctoCMS, type OctoConfig } from '../octocms.config';\nimport type { EntryMap } from './types';\n\n// configOctoCMS is widened to Config for admin internals; cast back to OctoConfig so\n// createQuery preserves literal collection/field names for type-safe queries.\nexport const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);\n`\n );\n}\n\n/**\n * Generate `configInit.ts` — a side-effect module that imports the app config\n * and registers it with the `octocms` config store.\n *\n * Importing this file ensures the singleton is populated even in serverless\n * cold starts where `cms/octocms.config.ts` (and therefore `withOctoCMS`) has not run.\n *\n * Emitted to `cms/__generated__/configInit.ts` by `npm run types:gen`.\n */\nexport function generateConfigInit(): string {\n return (\n CODEGEN_BANNER +\n `import { configOctoCMS } from '../octocms.config';\nimport { setConfig } from 'octocms/lib/configStore';\n\nsetConfig(configOctoCMS);\n`\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAOA,SAAS,WAAW,qBAAqB;AACzC,SAAS,YAAY;;;ACCd,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASvB,SAAS,WAAW,GAAmB;AAC5C,SAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC;AAC9C;AAGO,SAAS,cACd,OACA,iBACA,OAA2B,YACnB;AA3BV;AA4BE,UAAQ,MAAM,QAAQ;AAAA,IACpB,KAAK;AACH,aAAO,MAAM,OAAO,aAAa;AAAA,IACnC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,SAAS,QAAQ,WAAW;AAAA,IACrC,KAAK;AACH,aAAO;AAAA,IACT,KAAK,UAAU;AACb,YAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC,MAAM,IAAI,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK;AACjE,UAAI,MAAM,UAAU;AAClB,eAAO,MAAM,QAAQ,SAAS,IAAI,IAAI,KAAK,QAAQ,GAAG,KAAK;AAAA,MAC7D;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK,aAAa;AAChB,UAAI,SAAS,OAAO;AAClB,cAAM,eAAc,iBAAM,cAAN,mBAAiB,gBAAjB,YAAgC;AACpD,eAAO,gBAAgB,QAAQ,WAAW;AAAA,MAC5C;AACA,aAAO,mBAAmB,OAAO,eAAe;AAAA,IAClD;AAAA,IACA,KAAK,eAAe;AAClB,UAAI,SAAS,OAAO;AAClB,eAAO;AAAA,MACT;AACA,aAAO,qBAAqB,OAAO,eAAe;AAAA,IACpD;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,mBACP,OACA,iBACQ;AA7EV;AA8EE,QAAM,QAAO,iBAAM,cAAN,mBAAiB,gBAAjB,YAAiC,MAAM,aAAa,CAAC,MAAM,UAAU,IAAI,CAAC,GAAG,eAAe;AACzG,QAAM,aAAa,KAAK,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,OAAO;AAC1D,QAAM,QAAQ,WAAW,SAAS,IAAI,WAAW,KAAK,KAAK,IAAI,WAAW,CAAC;AAC3E,QAAM,eAAc,iBAAM,cAAN,mBAAiB,gBAAjB,YAAgC;AACpD,MAAI,gBAAgB,OAAO;AACzB,WAAO,WAAW,SAAS,IAAI,IAAI,KAAK,aAAa,GAAG,KAAK;AAAA,EAC/D;AACA,SAAO,WAAW,SAAS,IAAI,IAAI,KAAK,QAAQ,GAAG,KAAK;AAC1D;AAEA,SAAS,qBACP,OACA,iBACQ;AACR,QAAM,cAAc,MAAM,YAAY,SAAS,IAAI,CAAC,WAAW,gBAAgB,QAAQ,eAAe,CAAC;AACvG,SAAO,YAAY,KAAK,KAAK;AAC/B;AAEA,SAAS,gBAAgB,QAAiC,iBAA4C;AACpG,MAAI,gBAAgB,UAAU,OAAO,OAAO,eAAe,UAAU;AACnE,WAAO,GAAG,WAAW,OAAO,UAAU,CAAC;AAAA,EACzC;AACA,MAAI,OAAO,QAAQ;AACjB,UAAM,UAAU,OAAO,QAAQ,OAAO,MAAM;AAC5C,QAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,UAAM,QAAQ,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,IAAI,KAAK,cAAc,GAAG,eAAe,CAAC,GAAG;AAC3F,WAAO;AAAA,EAAM,MAAM,KAAK,IAAI,CAAC;AAAA;AAAA,EAC/B;AACA,SAAO;AACT;AAMO,SAAS,cAAc,KAAa,iBAA4C;AACrF,QAAM,QAAkB;AAAA,IACtB,iBAAiB;AAAA,IACjB;AAAA,EACF;AAGA,aAAW,OAAO,iBAAiB;AACjC,UAAM,MAAM,IAAI,YAAY,GAAmC;AAC/D,UAAM,SAAS,WAAW,GAAG;AAC7B,UAAM,KAAK,oBAAoB,MAAM,UAAU;AAC/C,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,IAAI,MAAM,GAAG;AAC3D,YAAM,SAAS,cAAc,OAAO,eAAe;AACnD,YAAM,KAAK,KAAK,SAAS,KAAK,MAAM,GAAG;AAAA,IACzC;AACA,UAAM,KAAK,GAAG;AACd,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,aAAW,OAAO,iBAAiB;AACjC,UAAM,SAAS,WAAW,GAAG;AAC7B,UAAM,KAAK,oBAAoB,MAAM,SAAS;AAC9C,UAAM,KAAK,+BAA+B,GAAG,2BAA2B;AACxE,UAAM,KAAK,aAAa,MAAM,SAAS;AACvC,UAAM,KAAK,GAAG;AACd,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,QAAM,aAAa,gBAAgB,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,OAAO;AACrE,QAAM,KAAK,0BAA0B,WAAW,KAAK,KAAK,CAAC,GAAG;AAC9D,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,0BAA0B;AACrC,aAAW,OAAO,iBAAiB;AACjC,UAAM,KAAK,KAAK,GAAG,KAAK,WAAW,GAAG,CAAC,QAAQ;AAAA,EACjD;AACA,QAAM,KAAK,IAAI;AACf,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,cAAc,KAAa,iBAAoC,YAAuC;AACpH,QAAM,QAAkB,CAAC;AAGzB,QAAM,KAAK,iCAAiC;AAC5C,aAAW,OAAO,iBAAiB;AACjC,UAAM,KAAK,KAAK,WAAW,GAAG,CAAC,MAAM,GAAG,IAAI;AAAA,EAC9C;AACA,QAAM,KAAK,aAAa;AACxB,QAAM,KAAK,oFAAoF;AAC/F,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,oCAAoC,gBAAgB,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,aAAa;AAC3G,QAAM,KAAK,EAAE;AAGb,aAAW,OAAO,iBAAiB;AACjC,UAAM,MAAM,IAAI,YAAY,GAAmC;AAC/D,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,IAAI,MAAM,GAAG;AAC3D,UAAI,MAAM,WAAW,SAAU;AAC/B,YAAM,WAAW,GAAG,WAAW,GAAG,CAAC,GAAG,WAAW,SAAS,CAAC;AAC3D,YAAM,KAAK,gBAAgB,QAAQ,MAAM;AACzC,iBAAW,OAAO,MAAM,SAAS;AAC/B,cAAM,KAAK,KAAK,WAAW,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,IAAI;AAAA,MAC1D;AACA,YAAM,KAAK,aAAa;AACxB,YAAM,KAAK,eAAe,QAAQ,cAAc,QAAQ,kBAAkB,QAAQ,IAAI;AACtF,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAGA,QAAM,KAAK,8BAA8B;AACzC,aAAW,MAAM,YAAY;AAC3B,UAAM,KAAK,KAAK,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI;AAAA,EAC5C;AACA,QAAM,KAAK,aAAa;AACxB,QAAM,KAAK,2EAA2E;AACtF,QAAM,KAAK,EAAE;AAEb,SAAO,iBAAiB,MAAM,KAAK,IAAI;AACzC;AAEO,SAAS,qBAAqB,KAAa,iBAA4C;AAC5F,QAAM,QAAkB;AAAA,IACtB,iBACE;AAAA,EAKJ;AAEA,aAAW,OAAO,iBAAiB;AACjC,UAAM,MAAM,IAAI,YAAY,GAAmC;AAC/D,UAAM,SAAS,WAAW,GAAG;AAE7B,UAAM,KAAK,uBAAuB,MAAM,UAAU;AAClD,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,IAAI,MAAM,GAAG;AAC3D,UAAI,MAAM,WAAW,cAAc,MAAM,WAAW,WAAY;AAChE,YAAM,SAAS,cAAc,OAAO,iBAAiB,KAAK;AAC1D,YAAM,KAAK,KAAK,SAAS,KAAK,MAAM,GAAG;AAAA,IACzC;AACA,UAAM,KAAK,GAAG;AACd,UAAM,KAAK,EAAE;AAEb,UAAM,KAAK,uBAAuB,MAAM,SAAS;AACjD,UAAM,KAAK,+BAA+B,GAAG,2BAA2B;AACxE,UAAM,KAAK,gBAAgB,MAAM,SAAS;AAC1C,UAAM,KAAK,GAAG;AACd,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,QAAM,KAAK,6BAA6B;AACxC,aAAW,OAAO,iBAAiB;AACjC,UAAM,KAAK,KAAK,GAAG,QAAQ,WAAW,GAAG,CAAC,QAAQ;AAAA,EACpD;AACA,QAAM,KAAK,IAAI;AACf,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,gBAAwB;AACtC,SAAO,iBAAiB;AAC1B;;;ADtOA,eAAsB,gBAAgB,aAAoC;AACxE,MAAI,OAAO,gBAAgB;AAE3B,QAAM,SAAS,MAAM,kBAAkB,WAAW;AAClD,QAAM,cAAc,MAAM,gBAAgB,WAAW;AACrD,QAAM,aAAa,MAAM,eAAe,WAAW;AAEnD,MAAI,KAAK,sBAAsB;AAC/B,MAAI;AACF,mBAAe,QAAQ,WAAW;AAAA,EACpC,SAAS,GAAG;AACV,QAAI,MAAM,OAAQ,EAAY,OAAO,CAAC;AACtC,YAAQ,WAAW;AACnB;AAAA,EACF;AACA,MAAI,QAAQ,GAAG,YAAY,MAAM,wBAAwB;AAEzD,MAAI,MAAM;AACV,MAAI,KAAK,qBAAqB;AAE9B,QAAM,eAAe,KAAK,aAAa,OAAO,eAAe;AAC7D,YAAU,cAAc,EAAE,WAAW,KAAK,CAAC;AAE3C,QAAM,QAAQ;AAAA,IACZ,EAAE,MAAM,YAAY,SAAS,cAAc,QAAQ,WAAW,EAAE;AAAA,IAChE,EAAE,MAAM,YAAY,SAAS,cAAc,QAAQ,aAAa,UAAU,EAAE;AAAA,IAC5E,EAAE,MAAM,gBAAgB,SAAS,qBAAqB,QAAQ,WAAW,EAAE;AAAA,IAC3E,EAAE,MAAM,YAAY,SAAS,cAAc,EAAE;AAAA,EAC/C;AAEA,aAAW,QAAQ,OAAO;AACxB,kBAAc,KAAK,cAAc,KAAK,IAAI,GAAG,KAAK,SAAS,MAAM;AACjE,QAAI,QAAQ,qBAAqB,KAAK,IAAI,EAAE;AAAA,EAC9C;AAEA,MAAI,MAAM;AACZ;","names":[]}