@hoardodile/create-plugin 0.1.1 → 0.1.3

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/index.js CHANGED
@@ -22,12 +22,14 @@ var SDK_DEP_NAMES = [
22
22
 
23
23
  // src/rewrite.ts
24
24
  var THIRD_PARTY_VERSIONS = {
25
+ "@release-it/conventional-changelog": "^12.0.0",
25
26
  "@types/node": "^26.2.0",
26
27
  "@types/react": "^19.2.18",
27
28
  "@types/react-dom": "^19.2.4",
28
29
  jsdom: "^30.0.1",
29
30
  react: "^19.2.8",
30
31
  "react-dom": "^19.2.8",
32
+ "release-it": "^21.0.2",
31
33
  typescript: "^7.0.2",
32
34
  vite: "^8.2.2",
33
35
  vitest: "^4.1.11"
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sdk-deps.gen.ts","../src/rewrite.ts","../src/index.ts"],"names":["join"],"mappings":"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","file":"index.js","sourcesContent":["// GENERATED by scripts/gen-sdk-deps.mjs — never hand-edit.\n// The published SDK closure a scaffolded plugin can depend on; kept in\n// lockstep with scripts/lib/sdk-closure.mjs (see sdks:pack).\nexport const SDK_DEP_NAMES: readonly string[] = [\n\t\"@hoardodile/cli\",\n\t\"@hoardodile/host\",\n\t\"@hoardodile/host-web\",\n\t\"@hoardodile/i18n\",\n\t\"@hoardodile/sdk-react\",\n\t\"@hoardodile/sdk-server\",\n\t\"@hoardodile/sdk-types\",\n\t\"@hoardodile/sdk-web\",\n\t\"@hoardodile/ui\",\n\t\"@hoardodile/workbench\",\n]\n","/**\n * Scaffold-time rewrites applied to the embedded template copy: fresh\n * manifest identity and concrete dependency specs (the template uses\n * `workspace:*` / `catalog:` which only resolve inside the monorepo).\n */\nimport { join } from \"node:path\"\nimport { SDK_DEP_NAMES } from \"./sdk-deps.gen.ts\"\n\n/** Concrete versions for the catalog: specs the template uses. */\nexport const THIRD_PARTY_VERSIONS: Readonly<Record<string, string>> = {\n\t\"@types/node\": \"^26.2.0\",\n\t\"@types/react\": \"^19.2.18\",\n\t\"@types/react-dom\": \"^19.2.4\",\n\tjsdom: \"^30.0.1\",\n\treact: \"^19.2.8\",\n\t\"react-dom\": \"^19.2.8\",\n\ttypescript: \"^7.0.2\",\n\tvite: \"^8.2.2\",\n\tvitest: \"^4.1.11\",\n}\n\nexport type ManifestShape = {\n\tid: string\n\tname: string\n\tdescription: string\n\tversion: string\n\ti18n?: {\n\t\tname?: Record<string, string>\n\t\tdescription?: Record<string, string>\n\t}\n}\n\nexport function rewriteManifest(\n\tmanifest: ManifestShape,\n\tpluginName: string,\n): ManifestShape {\n\tmanifest.id = crypto.randomUUID()\n\tmanifest.name = pluginName\n\tmanifest.description = `Content plugin: ${pluginName}`\n\tif (manifest.i18n?.name !== undefined) {\n\t\tmanifest.i18n.name.en = pluginName\n\t}\n\tif (manifest.i18n?.description !== undefined) {\n\t\tmanifest.i18n.description.en = `Content plugin: ${pluginName}`\n\t}\n\tmanifest.version = \"0.0.1\"\n\treturn manifest\n}\n\nexport type PackageJson = {\n\tname: string\n\tversion?: string\n\tdependencies?: Record<string, string>\n\tdevDependencies?: Record<string, string>\n}\n\nexport function tarballSpec(\n\ttarballsDir: string,\n\tdep: string,\n\tversion: string,\n): string {\n\tconst fileName = dep.replace(\"@\", \"\").replace(\"/\", \"-\")\n\treturn `file:${join(tarballsDir, `${fileName}-${version}.tgz`).replaceAll(\"\\\\\", \"/\")}`\n}\n\nfunction rewriteDepBlock(\n\tdeps: Record<string, string> | undefined,\n\ttarballsDir: string | undefined,\n\tsdkVersion: string,\n): Record<string, string> {\n\tconst out = { ...deps }\n\tfor (const [dep, spec] of Object.entries(out)) {\n\t\tif (SDK_DEP_NAMES.includes(dep)) {\n\t\t\tout[dep] =\n\t\t\t\ttarballsDir !== undefined\n\t\t\t\t\t? tarballSpec(tarballsDir, dep, sdkVersion)\n\t\t\t\t\t: // `^0.2.0-alpha.3` would never match the 0.2.0 stable\n\t\t\t\t\t\t// release (semver keeps prereleases out of plain ranges),\n\t\t\t\t\t\t// so npm specs drop the prerelease suffix.\n\t\t\t\t\t\t`^${sdkVersion.split(\"-\")[0]}`\n\t\t} else if (spec === \"catalog:\") {\n\t\t\tconst version = THIRD_PARTY_VERSIONS[dep]\n\t\t\tif (version === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`template dependency \"${dep}\" has no concrete version mapping`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tout[dep] = version\n\t\t}\n\t}\n\treturn out\n}\n\nexport function rewritePackageJson(\n\tpkg: PackageJson,\n\tpluginName: string,\n\topts: { readonly tarballsDir?: string; readonly sdkVersion: string },\n): PackageJson {\n\tpkg.name = pluginName\n\tdelete pkg.version\n\tpkg.version = \"0.0.1\"\n\tif (pkg.dependencies !== undefined) {\n\t\tpkg.dependencies = rewriteDepBlock(\n\t\t\tpkg.dependencies,\n\t\t\topts.tarballsDir,\n\t\t\topts.sdkVersion,\n\t\t)\n\t}\n\tif (pkg.devDependencies !== undefined) {\n\t\tpkg.devDependencies = rewriteDepBlock(\n\t\t\tpkg.devDependencies,\n\t\t\topts.tarballsDir,\n\t\t\topts.sdkVersion,\n\t\t)\n\t}\n\treturn pkg\n}\n\n/**\n * Install-script dependencies that land in a scaffolded plugin through\n * host's optionalDependencies (the same names as the root workspace's\n * allowBuilds). pnpm refuses to run their build scripts without an\n * explicit approval, so the generated workspace approves them up front.\n */\nconst ALLOWED_BUILDS = [\n\t\"@derhuerst/ffprobe-static\",\n\t\"@hoardodile/7z-bin\",\n\t\"ffmpeg-static\",\n]\n\nexport function tarballOverridesYaml(\n\ttarballsDir: string,\n\tsdkVersion: string,\n): string {\n\tconst lines = SDK_DEP_NAMES.map(\n\t\t(dep) => ` '${dep}': '${tarballSpec(tarballsDir, dep, sdkVersion)}'`,\n\t).join(\"\\n\")\n\tconst builds = ALLOWED_BUILDS.map((dep) => ` '${dep}': true`).join(\"\\n\")\n\treturn [\n\t\t\"# Redirect the cross-SDK 0.0.0 specs packed into the tarballs to the\",\n\t\t\"# sibling tarballs in this workspace; approve the install scripts of\",\n\t\t\"# host's optional binaries (ffmpeg/ffprobe/7-Zip) so pnpm runs them.\",\n\t\t\"overrides:\",\n\t\tlines,\n\t\t\"allowBuilds:\",\n\t\tbuilds,\n\t\t\"\",\n\t].join(\"\\n\")\n}\n","#!/usr/bin/env node\n/**\n * `create-hoardodile-plugin` — scaffold a new content plugin from the\n * embedded template copy (`src/template/`, kept in sync with\n * `plugins/template` by scripts/sync-template.mjs).\n *\n * Flow: interactive prompts (name, id auto-generated) → copy template →\n * rewrite manifest + package.json → install dependencies → validate the\n * manifest → print the dev loop entry points.\n *\n * create-hoardodile-plugin my-plugin\n * create-hoardodile-plugin my-plugin --tarballs ../hoardodile/tmp/sdks\n *\n * `--tarballs <dir>` rewires the SDK deps to packed tarballs plus a\n * pnpm-workspace.yaml with the cross-package overrides — used by the\n * release smoke test and for offline installs.\n */\nimport { spawn } from \"node:child_process\"\nimport {\n\tcpSync,\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\twriteFileSync,\n} from \"node:fs\"\nimport { dirname, join, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\nimport {\n\tcancel,\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\toutro,\n\ttext,\n} from \"@clack/prompts\"\nimport { pluginManifest } from \"@hoardodile/sdk-types/schema\"\nimport {\n\trewriteManifest,\n\trewritePackageJson,\n\ttarballOverridesYaml,\n} from \"./rewrite.ts\"\n\nconst ROOT = resolve(dirname(fileURLToPath(import.meta.url)), \"..\")\n// The template ships inside dist (dist/template) — the bin always runs\n// from the built artifact, so resolve relative to this module.\nconst TEMPLATE_DIR = resolve(\n\tdirname(fileURLToPath(import.meta.url)),\n\t\"template\",\n)\nconst SELF_VERSION = JSON.parse(\n\treadFileSync(join(ROOT, \"package.json\"), \"utf8\"),\n).version\n\nfunction writeJson(path: string, value: unknown): void {\n\twriteFileSync(path, `${JSON.stringify(value, null, \"\\t\")}\\n`)\n}\n\nfunction writeTarballOverrides(targetDir: string, tarballsDir: string): void {\n\twriteFileSync(\n\t\tjoin(targetDir, \"pnpm-workspace.yaml\"),\n\t\ttarballOverridesYaml(tarballsDir, SELF_VERSION),\n\t)\n}\n\nasync function runInstall(targetDir: string): Promise<void> {\n\tlog.step(\"Installing dependencies (pnpm install)\")\n\treturn new Promise<void>((resolveDone, reject) => {\n\t\tconst child = spawn(\"pnpm\", [\"install\"], {\n\t\t\tcwd: targetDir,\n\t\t\tstdio: \"inherit\",\n\t\t\tshell: process.platform === \"win32\",\n\t\t})\n\t\tchild.on(\"error\", reject)\n\t\tchild.on(\"exit\", (code) =>\n\t\t\tcode === 0\n\t\t\t\t? resolveDone()\n\t\t\t\t: reject(new Error(`pnpm install exited ${code}`)),\n\t\t)\n\t})\n}\n\nexport async function main() {\n\tconst positional = process.argv.slice(2).filter((a) => !a.startsWith(\"--\"))\n\tconst tarballsFlag = process.argv.indexOf(\"--tarballs\")\n\tconst tarballsDir =\n\t\ttarballsFlag !== -1\n\t\t\t? resolve(process.argv[tarballsFlag + 1] ?? \"\")\n\t\t\t: undefined\n\n\tintro(\"hoardodile plugin scaffold\")\n\n\tconst providedName = positional[0]\n\tconst pluginName =\n\t\tprovidedName ??\n\t\t(await text({\n\t\t\tmessage: \"Plugin name (also the directory name, npm-style):\",\n\t\t\tvalidate: (v) =>\n\t\t\t\t/^[a-z0-9][a-z0-9-]*$/.test(v ?? \"\")\n\t\t\t\t\t? undefined\n\t\t\t\t\t: \"lowercase letters, digits and dashes only\",\n\t\t}))\n\tif (isCancel(pluginName)) {\n\t\tcancel(\"scaffold cancelled\")\n\t\tprocess.exit(1)\n\t}\n\n\tconst targetDir = resolve(pluginName)\n\tif (existsSync(targetDir) && readdirSync(targetDir).length > 0) {\n\t\tconst proceed = await confirm({\n\t\t\tmessage: `${targetDir} is not empty — scaffold into it anyway?`,\n\t\t\tinitialValue: false,\n\t\t})\n\t\tif (isCancel(proceed) || !proceed) {\n\t\t\tcancel(\"scaffold cancelled\")\n\t\t\tprocess.exit(1)\n\t\t}\n\t}\n\n\tlog.step(`Copying template into ${targetDir}`)\n\tmkdirSync(targetDir, { recursive: true })\n\t// dist/template is a build artifact (already filtered when copied in);\n\t// copy it wholesale so template source dirs inside it survive.\n\tcpSync(TEMPLATE_DIR, targetDir, { recursive: true })\n\n\tlog.step(\"Rewriting manifest and package.json\")\n\tconst manifestPath = join(targetDir, \"manifest.json\")\n\tconst pkgPath = join(targetDir, \"package.json\")\n\twriteJson(\n\t\tmanifestPath,\n\t\trewriteManifest(JSON.parse(readFileSync(manifestPath, \"utf8\")), pluginName),\n\t)\n\twriteJson(\n\t\tpkgPath,\n\t\trewritePackageJson(JSON.parse(readFileSync(pkgPath, \"utf8\")), pluginName, {\n\t\t\ttarballsDir,\n\t\t\tsdkVersion: SELF_VERSION,\n\t\t}),\n\t)\n\n\tconst parsed = pluginManifest.safeParse(\n\t\tJSON.parse(readFileSync(manifestPath, \"utf8\")),\n\t)\n\tif (!parsed.success) {\n\t\tprocess.exitCode = 1\n\t\tlog.error(`generated manifest is invalid: ${parsed.error.message}`)\n\t\treturn\n\t}\n\n\tif (tarballsDir !== undefined) {\n\t\tlog.step(`Rewiring SDK deps to tarballs in ${tarballsDir}`)\n\t\twriteTarballOverrides(targetDir, tarballsDir)\n\t}\n\n\ttry {\n\t\tawait runInstall(targetDir)\n\t} catch (err) {\n\t\tprocess.exitCode = 1\n\t\tlog.error(\n\t\t\t`install failed: ${err instanceof Error ? err.message : String(err)}`,\n\t\t)\n\t\treturn\n\t}\n\n\toutro(\"Plugin scaffolded. Next steps:\")\n\tconsole.log(` cd ${targetDir}`)\n\tconsole.log(\n\t\t\" pnpm build # build dist/ (client + server bundle + manifest)\",\n\t)\n\tconsole.log(\n\t\t\" pnpm dev # watch-build + serve the workbench (http://127.0.0.1:5199)\",\n\t)\n\tconsole.log(\" pnpm test # unit tests against the fixture API\")\n\tconsole.log(\" hoardodile plugin run detect testdata --plugin-dir dist\")\n\tconsole.log(\n\t\t\" # Replace the manifest id? No — it was generated fresh. Zip dist/ contents and upload in Settings → Plugins.\",\n\t)\n}\n\nif (\n\tprocess.argv[1] !== undefined &&\n\tresolve(process.argv[1]) === fileURLToPath(import.meta.url)\n) {\n\tmain().catch((err) => {\n\t\tlog.error(err instanceof Error ? err.message : String(err))\n\t\tprocess.exit(1)\n\t})\n}\n"]}
1
+ {"version":3,"sources":["../src/sdk-deps.gen.ts","../src/rewrite.ts","../src/index.ts"],"names":["join"],"mappings":"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","file":"index.js","sourcesContent":["// GENERATED by scripts/gen-sdk-deps.mjs — never hand-edit.\n// The published SDK closure a scaffolded plugin can depend on; kept in\n// lockstep with scripts/lib/sdk-closure.mjs (see sdks:pack).\nexport const SDK_DEP_NAMES: readonly string[] = [\n\t\"@hoardodile/cli\",\n\t\"@hoardodile/host\",\n\t\"@hoardodile/host-web\",\n\t\"@hoardodile/i18n\",\n\t\"@hoardodile/sdk-react\",\n\t\"@hoardodile/sdk-server\",\n\t\"@hoardodile/sdk-types\",\n\t\"@hoardodile/sdk-web\",\n\t\"@hoardodile/ui\",\n\t\"@hoardodile/workbench\",\n]\n","/**\n * Scaffold-time rewrites applied to the embedded template copy: fresh\n * manifest identity and concrete dependency specs (the template uses\n * `workspace:*` / `catalog:` which only resolve inside the monorepo).\n */\nimport { join } from \"node:path\"\nimport { SDK_DEP_NAMES } from \"./sdk-deps.gen.ts\"\n\n/** Concrete versions for the catalog: specs the template uses. */\nexport const THIRD_PARTY_VERSIONS: Readonly<Record<string, string>> = {\n\t\"@release-it/conventional-changelog\": \"^12.0.0\",\n\t\"@types/node\": \"^26.2.0\",\n\t\"@types/react\": \"^19.2.18\",\n\t\"@types/react-dom\": \"^19.2.4\",\n\tjsdom: \"^30.0.1\",\n\treact: \"^19.2.8\",\n\t\"react-dom\": \"^19.2.8\",\n\t\"release-it\": \"^21.0.2\",\n\ttypescript: \"^7.0.2\",\n\tvite: \"^8.2.2\",\n\tvitest: \"^4.1.11\",\n}\n\nexport type ManifestShape = {\n\tid: string\n\tname: string\n\tdescription: string\n\tversion: string\n\ti18n?: {\n\t\tname?: Record<string, string>\n\t\tdescription?: Record<string, string>\n\t}\n}\n\nexport function rewriteManifest(\n\tmanifest: ManifestShape,\n\tpluginName: string,\n): ManifestShape {\n\tmanifest.id = crypto.randomUUID()\n\tmanifest.name = pluginName\n\tmanifest.description = `Content plugin: ${pluginName}`\n\tif (manifest.i18n?.name !== undefined) {\n\t\tmanifest.i18n.name.en = pluginName\n\t}\n\tif (manifest.i18n?.description !== undefined) {\n\t\tmanifest.i18n.description.en = `Content plugin: ${pluginName}`\n\t}\n\tmanifest.version = \"0.0.1\"\n\treturn manifest\n}\n\nexport type PackageJson = {\n\tname: string\n\tversion?: string\n\tdependencies?: Record<string, string>\n\tdevDependencies?: Record<string, string>\n}\n\nexport function tarballSpec(\n\ttarballsDir: string,\n\tdep: string,\n\tversion: string,\n): string {\n\tconst fileName = dep.replace(\"@\", \"\").replace(\"/\", \"-\")\n\treturn `file:${join(tarballsDir, `${fileName}-${version}.tgz`).replaceAll(\"\\\\\", \"/\")}`\n}\n\nfunction rewriteDepBlock(\n\tdeps: Record<string, string> | undefined,\n\ttarballsDir: string | undefined,\n\tsdkVersion: string,\n): Record<string, string> {\n\tconst out = { ...deps }\n\tfor (const [dep, spec] of Object.entries(out)) {\n\t\tif (SDK_DEP_NAMES.includes(dep)) {\n\t\t\tout[dep] =\n\t\t\t\ttarballsDir !== undefined\n\t\t\t\t\t? tarballSpec(tarballsDir, dep, sdkVersion)\n\t\t\t\t\t: // `^0.2.0-alpha.3` would never match the 0.2.0 stable\n\t\t\t\t\t\t// release (semver keeps prereleases out of plain ranges),\n\t\t\t\t\t\t// so npm specs drop the prerelease suffix.\n\t\t\t\t\t\t`^${sdkVersion.split(\"-\")[0]}`\n\t\t} else if (spec === \"catalog:\") {\n\t\t\tconst version = THIRD_PARTY_VERSIONS[dep]\n\t\t\tif (version === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`template dependency \"${dep}\" has no concrete version mapping`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tout[dep] = version\n\t\t}\n\t}\n\treturn out\n}\n\nexport function rewritePackageJson(\n\tpkg: PackageJson,\n\tpluginName: string,\n\topts: { readonly tarballsDir?: string; readonly sdkVersion: string },\n): PackageJson {\n\tpkg.name = pluginName\n\tdelete pkg.version\n\tpkg.version = \"0.0.1\"\n\tif (pkg.dependencies !== undefined) {\n\t\tpkg.dependencies = rewriteDepBlock(\n\t\t\tpkg.dependencies,\n\t\t\topts.tarballsDir,\n\t\t\topts.sdkVersion,\n\t\t)\n\t}\n\tif (pkg.devDependencies !== undefined) {\n\t\tpkg.devDependencies = rewriteDepBlock(\n\t\t\tpkg.devDependencies,\n\t\t\topts.tarballsDir,\n\t\t\topts.sdkVersion,\n\t\t)\n\t}\n\treturn pkg\n}\n\n/**\n * Install-script dependencies that land in a scaffolded plugin through\n * host's optionalDependencies (the same names as the root workspace's\n * allowBuilds). pnpm refuses to run their build scripts without an\n * explicit approval, so the generated workspace approves them up front.\n */\nconst ALLOWED_BUILDS = [\n\t\"@derhuerst/ffprobe-static\",\n\t\"@hoardodile/7z-bin\",\n\t\"ffmpeg-static\",\n]\n\nexport function tarballOverridesYaml(\n\ttarballsDir: string,\n\tsdkVersion: string,\n): string {\n\tconst lines = SDK_DEP_NAMES.map(\n\t\t(dep) => ` '${dep}': '${tarballSpec(tarballsDir, dep, sdkVersion)}'`,\n\t).join(\"\\n\")\n\tconst builds = ALLOWED_BUILDS.map((dep) => ` '${dep}': true`).join(\"\\n\")\n\treturn [\n\t\t\"# Redirect the cross-SDK 0.0.0 specs packed into the tarballs to the\",\n\t\t\"# sibling tarballs in this workspace; approve the install scripts of\",\n\t\t\"# host's optional binaries (ffmpeg/ffprobe/7-Zip) so pnpm runs them.\",\n\t\t\"overrides:\",\n\t\tlines,\n\t\t\"allowBuilds:\",\n\t\tbuilds,\n\t\t\"\",\n\t].join(\"\\n\")\n}\n","#!/usr/bin/env node\n/**\n * `create-hoardodile-plugin` — scaffold a new content plugin from the\n * embedded template copy (`src/template/`, kept in sync with\n * `plugins/template` by scripts/sync-template.mjs).\n *\n * Flow: interactive prompts (name, id auto-generated) → copy template →\n * rewrite manifest + package.json → install dependencies → validate the\n * manifest → print the dev loop entry points.\n *\n * create-hoardodile-plugin my-plugin\n * create-hoardodile-plugin my-plugin --tarballs ../hoardodile/tmp/sdks\n *\n * `--tarballs <dir>` rewires the SDK deps to packed tarballs plus a\n * pnpm-workspace.yaml with the cross-package overrides — used by the\n * release smoke test and for offline installs.\n */\nimport { spawn } from \"node:child_process\"\nimport {\n\tcpSync,\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\twriteFileSync,\n} from \"node:fs\"\nimport { dirname, join, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\nimport {\n\tcancel,\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\toutro,\n\ttext,\n} from \"@clack/prompts\"\nimport { pluginManifest } from \"@hoardodile/sdk-types/schema\"\nimport {\n\trewriteManifest,\n\trewritePackageJson,\n\ttarballOverridesYaml,\n} from \"./rewrite.ts\"\n\nconst ROOT = resolve(dirname(fileURLToPath(import.meta.url)), \"..\")\n// The template ships inside dist (dist/template) — the bin always runs\n// from the built artifact, so resolve relative to this module.\nconst TEMPLATE_DIR = resolve(\n\tdirname(fileURLToPath(import.meta.url)),\n\t\"template\",\n)\nconst SELF_VERSION = JSON.parse(\n\treadFileSync(join(ROOT, \"package.json\"), \"utf8\"),\n).version\n\nfunction writeJson(path: string, value: unknown): void {\n\twriteFileSync(path, `${JSON.stringify(value, null, \"\\t\")}\\n`)\n}\n\nfunction writeTarballOverrides(targetDir: string, tarballsDir: string): void {\n\twriteFileSync(\n\t\tjoin(targetDir, \"pnpm-workspace.yaml\"),\n\t\ttarballOverridesYaml(tarballsDir, SELF_VERSION),\n\t)\n}\n\nasync function runInstall(targetDir: string): Promise<void> {\n\tlog.step(\"Installing dependencies (pnpm install)\")\n\treturn new Promise<void>((resolveDone, reject) => {\n\t\tconst child = spawn(\"pnpm\", [\"install\"], {\n\t\t\tcwd: targetDir,\n\t\t\tstdio: \"inherit\",\n\t\t\tshell: process.platform === \"win32\",\n\t\t})\n\t\tchild.on(\"error\", reject)\n\t\tchild.on(\"exit\", (code) =>\n\t\t\tcode === 0\n\t\t\t\t? resolveDone()\n\t\t\t\t: reject(new Error(`pnpm install exited ${code}`)),\n\t\t)\n\t})\n}\n\nexport async function main() {\n\tconst positional = process.argv.slice(2).filter((a) => !a.startsWith(\"--\"))\n\tconst tarballsFlag = process.argv.indexOf(\"--tarballs\")\n\tconst tarballsDir =\n\t\ttarballsFlag !== -1\n\t\t\t? resolve(process.argv[tarballsFlag + 1] ?? \"\")\n\t\t\t: undefined\n\n\tintro(\"hoardodile plugin scaffold\")\n\n\tconst providedName = positional[0]\n\tconst pluginName =\n\t\tprovidedName ??\n\t\t(await text({\n\t\t\tmessage: \"Plugin name (also the directory name, npm-style):\",\n\t\t\tvalidate: (v) =>\n\t\t\t\t/^[a-z0-9][a-z0-9-]*$/.test(v ?? \"\")\n\t\t\t\t\t? undefined\n\t\t\t\t\t: \"lowercase letters, digits and dashes only\",\n\t\t}))\n\tif (isCancel(pluginName)) {\n\t\tcancel(\"scaffold cancelled\")\n\t\tprocess.exit(1)\n\t}\n\n\tconst targetDir = resolve(pluginName)\n\tif (existsSync(targetDir) && readdirSync(targetDir).length > 0) {\n\t\tconst proceed = await confirm({\n\t\t\tmessage: `${targetDir} is not empty — scaffold into it anyway?`,\n\t\t\tinitialValue: false,\n\t\t})\n\t\tif (isCancel(proceed) || !proceed) {\n\t\t\tcancel(\"scaffold cancelled\")\n\t\t\tprocess.exit(1)\n\t\t}\n\t}\n\n\tlog.step(`Copying template into ${targetDir}`)\n\tmkdirSync(targetDir, { recursive: true })\n\t// dist/template is a build artifact (already filtered when copied in);\n\t// copy it wholesale so template source dirs inside it survive.\n\tcpSync(TEMPLATE_DIR, targetDir, { recursive: true })\n\n\tlog.step(\"Rewriting manifest and package.json\")\n\tconst manifestPath = join(targetDir, \"manifest.json\")\n\tconst pkgPath = join(targetDir, \"package.json\")\n\twriteJson(\n\t\tmanifestPath,\n\t\trewriteManifest(JSON.parse(readFileSync(manifestPath, \"utf8\")), pluginName),\n\t)\n\twriteJson(\n\t\tpkgPath,\n\t\trewritePackageJson(JSON.parse(readFileSync(pkgPath, \"utf8\")), pluginName, {\n\t\t\ttarballsDir,\n\t\t\tsdkVersion: SELF_VERSION,\n\t\t}),\n\t)\n\n\tconst parsed = pluginManifest.safeParse(\n\t\tJSON.parse(readFileSync(manifestPath, \"utf8\")),\n\t)\n\tif (!parsed.success) {\n\t\tprocess.exitCode = 1\n\t\tlog.error(`generated manifest is invalid: ${parsed.error.message}`)\n\t\treturn\n\t}\n\n\tif (tarballsDir !== undefined) {\n\t\tlog.step(`Rewiring SDK deps to tarballs in ${tarballsDir}`)\n\t\twriteTarballOverrides(targetDir, tarballsDir)\n\t}\n\n\ttry {\n\t\tawait runInstall(targetDir)\n\t} catch (err) {\n\t\tprocess.exitCode = 1\n\t\tlog.error(\n\t\t\t`install failed: ${err instanceof Error ? err.message : String(err)}`,\n\t\t)\n\t\treturn\n\t}\n\n\toutro(\"Plugin scaffolded. Next steps:\")\n\tconsole.log(` cd ${targetDir}`)\n\tconsole.log(\n\t\t\" pnpm build # build dist/ (client + server bundle + manifest)\",\n\t)\n\tconsole.log(\n\t\t\" pnpm dev # watch-build + serve the workbench (http://127.0.0.1:5199)\",\n\t)\n\tconsole.log(\" pnpm test # unit tests against the fixture API\")\n\tconsole.log(\" hoardodile plugin run detect testdata --plugin-dir dist\")\n\tconsole.log(\n\t\t\" # Replace the manifest id? No — it was generated fresh. Zip dist/ contents and upload in Settings → Plugins.\",\n\t)\n}\n\nif (\n\tprocess.argv[1] !== undefined &&\n\tresolve(process.argv[1]) === fileURLToPath(import.meta.url)\n) {\n\tmain().catch((err) => {\n\t\tlog.error(err instanceof Error ? err.message : String(err))\n\t\tprocess.exit(1)\n\t})\n}\n"]}
@@ -0,0 +1,57 @@
1
+ name: Bug report
2
+ description: File a bug report against this hoardodile plugin
3
+ title: "[Bug]: "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to fill out this bug report.
10
+ Minimal reproduction steps first — the title can stay generic until the steps are clear.
11
+ - type: input
12
+ id: hoardodile-version
13
+ attributes:
14
+ label: hoardodile version
15
+ description: The version shown in Settings → About.
16
+ placeholder: 0.x.x
17
+ validations:
18
+ required: true
19
+ - type: input
20
+ id: plugin-version
21
+ attributes:
22
+ label: Plugin version
23
+ description: The version in Settings → Plugins (vX.Y.Z), or the marketplace's latest release if installing fresh.
24
+ placeholder: 0.0.1
25
+ validations:
26
+ required: true
27
+ - type: textarea
28
+ id: steps
29
+ attributes:
30
+ label: Steps to reproduce
31
+ description: Minimal, ordered steps — what did you do to get here?
32
+ placeholder: |
33
+ 1. …
34
+ 2. …
35
+ 3. …
36
+ validations:
37
+ required: true
38
+ - type: textarea
39
+ id: expected
40
+ attributes:
41
+ label: Expected behavior
42
+ description: What did you expect to happen?
43
+ validations:
44
+ required: true
45
+ - type: textarea
46
+ id: actual
47
+ attributes:
48
+ label: Actual behavior
49
+ description: What actually happened instead?
50
+ validations:
51
+ required: true
52
+ - type: textarea
53
+ id: logs
54
+ attributes:
55
+ label: Logs / screenshots
56
+ description: Paste the relevant console or server logs, or attach screenshots.
57
+ render: shell
@@ -0,0 +1,28 @@
1
+ name: Feature request
2
+ description: Suggest an idea for this plugin
3
+ title: "[Feature]: "
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for suggesting! Describe the problem you are solving, not just the feature.
10
+ - type: textarea
11
+ id: problem
12
+ attributes:
13
+ label: Problem
14
+ description: What problem does this feature solve? What is the current pain?
15
+ validations:
16
+ required: true
17
+ - type: textarea
18
+ id: solution
19
+ attributes:
20
+ label: Proposed solution
21
+ description: What would you expect to happen?
22
+ validations:
23
+ required: true
24
+ - type: textarea
25
+ id: alternatives
26
+ attributes:
27
+ label: Alternatives
28
+ description: Workarounds or other plugins that get partway there.
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: npm
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ - package-ecosystem: github-actions
8
+ directory: "/"
9
+ schedule:
10
+ interval: weekly
@@ -0,0 +1,47 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths-ignore:
7
+ - "**.md"
8
+ pull_request:
9
+ paths-ignore:
10
+ - "**.md"
11
+
12
+ # A superseded push cancels the stale run instead of queueing behind it.
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ # One leg is enough: lint, build and test against the SDK source.
22
+ checks:
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 20
25
+ steps:
26
+ - uses: actions/checkout@v7
27
+
28
+ - uses: pnpm/action-setup@v6
29
+ with:
30
+ version: 11
31
+
32
+ - uses: actions/setup-node@v7
33
+ with:
34
+ node-version-file: .nvmrc
35
+ cache: pnpm
36
+
37
+ - name: Install dependencies
38
+ run: pnpm install
39
+
40
+ - name: Lint
41
+ run: pnpm lint
42
+
43
+ - name: Build
44
+ run: pnpm build
45
+
46
+ - name: Test
47
+ run: pnpm test
@@ -1,5 +1,13 @@
1
1
  name: release
2
2
 
3
+ # Normally the tag is produced by `pnpm release <version>` (release-it bumps
4
+ # package.json + manifest.json, writes CHANGELOG.md, commits, tags and pushes).
5
+ # This workflow is the publisher: on tag push it builds, packages
6
+ # (`release/<id>-<version>.zip` + `.sha256`) and creates a *published* GitHub
7
+ # release the marketplace picks up — so no local GITHUB_TOKEN or `gh` CLI is
8
+ # needed. Pushing the tag manually (`git tag v<version> && git push origin
9
+ # v<version>`) still works as a fallback.
10
+
3
11
  on:
4
12
  push:
5
13
  tags: ["v*"]
@@ -11,13 +19,13 @@ jobs:
11
19
  release:
12
20
  runs-on: ubuntu-latest
13
21
  steps:
14
- - uses: actions/checkout@v4
22
+ - uses: actions/checkout@v7
15
23
 
16
- - uses: pnpm/action-setup@v4
24
+ - uses: pnpm/action-setup@v6
17
25
  with:
18
26
  version: 11
19
27
 
20
- - uses: actions/setup-node@v4
28
+ - uses: actions/setup-node@v7
21
29
  with:
22
30
  node-version: 24
23
31
  cache: pnpm
@@ -39,5 +47,8 @@ jobs:
39
47
  env:
40
48
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41
49
  run: |
42
- zip=$(ls release/*.zip)
43
- gh release create "$GITHUB_REF_NAME" "$zip" "$zip.sha256" --generate-notes
50
+ files=$(ls release/*)
51
+ if ls intro.*.md >/dev/null 2>&1; then
52
+ files="$files intro.*.md"
53
+ fi
54
+ gh release create "$GITHUB_REF_NAME" $files --generate-notes
@@ -0,0 +1 @@
1
+ 24
@@ -0,0 +1,63 @@
1
+ # Contributing to this plugin
2
+
3
+ Thanks for contributing! This is a hoardodile content plugin — sections below
4
+ cover the dev loop, quality gates, and how releases and the marketplace work.
5
+
6
+ ## Development setup
7
+
8
+ - Node.js ≥ 24, pnpm 11.
9
+ - Clone the repository, then:
10
+
11
+ ```bash
12
+ pnpm install
13
+ pnpm build # dist/ (client + server bundle + manifest)
14
+ pnpm dev # watch-build + workbench at http://127.0.0.1:5199
15
+ pnpm test # Vitest unit tests against the fixture API
16
+ ```
17
+
18
+ `pnpm exec hoardodile plugin run detect testdata --plugin-dir dist` runs the
19
+ detect hook through the same sandboxed worker the server uses.
20
+
21
+ ## Code style
22
+
23
+ - TypeScript strict (`pnpm lint` = `tsc --noEmit`); no `any` without a comment.
24
+ - Prefer type guards and `satisfies` over `as`.
25
+ - Keep the plugin's own logic in `src/`; `manifest.json` at the repo root is
26
+ the single source of truth for the plugin's identity, permissions and UI
27
+ preferences.
28
+ - Add tests next to the code they cover; keep the fixture API usage minimal.
29
+
30
+ ## Releases
31
+
32
+ Bump `version` in `manifest.json` on user-visible changes, then release with
33
+ one command:
34
+
35
+ ```bash
36
+ pnpm release <version>
37
+ ```
38
+
39
+ release-it bumps `package.json` **and** `manifest.json` (kept in lockstep by
40
+ `scripts/sync-version.mjs`), writes `CHANGELOG.md` from Conventional Commits,
41
+ commits `chore(release): v<version>`, tags and pushes. Run it on `main` with a
42
+ clean working tree. `.github/workflows/release.yml` then builds, runs
43
+ `hoardodile plugin package` (`release/<id>-<version>.zip` + `.sha256`) and
44
+ publishes the GitHub release. The tag must match `v<manifest.version>` — the
45
+ workflow fails otherwise. Your version is independent of the hoardodile app
46
+ version.
47
+
48
+ Pushing the tag by hand still works as a fallback:
49
+ `git tag v<version> && git push origin v<version>`.
50
+
51
+ ## Marketplace publishing
52
+
53
+ 1. Add the repository address to your registry repo's `registry.json`.
54
+ 2. Ship `intro.<locale>.md` files (see the README) so each release carries a
55
+ version-pinned introduction the app can show.
56
+
57
+ ## Issues and pull requests
58
+
59
+ - Bug reports and feature requests go through the issue templates
60
+ (**New issue** → bug report / feature request).
61
+ - Pull requests should stay focused: one cohesive change, a matching test,
62
+ and a description of the user-visible behavior.
63
+ - Security issues are **not** filed as public issues — see `SECURITY.md`.
@@ -45,28 +45,69 @@ pnpm run detect:smoke # sandboxed detect against testdata (needs a build first)
45
45
  `hoardodile plugin run` runs hooks through the same worker sandbox the
46
46
  server uses — the exact production execution path.
47
47
 
48
+ ## Requirements
49
+
50
+ - hoardodile **≥ 0.1.1** — the built-in plugin marketplace
51
+ (**Settings → Marketplace**) and the batched asset-download API
52
+ (`download([…])`) when the manifest declares `"download": true`.
53
+ The marketplace's Intro and Release notes tabs and release intro
54
+ assets are read by newer builds; older builds still list and install
55
+ the plugin normally.
56
+ - `"minAppVersion"` in `manifest.json` declares the lowest hoardodile
57
+ release this plugin runs on. Hosts below it refuse to install or update
58
+ the plugin (the marketplace gates the install/update entries and zip
59
+ uploads are blocked with an explanation), so bump it only when the
60
+ plugin really needs a newer app. Omit it for plugins that support every
61
+ release.
62
+ - The plugin's version is independent of the hoardodile release
63
+ version; bump it on user-visible changes.
64
+ - Dev loop: Node ≥ 24, pnpm 11.
65
+
48
66
  ## Deploying
49
67
 
50
- Publish to the marketplace with two steps:
68
+ Publish to the marketplace with one command:
51
69
 
52
70
  ```bash
53
71
  # 1. Add the repository address to your registry repo's registry.json:
54
72
  # { "version": 1, "plugins": ["https://github.com/<owner>/<repo>"] }
55
73
 
56
- # 2. Tag the release — `.github/workflows/release.yml` builds, packages
57
- # (`release/<id>-<version>.zip` + `.sha256`) and publishes the GitHub
58
- # release automatically. No local `gh` CLI or token needed.
59
- git tag v<version> && git push origin v<version>
74
+ # 2. One-click release — release-it bumps the version in package.json AND
75
+ # manifest.json, writes CHANGELOG.md from Conventional Commits, commits,
76
+ # tags `v<version>` and pushes. The tag-triggered `.github/workflows/
77
+ # release.yml` then builds, packages (`release/<id>-<version>.zip` +
78
+ # `.sha256`) and publishes the GitHub release. No local `gh` CLI or token.
79
+ pnpm release <version>
60
80
  ```
61
81
 
62
- The tag must match the manifest version (`v<manifest.version>`) — the
63
- workflow fails otherwise. Then paste the registry repo address once in
64
- **Settings → Marketplace**. The app reads the registry, each plugin's
65
- manifest and its latest release — names, versions, permissions and
66
- release notes come straight from GitHub, so the list never needs editing
67
- again. The zip asset is `<id>-<version>.zip` (produced by
68
- `hoardodile plugin package`); before the first release the plugin shows
69
- up with a "no release" state.
82
+ On `main`, with a clean working tree. The tag must match the manifest version
83
+ (`v<manifest.version>`) — the workflow fails otherwise. Then paste the registry
84
+ repo address once in **Settings → Marketplace**. The app reads the registry,
85
+ each plugin's manifest and its latest release — names, versions, permissions and
86
+ release notes come straight from GitHub, so the list never needs editing again.
87
+ The zip asset is `<id>-<version>.zip` (produced by `hoardodile plugin package`);
88
+ before the first release the plugin shows up with a "no release" state.
89
+
90
+ Prefer pushing a tag manually (no release-it)? It still works — the workflow
91
+ does the same build/package/publish:
92
+
93
+ ```bash
94
+ git tag v<version> && git push origin v<version>
95
+ ```
70
96
 
71
97
  Local installs (zip upload in **Settings → Plugins**) still work for
72
98
  private packages.
99
+
100
+ ## Publishing an introduction
101
+
102
+ The marketplace detail view shows a per-release **Intro** tab. Ship one
103
+ markdown file per supported language at the repository root, named
104
+ `intro.<locale>.md` (e.g. `intro.en.md`, `intro.zh.md`) — `release.yml`
105
+ uploads them alongside the zip, so **each release carries its own
106
+ introduction** and every version shows independent notes. Use the app's
107
+ supported language codes as file names (`en`, `zh`, `ja`, `de`, `es`) —
108
+ a region-coded name like `intro.zh-CN.md` only matches a UI language
109
+ resolved to that exact code, so `intro.zh.md` is what Chinese users see.
110
+
111
+ The app resolves the intro for the user's UI language (exact locale → base
112
+ language → `en` → the only shipped language); the release body always shows
113
+ in the **Release notes** tab.
@@ -0,0 +1,26 @@
1
+ # Security policy
2
+
3
+ Hoardodile plugins run as **server-side code** inside the app's restricted
4
+ plugin sandbox — treat a plugin like any third-party dependency: only publish
5
+ or install from sources you trust. The manifest declares the capabilities the
6
+ sandbox grants; installs require explicit user consent.
7
+
8
+ ## Reporting a vulnerability
9
+
10
+ Please report security issues **privately** — do **not** open a public issue,
11
+ pull request or discussion that reveals the details.
12
+
13
+ 1. Open the repository's **Security** tab on GitHub.
14
+ 2. Click **Report a vulnerability** to create a private advisory.
15
+ 3. Include the affected hoardodile and plugin versions, a description of the
16
+ vulnerability, reproduction steps and any proof of concept.
17
+
18
+ Private advisories stay invisible to the public until you publish the fix; we
19
+ coordinate the disclosure timeline with you before anything goes public.
20
+
21
+ ## What counts as a security issue
22
+
23
+ Anything that lets a crafted resource or plugin install break out of the
24
+ plugin sandbox, escape the plugin's vault, or read/delete data outside the
25
+ plugin's own scope. For usage questions and non-security bugs use the issue
26
+ templates instead.
@@ -0,0 +1,18 @@
1
+ # My plugin
2
+
3
+ _Replace this introduction with a real overview: what content the plugin
4
+ detects, how it renders it, and where users see it._
5
+
6
+ This introduction ships with **every GitHub release** — edit it per release so
7
+ each version presents its own notes in the marketplace.
8
+
9
+ ## Features
10
+
11
+ - Detects resources containing … and renders them inline.
12
+ - Declares the following permissions: _see `manifest.json`_.
13
+
14
+ ## Requirements
15
+
16
+ - hoardodile ≥ 0.1.1 (see the repository README for details).
17
+ - Trust the repository before installing — plugin code runs server-side in a
18
+ restricted sandbox.
@@ -0,0 +1,15 @@
1
+ # 我的插件
2
+
3
+ _把这段介绍替换为真实内容:插件识别什么内容、如何渲染、用户在何处看到效果。_
4
+
5
+ 本介绍随**每个 GitHub Release** 一同发布——请随版本更新,让每个版本在插件市场中呈现各自的介绍。
6
+
7
+ ## 功能
8
+
9
+ - 识别包含……的资源并以内嵌方式渲染。
10
+ - 声明的权限:_参见 `manifest.json`_。
11
+
12
+ ## 要求
13
+
14
+ - hoardodile ≥ 0.1.1(详见仓库 README)。
15
+ - 安装前请确认信任该仓库——插件代码在受限沙箱中作为服务端代码运行。
@@ -3,6 +3,7 @@
3
3
  "name": "Template",
4
4
  "description": "Template plugin — copy this directory to start your own plugin",
5
5
  "version": "0.0.0",
6
+ "minAppVersion": "0.1.1",
6
7
  "permissions": {
7
8
  "sourceMeta": true,
8
9
  "searchMeta": false,
@@ -10,7 +10,32 @@
10
10
  "watch": "hoardodile plugin build --watch",
11
11
  "detect:smoke": "hoardodile plugin run detect testdata --plugin-dir dist",
12
12
  "lint": "tsc --noEmit",
13
- "test": "vitest run"
13
+ "test": "vitest run",
14
+ "release": "node scripts/release.mjs"
15
+ },
16
+ "release-it": {
17
+ "git": {
18
+ "commitMessage": "chore(release): v${version}",
19
+ "tagName": "v${version}",
20
+ "requireBranch": "main"
21
+ },
22
+ "github": {
23
+ "release": false
24
+ },
25
+ "npm": {
26
+ "publish": false
27
+ },
28
+ "plugins": {
29
+ "@release-it/conventional-changelog": {
30
+ "preset": {
31
+ "name": "conventionalcommits"
32
+ },
33
+ "infile": "CHANGELOG.md"
34
+ }
35
+ },
36
+ "hooks": {
37
+ "after:bump": "node scripts/sync-version.mjs"
38
+ }
14
39
  },
15
40
  "dependencies": {
16
41
  "@hoardodile/sdk-react": "workspace:*",
@@ -29,6 +54,8 @@
29
54
  "jsdom": "catalog:",
30
55
  "typescript": "catalog:",
31
56
  "vite": "catalog:",
32
- "vitest": "catalog:"
57
+ "vitest": "catalog:",
58
+ "release-it": "catalog:",
59
+ "@release-it/conventional-changelog": "catalog:"
33
60
  }
34
61
  }
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `pnpm release <version>` — one-click release for this plugin.
4
+ *
5
+ * Runs release-it, which bumps `package.json`, syncs the new version into
6
+ * `manifest.json` (after:bump → scripts/sync-version.mjs), writes a
7
+ * Conventional-Commits `CHANGELOG.md`, commits `chore(release): v<version>`,
8
+ * tags `v<version>` and pushes. Publishing the GitHub release itself is CI's
9
+ * job: the pushed tag triggers `.github/workflows/release.yml`, which builds,
10
+ * packages (`release/<id>-<version>.zip` + `.sha256`) and creates the
11
+ * published release the marketplace picks up — so no local GITHUB_TOKEN or
12
+ * `gh` CLI is needed. Manual `git tag v<version> && git push origin v<version>`
13
+ * still works as a fallback.
14
+ *
15
+ * release-it is launched with process.execPath — on Windows the `pnpm`/`.cmd`
16
+ * shims are not reliably launchable, so invoking the JS entry is uniform.
17
+ *
18
+ * node scripts/release.mjs [release-it args...]
19
+ */
20
+
21
+ import { spawnSync } from "node:child_process"
22
+ import { existsSync } from "node:fs"
23
+ import { dirname, resolve } from "node:path"
24
+ import { fileURLToPath } from "node:url"
25
+
26
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..")
27
+
28
+ const releaseItBin = resolve(
29
+ ROOT,
30
+ "node_modules",
31
+ "release-it",
32
+ "bin",
33
+ "release-it.js",
34
+ )
35
+ if (!existsSync(releaseItBin)) {
36
+ console.error(
37
+ `release-it not found at ${releaseItBin} — run pnpm install first.`,
38
+ )
39
+ process.exit(1)
40
+ }
41
+
42
+ const result = spawnSync(
43
+ process.execPath,
44
+ [releaseItBin, ...process.argv.slice(2)],
45
+ {
46
+ stdio: "inherit",
47
+ env: process.env,
48
+ },
49
+ )
50
+ if (result.error) {
51
+ console.error(`failed to launch release-it: ${result.error}`)
52
+ process.exit(1)
53
+ }
54
+ process.exit(result.status ?? 1)
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sync the plugin version from `package.json` into `manifest.json`. Invoked by
4
+ * release-it's after:bump hook (the version was just bumped in package.json),
5
+ * so the tag `v<version>` and the packaged zip name match the manifest the
6
+ * marketplace reads. Idempotent; also safe to run standalone.
7
+ *
8
+ * `manifest.json` is biome-canonical, so patch only the version value —
9
+ * JSON.parse + JSON.stringify would reflow arrays and need a post-format pass.
10
+ *
11
+ * node scripts/sync-version.mjs
12
+ */
13
+
14
+ import { readFileSync, writeFileSync } from "node:fs"
15
+
16
+ const { version } = JSON.parse(readFileSync("package.json", "utf8"))
17
+ const path = "manifest.json"
18
+
19
+ let source
20
+ try {
21
+ source = readFileSync(path, "utf8")
22
+ } catch {
23
+ throw new Error(`could not read ${path} — is this the plugin root?`)
24
+ }
25
+
26
+ const next = source.replace(/("version"\s*:\s*)"[^"]*"/, `$1"${version}"`)
27
+ if (next === source) {
28
+ console.log(`unchanged ${path} (${version})`)
29
+ process.exit(0)
30
+ }
31
+
32
+ // Guard: the patch must stay valid JSON carrying the requested version.
33
+ const patched = JSON.parse(next)
34
+ if (patched.version !== version) {
35
+ throw new Error(`version field mismatch after syncing ${path}`)
36
+ }
37
+ writeFileSync(path, next)
38
+ console.log(`synced ${path} -> ${version}`)
@@ -21,6 +21,21 @@ export default definePlugin<TemplateSchema>({
21
21
  // so sourceMeta never rescans.
22
22
  { ok: true, hdtplCount: hdtpl.length }
23
23
  },
24
+ // Optional: the host runs this once after a successful install/update
25
+ // commit (marketplace install/update, zip uploads), with an
26
+ // install-scoped API — no resource is attached (the file surface is
27
+ // empty) but `download` still works behind the shared consent
28
+ // dialog. Best-effort by contract: a throw (or a denied consent)
29
+ // never fails the install, so re-check at runtime.
30
+ //
31
+ // onInstall: async (api) => {
32
+ // await api.download({
33
+ // url: "https://example.com/runtime.min.js",
34
+ // dest: "runtime/runtime.min.js",
35
+ // sha256: "…64 lowercase hex…",
36
+ // reason: "…shown in the consent dialog…",
37
+ // })
38
+ // },
24
39
  sourceMeta: buildSourceMeta,
25
40
  })
26
41
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoardodile/create-plugin",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "description": "Scaffold a hoardodile content plugin.",
6
6
  "keywords": [
@@ -37,7 +37,7 @@
37
37
  "dependencies": {
38
38
  "@clack/prompts": "^1.7.0",
39
39
  "zod": "^4.4.3",
40
- "@hoardodile/sdk-types": "0.1.1"
40
+ "@hoardodile/sdk-types": "0.1.3"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^26.2.0",