@hoardodile/create-plugin 0.1.4 → 0.1.6

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.
@@ -43,15 +43,15 @@ jobs:
43
43
  - name: Package the release artifacts
44
44
  run: pnpm exec hoardodile plugin package --skip-build
45
45
 
46
- - name: Gate the introduction (intro/ must be flat, images by bare filename)
47
- run: pnpm intro:check
46
+ - name: Gate the readme (readme/ must be flat, images by bare filename)
47
+ run: pnpm readme:check
48
48
 
49
49
  - name: Publish the GitHub release
50
50
  env:
51
51
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52
52
  run: |
53
53
  files=$(ls release/*)
54
- if [ -d intro ]; then
55
- files="$files intro/*"
54
+ if [ -d readme ]; then
55
+ files="$files readme/*"
56
56
  fi
57
57
  gh release create "$GITHUB_REF_NAME" $files --generate-notes
@@ -51,8 +51,8 @@ Pushing the tag by hand still works as a fallback:
51
51
  ## Marketplace publishing
52
52
 
53
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.
54
+ 2. Ship a `README.md` fallback plus `README.<locale>.md` files (see the
55
+ README) so each release carries a version-pinned readme the app can show.
56
56
 
57
57
  ## Issues and pull requests
58
58
 
@@ -50,7 +50,7 @@ server uses — the exact production execution path.
50
50
  - hoardodile **≥ 0.1.1** — the built-in plugin marketplace
51
51
  (**Settings → Marketplace**) and the batched asset-download API
52
52
  (`download([…])`) when the manifest declares `"download": true`.
53
- The marketplace's Intro and Release notes tabs and release intro
53
+ The marketplace's Readme and Release notes tabs and release readme
54
54
  assets are read by newer builds; older builds still list and install
55
55
  the plugin normally.
56
56
  - `"minAppVersion"` in `manifest.json` declares the lowest hoardodile
@@ -97,38 +97,42 @@ git tag v<version> && git push origin v<version>
97
97
  Local installs (zip upload in **Settings → Plugins**) still work for
98
98
  private packages.
99
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 inside the **`intro/` folder**, named
104
- `intro.<locale>.md` (e.g. `intro/intro.en.md`, `intro/intro.zh.md`) —
105
- `release.yml` uploads the whole folder alongside the zip, so **each release
106
- carries its own introduction** and every version shows independent notes.
107
- Use the app's supported language codes as file names (`en`, `zh`, `ja`,
108
- `de`, `es`) a region-coded name like `intro.zh-CN.md` only matches a UI
109
- language resolved to that exact code, so `intro.zh.md` is what Chinese
110
- users see.
100
+ ## Publishing a readme
101
+
102
+ The marketplace detail view shows a per-release **Readme** tab. Ship the
103
+ readme markdown in the **`readme/` folder** as a bare **`README.md`**
104
+ fallback, plus one `README.<locale>.md` file per extra language (e.g.
105
+ `readme/README.md`, `readme/README.zh.md`) — `release.yml` uploads the whole
106
+ folder alongside the zip, so **each release carries its own readme** and
107
+ every version shows independent notes.
108
+ `README.md` is the fallback the app shows for any language without a
109
+ specific file, so English normally lives there and you do **not** need a
110
+ `README.en.md`. Use the app's supported language codes for the extra files
111
+ (`zh`, `ja`, `de`, `es`) — a region-coded name like `README.zh-CN.md` only
112
+ matches a UI language resolved to that exact code, so `README.zh.md` is what
113
+ Chinese users see.
111
114
 
112
115
  ### Adding images
113
116
 
114
- An introduction may reference images. Place the image in `intro/` and
117
+ A readme may reference images. Place the image in `readme/` and
115
118
  reference it by its **bare filename**:
116
119
 
117
120
  ```md
118
121
  ![Plugin screenshot](screenshot.png)
119
122
  ```
120
123
 
121
- Every file in `intro/` is published as a release asset on each release, and
124
+ Every file in `readme/` is published as a release asset on each release, and
122
125
  the app resolves a relative image reference against that release's download
123
- URL. Because a GitHub release is a flat list of assets, the `intro/` folder
126
+ URL. Because a GitHub release is a flat list of assets, the `readme/` folder
124
127
  must stay **flat** and references must be bare filenames — a nested path
125
128
  like `![alt](img/shot.png)` resolves to a URL the release does not serve and
126
129
  the image breaks. Absolute `http(s)://` and `data:` image URIs are allowed.
127
130
 
128
- `pnpm intro:check` (run by `release.yml` before publishing) gates this: it
129
- fails the release if `intro/` is absent-and-required, is not flat, ships no
130
- `intro.<locale>.md`, or references an image by a nested/missing path.
131
+ `pnpm readme:check` (run by `release.yml` before publishing) gates this: it
132
+ fails the release if `readme/` is absent-and-required, is not flat, ships no
133
+ `README.md` / `README.<locale>.md`, or references an image by a
134
+ nested/missing path.
131
135
 
132
- The app resolves the intro for the user's UI language (exact locale → base
133
- language → `en` → the only shipped language); the release body always shows
136
+ The app resolves the readme for the user's UI language (exact locale → base
137
+ language → the `README.md` fallback); the release body always shows
134
138
  in the **Release notes** tab.
@@ -11,7 +11,7 @@
11
11
  "detect:smoke": "hoardodile plugin run detect testdata --plugin-dir dist",
12
12
  "lint": "tsc --noEmit",
13
13
  "test": "vitest run",
14
- "intro:check": "node scripts/check-intro.mjs",
14
+ "readme:check": "node scripts/check-readme.mjs",
15
15
  "release": "node scripts/release.mjs"
16
16
  },
17
17
  "release-it": {
@@ -1,9 +1,9 @@
1
1
  # My plugin
2
2
 
3
- _Replace this introduction with a real overview: what content the plugin
3
+ _Replace this readme with a real overview: what content the plugin
4
4
  detects, how it renders it, and where users see it._
5
5
 
6
- This introduction ships with **every GitHub release** — edit it per release so
6
+ This readme ships with **every GitHub release** — edit it per release so
7
7
  each version presents its own notes in the marketplace.
8
8
 
9
9
  ## Features
@@ -1,8 +1,8 @@
1
1
  # 我的插件
2
2
 
3
- _把这段介绍替换为真实内容:插件识别什么内容、如何渲染、用户在何处看到效果。_
3
+ _把这段说明替换为真实内容:插件识别什么内容、如何渲染、用户在何处看到效果。_
4
4
 
5
- 本介绍随**每个 GitHub Release** 一同发布——请随版本更新,让每个版本在插件市场中呈现各自的介绍。
5
+ 本说明随**每个 GitHub Release** 一同发布——请随版本更新,让每个版本在插件市场中呈现各自的说明。
6
6
 
7
7
  ## 功能
8
8
 
@@ -1,26 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Release gate for the plugin marketplace introduction images.
3
+ * Release gate for the plugin marketplace readme files.
4
4
  *
5
- * The marketplace reads each release's `intro.<locale>.md` asset and the
6
- * app resolves any image referenced inside it against the release's
7
- * download URL. Because a GitHub release is a flat list of assets, every
8
- * referenced image must be:
5
+ * The marketplace reads each release's `README.md` fallback asset and its
6
+ * `README.<locale>.md` assets, and the app resolves any image referenced
7
+ * inside them against the release's download URL. Because a GitHub release
8
+ * is a flat list of assets, every referenced image must be:
9
9
  *
10
- * 1. Shipped inside the `intro/` folder (the only folder the release
10
+ * 1. Shipped inside the `readme/` folder (the only folder the release
11
11
  * workflow uploads), and
12
12
  * 2. Referenced by its bare filename (`![alt](shot.png)`), never a
13
13
  * nested path (`img/shot.png`) — a nested path resolves to a URL the
14
14
  * release does not actually serve, so the image is silently broken.
15
15
  *
16
- * This gate fails a build/release when the `intro/` folder is absent, is
17
- * not flat, ships no `intro.<locale>.md`, or references an image by a
18
- * nested/missing path. External `http(s)://` and `data:` image URIs are
19
- * allowed (they are not release assets).
16
+ * This gate fails a build/release when the `readme/` folder is absent, is
17
+ * not flat, ships no `README.md` / `README.<locale>.md`, or references an
18
+ * image by a nested/missing path. External `http(s)://` and `data:` image
19
+ * URIs are allowed (they are not release assets).
20
20
  *
21
21
  * Usage:
22
- * node scripts/check-intro.mjs # checks ./intro
23
- * node scripts/check-intro.mjs <dir> # checks <dir>/intro
22
+ * node scripts/check-readme.mjs # checks ./readme
23
+ * node scripts/check-readme.mjs <dir> # checks <dir>/readme
24
24
  *
25
25
  * Dependency-free on purpose — it ships inside every scaffolded plugin.
26
26
  */
@@ -29,16 +29,18 @@ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"
29
29
  import { join, resolve } from "node:path"
30
30
 
31
31
  const ROOT = resolve(process.argv[2] ?? process.cwd())
32
- const INTRO_DIR = join(ROOT, "intro")
32
+ const README_DIR = join(ROOT, "readme")
33
33
 
34
34
  const RULE_SUMMARY =
35
- "intro/ must be flat; each intro.<locale>.md image is referenced by a " +
36
- "bare filename that exists in intro/ (absolute http(s)/data URIs are ok)"
35
+ "readme/ must be flat; each README image is referenced by a " +
36
+ "bare filename that exists in readme/ (absolute http(s)/data URIs are ok)"
37
37
 
38
38
  // `![alt](src)`, `![alt](src "title")`, `<img src="x">` (`src` images only).
39
39
  const MARKDOWN_IMG_RE = /!\[[^\]]*\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\)/g
