octocms 0.4.12 → 0.4.13
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.
- package/dist/admin/actions/entries.js +46 -45
- package/dist/admin/actions/entries.js.map +1 -1
- package/dist/admin/actions/files.d.ts +5 -0
- package/dist/admin/actions/files.d.ts.map +1 -1
- package/dist/admin/actions/files.js +48 -9
- package/dist/admin/actions/files.js.map +1 -1
- package/dist/admin/actions/search.js +2 -2
- package/dist/admin/actions/search.js.map +1 -1
- package/dist/agent/embedder.js +1 -1
- package/dist/agent/embedder.js.map +1 -1
- package/dist/agent/index.cjs +118 -41
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/tools/index.js +1 -1
- package/dist/agent/tools/index.js.map +1 -1
- package/dist/chunk-NAHOP7TG.js +7 -0
- package/dist/{chunk-L27J3XWV.js.map → chunk-NAHOP7TG.js.map} +1 -1
- package/dist/{chunk-TG624CCO.js → chunk-ZYUK2J5L.js} +4 -43
- package/dist/chunk-ZYUK2J5L.js.map +1 -0
- package/dist/cli/index.js +6 -6
- package/dist/cli/lib/codegen.d.ts +2 -8
- package/dist/cli/lib/codegen.d.ts.map +1 -1
- package/dist/cli/lib/codegen.js +11 -18
- package/dist/cli/lib/codegen.js.map +1 -1
- package/dist/cli/lib/project.js +2 -41
- package/dist/cli/lib/project.js.map +1 -1
- package/dist/components/FormReferenceField.d.ts.map +1 -1
- package/dist/components/FormReferenceField.js +1 -1
- package/dist/components/FormReferenceField.js.map +1 -1
- package/dist/{embeddingsGen-7MXSZQ43.js → embeddingsGen-FXWCPGB7.js} +39 -8
- package/dist/embeddingsGen-FXWCPGB7.js.map +1 -0
- package/dist/index.cjs +88 -68
- package/dist/index.cjs.map +1 -1
- package/dist/{init-N6K464EZ.js → init-KWH66PKY.js} +2 -2
- package/dist/lib/localReader.d.ts +13 -0
- package/dist/lib/localReader.d.ts.map +1 -1
- package/dist/lib/localReader.js +20 -0
- package/dist/lib/localReader.js.map +1 -1
- package/dist/lib/publicSearchIndex.d.ts.map +1 -1
- package/dist/lib/publicSearchIndex.js +2 -2
- package/dist/lib/publicSearchIndex.js.map +1 -1
- package/dist/query.cjs +88 -68
- package/dist/query.cjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/{typesGen-EYRZAA56.js → typesGen-MFAL3B4V.js} +32 -6
- package/dist/typesGen-MFAL3B4V.js.map +1 -0
- package/dist/{validate-6AFW6U2X.js → validate-AAW4IGWD.js} +2 -2
- package/package.json +1 -1
- package/dist/admin/consts.d.ts +0 -3
- package/dist/admin/consts.d.ts.map +0 -1
- package/dist/admin/consts.js +0 -24
- package/dist/admin/consts.js.map +0 -1
- package/dist/chunk-L27J3XWV.js +0 -7
- package/dist/chunk-TG624CCO.js.map +0 -1
- package/dist/embeddingsGen-7MXSZQ43.js.map +0 -1
- package/dist/typesGen-EYRZAA56.js.map +0 -1
- /package/dist/{init-N6K464EZ.js.map → init-KWH66PKY.js.map} +0 -0
- /package/dist/{validate-6AFW6U2X.js.map → validate-AAW4IGWD.js.map} +0 -0
|
@@ -46,7 +46,7 @@ const searchContentTool = {
|
|
|
46
46
|
if (hits.length === 0) {
|
|
47
47
|
return JSON.stringify({
|
|
48
48
|
results: [],
|
|
49
|
-
note: "No results \u2014 verify the query, or try a broader phrasing. If embeddings.json is missing, run `
|
|
49
|
+
note: "No results \u2014 verify the query, or try a broader phrasing. If embeddings.json is missing, run `npx octocms embeddings:gen` on your dev machine."
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
return JSON.stringify({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../agent/tools/index.ts"],"sourcesContent":["/**\n * Tool registry for the chat agent. Two flavours:\n *\n * - **Read-only tools** — `searchContent`, `listCollections`, `getEntry`. Run\n * directly on the server and return their result string to the model.\n * - **Proposal tools** — `proposeEdit`, `proposeNewEntry`. Validate the\n * payload, then return BOTH a string for the model and a `proposal`\n * object the chat loop emits as a `proposal` SSE event. The user must\n * explicitly approve in the UI before any write happens — see\n * `octocms/agent/proposals.ts`.\n *\n * Each tool exposes:\n * - `definition` — the JSON schema sent to the model.\n * - `run(input, ctx)` — server-side handler returning either a plain string\n * (the model sees it as the tool result) or `{ message, proposal? }`.\n * Errors are caught and stringified by the chat loop; we never throw out\n * of `run`.\n */\nimport { randomUUID } from 'node:crypto';\n\nimport type { NormalizedTool } from '../providers/types';\nimport type { Config } from '../../types';\nimport {\n acceptProposal as _acceptProposal,\n describeCreateSummary,\n describeEditSummary,\n fieldsToFormStrings,\n resolveEntryPath,\n type CreateProposal,\n type EditProposal,\n type Proposal,\n} from '../proposals';\nimport { searchContent } from '../search';\n\nexport type ToolRunResult =\n | string\n | {\n /** What the model sees as the tool result (must already be JSON-stringified). */\n message: string;\n /** Optional proposal — the chat loop emits it as an SSE event before the tool_result. */\n proposal?: Proposal;\n };\n\nexport type ToolHandler = {\n definition: NormalizedTool;\n run(input: unknown, ctx: ToolContext): Promise<ToolRunResult>;\n};\n\nexport type ToolContext = {\n config: Config;\n branch?: string;\n /**\n * Wire-level `tool_use_id` for the current invocation. Proposal tools embed\n * this in the proposal so the UI can correlate accept/reject with the\n * originating tool call.\n */\n toolUseId?: string;\n};\n\nconst searchContentTool: ToolHandler = {\n definition: {\n name: 'searchContent',\n description:\n 'Semantic search over all CMS entries. Use this BEFORE answering any question about content. Returns ranked hits with title, score, and a short excerpt.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Natural-language search query.' },\n k: {\n type: 'integer',\n description: 'Number of results to return (1–25). Defaults to 8.',\n minimum: 1,\n maximum: 25,\n },\n collection: {\n type: 'string',\n description: 'Optional collection name to restrict the search (e.g. \"post\").',\n },\n },\n required: ['query'],\n },\n },\n async run(input, ctx) {\n const { query, k, collection } = (input ?? {}) as { query?: unknown; k?: unknown; collection?: unknown };\n if (typeof query !== 'string' || !query.trim()) {\n return JSON.stringify({ error: 'query is required and must be a non-empty string' });\n }\n const hits = await searchContent(query, {\n k: typeof k === 'number' ? Math.max(1, Math.min(25, Math.floor(k))) : 8,\n collection: typeof collection === 'string' && collection.trim() ? collection.trim() : undefined,\n branch: ctx.branch,\n });\n if (hits.length === 0) {\n return JSON.stringify({\n results: [],\n note: 'No results — verify the query, or try a broader phrasing. If embeddings.json is missing, run `npm run embeddings:gen` on your dev machine.',\n });\n }\n return JSON.stringify({\n results: hits.map((h) => ({\n id: h.id,\n path: h.path,\n collection: h.collection,\n score: Number(h.score.toFixed(4)),\n title: h.title,\n excerpt: h.excerpt,\n })),\n });\n },\n};\n\nconst listCollectionsTool: ToolHandler = {\n definition: {\n name: 'listCollections',\n description:\n 'List all collections in the schema with their fields and types. Useful when the user asks about content shape.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n },\n async run(_input, ctx) {\n const collections = Object.entries(ctx.config.collections).map(([name, col]) => ({\n name,\n label: col.label,\n hasMany: Boolean(col.hasMany),\n fields: Object.entries(col.fields).map(([key, def]) => ({\n key,\n label: def.label,\n format: def.format,\n required: Boolean(def.required),\n })),\n }));\n return JSON.stringify({ collections });\n },\n};\n\nconst getEntryTool: ToolHandler = {\n definition: {\n name: 'getEntry',\n description:\n 'Fetch a single entry by its filename stem (the value returned in `id` from searchContent). Returns the raw `sys` + `fields` payload. Reference fields stay as their key strings — call getEntry again to expand them.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Filename stem, e.g. \"post-abc\".' },\n collection: {\n type: 'string',\n description: 'Optional collection name. If omitted, the tool searches all collections by id (slower).',\n },\n },\n required: ['id'],\n },\n },\n async run(input, ctx) {\n const { id, collection } = (input ?? {}) as { id?: unknown; collection?: unknown };\n if (typeof id !== 'string' || !id.trim()) {\n return JSON.stringify({ error: 'id is required and must be a non-empty string' });\n }\n const cleanId = id.trim().replace(/\\.json$/, '');\n const { getFile, getContentFiles } =\n (await import('../../admin/actions/files')) as typeof import('../../admin/actions/files');\n\n const colName = typeof collection === 'string' && collection.trim() ? collection.trim() : undefined;\n if (colName && !ctx.config.collections[colName as keyof typeof ctx.config.collections]) {\n return JSON.stringify({ error: `Unknown collection: ${colName}` });\n }\n\n const candidates = colName ? [colName] : Object.keys(ctx.config.collections);\n\n for (const c of candidates) {\n const entries = await getContentFiles(c).catch(() => [] as string[]);\n const match = entries.find((p) => {\n const stem = p\n .split('/')\n .pop()\n ?.replace(/\\.json$/, '');\n return stem === cleanId;\n });\n if (!match) continue;\n try {\n const payload = await getFile(match);\n return JSON.stringify({ path: match, entry: payload });\n } catch (err) {\n return JSON.stringify({\n error: `Failed to read entry: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n return JSON.stringify({ error: `No entry found with id \"${cleanId}\"` });\n },\n};\n\nconst proposeEditTool: ToolHandler = {\n definition: {\n name: 'proposeEdit',\n description:\n 'Propose changes to an existing entry. The user must explicitly accept the proposal in the UI before any write happens — you cannot save anything yourself. Always run `searchContent` and/or `getEntry` first to confirm the exact entry id and the existing field values you intend to change.',\n inputSchema: {\n type: 'object',\n properties: {\n entryId: {\n type: 'string',\n description: 'Filename stem of the entry to edit, e.g. \"post-abc\". Must match an existing entry.',\n },\n collection: {\n type: 'string',\n description: 'The collection the entry belongs to (e.g. \"post\"). Must match the entry.',\n },\n fieldChanges: {\n type: 'object',\n description:\n 'Object of fieldName → new value. Only include fields you want to change. For markdown fields pass the full new body as a string. For reference (cardinality:many) fields pass an array of filename stems. Existing fields you omit stay as-is.',\n additionalProperties: true,\n },\n reasoning: {\n type: 'string',\n description: 'One sentence explaining why this change. Shown to the user verbatim on the approval card.',\n },\n },\n required: ['entryId', 'collection', 'fieldChanges', 'reasoning'],\n },\n },\n async run(input, ctx) {\n const { entryId, collection, fieldChanges, reasoning } = (input ?? {}) as {\n entryId?: unknown;\n collection?: unknown;\n fieldChanges?: unknown;\n reasoning?: unknown;\n };\n if (typeof entryId !== 'string' || !entryId.trim()) {\n return JSON.stringify({ ok: false, error: 'entryId is required (filename stem like \"post-abc\")' });\n }\n if (typeof collection !== 'string' || !collection.trim()) {\n return JSON.stringify({ ok: false, error: 'collection is required' });\n }\n if (!fieldChanges || typeof fieldChanges !== 'object' || Array.isArray(fieldChanges)) {\n return JSON.stringify({ ok: false, error: 'fieldChanges must be an object of fieldName → new value' });\n }\n const reasoningStr = typeof reasoning === 'string' ? reasoning.trim() : '';\n if (!reasoningStr) {\n return JSON.stringify({ ok: false, error: 'reasoning is required (one sentence)' });\n }\n\n const cleanCollection = collection.trim();\n if (!(cleanCollection in ctx.config.collections)) {\n return JSON.stringify({ ok: false, error: `Unknown collection: ${cleanCollection}` });\n }\n\n const cleanId = entryId.trim().replace(/\\.json$/, '');\n const entryPath = await resolveEntryPath(cleanCollection, cleanId, ctx.config);\n if (!entryPath) {\n return JSON.stringify({ ok: false, error: `Entry \"${cleanId}\" not found in collection \"${cleanCollection}\".` });\n }\n\n // Re-validate the merged result against the schema. We need the existing\n // entry to merge against so we don't trip required-field checks on fields\n // the model isn't touching.\n const { getFile } = (await import('../../admin/actions/files')) as typeof import('../../admin/actions/files');\n let existing: { fields?: Record<string, unknown> };\n try {\n existing = await getFile(entryPath);\n } catch (err) {\n return JSON.stringify({\n ok: false,\n error: `Failed to read entry: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n const merged = { ...existing.fields, ...(fieldChanges as Record<string, unknown>) };\n const stringFields = fieldsToFormStrings(merged);\n\n const { validateEntryFields } =\n (await import('../../lib/validateEntryFields')) as typeof import('../../lib/validateEntryFields');\n const validation = validateEntryFields(cleanCollection, stringFields);\n if (!validation.ok) {\n return JSON.stringify({\n ok: false,\n error: 'Validation failed — fix the field values and try again.',\n fieldErrors: validation.fieldErrors,\n });\n }\n\n const summary = describeEditSummary(cleanCollection, cleanId, fieldChanges as Record<string, unknown>);\n const proposal: EditProposal = {\n id: `prop_${randomUUID()}`,\n kind: 'edit',\n toolUseId: ctx.toolUseId ?? '',\n collection: cleanCollection,\n entryPath,\n entryId: cleanId,\n fieldChanges: fieldChanges as Record<string, unknown>,\n reasoning: reasoningStr,\n summary,\n };\n return {\n message: JSON.stringify({\n ok: true,\n proposalId: proposal.id,\n summary,\n awaitingApproval: true,\n note: 'Proposal emitted. The user will accept or reject it in the UI — do NOT propose the same change again.',\n }),\n proposal,\n };\n },\n};\n\nconst proposeNewEntryTool: ToolHandler = {\n definition: {\n name: 'proposeNewEntry',\n description:\n 'Propose a brand-new entry in a collection. The user must explicitly accept the proposal in the UI before any write happens. Use `listCollections` first if you are not sure of the available fields.',\n inputSchema: {\n type: 'object',\n properties: {\n collection: { type: 'string', description: 'Collection name to create the entry in.' },\n fields: {\n type: 'object',\n description:\n 'Full proposed `fields` object. Required fields must be present. For markdown fields pass the full body as a string. For reference (cardinality:many) fields pass an array of filename stems.',\n additionalProperties: true,\n },\n reasoning: {\n type: 'string',\n description: 'One sentence explaining why this entry. Shown verbatim on the card.',\n },\n },\n required: ['collection', 'fields', 'reasoning'],\n },\n },\n async run(input, ctx) {\n const { collection, fields, reasoning } = (input ?? {}) as {\n collection?: unknown;\n fields?: unknown;\n reasoning?: unknown;\n };\n if (typeof collection !== 'string' || !collection.trim()) {\n return JSON.stringify({ ok: false, error: 'collection is required' });\n }\n if (!fields || typeof fields !== 'object' || Array.isArray(fields)) {\n return JSON.stringify({ ok: false, error: 'fields must be an object' });\n }\n const reasoningStr = typeof reasoning === 'string' ? reasoning.trim() : '';\n if (!reasoningStr) {\n return JSON.stringify({ ok: false, error: 'reasoning is required (one sentence)' });\n }\n\n const cleanCollection = collection.trim();\n if (!(cleanCollection in ctx.config.collections)) {\n return JSON.stringify({ ok: false, error: `Unknown collection: ${cleanCollection}` });\n }\n\n const stringFields = fieldsToFormStrings(fields as Record<string, unknown>);\n const { validateEntryFields } =\n (await import('../../lib/validateEntryFields')) as typeof import('../../lib/validateEntryFields');\n const validation = validateEntryFields(cleanCollection, stringFields);\n if (!validation.ok) {\n return JSON.stringify({\n ok: false,\n error: 'Validation failed — fix the field values and try again.',\n fieldErrors: validation.fieldErrors,\n });\n }\n\n const summary = describeCreateSummary(cleanCollection, fields as Record<string, unknown>);\n const proposal: CreateProposal = {\n id: `prop_${randomUUID()}`,\n kind: 'create',\n toolUseId: ctx.toolUseId ?? '',\n collection: cleanCollection,\n fields: fields as Record<string, unknown>,\n reasoning: reasoningStr,\n summary,\n };\n return {\n message: JSON.stringify({\n ok: true,\n proposalId: proposal.id,\n summary,\n awaitingApproval: true,\n note: 'Proposal emitted. The user will accept or reject it in the UI — do NOT propose the same entry again.',\n }),\n proposal,\n };\n },\n};\n\n/**\n * Phase 5 — match an uploaded document to a CMS entry.\n *\n * Two-tier strategy:\n * 1. URL hint match — if the user provides a URL or path, walk every\n * collection's `routeTemplate` (e.g. `'/blog/[slug]'`) and try to extract\n * field values. If the matched fields point at a real entry, return that\n * entry as the highest-confidence candidate.\n * 2. Search fallback — embed the document text and run `searchContent` over\n * the existing embeddings index. Returns the top hits.\n *\n * The model gets a ranked list with a `matchedBy` reason on each candidate\n * so it can surface them to the user and ask which one to update.\n */\nconst findEntryForDocumentTool: ToolHandler = {\n definition: {\n name: 'findEntryForDocument',\n description:\n 'Given the text of an uploaded document (and optionally a URL hint), suggest CMS entries that the document is most likely about. Returns ranked candidates with a reason for the match. Use this BEFORE proposing edits when the user uploads a PDF / DOCX without naming a specific entry.',\n inputSchema: {\n type: 'object',\n properties: {\n documentText: {\n type: 'string',\n description:\n 'The extracted text from the uploaded document — typically the first 1–2 paragraphs are enough to disambiguate.',\n },\n hintUrl: {\n type: 'string',\n description:\n \"Optional URL or path the user mentioned, e.g. '/blog/my-post'. When set, exact matches against any collection's `routeTemplate` rank highest.\",\n },\n k: {\n type: 'integer',\n description: 'Number of search-fallback candidates to return (1–10). Defaults to 5.',\n minimum: 1,\n maximum: 10,\n },\n },\n required: ['documentText'],\n },\n },\n async run(input, ctx) {\n const { documentText, hintUrl, k } = (input ?? {}) as {\n documentText?: unknown;\n hintUrl?: unknown;\n k?: unknown;\n };\n if (typeof documentText !== 'string' || !documentText.trim()) {\n return JSON.stringify({ error: 'documentText is required and must be a non-empty string' });\n }\n const limit = typeof k === 'number' ? Math.max(1, Math.min(10, Math.floor(k))) : 5;\n\n const candidates: Array<{\n id: string;\n path: string;\n collection: string;\n score: number;\n title: string;\n excerpt: string;\n matchedBy: 'routeTemplate' | 'search';\n }> = [];\n\n // 1) URL-hint matching against any collection's routeTemplate.\n if (typeof hintUrl === 'string' && hintUrl.trim()) {\n const cleanHint = hintUrl.trim();\n for (const [collectionName, collection] of Object.entries(ctx.config.collections)) {\n const template = (collection as { routeTemplate?: string }).routeTemplate;\n if (!template) continue;\n const fieldValues = matchRouteTemplate(template, cleanHint);\n if (!fieldValues) continue;\n const match = await findEntryByFieldValues(collectionName, fieldValues, ctx);\n if (match) {\n candidates.push({ ...match, matchedBy: 'routeTemplate' });\n }\n }\n }\n\n // 2) Search fallback — embed the document text and rank entries.\n const queryText = documentText.trim().slice(0, 2000);\n try {\n const hits = await searchContent(queryText, {\n k: limit,\n branch: ctx.branch,\n });\n for (const h of hits) {\n if (candidates.some((c) => c.path === h.path)) continue;\n candidates.push({ ...h, matchedBy: 'search' });\n }\n } catch (err) {\n return JSON.stringify({\n error: `Search fallback failed: ${err instanceof Error ? err.message : String(err)}`,\n candidates,\n });\n }\n\n if (candidates.length === 0) {\n return JSON.stringify({\n candidates: [],\n note: 'No candidates found — verify the document has searchable text, or ask the user which entry to update.',\n });\n }\n\n return JSON.stringify({\n candidates: candidates.map((c) => ({\n id: c.id,\n path: c.path,\n collection: c.collection,\n title: c.title,\n score: Number(c.score.toFixed(4)),\n excerpt: c.excerpt,\n matchedBy: c.matchedBy,\n })),\n });\n },\n};\n\n/**\n * Match a route template like `/blog/[slug]` (or `/items/[id]/[lang]`) against\n * a literal URL/path. Returns an object mapping each placeholder to the\n * captured value, or `null` if the template doesn't match. Query strings and\n * trailing slashes are ignored. Exposed for unit tests.\n */\nexport function matchRouteTemplate(template: string, url: string): Record<string, string> | null {\n // Drop scheme + host: '/blog/foo?x=1' → '/blog/foo'\n let path = url;\n const protoIdx = path.indexOf('://');\n if (protoIdx !== -1) {\n const slash = path.indexOf('/', protoIdx + 3);\n path = slash === -1 ? '/' : path.slice(slash);\n }\n const queryIdx = path.indexOf('?');\n if (queryIdx !== -1) path = path.slice(0, queryIdx);\n\n const norm = (s: string) => s.replace(/\\/+$/, '') || '/';\n const tplParts = norm(template).split('/');\n const urlParts = norm(path).split('/');\n if (tplParts.length !== urlParts.length) return null;\n\n const out: Record<string, string> = {};\n for (let i = 0; i < tplParts.length; i++) {\n const tp = tplParts[i];\n const up = urlParts[i];\n const m = tp.match(/^\\[(.+)\\]$/);\n if (m) {\n if (!up) return null;\n out[m[1]] = decodeURIComponent(up);\n } else if (tp !== up) {\n return null;\n }\n }\n return out;\n}\n\nasync function findEntryByFieldValues(\n collectionName: string,\n fieldValues: Record<string, string>,\n ctx: ToolContext,\n): Promise<{ id: string; path: string; collection: string; score: number; title: string; excerpt: string } | null> {\n const { getFile, getContentFiles } =\n (await import('../../admin/actions/files')) as typeof import('../../admin/actions/files');\n const { resolveEntryTitle, resolveEntryId, buildEntryExcerpt } =\n (await import('../../lib/resolveEntryTitle')) as typeof import('../../lib/resolveEntryTitle');\n\n const entries = await getContentFiles(collectionName).catch(() => [] as string[]);\n for (const p of entries) {\n let payload: { sys?: { id?: unknown; type?: unknown }; fields?: Record<string, unknown> };\n try {\n payload = (await getFile(p)) as typeof payload;\n } catch {\n continue;\n }\n let allMatch = true;\n for (const [key, expected] of Object.entries(fieldValues)) {\n const actual = payload.fields?.[key];\n if (typeof actual !== 'string' || actual !== expected) {\n // Also accept matching against the filename stem when the placeholder is `id`.\n if (key === 'id') {\n const stem = p\n .split('/')\n .pop()\n ?.replace(/\\.json$/, '');\n if (stem === expected) continue;\n }\n allMatch = false;\n break;\n }\n }\n if (!allMatch) continue;\n return {\n id: resolveEntryId(ctx.config, p, payload),\n path: p,\n collection: collectionName,\n score: 1,\n title: resolveEntryTitle(ctx.config, p, payload),\n excerpt: buildEntryExcerpt(ctx.config, p, payload),\n };\n }\n return null;\n}\n\nexport const READ_ONLY_TOOLS: ToolHandler[] = [\n searchContentTool,\n listCollectionsTool,\n getEntryTool,\n findEntryForDocumentTool,\n];\n\nexport const PROPOSAL_TOOLS: ToolHandler[] = [proposeEditTool, proposeNewEntryTool];\n\nexport const ALL_TOOLS: ToolHandler[] = [...READ_ONLY_TOOLS, ...PROPOSAL_TOOLS];\n\nexport function getToolHandler(name: string): ToolHandler | undefined {\n return ALL_TOOLS.find((t) => t.definition.name === name);\n}\n\nexport function getToolDefinitions(): NormalizedTool[] {\n return ALL_TOOLS.map((t) => t.definition);\n}\n\n// Re-exported so callers don't need to reach into `proposals.ts` for the\n// server-side accept handler.\nexport { _acceptProposal as acceptProposal };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../agent/tools/index.ts"],"sourcesContent":["/**\n * Tool registry for the chat agent. Two flavours:\n *\n * - **Read-only tools** — `searchContent`, `listCollections`, `getEntry`. Run\n * directly on the server and return their result string to the model.\n * - **Proposal tools** — `proposeEdit`, `proposeNewEntry`. Validate the\n * payload, then return BOTH a string for the model and a `proposal`\n * object the chat loop emits as a `proposal` SSE event. The user must\n * explicitly approve in the UI before any write happens — see\n * `octocms/agent/proposals.ts`.\n *\n * Each tool exposes:\n * - `definition` — the JSON schema sent to the model.\n * - `run(input, ctx)` — server-side handler returning either a plain string\n * (the model sees it as the tool result) or `{ message, proposal? }`.\n * Errors are caught and stringified by the chat loop; we never throw out\n * of `run`.\n */\nimport { randomUUID } from 'node:crypto';\n\nimport type { NormalizedTool } from '../providers/types';\nimport type { Config } from '../../types';\nimport {\n acceptProposal as _acceptProposal,\n describeCreateSummary,\n describeEditSummary,\n fieldsToFormStrings,\n resolveEntryPath,\n type CreateProposal,\n type EditProposal,\n type Proposal,\n} from '../proposals';\nimport { searchContent } from '../search';\n\nexport type ToolRunResult =\n | string\n | {\n /** What the model sees as the tool result (must already be JSON-stringified). */\n message: string;\n /** Optional proposal — the chat loop emits it as an SSE event before the tool_result. */\n proposal?: Proposal;\n };\n\nexport type ToolHandler = {\n definition: NormalizedTool;\n run(input: unknown, ctx: ToolContext): Promise<ToolRunResult>;\n};\n\nexport type ToolContext = {\n config: Config;\n branch?: string;\n /**\n * Wire-level `tool_use_id` for the current invocation. Proposal tools embed\n * this in the proposal so the UI can correlate accept/reject with the\n * originating tool call.\n */\n toolUseId?: string;\n};\n\nconst searchContentTool: ToolHandler = {\n definition: {\n name: 'searchContent',\n description:\n 'Semantic search over all CMS entries. Use this BEFORE answering any question about content. Returns ranked hits with title, score, and a short excerpt.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Natural-language search query.' },\n k: {\n type: 'integer',\n description: 'Number of results to return (1–25). Defaults to 8.',\n minimum: 1,\n maximum: 25,\n },\n collection: {\n type: 'string',\n description: 'Optional collection name to restrict the search (e.g. \"post\").',\n },\n },\n required: ['query'],\n },\n },\n async run(input, ctx) {\n const { query, k, collection } = (input ?? {}) as { query?: unknown; k?: unknown; collection?: unknown };\n if (typeof query !== 'string' || !query.trim()) {\n return JSON.stringify({ error: 'query is required and must be a non-empty string' });\n }\n const hits = await searchContent(query, {\n k: typeof k === 'number' ? Math.max(1, Math.min(25, Math.floor(k))) : 8,\n collection: typeof collection === 'string' && collection.trim() ? collection.trim() : undefined,\n branch: ctx.branch,\n });\n if (hits.length === 0) {\n return JSON.stringify({\n results: [],\n note: 'No results — verify the query, or try a broader phrasing. If embeddings.json is missing, run `npx octocms embeddings:gen` on your dev machine.',\n });\n }\n return JSON.stringify({\n results: hits.map((h) => ({\n id: h.id,\n path: h.path,\n collection: h.collection,\n score: Number(h.score.toFixed(4)),\n title: h.title,\n excerpt: h.excerpt,\n })),\n });\n },\n};\n\nconst listCollectionsTool: ToolHandler = {\n definition: {\n name: 'listCollections',\n description:\n 'List all collections in the schema with their fields and types. Useful when the user asks about content shape.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n },\n async run(_input, ctx) {\n const collections = Object.entries(ctx.config.collections).map(([name, col]) => ({\n name,\n label: col.label,\n hasMany: Boolean(col.hasMany),\n fields: Object.entries(col.fields).map(([key, def]) => ({\n key,\n label: def.label,\n format: def.format,\n required: Boolean(def.required),\n })),\n }));\n return JSON.stringify({ collections });\n },\n};\n\nconst getEntryTool: ToolHandler = {\n definition: {\n name: 'getEntry',\n description:\n 'Fetch a single entry by its filename stem (the value returned in `id` from searchContent). Returns the raw `sys` + `fields` payload. Reference fields stay as their key strings — call getEntry again to expand them.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Filename stem, e.g. \"post-abc\".' },\n collection: {\n type: 'string',\n description: 'Optional collection name. If omitted, the tool searches all collections by id (slower).',\n },\n },\n required: ['id'],\n },\n },\n async run(input, ctx) {\n const { id, collection } = (input ?? {}) as { id?: unknown; collection?: unknown };\n if (typeof id !== 'string' || !id.trim()) {\n return JSON.stringify({ error: 'id is required and must be a non-empty string' });\n }\n const cleanId = id.trim().replace(/\\.json$/, '');\n const { getFile, getContentFiles } =\n (await import('../../admin/actions/files')) as typeof import('../../admin/actions/files');\n\n const colName = typeof collection === 'string' && collection.trim() ? collection.trim() : undefined;\n if (colName && !ctx.config.collections[colName as keyof typeof ctx.config.collections]) {\n return JSON.stringify({ error: `Unknown collection: ${colName}` });\n }\n\n const candidates = colName ? [colName] : Object.keys(ctx.config.collections);\n\n for (const c of candidates) {\n const entries = await getContentFiles(c).catch(() => [] as string[]);\n const match = entries.find((p) => {\n const stem = p\n .split('/')\n .pop()\n ?.replace(/\\.json$/, '');\n return stem === cleanId;\n });\n if (!match) continue;\n try {\n const payload = await getFile(match);\n return JSON.stringify({ path: match, entry: payload });\n } catch (err) {\n return JSON.stringify({\n error: `Failed to read entry: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n return JSON.stringify({ error: `No entry found with id \"${cleanId}\"` });\n },\n};\n\nconst proposeEditTool: ToolHandler = {\n definition: {\n name: 'proposeEdit',\n description:\n 'Propose changes to an existing entry. The user must explicitly accept the proposal in the UI before any write happens — you cannot save anything yourself. Always run `searchContent` and/or `getEntry` first to confirm the exact entry id and the existing field values you intend to change.',\n inputSchema: {\n type: 'object',\n properties: {\n entryId: {\n type: 'string',\n description: 'Filename stem of the entry to edit, e.g. \"post-abc\". Must match an existing entry.',\n },\n collection: {\n type: 'string',\n description: 'The collection the entry belongs to (e.g. \"post\"). Must match the entry.',\n },\n fieldChanges: {\n type: 'object',\n description:\n 'Object of fieldName → new value. Only include fields you want to change. For markdown fields pass the full new body as a string. For reference (cardinality:many) fields pass an array of filename stems. Existing fields you omit stay as-is.',\n additionalProperties: true,\n },\n reasoning: {\n type: 'string',\n description: 'One sentence explaining why this change. Shown to the user verbatim on the approval card.',\n },\n },\n required: ['entryId', 'collection', 'fieldChanges', 'reasoning'],\n },\n },\n async run(input, ctx) {\n const { entryId, collection, fieldChanges, reasoning } = (input ?? {}) as {\n entryId?: unknown;\n collection?: unknown;\n fieldChanges?: unknown;\n reasoning?: unknown;\n };\n if (typeof entryId !== 'string' || !entryId.trim()) {\n return JSON.stringify({ ok: false, error: 'entryId is required (filename stem like \"post-abc\")' });\n }\n if (typeof collection !== 'string' || !collection.trim()) {\n return JSON.stringify({ ok: false, error: 'collection is required' });\n }\n if (!fieldChanges || typeof fieldChanges !== 'object' || Array.isArray(fieldChanges)) {\n return JSON.stringify({ ok: false, error: 'fieldChanges must be an object of fieldName → new value' });\n }\n const reasoningStr = typeof reasoning === 'string' ? reasoning.trim() : '';\n if (!reasoningStr) {\n return JSON.stringify({ ok: false, error: 'reasoning is required (one sentence)' });\n }\n\n const cleanCollection = collection.trim();\n if (!(cleanCollection in ctx.config.collections)) {\n return JSON.stringify({ ok: false, error: `Unknown collection: ${cleanCollection}` });\n }\n\n const cleanId = entryId.trim().replace(/\\.json$/, '');\n const entryPath = await resolveEntryPath(cleanCollection, cleanId, ctx.config);\n if (!entryPath) {\n return JSON.stringify({ ok: false, error: `Entry \"${cleanId}\" not found in collection \"${cleanCollection}\".` });\n }\n\n // Re-validate the merged result against the schema. We need the existing\n // entry to merge against so we don't trip required-field checks on fields\n // the model isn't touching.\n const { getFile } = (await import('../../admin/actions/files')) as typeof import('../../admin/actions/files');\n let existing: { fields?: Record<string, unknown> };\n try {\n existing = await getFile(entryPath);\n } catch (err) {\n return JSON.stringify({\n ok: false,\n error: `Failed to read entry: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n const merged = { ...existing.fields, ...(fieldChanges as Record<string, unknown>) };\n const stringFields = fieldsToFormStrings(merged);\n\n const { validateEntryFields } =\n (await import('../../lib/validateEntryFields')) as typeof import('../../lib/validateEntryFields');\n const validation = validateEntryFields(cleanCollection, stringFields);\n if (!validation.ok) {\n return JSON.stringify({\n ok: false,\n error: 'Validation failed — fix the field values and try again.',\n fieldErrors: validation.fieldErrors,\n });\n }\n\n const summary = describeEditSummary(cleanCollection, cleanId, fieldChanges as Record<string, unknown>);\n const proposal: EditProposal = {\n id: `prop_${randomUUID()}`,\n kind: 'edit',\n toolUseId: ctx.toolUseId ?? '',\n collection: cleanCollection,\n entryPath,\n entryId: cleanId,\n fieldChanges: fieldChanges as Record<string, unknown>,\n reasoning: reasoningStr,\n summary,\n };\n return {\n message: JSON.stringify({\n ok: true,\n proposalId: proposal.id,\n summary,\n awaitingApproval: true,\n note: 'Proposal emitted. The user will accept or reject it in the UI — do NOT propose the same change again.',\n }),\n proposal,\n };\n },\n};\n\nconst proposeNewEntryTool: ToolHandler = {\n definition: {\n name: 'proposeNewEntry',\n description:\n 'Propose a brand-new entry in a collection. The user must explicitly accept the proposal in the UI before any write happens. Use `listCollections` first if you are not sure of the available fields.',\n inputSchema: {\n type: 'object',\n properties: {\n collection: { type: 'string', description: 'Collection name to create the entry in.' },\n fields: {\n type: 'object',\n description:\n 'Full proposed `fields` object. Required fields must be present. For markdown fields pass the full body as a string. For reference (cardinality:many) fields pass an array of filename stems.',\n additionalProperties: true,\n },\n reasoning: {\n type: 'string',\n description: 'One sentence explaining why this entry. Shown verbatim on the card.',\n },\n },\n required: ['collection', 'fields', 'reasoning'],\n },\n },\n async run(input, ctx) {\n const { collection, fields, reasoning } = (input ?? {}) as {\n collection?: unknown;\n fields?: unknown;\n reasoning?: unknown;\n };\n if (typeof collection !== 'string' || !collection.trim()) {\n return JSON.stringify({ ok: false, error: 'collection is required' });\n }\n if (!fields || typeof fields !== 'object' || Array.isArray(fields)) {\n return JSON.stringify({ ok: false, error: 'fields must be an object' });\n }\n const reasoningStr = typeof reasoning === 'string' ? reasoning.trim() : '';\n if (!reasoningStr) {\n return JSON.stringify({ ok: false, error: 'reasoning is required (one sentence)' });\n }\n\n const cleanCollection = collection.trim();\n if (!(cleanCollection in ctx.config.collections)) {\n return JSON.stringify({ ok: false, error: `Unknown collection: ${cleanCollection}` });\n }\n\n const stringFields = fieldsToFormStrings(fields as Record<string, unknown>);\n const { validateEntryFields } =\n (await import('../../lib/validateEntryFields')) as typeof import('../../lib/validateEntryFields');\n const validation = validateEntryFields(cleanCollection, stringFields);\n if (!validation.ok) {\n return JSON.stringify({\n ok: false,\n error: 'Validation failed — fix the field values and try again.',\n fieldErrors: validation.fieldErrors,\n });\n }\n\n const summary = describeCreateSummary(cleanCollection, fields as Record<string, unknown>);\n const proposal: CreateProposal = {\n id: `prop_${randomUUID()}`,\n kind: 'create',\n toolUseId: ctx.toolUseId ?? '',\n collection: cleanCollection,\n fields: fields as Record<string, unknown>,\n reasoning: reasoningStr,\n summary,\n };\n return {\n message: JSON.stringify({\n ok: true,\n proposalId: proposal.id,\n summary,\n awaitingApproval: true,\n note: 'Proposal emitted. The user will accept or reject it in the UI — do NOT propose the same entry again.',\n }),\n proposal,\n };\n },\n};\n\n/**\n * Phase 5 — match an uploaded document to a CMS entry.\n *\n * Two-tier strategy:\n * 1. URL hint match — if the user provides a URL or path, walk every\n * collection's `routeTemplate` (e.g. `'/blog/[slug]'`) and try to extract\n * field values. If the matched fields point at a real entry, return that\n * entry as the highest-confidence candidate.\n * 2. Search fallback — embed the document text and run `searchContent` over\n * the existing embeddings index. Returns the top hits.\n *\n * The model gets a ranked list with a `matchedBy` reason on each candidate\n * so it can surface them to the user and ask which one to update.\n */\nconst findEntryForDocumentTool: ToolHandler = {\n definition: {\n name: 'findEntryForDocument',\n description:\n 'Given the text of an uploaded document (and optionally a URL hint), suggest CMS entries that the document is most likely about. Returns ranked candidates with a reason for the match. Use this BEFORE proposing edits when the user uploads a PDF / DOCX without naming a specific entry.',\n inputSchema: {\n type: 'object',\n properties: {\n documentText: {\n type: 'string',\n description:\n 'The extracted text from the uploaded document — typically the first 1–2 paragraphs are enough to disambiguate.',\n },\n hintUrl: {\n type: 'string',\n description:\n \"Optional URL or path the user mentioned, e.g. '/blog/my-post'. When set, exact matches against any collection's `routeTemplate` rank highest.\",\n },\n k: {\n type: 'integer',\n description: 'Number of search-fallback candidates to return (1–10). Defaults to 5.',\n minimum: 1,\n maximum: 10,\n },\n },\n required: ['documentText'],\n },\n },\n async run(input, ctx) {\n const { documentText, hintUrl, k } = (input ?? {}) as {\n documentText?: unknown;\n hintUrl?: unknown;\n k?: unknown;\n };\n if (typeof documentText !== 'string' || !documentText.trim()) {\n return JSON.stringify({ error: 'documentText is required and must be a non-empty string' });\n }\n const limit = typeof k === 'number' ? Math.max(1, Math.min(10, Math.floor(k))) : 5;\n\n const candidates: Array<{\n id: string;\n path: string;\n collection: string;\n score: number;\n title: string;\n excerpt: string;\n matchedBy: 'routeTemplate' | 'search';\n }> = [];\n\n // 1) URL-hint matching against any collection's routeTemplate.\n if (typeof hintUrl === 'string' && hintUrl.trim()) {\n const cleanHint = hintUrl.trim();\n for (const [collectionName, collection] of Object.entries(ctx.config.collections)) {\n const template = (collection as { routeTemplate?: string }).routeTemplate;\n if (!template) continue;\n const fieldValues = matchRouteTemplate(template, cleanHint);\n if (!fieldValues) continue;\n const match = await findEntryByFieldValues(collectionName, fieldValues, ctx);\n if (match) {\n candidates.push({ ...match, matchedBy: 'routeTemplate' });\n }\n }\n }\n\n // 2) Search fallback — embed the document text and rank entries.\n const queryText = documentText.trim().slice(0, 2000);\n try {\n const hits = await searchContent(queryText, {\n k: limit,\n branch: ctx.branch,\n });\n for (const h of hits) {\n if (candidates.some((c) => c.path === h.path)) continue;\n candidates.push({ ...h, matchedBy: 'search' });\n }\n } catch (err) {\n return JSON.stringify({\n error: `Search fallback failed: ${err instanceof Error ? err.message : String(err)}`,\n candidates,\n });\n }\n\n if (candidates.length === 0) {\n return JSON.stringify({\n candidates: [],\n note: 'No candidates found — verify the document has searchable text, or ask the user which entry to update.',\n });\n }\n\n return JSON.stringify({\n candidates: candidates.map((c) => ({\n id: c.id,\n path: c.path,\n collection: c.collection,\n title: c.title,\n score: Number(c.score.toFixed(4)),\n excerpt: c.excerpt,\n matchedBy: c.matchedBy,\n })),\n });\n },\n};\n\n/**\n * Match a route template like `/blog/[slug]` (or `/items/[id]/[lang]`) against\n * a literal URL/path. Returns an object mapping each placeholder to the\n * captured value, or `null` if the template doesn't match. Query strings and\n * trailing slashes are ignored. Exposed for unit tests.\n */\nexport function matchRouteTemplate(template: string, url: string): Record<string, string> | null {\n // Drop scheme + host: '/blog/foo?x=1' → '/blog/foo'\n let path = url;\n const protoIdx = path.indexOf('://');\n if (protoIdx !== -1) {\n const slash = path.indexOf('/', protoIdx + 3);\n path = slash === -1 ? '/' : path.slice(slash);\n }\n const queryIdx = path.indexOf('?');\n if (queryIdx !== -1) path = path.slice(0, queryIdx);\n\n const norm = (s: string) => s.replace(/\\/+$/, '') || '/';\n const tplParts = norm(template).split('/');\n const urlParts = norm(path).split('/');\n if (tplParts.length !== urlParts.length) return null;\n\n const out: Record<string, string> = {};\n for (let i = 0; i < tplParts.length; i++) {\n const tp = tplParts[i];\n const up = urlParts[i];\n const m = tp.match(/^\\[(.+)\\]$/);\n if (m) {\n if (!up) return null;\n out[m[1]] = decodeURIComponent(up);\n } else if (tp !== up) {\n return null;\n }\n }\n return out;\n}\n\nasync function findEntryByFieldValues(\n collectionName: string,\n fieldValues: Record<string, string>,\n ctx: ToolContext,\n): Promise<{ id: string; path: string; collection: string; score: number; title: string; excerpt: string } | null> {\n const { getFile, getContentFiles } =\n (await import('../../admin/actions/files')) as typeof import('../../admin/actions/files');\n const { resolveEntryTitle, resolveEntryId, buildEntryExcerpt } =\n (await import('../../lib/resolveEntryTitle')) as typeof import('../../lib/resolveEntryTitle');\n\n const entries = await getContentFiles(collectionName).catch(() => [] as string[]);\n for (const p of entries) {\n let payload: { sys?: { id?: unknown; type?: unknown }; fields?: Record<string, unknown> };\n try {\n payload = (await getFile(p)) as typeof payload;\n } catch {\n continue;\n }\n let allMatch = true;\n for (const [key, expected] of Object.entries(fieldValues)) {\n const actual = payload.fields?.[key];\n if (typeof actual !== 'string' || actual !== expected) {\n // Also accept matching against the filename stem when the placeholder is `id`.\n if (key === 'id') {\n const stem = p\n .split('/')\n .pop()\n ?.replace(/\\.json$/, '');\n if (stem === expected) continue;\n }\n allMatch = false;\n break;\n }\n }\n if (!allMatch) continue;\n return {\n id: resolveEntryId(ctx.config, p, payload),\n path: p,\n collection: collectionName,\n score: 1,\n title: resolveEntryTitle(ctx.config, p, payload),\n excerpt: buildEntryExcerpt(ctx.config, p, payload),\n };\n }\n return null;\n}\n\nexport const READ_ONLY_TOOLS: ToolHandler[] = [\n searchContentTool,\n listCollectionsTool,\n getEntryTool,\n findEntryForDocumentTool,\n];\n\nexport const PROPOSAL_TOOLS: ToolHandler[] = [proposeEditTool, proposeNewEntryTool];\n\nexport const ALL_TOOLS: ToolHandler[] = [...READ_ONLY_TOOLS, ...PROPOSAL_TOOLS];\n\nexport function getToolHandler(name: string): ToolHandler | undefined {\n return ALL_TOOLS.find((t) => t.definition.name === name);\n}\n\nexport function getToolDefinitions(): NormalizedTool[] {\n return ALL_TOOLS.map((t) => t.definition);\n}\n\n// Re-exported so callers don't need to reach into `proposals.ts` for the\n// server-side accept handler.\nexport { _acceptProposal as acceptProposal };\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"octocms\",\n \"version\": \"0.4.
|
|
1
|
+
{"version":3,"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"octocms\",\n \"version\": \"0.4.13\",\n \"description\": \"A file-based CMS for Next.js — schema-driven, Git-backed, no database\",\n \"license\": \"MIT\",\n \"type\": \"module\",\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.ts\",\n \"require\": \"./dist/index.cjs\",\n \"import\": \"./dist/index.js\"\n },\n \"./query\": {\n \"types\": \"./dist/query.d.ts\",\n \"require\": \"./dist/query.cjs\",\n \"import\": \"./dist/query.js\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"require\": \"./dist/config.cjs\",\n \"import\": \"./dist/config.js\"\n },\n \"./defineConfig\": {\n \"types\": \"./dist/defineConfig.d.ts\",\n \"require\": \"./dist/defineConfig.cjs\",\n \"import\": \"./dist/defineConfig.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"require\": \"./dist/types.cjs\",\n \"import\": \"./dist/types.js\"\n },\n \"./withOctoCMS\": {\n \"types\": \"./dist/withOctoCMS.d.ts\",\n \"require\": \"./dist/withOctoCMS.cjs\",\n \"import\": \"./dist/withOctoCMS.js\"\n },\n \"./agent\": {\n \"types\": \"./dist/agent/index.d.ts\",\n \"require\": \"./dist/agent/index.cjs\",\n \"import\": \"./dist/agent/index.js\"\n },\n \"./schema\": {\n \"types\": \"./dist/schema/index.d.ts\",\n \"import\": \"./dist/schema/index.js\"\n },\n \"./components/public\": {\n \"types\": \"./dist/components/public/index.d.ts\",\n \"require\": \"./dist/components/public/index.cjs\",\n \"import\": \"./dist/components/public/index.js\"\n },\n \"./lib/configStore\": {\n \"types\": \"./dist/lib/configStore.d.ts\",\n \"require\": \"./dist/lib/configStore.cjs\",\n \"import\": \"./dist/lib/configStore.js\"\n },\n \"./admin\": {\n \"types\": \"./dist/admin/index.d.ts\",\n \"import\": \"./dist/admin/index.js\"\n },\n \"./admin/*\": {\n \"types\": \"./dist/admin/*.d.ts\",\n \"import\": \"./dist/admin/*.js\"\n },\n \"./components/*\": {\n \"types\": \"./dist/components/*.d.ts\",\n \"import\": \"./dist/components/*.js\"\n },\n \"./hooks/*\": {\n \"types\": \"./dist/hooks/*.d.ts\",\n \"import\": \"./dist/hooks/*.js\"\n },\n \"./lib/*\": {\n \"types\": \"./dist/lib/*.d.ts\",\n \"import\": \"./dist/lib/*.js\"\n },\n \"./schema/*\": {\n \"types\": \"./dist/schema/*.d.ts\",\n \"import\": \"./dist/schema/*.js\"\n },\n \"./utils/*\": {\n \"types\": \"./dist/utils/*.d.ts\",\n \"import\": \"./dist/utils/*.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 && tsc -p tsconfig.build.json && cp globals.css dist/globals.css\",\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 \"@anthropic-ai/sdk\": \">=0.91\",\n \"@huggingface/transformers\": \">=4\",\n \"@mdxeditor/editor\": \">=3\",\n \"@radix-ui/react-avatar\": \">=1\",\n \"@radix-ui/react-dialog\": \">=1\",\n \"@radix-ui/react-dropdown-menu\": \">=2\",\n \"@radix-ui/react-label\": \">=2\",\n \"@radix-ui/react-select\": \">=2\",\n \"@radix-ui/react-slot\": \">=1\",\n \"@radix-ui/react-tabs\": \">=1\",\n \"@radix-ui/react-toast\": \">=1\",\n \"@tanstack/react-query\": \">=5\",\n \"class-variance-authority\": \">=0.7\",\n \"clsx\": \">=2\",\n \"glob\": \">=11\",\n \"lucide-react\": \">=1\",\n \"mammoth\": \">=1.12\",\n \"minisearch\": \">=7\",\n \"next\": \">=15\",\n \"next-auth\": \">=4\",\n \"octokit\": \">=4\",\n \"openai\": \">=4\",\n \"pdfjs-dist\": \">=4\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\",\n \"react-markdown\": \">=10\",\n \"rehype-sanitize\": \">=6\",\n \"remark-gfm\": \">=4\",\n \"remark-mdx\": \">=3\",\n \"sharp\": \">=0.34\",\n \"slugify\": \">=1\",\n \"sonner\": \">=2\",\n \"tailwind-merge\": \">=3\",\n \"zod\": \">=4\"\n },\n \"peerDependenciesMeta\": {\n \"@anthropic-ai/sdk\": {\n \"optional\": true\n },\n \"@huggingface/transformers\": {\n \"optional\": true\n },\n \"mammoth\": {\n \"optional\": true\n },\n \"openai\": {\n \"optional\": true\n },\n \"pdfjs-dist\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@tanstack/react-query\": \"^5.100.9\",\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"],"mappings":";AAEE,cAAW;","names":[]}
|
|
@@ -37,52 +37,13 @@ async function loadProjectConfig(projectRoot) {
|
|
|
37
37
|
return mod.configOctoCMS;
|
|
38
38
|
}
|
|
39
39
|
async function loadCollections(projectRoot) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const localOctocms = resolve(projectRoot, "octocms");
|
|
43
|
-
if (existsSync(localOctocms)) {
|
|
44
|
-
alias["octocms/"] = localOctocms + "/";
|
|
45
|
-
}
|
|
46
|
-
const jiti = createJiti(join(projectRoot, "__cli_loader__.ts"), {
|
|
47
|
-
fsCache: false,
|
|
48
|
-
moduleCache: false,
|
|
49
|
-
alias
|
|
50
|
-
});
|
|
51
|
-
const mod = await jiti.import(join(projectRoot, "octocms/admin/consts.ts"), {
|
|
52
|
-
default: true,
|
|
53
|
-
try: true
|
|
54
|
-
});
|
|
55
|
-
if (!mod || !Array.isArray(mod.COLLECTIONS)) {
|
|
56
|
-
throw new Error("Could not load COLLECTIONS from octocms/admin/consts.ts");
|
|
57
|
-
}
|
|
58
|
-
return mod.COLLECTIONS;
|
|
59
|
-
}
|
|
60
|
-
async function loadFieldTypes(projectRoot) {
|
|
61
|
-
const { createJiti } = await import("jiti");
|
|
62
|
-
const alias = {};
|
|
63
|
-
const localOctocms = resolve(projectRoot, "octocms");
|
|
64
|
-
if (existsSync(localOctocms)) {
|
|
65
|
-
alias["octocms/"] = localOctocms + "/";
|
|
66
|
-
}
|
|
67
|
-
const jiti = createJiti(join(projectRoot, "__cli_loader__.ts"), {
|
|
68
|
-
fsCache: false,
|
|
69
|
-
moduleCache: false,
|
|
70
|
-
alias
|
|
71
|
-
});
|
|
72
|
-
const mod = await jiti.import(join(projectRoot, "octocms/admin/consts.ts"), {
|
|
73
|
-
default: true,
|
|
74
|
-
try: true
|
|
75
|
-
});
|
|
76
|
-
if (!mod || !Array.isArray(mod.FIELD_TYPES)) {
|
|
77
|
-
throw new Error("Could not load FIELD_TYPES from octocms/admin/consts.ts");
|
|
78
|
-
}
|
|
79
|
-
return mod.FIELD_TYPES;
|
|
40
|
+
const config = await loadProjectConfig(projectRoot);
|
|
41
|
+
return Object.keys(config.collections);
|
|
80
42
|
}
|
|
81
43
|
|
|
82
44
|
export {
|
|
83
45
|
resolveProjectRoot,
|
|
84
46
|
loadProjectConfig,
|
|
85
|
-
loadCollections
|
|
86
|
-
loadFieldTypes
|
|
47
|
+
loadCollections
|
|
87
48
|
};
|
|
88
|
-
//# sourceMappingURL=chunk-
|
|
49
|
+
//# sourceMappingURL=chunk-ZYUK2J5L.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 * Derive the collection name list from the user's config.\n *\n * Collection identity lives in `cms/schema.json` (mirrored into\n * `cms/__generated__/schema.ts`); the package has no business hard-coding\n * names. This mirrors `regenerateAll`'s pattern: `Object.keys(config.collections)`.\n */\nexport async function loadCollections(projectRoot: string): Promise<readonly string[]> {\n const config = await loadProjectConfig(projectRoot);\n return Object.keys(config.collections);\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,MAAM;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;AASA,eAAsB,gBAAgB,aAAiD;AACrF,QAAM,SAAS,MAAM,kBAAkB,WAAW;AAClD,SAAO,OAAO,KAAK,OAAO,WAAW;AACvC;","names":[]}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
version
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-NAHOP7TG.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveProjectRoot
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-ZYUK2J5L.js";
|
|
8
8
|
import {
|
|
9
9
|
fmt,
|
|
10
10
|
log
|
|
@@ -164,7 +164,7 @@ async function main() {
|
|
|
164
164
|
try {
|
|
165
165
|
switch (command) {
|
|
166
166
|
case "init": {
|
|
167
|
-
const { initCommand } = await import("../init-
|
|
167
|
+
const { initCommand } = await import("../init-KWH66PKY.js");
|
|
168
168
|
await initCommand(process.cwd(), { yes: flags.yes === true });
|
|
169
169
|
break;
|
|
170
170
|
}
|
|
@@ -177,19 +177,19 @@ async function main() {
|
|
|
177
177
|
}
|
|
178
178
|
case "types:gen": {
|
|
179
179
|
const projectRoot = resolveProjectRoot();
|
|
180
|
-
const { typesGenCommand } = await import("../typesGen-
|
|
180
|
+
const { typesGenCommand } = await import("../typesGen-MFAL3B4V.js");
|
|
181
181
|
await typesGenCommand(projectRoot);
|
|
182
182
|
break;
|
|
183
183
|
}
|
|
184
184
|
case "embeddings:gen": {
|
|
185
185
|
const projectRoot = resolveProjectRoot();
|
|
186
|
-
const { embeddingsGenCommand } = await import("../embeddingsGen-
|
|
186
|
+
const { embeddingsGenCommand } = await import("../embeddingsGen-FXWCPGB7.js");
|
|
187
187
|
await embeddingsGenCommand(projectRoot);
|
|
188
188
|
break;
|
|
189
189
|
}
|
|
190
190
|
case "validate": {
|
|
191
191
|
const projectRoot = resolveProjectRoot();
|
|
192
|
-
const { validateCommand } = await import("../validate-
|
|
192
|
+
const { validateCommand } = await import("../validate-AAW4IGWD.js");
|
|
193
193
|
await validateCommand(projectRoot);
|
|
194
194
|
break;
|
|
195
195
|
}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* Moved here from `scripts/generate-types.ts` as part of Phase 4 (CLI).
|
|
5
5
|
* The script now imports these functions; the CLI `types:gen` command calls them directly.
|
|
6
6
|
*/
|
|
7
|
+
import { FIELD_FORMATS } from '../../schema/fieldFormats';
|
|
7
8
|
import type { CollectionField, Config } from '../../types';
|
|
9
|
+
export { FIELD_FORMATS };
|
|
8
10
|
export declare const CODEGEN_BANNER = "/*\n * AUTO-GENERATED \u2014 DO NOT EDIT.\n * Generated from cms/schema.json.\n * Run `npx octocms types:gen` to regenerate.\n */\n\n";
|
|
9
11
|
/** Capitalize the first letter of a string: `post` → `Post`, `homePage` → `HomePage`. */
|
|
10
12
|
export declare function pascalCase(s: string): string;
|
|
@@ -43,14 +45,6 @@ export declare function generateSchemaShim(cfg: Config): string;
|
|
|
43
45
|
* Emitted to `cms/__generated__/configInit.ts` by `npm run types:gen`.
|
|
44
46
|
*/
|
|
45
47
|
export declare function generateConfigInit(): string;
|
|
46
|
-
/**
|
|
47
|
-
* The fixed list of supported field formats. Mirrors `FieldFormat` in
|
|
48
|
-
* `octocms/types.ts` and `FIELD_TYPES` in `octocms/admin/consts.ts`.
|
|
49
|
-
*
|
|
50
|
-
* Kept as a runtime constant so `regenerateAll()` does not need to import
|
|
51
|
-
* `octocms/admin/consts` (which would pull admin code into the CLI surface).
|
|
52
|
-
*/
|
|
53
|
-
export declare const FIELD_FORMATS: readonly ["string", "text", "markdown", "boolean", "reference", "image", "number", "datetime", "json", "slug", "select", "url", "color", "conditional", "richtext"];
|
|
54
48
|
/**
|
|
55
49
|
* Regenerate every schema-driven artifact in memory and return them as a
|
|
56
50
|
* `path -> content` map. The visual schema-editor server action commits the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../../cli/lib/codegen.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAA2B,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../../cli/lib/codegen.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAA2B,MAAM,aAAa,CAAC;AAMpF,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,eAAO,MAAM,cAAc,0IAM1B,CAAC;AAEF,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,eAAe,EACtB,eAAe,EAAE,SAAS,MAAM,EAAE,EAClC,IAAI,GAAE,UAAU,GAAG,KAAkB,GACpC,MAAM,CA6CR;AAyCD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAqDrF;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,MAAM,EAAE,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CA0CpH;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAuC5F;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAYtC;AAsED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAYtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAW3C;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAoB5E"}
|
package/dist/cli/lib/codegen.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "../../chunk-B5LE2OEC.js";
|
|
2
|
+
import { FIELD_FORMATS } from "../../schema/fieldFormats";
|
|
2
3
|
import { generateAgentIndex, generateAgentOverview, generateAgentSchema } from "./agentDocs";
|
|
3
4
|
import { generateSchemaDocs } from "./schemaDocs";
|
|
4
5
|
import { validateConfig } from "./validateConfig";
|
|
@@ -113,7 +114,16 @@ function generateTypes(cfg, collectionNames) {
|
|
|
113
114
|
lines.push("");
|
|
114
115
|
}
|
|
115
116
|
const entryNames = collectionNames.map((k) => `${pascalCase(k)}Entry`);
|
|
116
|
-
|
|
117
|
+
const inlineAnyEntry = `export type AnyEntry = ${entryNames.join(" | ")};`;
|
|
118
|
+
if (inlineAnyEntry.length > 120) {
|
|
119
|
+
lines.push("export type AnyEntry =");
|
|
120
|
+
entryNames.forEach((name, i) => {
|
|
121
|
+
const suffix = i === entryNames.length - 1 ? ";" : "";
|
|
122
|
+
lines.push(` | ${name}${suffix}`);
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
lines.push(inlineAnyEntry);
|
|
126
|
+
}
|
|
117
127
|
lines.push("");
|
|
118
128
|
lines.push("export type EntryMap = {");
|
|
119
129
|
for (const key of collectionNames) {
|
|
@@ -288,23 +298,6 @@ setConfig(userConfig.configOctoCMS);
|
|
|
288
298
|
if (userConfig.agentConfig) setAgentConfig(userConfig.agentConfig);
|
|
289
299
|
`;
|
|
290
300
|
}
|
|
291
|
-
const FIELD_FORMATS = [
|
|
292
|
-
"string",
|
|
293
|
-
"text",
|
|
294
|
-
"markdown",
|
|
295
|
-
"boolean",
|
|
296
|
-
"reference",
|
|
297
|
-
"image",
|
|
298
|
-
"number",
|
|
299
|
-
"datetime",
|
|
300
|
-
"json",
|
|
301
|
-
"slug",
|
|
302
|
-
"select",
|
|
303
|
-
"url",
|
|
304
|
-
"color",
|
|
305
|
-
"conditional",
|
|
306
|
-
"richtext"
|
|
307
|
-
];
|
|
308
301
|
function regenerateAll(cfg) {
|
|
309
302
|
const collectionNames = Object.keys(cfg.collections);
|
|
310
303
|
validateConfig(cfg, collectionNames);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../cli/lib/codegen.ts"],"sourcesContent":["/**\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';\nimport { generateAgentIndex, generateAgentOverview, generateAgentSchema } from './agentDocs';\nimport { generateSchemaDocs } from './schemaDocs';\nimport { validateConfig } from './validateConfig';\n\nexport const CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated from cms/schema.json.\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 * Serialize a config value to TypeScript source.\n *\n * Output matches the project's oxfmt style closely enough that no post-format\n * step is needed — important because the visual Content Model editor regenerates\n * this shim from a server action running on Vercel in production, where\n * spawning `oxfmt` (a dev tool) is not possible.\n *\n * Style rules emitted directly:\n * - Single quotes for strings (escaped if needed).\n * - Bare keys when the property name is a valid JS identifier; quoted otherwise.\n * - Trailing commas after every element of multi-line arrays/objects.\n * - `as const` appended to the `options` / `defaultOptions` arrays of select\n * fields so option `value` strings narrow to literal-union types.\n *\n * As a safety net, `cms/__generated__/schema.ts` is also listed in oxfmt's\n * `ignorePatterns` (`.oxfmtrc.json`) so any future style drift will not fail\n * `npm run fmt:check`.\n */\nconst JS_IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst RESERVED = new Set([\n 'break',\n 'case',\n 'catch',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'export',\n 'extends',\n 'false',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'import',\n 'in',\n 'instanceof',\n 'new',\n 'null',\n 'return',\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield',\n]);\n\nfunction quoteString(s: string): string {\n // Single-quoted; escape backslashes, single quotes, and control chars.\n return `'${s.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\").replace(/\\n/g, '\\\\n').replace(/\\r/g, '\\\\r')}'`;\n}\n\nfunction formatKey(k: string): string {\n return JS_IDENT.test(k) && !RESERVED.has(k) ? k : quoteString(k);\n}\n\nexport function serializeConfigToTS(cfg: Config): string {\n function emit(value: unknown, indent: string, parentFieldFormat?: string, key?: string): string {\n if (value === null) return 'null';\n if (typeof value === 'boolean') return value ? 'true' : 'false';\n if (typeof value === 'number') return String(value);\n if (typeof value === 'string') return quoteString(value);\n if (Array.isArray(value)) {\n const needsAsConst = parentFieldFormat === 'select' && (key === 'options' || key === 'defaultOptions');\n const suffix = needsAsConst ? ' as const' : '';\n if (value.length === 0) return `[]${suffix}`;\n const inner = indent + ' ';\n const items = value.map((v) => `${inner}${emit(v, inner)}`).join(',\\n');\n return `[\\n${items},\\n${indent}]${suffix}`;\n }\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const fmt = typeof obj.format === 'string' ? obj.format : undefined;\n const inner = indent + ' ';\n const entries = Object.entries(obj).map(([k, v]) => `${inner}${formatKey(k)}: ${emit(v, inner, fmt, k)}`);\n return `{\\n${entries.join(',\\n')},\\n${indent}}`;\n }\n throw new Error(`Unsupported value type in schema: ${typeof value}`);\n }\n return emit(cfg, '');\n}\n\n/**\n * Generate `cms/__generated__/schema.ts` — a TypeScript shim that re-emits\n * `cms/schema.json` as a `defineConfig()` call. This preserves literal types\n * (collection names, field names, field formats, select option values) for the\n * downstream `query()` type inference, which JSON imports cannot do on their own.\n *\n * `cms/schema.json` is the source of truth; this shim mirrors it. `npm run\n * types:check` fails if they drift.\n */\nexport function generateSchemaShim(cfg: Config): string {\n // Use a relative import (not the `octocms/*` alias) because this file is\n // pulled in by `cms/octocms.config.ts`, which Next.js loads through the\n // CommonJS resolver for `next.config.ts` — that resolver does not honour\n // tsconfig paths. The original hand-written config used the same workaround.\n return (\n CODEGEN_BANNER +\n `import { defineConfig } from '../../octocms/defineConfig';\n\nexport const schema = defineConfig(${serializeConfigToTS(cfg)});\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 * as userConfig from '../octocms.config';\nimport { setConfig } from 'octocms/lib/configStore';\nimport { setAgentConfig } from 'octocms/agent/configStore';\n\nsetConfig(userConfig.configOctoCMS);\nif (userConfig.agentConfig) setAgentConfig(userConfig.agentConfig);\n`\n );\n}\n\n// ---------------------------------------------------------------------------\n// regenerateAll — single entry point that produces every schema-driven file\n// ---------------------------------------------------------------------------\n\n/**\n * The fixed list of supported field formats. Mirrors `FieldFormat` in\n * `octocms/types.ts` and `FIELD_TYPES` in `octocms/admin/consts.ts`.\n *\n * Kept as a runtime constant so `regenerateAll()` does not need to import\n * `octocms/admin/consts` (which would pull admin code into the CLI surface).\n */\nexport const FIELD_FORMATS = [\n 'string',\n 'text',\n 'markdown',\n 'boolean',\n 'reference',\n 'image',\n 'number',\n 'datetime',\n 'json',\n 'slug',\n 'select',\n 'url',\n 'color',\n 'conditional',\n 'richtext',\n] as const;\n\n/**\n * Regenerate every schema-driven artifact in memory and return them as a\n * `path -> content` map. The visual schema-editor server action commits the\n * map as a single batch; the `npm run *:gen` scripts pick the subset they\n * need and write to disk.\n *\n * Throws if the config is invalid (via `validateConfig`).\n *\n * Output paths are repo-relative and stable. Excluded from this map:\n * - `docs/generated/api-routes.md` — built by scanning `src/app/api/` on disk,\n * not derivable from the schema. The `generate-docs.ts` script writes it\n * separately.\n */\nexport function regenerateAll(cfg: Config): { files: Record<string, string> } {\n const collectionNames = Object.keys(cfg.collections);\n validateConfig(cfg, collectionNames);\n\n return {\n files: {\n 'cms/schema.json': JSON.stringify(cfg, null, 2) + '\\n',\n 'cms/__generated__/schema.ts': generateSchemaShim(cfg),\n 'cms/__generated__/types.ts': generateTypes(cfg, collectionNames),\n 'cms/__generated__/enums.ts': generateEnums(cfg, collectionNames, FIELD_FORMATS),\n 'cms/__generated__/content.d.ts': generateContentDecls(cfg, collectionNames),\n 'cms/__generated__/index.ts': generateIndex(),\n 'cms/__generated__/query.ts': generateQuery(),\n 'cms/__generated__/configInit.ts': generateConfigInit(),\n 'docs/generated/schema.md': generateSchemaDocs(cfg, collectionNames, FIELD_FORMATS),\n 'octocms/docs/index.md': generateAgentIndex(),\n 'octocms/docs/overview.md': generateAgentOverview(cfg, collectionNames),\n 'octocms/docs/schema.md': generateAgentSchema(cfg, collectionNames),\n },\n };\n}\n"],"mappings":";AAQA,SAAS,oBAAoB,uBAAuB,2BAA2B;AAC/E,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAExB,MAAM,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;AA9BV;AA+BE,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;AAhFV;AAiFE,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;AASO,SAAS,gBAAwB;AACtC,SACE,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASJ;AAqBA,MAAM,WAAW;AACjB,MAAM,WAAW,oBAAI,IAAI;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,YAAY,GAAmB;AAEtC,SAAO,IAAI,EAAE,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK,EAAE,QAAQ,OAAO,KAAK,EAAE,QAAQ,OAAO,KAAK,CAAC;AACtG;AAEA,SAAS,UAAU,GAAmB;AACpC,SAAO,SAAS,KAAK,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,IAAI,YAAY,CAAC;AACjE;AAEO,SAAS,oBAAoB,KAAqB;AACvD,WAAS,KAAK,OAAgB,QAAgB,mBAA4B,KAAsB;AAC9F,QAAI,UAAU,KAAM,QAAO;AAC3B,QAAI,OAAO,UAAU,UAAW,QAAO,QAAQ,SAAS;AACxD,QAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK;AAClD,QAAI,OAAO,UAAU,SAAU,QAAO,YAAY,KAAK;AACvD,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAM,eAAe,sBAAsB,aAAa,QAAQ,aAAa,QAAQ;AACrF,YAAM,SAAS,eAAe,cAAc;AAC5C,UAAI,MAAM,WAAW,EAAG,QAAO,KAAK,MAAM;AAC1C,YAAM,QAAQ,SAAS;AACvB,YAAM,QAAQ,MAAM,IAAI,CAAC,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,EAAE,EAAE,KAAK,KAAK;AACtE,aAAO;AAAA,EAAM,KAAK;AAAA,EAAM,MAAM,IAAI,MAAM;AAAA,IAC1C;AACA,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,MAAM;AACZ,YAAM,MAAM,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS;AAC1D,YAAM,QAAQ,SAAS;AACvB,YAAM,UAAU,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC,CAAC,KAAK,KAAK,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE;AACxG,aAAO;AAAA,EAAM,QAAQ,KAAK,KAAK,CAAC;AAAA,EAAM,MAAM;AAAA,IAC9C;AACA,UAAM,IAAI,MAAM,qCAAqC,OAAO,KAAK,EAAE;AAAA,EACrE;AACA,SAAO,KAAK,KAAK,EAAE;AACrB;AAWO,SAAS,mBAAmB,KAAqB;AAKtD,SACE,iBACA;AAAA;AAAA,qCAEiC,oBAAoB,GAAG,CAAC;AAAA;AAG7D;AAWO,SAAS,qBAA6B;AAC3C,SACE,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQJ;AAaO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeO,SAAS,cAAc,KAAgD;AAC5E,QAAM,kBAAkB,OAAO,KAAK,IAAI,WAAW;AACnD,iBAAe,KAAK,eAAe;AAEnC,SAAO;AAAA,IACL,OAAO;AAAA,MACL,mBAAmB,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI;AAAA,MAClD,+BAA+B,mBAAmB,GAAG;AAAA,MACrD,8BAA8B,cAAc,KAAK,eAAe;AAAA,MAChE,8BAA8B,cAAc,KAAK,iBAAiB,aAAa;AAAA,MAC/E,kCAAkC,qBAAqB,KAAK,eAAe;AAAA,MAC3E,8BAA8B,cAAc;AAAA,MAC5C,8BAA8B,cAAc;AAAA,MAC5C,mCAAmC,mBAAmB;AAAA,MACtD,4BAA4B,mBAAmB,KAAK,iBAAiB,aAAa;AAAA,MAClF,yBAAyB,mBAAmB;AAAA,MAC5C,4BAA4B,sBAAsB,KAAK,eAAe;AAAA,MACtE,0BAA0B,oBAAoB,KAAK,eAAe;AAAA,IACpE;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../cli/lib/codegen.ts"],"sourcesContent":["/**\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 { FIELD_FORMATS } from '../../schema/fieldFormats';\nimport type { CollectionField, Config, ConditionalBranchConfig } from '../../types';\nimport { generateAgentIndex, generateAgentOverview, generateAgentSchema } from './agentDocs';\nimport { generateSchemaDocs } from './schemaDocs';\nimport { validateConfig } from './validateConfig';\n\n// Re-exported so existing call sites (`regenerateAll.test.ts`) keep working.\nexport { FIELD_FORMATS };\n\nexport const CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated from cms/schema.json.\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 — wrap to one-per-line when the inline form would exceed\n // oxfmt's 120-char limit, so codegen output matches the formatter.\n const entryNames = collectionNames.map((k) => `${pascalCase(k)}Entry`);\n const inlineAnyEntry = `export type AnyEntry = ${entryNames.join(' | ')};`;\n if (inlineAnyEntry.length > 120) {\n lines.push('export type AnyEntry =');\n entryNames.forEach((name, i) => {\n const suffix = i === entryNames.length - 1 ? ';' : '';\n lines.push(` | ${name}${suffix}`);\n });\n } else {\n lines.push(inlineAnyEntry);\n }\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 * Serialize a config value to TypeScript source.\n *\n * Output matches the project's oxfmt style closely enough that no post-format\n * step is needed — important because the visual Content Model editor regenerates\n * this shim from a server action running on Vercel in production, where\n * spawning `oxfmt` (a dev tool) is not possible.\n *\n * Style rules emitted directly:\n * - Single quotes for strings (escaped if needed).\n * - Bare keys when the property name is a valid JS identifier; quoted otherwise.\n * - Trailing commas after every element of multi-line arrays/objects.\n * - `as const` appended to the `options` / `defaultOptions` arrays of select\n * fields so option `value` strings narrow to literal-union types.\n *\n * As a safety net, `cms/__generated__/schema.ts` is also listed in oxfmt's\n * `ignorePatterns` (`.oxfmtrc.json`) so any future style drift will not fail\n * `npm run fmt:check`.\n */\nconst JS_IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst RESERVED = new Set([\n 'break',\n 'case',\n 'catch',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'export',\n 'extends',\n 'false',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'import',\n 'in',\n 'instanceof',\n 'new',\n 'null',\n 'return',\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield',\n]);\n\nfunction quoteString(s: string): string {\n // Single-quoted; escape backslashes, single quotes, and control chars.\n return `'${s.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\").replace(/\\n/g, '\\\\n').replace(/\\r/g, '\\\\r')}'`;\n}\n\nfunction formatKey(k: string): string {\n return JS_IDENT.test(k) && !RESERVED.has(k) ? k : quoteString(k);\n}\n\nexport function serializeConfigToTS(cfg: Config): string {\n function emit(value: unknown, indent: string, parentFieldFormat?: string, key?: string): string {\n if (value === null) return 'null';\n if (typeof value === 'boolean') return value ? 'true' : 'false';\n if (typeof value === 'number') return String(value);\n if (typeof value === 'string') return quoteString(value);\n if (Array.isArray(value)) {\n const needsAsConst = parentFieldFormat === 'select' && (key === 'options' || key === 'defaultOptions');\n const suffix = needsAsConst ? ' as const' : '';\n if (value.length === 0) return `[]${suffix}`;\n const inner = indent + ' ';\n const items = value.map((v) => `${inner}${emit(v, inner)}`).join(',\\n');\n return `[\\n${items},\\n${indent}]${suffix}`;\n }\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const fmt = typeof obj.format === 'string' ? obj.format : undefined;\n const inner = indent + ' ';\n const entries = Object.entries(obj).map(([k, v]) => `${inner}${formatKey(k)}: ${emit(v, inner, fmt, k)}`);\n return `{\\n${entries.join(',\\n')},\\n${indent}}`;\n }\n throw new Error(`Unsupported value type in schema: ${typeof value}`);\n }\n return emit(cfg, '');\n}\n\n/**\n * Generate `cms/__generated__/schema.ts` — a TypeScript shim that re-emits\n * `cms/schema.json` as a `defineConfig()` call. This preserves literal types\n * (collection names, field names, field formats, select option values) for the\n * downstream `query()` type inference, which JSON imports cannot do on their own.\n *\n * `cms/schema.json` is the source of truth; this shim mirrors it. `npm run\n * types:check` fails if they drift.\n */\nexport function generateSchemaShim(cfg: Config): string {\n // Use a relative import (not the `octocms/*` alias) because this file is\n // pulled in by `cms/octocms.config.ts`, which Next.js loads through the\n // CommonJS resolver for `next.config.ts` — that resolver does not honour\n // tsconfig paths. The original hand-written config used the same workaround.\n return (\n CODEGEN_BANNER +\n `import { defineConfig } from '../../octocms/defineConfig';\n\nexport const schema = defineConfig(${serializeConfigToTS(cfg)});\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 * as userConfig from '../octocms.config';\nimport { setConfig } from 'octocms/lib/configStore';\nimport { setAgentConfig } from 'octocms/agent/configStore';\n\nsetConfig(userConfig.configOctoCMS);\nif (userConfig.agentConfig) setAgentConfig(userConfig.agentConfig);\n`\n );\n}\n\n// ---------------------------------------------------------------------------\n// regenerateAll — single entry point that produces every schema-driven file\n// ---------------------------------------------------------------------------\n\n/**\n * Regenerate every schema-driven artifact in memory and return them as a\n * `path -> content` map. The visual schema-editor server action commits the\n * map as a single batch; the `npm run *:gen` scripts pick the subset they\n * need and write to disk.\n *\n * Throws if the config is invalid (via `validateConfig`).\n *\n * Output paths are repo-relative and stable. Excluded from this map:\n * - `docs/generated/api-routes.md` — built by scanning `src/app/api/` on disk,\n * not derivable from the schema. The `generate-docs.ts` script writes it\n * separately.\n */\nexport function regenerateAll(cfg: Config): { files: Record<string, string> } {\n const collectionNames = Object.keys(cfg.collections);\n validateConfig(cfg, collectionNames);\n\n return {\n files: {\n 'cms/schema.json': JSON.stringify(cfg, null, 2) + '\\n',\n 'cms/__generated__/schema.ts': generateSchemaShim(cfg),\n 'cms/__generated__/types.ts': generateTypes(cfg, collectionNames),\n 'cms/__generated__/enums.ts': generateEnums(cfg, collectionNames, FIELD_FORMATS),\n 'cms/__generated__/content.d.ts': generateContentDecls(cfg, collectionNames),\n 'cms/__generated__/index.ts': generateIndex(),\n 'cms/__generated__/query.ts': generateQuery(),\n 'cms/__generated__/configInit.ts': generateConfigInit(),\n 'docs/generated/schema.md': generateSchemaDocs(cfg, collectionNames, FIELD_FORMATS),\n 'octocms/docs/index.md': generateAgentIndex(),\n 'octocms/docs/overview.md': generateAgentOverview(cfg, collectionNames),\n 'octocms/docs/schema.md': generateAgentSchema(cfg, collectionNames),\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/lib/project.js
CHANGED
|
@@ -37,50 +37,11 @@ async function loadProjectConfig(projectRoot) {
|
|
|
37
37
|
return mod.configOctoCMS;
|
|
38
38
|
}
|
|
39
39
|
async function loadCollections(projectRoot) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const localOctocms = resolve(projectRoot, "octocms");
|
|
43
|
-
if (existsSync(localOctocms)) {
|
|
44
|
-
alias["octocms/"] = localOctocms + "/";
|
|
45
|
-
}
|
|
46
|
-
const jiti = createJiti(join(projectRoot, "__cli_loader__.ts"), {
|
|
47
|
-
fsCache: false,
|
|
48
|
-
moduleCache: false,
|
|
49
|
-
alias
|
|
50
|
-
});
|
|
51
|
-
const mod = await jiti.import(join(projectRoot, "octocms/admin/consts.ts"), {
|
|
52
|
-
default: true,
|
|
53
|
-
try: true
|
|
54
|
-
});
|
|
55
|
-
if (!mod || !Array.isArray(mod.COLLECTIONS)) {
|
|
56
|
-
throw new Error("Could not load COLLECTIONS from octocms/admin/consts.ts");
|
|
57
|
-
}
|
|
58
|
-
return mod.COLLECTIONS;
|
|
59
|
-
}
|
|
60
|
-
async function loadFieldTypes(projectRoot) {
|
|
61
|
-
const { createJiti } = await import("jiti");
|
|
62
|
-
const alias = {};
|
|
63
|
-
const localOctocms = resolve(projectRoot, "octocms");
|
|
64
|
-
if (existsSync(localOctocms)) {
|
|
65
|
-
alias["octocms/"] = localOctocms + "/";
|
|
66
|
-
}
|
|
67
|
-
const jiti = createJiti(join(projectRoot, "__cli_loader__.ts"), {
|
|
68
|
-
fsCache: false,
|
|
69
|
-
moduleCache: false,
|
|
70
|
-
alias
|
|
71
|
-
});
|
|
72
|
-
const mod = await jiti.import(join(projectRoot, "octocms/admin/consts.ts"), {
|
|
73
|
-
default: true,
|
|
74
|
-
try: true
|
|
75
|
-
});
|
|
76
|
-
if (!mod || !Array.isArray(mod.FIELD_TYPES)) {
|
|
77
|
-
throw new Error("Could not load FIELD_TYPES from octocms/admin/consts.ts");
|
|
78
|
-
}
|
|
79
|
-
return mod.FIELD_TYPES;
|
|
40
|
+
const config = await loadProjectConfig(projectRoot);
|
|
41
|
+
return Object.keys(config.collections);
|
|
80
42
|
}
|
|
81
43
|
export {
|
|
82
44
|
loadCollections,
|
|
83
|
-
loadFieldTypes,
|
|
84
45
|
loadProjectConfig,
|
|
85
46
|
resolveProjectRoot
|
|
86
47
|
};
|