From c2a24b9162d3b8302b515eb04f2ec63db53d588a Mon Sep 17 00:00:00 2001 From: svemagie <869694+svemagie@users.noreply.github.com> Date: Mon, 9 Mar 2026 15:24:00 +0100 Subject: [PATCH] Expose AI fields in /posts article editor --- indiekit.config.mjs | 6 + package.json | 4 +- scripts/patch-endpoint-posts-ai-fields.mjs | 138 +++++++++++++++++++++ 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 scripts/patch-endpoint-posts-ai-fields.mjs diff --git a/indiekit.config.mjs b/indiekit.config.mjs index e2dee6a5..4edb0605 100644 --- a/indiekit.config.mjs +++ b/indiekit.config.mjs @@ -193,6 +193,12 @@ export default { path: "content/articles/{slug}.md", url: `${publicationBaseUrl}/articles/{slug}/`, }, + fields: { + aiTextLevel: {}, + aiCodeLevel: {}, + aiTools: {}, + aiDescription: {}, + }, }, note: { name: "Notiz", diff --git a/package.json b/package.json index dcd9959e..28a68bb2 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "postinstall": "node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-docloader-loglevel.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs", - "serve": "export NODE_ENV=${NODE_ENV:-production} INDIEKIT_DEBUG=${INDIEKIT_DEBUG:-0} && node scripts/preflight-production-security.mjs && node scripts/preflight-mongo-connection.mjs && node scripts/preflight-activitypub-rsa-key.mjs && node scripts/preflight-activitypub-profile-urls.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-docloader-loglevel.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs", + "postinstall": "node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-docloader-loglevel.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs", + "serve": "export NODE_ENV=${NODE_ENV:-production} INDIEKIT_DEBUG=${INDIEKIT_DEBUG:-0} && node scripts/preflight-production-security.mjs && node scripts/preflight-mongo-connection.mjs && node scripts/preflight-activitypub-rsa-key.mjs && node scripts/preflight-activitypub-profile-urls.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-activitypub-docloader-loglevel.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-conversations-mastodon-disconnect.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], diff --git a/scripts/patch-endpoint-posts-ai-fields.mjs b/scripts/patch-endpoint-posts-ai-fields.mjs new file mode 100644 index 00000000..0fa9339c --- /dev/null +++ b/scripts/patch-endpoint-posts-ai-fields.mjs @@ -0,0 +1,138 @@ +import { access, mkdir, readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; + +const endpointCandidates = [ + "node_modules/@rmdes/indiekit-endpoint-posts", + "node_modules/@indiekit/endpoint-posts", + "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-posts", + "node_modules/@indiekit/indiekit/node_modules/@indiekit/endpoint-posts", +]; + +const templates = { + "aiTextLevel-field.njk": [ + '{% set aiTextLevelValue = fieldData("aiTextLevel").value or (properties.ai.textLevel if properties.ai and properties.ai.textLevel is defined else properties.aiTextLevel) or "0" %}', + "{{ radios({", + ' name: "aiTextLevel",', + " values: aiTextLevelValue,", + " fieldset: {", + ' legend: "AI Text-Einsatz",', + " optional: true", + " },", + " items: [{", + ' label: "0 - Kein KI-Text",', + ' value: "0"', + " }, {", + ' label: "1 - Leichte KI-Hilfe",', + ' value: "1"', + " }, {", + ' label: "2 - Teilweise KI-generiert",', + ' value: "2"', + " }, {", + ' label: "3 - Ueberwiegend KI-generiert",', + ' value: "3"', + " }]", + "}) }}", + ].join("\n"), + "aiCodeLevel-field.njk": [ + '{% set aiCodeLevelValue = fieldData("aiCodeLevel").value or (properties.ai.codeLevel if properties.ai and properties.ai.codeLevel is defined else properties.aiCodeLevel) or "0" %}', + "{{ radios({", + ' name: "aiCodeLevel",', + " values: aiCodeLevelValue,", + " fieldset: {", + ' legend: "AI Code-Einsatz",', + " optional: true", + " },", + " items: [{", + ' label: "0 - Kein KI-Code",', + ' value: "0"', + " }, {", + ' label: "1 - Leichte KI-Hilfe",', + ' value: "1"', + " }, {", + ' label: "2 - Teilweise KI-generiert",', + ' value: "2"', + " }, {", + ' label: "3 - Ueberwiegend KI-generiert",', + ' value: "3"', + " }]", + "}) }}", + ].join("\n"), + "aiTools-field.njk": [ + '{% set aiToolsValue = fieldData("aiTools").value or (properties.ai.aiTools if properties.ai and properties.ai.aiTools is defined else properties.aiTools) %}', + "{{ input({", + ' name: "aiTools",', + " value: aiToolsValue,", + ' label: "AI Tools",', + ' hint: "Optional, komma-separiert (z. B. Claude, ChatGPT, Copilot)",', + " optional: true", + "}) }}", + ].join("\n"), + "aiDescription-field.njk": [ + '{% set aiDescriptionValue = fieldData("aiDescription").value or (properties.ai.aiDescription if properties.ai and properties.ai.aiDescription is defined else properties.aiDescription) %}', + "{{ textarea({", + ' name: "aiDescription",', + " value: aiDescriptionValue,", + ' label: "AI Beschreibung",', + ' hint: "Optional: kurze Erlaeuterung, wie KI verwendet wurde",', + " optional: true", + "}) }}", + ].join("\n"), +}; + +async function exists(filePath) { + try { + await access(filePath); + return true; + } catch { + return false; + } +} + +let checkedEndpoints = 0; +let checkedFiles = 0; +let patchedFiles = 0; + +for (const endpointPath of endpointCandidates) { + if (!(await exists(endpointPath))) { + continue; + } + + const includeDir = path.join(endpointPath, "includes", "post-types"); + if (!(await exists(includeDir))) { + continue; + } + + checkedEndpoints += 1; + await mkdir(includeDir, { recursive: true }); + + for (const [fileName, template] of Object.entries(templates)) { + checkedFiles += 1; + + const filePath = path.join(includeDir, fileName); + const desired = `${template}\n`; + + let current = ""; + if (await exists(filePath)) { + current = await readFile(filePath, "utf8"); + } + + if (current === desired) { + continue; + } + + await writeFile(filePath, desired, "utf8"); + patchedFiles += 1; + } +} + +if (checkedEndpoints === 0) { + console.log("[postinstall] No endpoint-posts package directories found"); +} else if (checkedFiles === 0) { + console.log("[postinstall] No endpoint-posts AI field templates checked"); +} else if (patchedFiles === 0) { + console.log("[postinstall] endpoint-posts AI field templates already patched"); +} else { + console.log( + `[postinstall] Patched endpoint-posts AI field templates in ${patchedFiles}/${checkedFiles} file(s)`, + ); +}