40
40
  const HTML_IMG_RE = /<img\b[^>]*\bsrc\s*=\s*(["'])([^"']+)\1/gi
41
41
  const EXT_URL_RE = /^(?:https?:\/\/|data:)/i
42
+ /** `README.md` or `README.<locale>.md` — the marketplace readme assets. */
43
+ const README_FILE_RE = /^(?:README\.md|README\.[A-Za-z0-9-]+\.md)$/
42
44
 
43
45
  function isRelative(src) {
44
46
  return !EXT_URL_RE.test(src)
@@ -46,7 +48,7 @@ function isRelative(src) {
46
48
 
47
49
  /**
48
50
  * A relative reference is valid only as a flat bare filename that exists
49
- * inside `intro/` — not a nested path and not a missing/unshipsed file.
51
+ * inside `readme/` — not a nested path and not a missing/unshipsed file.
50
52
  */
51
53
  function resolveRelativeRef(src, file, issues) {
52
54
  const trimmed = src.trim().replace(/^\.\//, "")
@@ -64,10 +66,10 @@ function resolveRelativeRef(src, file, issues) {
64
66
  )
65
67
  return
66
68
  }
67
- const target = join(INTRO_DIR, trimmed)
69
+ const target = join(README_DIR, trimmed)
68
70
  if (!existsSync(target) || !statSync(target).isFile()) {
69
71
  issues.push(
70
- `${file}: image "${src}" is not in intro/ — every referenced image must be committed there (it is published with the release)`,
72
+ `${file}: image "${src}" is not in readme/ — every referenced image must be committed there (it is published with the release)`,
71
73
  )
72
74
  }
73
75
  }
@@ -80,55 +82,52 @@ function collectImageRefs(text) {
80
82
  }
81
83
 
82
84
  function main() {
83
- if (!existsSync(INTRO_DIR)) {
85
+ if (!existsSync(README_DIR)) {
84
86
  console.log(
85
- "[check-intro] no intro/ folder — nothing to gate (a release without an introduction is valid).",
87
+ "[check-readme] no readme/ folder — nothing to gate (a release without a readme is valid).",
86
88
  )
87
89
  return
88
90
  }
89
91
 
90
- const entries = readdirSync(INTRO_DIR, { withFileTypes: true })
92
+ const entries = readdirSync(README_DIR, { withFileTypes: true })
91
93
  const issues = []
92
94
 
93
95
  // 1. Flat-only: any subdirectory makes the folder publish incorrectly.
94
96
  for (const entry of entries) {
95
97
  if (entry.isDirectory()) {
96
98
  issues.push(
97
- `intro/${entry.name}/ is a subdirectory — the intro folder must be flat (release assets are a flat list)`,
99
+ `readme/${entry.name}/ is a subdirectory — the readme folder must be flat (release assets are a flat list)`,
98
100
  )
99
101
  }
100
102
  }
101
103
 
102
104
  const mdFiles = entries
103
- .filter(
104
- (entry) =>
105
- entry.isFile() && /^intro\.[A-Za-z0-9-]+\.md$/.test(entry.name),
106
- )
105
+ .filter((entry) => entry.isFile() && README_FILE_RE.test(entry.name))
107
106
  .map((entry) => entry.name)
108
107
 
109
108
  if (mdFiles.length === 0) {
110
109
  issues.push(
111
- "intro/ has no intro.<locale>.md — the release would ship images but the marketplace could not display an introduction",
110
+ "readme/ has no README.md / README.<locale>.md — the release would ship images but the marketplace could not display a readme",
112
111
  )
113
112
  }
114
113
 
115
- // 2. Flat, present image references inside each intro markdown.
114
+ // 2. Flat, present image references inside each readme markdown.
116
115
  for (const name of mdFiles) {
117
- const text = readFileSync(join(INTRO_DIR, name), "utf-8")
116
+ const text = readFileSync(join(README_DIR, name), "utf-8")
118
117
  for (const src of collectImageRefs(text)) {
119
- if (isRelative(src)) resolveRelativeRef(src, `intro/${name}`, issues)
118
+ if (isRelative(src)) resolveRelativeRef(src, `readme/${name}`, issues)
120
119
  }
121
120
  }
122
121
 
123
122
  if (issues.length > 0) {
124
- console.error("[check-intro] gate failed:")
123
+ console.error("[check-readme] gate failed:")
125
124
  for (const issue of issues) console.error(` - ${issue}`)
126
125
  console.error(`\n${RULE_SUMMARY}`)
127
126
  process.exit(1)
128
127
  }
129
128
 
130
129
  console.log(
131
- `[check-intro] intro/ ok — ${mdFiles.length} introduction file(s), flat references only.`,
130
+ `[check-readme] readme/ ok — ${mdFiles.length} readme file(s), flat references only.`,
132
131
  )
133
132
  }
134
133
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoardodile/create-plugin",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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.4"
40
+ "@hoardodile/sdk-types": "0.1.6"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^26.2.0",