meowpress 0.1.1-alpha.0 → 0.1.1-alpha.1

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/README.md CHANGED
@@ -1,19 +1,19 @@
1
1
  # Meowpress
2
2
 
3
- `meowpress` 提供静态站点的内容读取、页面渲染、主题和构建流程。
4
- 消费者持有站点配置与内容,通过本包构建;本包不持有应用的文章或输出目录。
3
+ `meowpress` provides content reading, page rendering, themes and the build pipeline for static sites.
4
+ Consumers own the site configuration and content and build through this package; the package does not own the application's posts or output directory.
5
5
 
6
- 当前准备 `0.1.1-alpha.0` 本地候选,尚未发布该版本。CSS 与 JSX 均为必需 peer,允许 `^0.1.0 || ^0.1.1-alpha.0`,保留稳定版兼容范围,并接受本轮 JSX/CSS alpha。宿主选定共享的 CSS/JSX 模块,本包不私装另一份 CSS;不依赖 Meowtail 或 MeowSlides。实际包外构建与主题身份验收绑定精确 tgz,不通过 override 绕过 peer 合同。发布仍需独立明确授权。
6
+ `0.1.1-alpha.0` has been published and accepted from the registry. The current `0.1.1-alpha.1` candidate updates the English site and CLI defaults and is not yet published. CSS and JSX are both required peers, allowing `^0.1.0 || ^0.1.1-alpha.0`, keeping the stable compatibility range and accepting this round's JSX/CSS alphas. The host selects the shared CSS/JSX modules, and this package does not privately install another CSS copy; it does not depend on Meowtail or MeowSlides. Actual out-of-package builds and theme identity acceptance are bound to exact tgz files, and peer contracts are not bypassed through overrides. Publishing still requires separate explicit authorization.
7
7
 
8
- 本包是独立内容发布库,源码位于 `packages/meowpress`,已有公开构建入口、独立测试与类型检查,
9
- 不依赖 Assistant、WorkCell、Deno 或特定 Blog 的内容与运行状态。样式生成来自 `meowcss`,
10
- HTML 渲染来自 `meowjsx/web`,无需安装 MeowUI。
8
+ This package is a standalone content publishing library with source in `packages/meowpress`; it already has a public build entry, independent tests and typechecking,
9
+ and does not depend on Assistant, WorkCell, Deno or the content and runtime state of a specific Blog. Style generation comes from `meowcss`,
10
+ and HTML rendering comes from `meowjsx/web`; MeowUI does not need to be installed.
11
11
 
12
- ## 入口
12
+ ## Entries
13
13
 
14
- - `meowpress/build`:`meowSite()` 定义配置,`buildSite()` 执行构建;这是唯一对外 export。
15
- 内容读取、页面渲染、技能索引与主题是包内模块。
16
- - `meowpress --config ./site.config.ts`:Bun CLI,加载消费者提供的配置并构建。
14
+ - `meowpress/build`: `meowSite()` defines configuration and `buildSite()` performs the build; this is the only public export.
15
+ Content reading, page rendering, skill indexing and themes are internal package modules.
16
+ - `meowpress --config ./site.config.ts`: Bun CLI that loads the consumer-provided configuration and builds.
17
17
 
18
18
  ```ts
19
19
  import { meowSite } from "meowpress/build";
@@ -25,31 +25,31 @@ export default meowSite({
25
25
  });
26
26
  ```
27
27
 
28
- 配置中的目录由应用明确提供;默认主题从本包解析,不依赖启动目录。
29
- 可通过 `theme: defineTheme(...)` 替换整套主题;所有静态页面输出该主题的根属性和默认选项。
30
- 构建将 `theme.cssText` 写入临时 CSS,再由 Bun 处理字体与其他资源,最终通过 stylesheet 链接交付,
31
- 无需客户端 JavaScript 即可应用主题。默认字体 Geist 的文件随站点打包,不依赖外部字体服务。
32
- 使用默认字体时,输出同时包含 `licenses/geist-OFL.txt`,保留字体的 SIL OFL 许可。
33
- 默认插画使用包内矢量与 CSS,不要求业务图片。可用 `site.images` 的 `hero`、`feed`、`about`
34
- 显式设置装饰图路径,例如 `images/cover.svg`;路径相对内容根的 `assets/`,库负责各页面深度,
35
- 资源沿现有资产构建流程交付。未设置 About 图片时使用站点名首字母。
36
- 内容源包含 `posts/`、`thoughts/` 和可选资源;以下划线开头的草稿不进入发布输出。
37
- 站点有自己的主题,不隐式安装 MeowUI 的应用主题。
28
+ Directories in the configuration are provided explicitly by the application; the default theme resolves from this package and does not depend on the startup directory.
29
+ The whole theme can be replaced with `theme: defineTheme(...)`; all static pages output that theme's root attributes and default options.
30
+ The build writes `theme.cssText` to a temporary CSS file, then lets Bun handle fonts and other assets, and finally delivers through a stylesheet link,
31
+ so the theme applies without client-side JavaScript. Files for the default Geist font are bundled with the site and do not depend on an external font service.
32
+ When the default font is used, the output also includes `licenses/geist-OFL.txt`, preserving the font's SIL OFL license.
33
+ Default illustrations use in-package vectors and CSS and require no business images. The `hero`, `feed` and `about` keys of `site.images`
34
+ can explicitly set decorative image paths, for example `images/cover.svg`; paths are relative to the content root's `assets/`, the library handles each page depth,
35
+ and assets are delivered along the existing asset build flow. When no About image is set, the first letter of the site name is used.
36
+ The content source contains `posts/`, `thoughts/` and optional assets; drafts whose names start with an underscore do not enter the published output.
37
+ The site has its own theme and does not implicitly install MeowUI's application theme.
38
38
 
39
- ## 验证与构建
39
+ ## Verification and build
40
40
 
41
- 安装 `meowpress` 及其 `meowcss`、`meowjsx` 依赖后,在消费者目录运行:
41
+ After installing `meowpress` and its `meowcss` and `meowjsx` dependencies, run in the consumer directory:
42
42
 
43
43
  ```sh
44
44
  bunx --no-install meowpress --config ./site.config.ts
45
45
  ```
46
46
 
47
- CLI 需要 Bun,输出位置由 `outputDirectory` 决定。字体文件从本包的正式 Geist 依赖解析,
48
- 不要求消费者复制源码、安装工作区根依赖或访问外部字体服务。
47
+ The CLI requires Bun, and the output location is determined by `outputDirectory`. Font files resolve from this package's official Geist dependency,
48
+ and consumers are not required to copy source, install workspace-root dependencies or access an external font service.
49
49
 
50
- ## 独立验证
50
+ ## Independent verification
51
51
 
52
- 仓库依赖就绪后运行 `bun run --cwd packages/meowpress test` 和
53
- `bun run --cwd packages/meowpress typecheck`。测试位于 `tests/unit/`;真实构建测试通过公开
54
- `meowpress/build` 入口创建临时内容、主题和图片,
55
- 覆盖 Markdown、MDX、Thought 输出及草稿页面/资产排除,不读取 Blog 内容或调用 Blog 构建。
52
+ Once repository dependencies are ready, run `bun run --cwd packages/meowpress test` and
53
+ `bun run --cwd packages/meowpress typecheck`. Tests live in `tests/unit/`; real build tests create temporary content, themes and images through the public
54
+ `meowpress/build` entry,
55
+ covering Markdown, MDX, Thought output and draft page/asset exclusion, without reading Blog content or invoking the Blog build.
@@ -1,6 +1,6 @@
1
1
  export const DEFAULT_SITE = {
2
2
  name: "Meowpress site",
3
3
  id: "meowpress",
4
- description: "长文与碎片想法的混排时间线。",
4
+ description: "A mixed timeline of long-form posts and fragmentary thoughts.",
5
5
  contentDirectory: "content",
6
6
  };
package/dist/src/site.js CHANGED
@@ -8,9 +8,9 @@ import { layoutSkillGraph } from "./skill-graph.js";
8
8
  function SiteHeader({ activePath, site }) {
9
9
  return (h("header", { className: "site" },
10
10
  h("a", { className: "site-name", href: "/" }, site.name),
11
- h("nav", { className: "site-nav", "aria-label": "\u4E3B\u5BFC\u822A" },
11
+ h("nav", { className: "site-nav", "aria-label": "Primary navigation" },
12
12
  h("a", { className: activePath === "/skills/" ? "active" : "", href: "/skills/" }, "Skills"),
13
- h("a", { className: activePath === "/about/" ? "active" : "", href: "/about/" }, "\u5173\u4E8E"))));
13
+ h("a", { className: activePath === "/about/" ? "active" : "", href: "/about/" }, "About"))));
14
14
  }
15
15
  function SiteFooter({ site }) {
16
16
  return (h("footer", { className: "site" },
@@ -26,7 +26,7 @@ function SiteFooter({ site }) {
26
26
  }
27
27
  function Document({ title, description, activePath, styleHref, children, theme, site, }) {
28
28
  const documentTitle = title === site.name ? site.name : `${title} · ${site.name}`;
29
- return (h("html", { lang: "zh-CN", ...themeAttributes(theme) },
29
+ return (h("html", { lang: "en", ...themeAttributes(theme) },
30
30
  h("head", null,
31
31
  h("meta", { charSet: "UTF-8" }),
32
32
  h("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
@@ -46,15 +46,15 @@ function pageHtml(props) {
46
46
  }
47
47
  function dateLabel(dateKey) {
48
48
  if (dateKey === "undated")
49
- return { date: "未标日期", weekday: "" };
49
+ return { date: "Undated", weekday: "" };
50
50
  const date = new Date(`${dateKey}T00:00:00+08:00`);
51
51
  return {
52
- date: new Intl.DateTimeFormat("zh-CN", {
52
+ date: new Intl.DateTimeFormat("en-US", {
53
53
  timeZone: "Asia/Shanghai",
54
54
  month: "long",
55
55
  day: "numeric",
56
56
  }).format(date),
57
- weekday: new Intl.DateTimeFormat("zh-CN", {
57
+ weekday: new Intl.DateTimeFormat("en-US", {
58
58
  timeZone: "Asia/Shanghai",
59
59
  weekday: "short",
60
60
  year: "numeric",
@@ -68,9 +68,9 @@ function Hero({ image }) {
68
68
  return (h("section", { className: "hero", "aria-labelledby": "hero-title" },
69
69
  h("div", { className: "hero-copy" },
70
70
  h("h1", { id: "hero-title" },
71
- "\u4E00\u4E07\u5E74\u592A\u4E45\uFF0C",
71
+ "Ten thousand years is too long;",
72
72
  h("br", null),
73
- h("em", null, "\u53EA\u771F\u671D\u5915\u3002"))),
73
+ h("em", null, "only this day is true."))),
74
74
  h("div", { className: "hero-work", "aria-hidden": "true" },
75
75
  h("svg", { className: "hero-doodle", viewBox: "0 0 260 190" },
76
76
  h("path", { className: "doodle-loop", d: "M24 96C20 45 58 18 122 20c72 2 116 33 114 84-2 48-48 70-113 68-65-2-96-27-99-76Z" }),
@@ -104,7 +104,7 @@ function ThoughtCard({ item, linked = false }) {
104
104
  const body = (h(Fragment, null,
105
105
  h("div", { className: "time" },
106
106
  h("span", { className: "t" }, item.timeLabel || item.dateKey),
107
- " \u00B7 \u60F3\u6CD5"),
107
+ " \u00B7 Thought"),
108
108
  h("div", { className: "body", dangerouslySetInnerHTML: { __html: withoutLeadingHeading(item.html) } }),
109
109
  h(Tags, { item: item })));
110
110
  if (!linked)
@@ -113,18 +113,18 @@ function ThoughtCard({ item, linked = false }) {
113
113
  h("a", { className: "thought-link", href: itemUrl(item) }, body)));
114
114
  }
115
115
  function PostCard({ item }) {
116
- const category = typeof item.metadata.category === "string" ? item.metadata.category : "文章";
116
+ const category = typeof item.metadata.category === "string" ? item.metadata.category : "Post";
117
117
  return (h("a", { className: "post-card", href: itemUrl(item), "data-kind": "post" },
118
118
  h("div", { className: "card-top" },
119
119
  h("span", { className: "kind" }, category),
120
120
  h("span", { className: "meta" },
121
- "\u7EA6 ",
121
+ "About ",
122
122
  item.readingMinutes,
123
- " \u5206\u949F \u00B7 ",
123
+ " min \u00B7 ",
124
124
  item.characterCount,
125
- " \u5B57")),
125
+ " characters")),
126
126
  h("h3", null, item.title),
127
- h("p", { className: "excerpt" }, item.excerpt || "这篇文章还没有摘要。"),
127
+ h("p", { className: "excerpt" }, item.excerpt || "This post has no summary yet."),
128
128
  h(Tags, { item: item })));
129
129
  }
130
130
  function groupByDate(items) {
@@ -168,7 +168,7 @@ function FeedDecor({ image }) {
168
168
  function Feed({ items, image }) {
169
169
  if (items.length === 0) {
170
170
  return (h("main", { className: "feed feed-empty" },
171
- h("p", { className: "empty-state" }, "\u8FD8\u6CA1\u6709\u516C\u5F00\u5185\u5BB9\u3002"),
171
+ h("p", { className: "empty-state" }, "No public content yet."),
172
172
  h(FeedDecor, { image: image })));
173
173
  }
174
174
  return (h("main", { className: "feed" },
@@ -185,15 +185,15 @@ function Feed({ items, image }) {
185
185
  }
186
186
  function Filter({ posts, thoughts }) {
187
187
  const total = posts + thoughts;
188
- return (h("div", { className: "tag-filter", "data-filter-group": "feed", role: "group", "aria-label": "\u7B5B\u9009\u9996\u9875\u5185\u5BB9" },
188
+ return (h("div", { className: "tag-filter", "data-filter-group": "feed", role: "group", "aria-label": "Filter home feed" },
189
189
  h("button", { type: "button", "data-filter": "all", className: "active", "aria-pressed": "true" },
190
- "\u5168\u90E8",
190
+ "All",
191
191
  h("i", null, total)),
192
192
  h("button", { type: "button", "data-filter": "post", "aria-pressed": "false" },
193
- "\u6587\u7AE0",
193
+ "Posts",
194
194
  h("i", null, posts)),
195
195
  h("button", { type: "button", "data-filter": "thought", "aria-pressed": "false" },
196
- "\u60F3\u6CD5",
196
+ "Thoughts",
197
197
  h("i", null, thoughts))));
198
198
  }
199
199
  const FILTER_SCRIPT = `(() => {
@@ -258,41 +258,43 @@ export function listPage(kind, items, theme = blogTheme, site = DEFAULT_SITE) {
258
258
  return pageHtml({
259
259
  site,
260
260
  theme,
261
- title: isPost ? "文章" : "想法",
261
+ title: isPost ? "Posts" : "Thoughts",
262
262
  activePath: isPost ? "/posts/" : "/thoughts/",
263
263
  styleHref: "../blog-theme.css",
264
264
  children: (h("main", { className: "listing" },
265
265
  h("header", { className: "listing-head" },
266
266
  h("span", { className: "kind" }, isPost ? "Posts" : "Thoughts"),
267
- h("h1", null, isPost ? "文章" : "想法"),
268
- h("p", null, isPost ? "从碎片里长出来的完整论述。" : "经过剪裁、可以直接展示的短想法。")),
269
- h("div", { className: isPost ? "post-list" : "thought-list" }, items.length === 0 ? (h("p", { className: "empty-state" }, "\u8FD8\u6CA1\u6709\u516C\u5F00\u5185\u5BB9\u3002")) : (items.map((item) => isPost ? h(PostCard, { item: item }) : h(ThoughtCard, { item: item, linked: true })))))),
267
+ h("h1", null, isPost ? "Posts" : "Thoughts"),
268
+ h("p", null, isPost
269
+ ? "Complete arguments grown from fragments."
270
+ : "Short, trimmed thoughts ready to show as they are.")),
271
+ h("div", { className: isPost ? "post-list" : "thought-list" }, items.length === 0 ? (h("p", { className: "empty-state" }, "No public content yet.")) : (items.map((item) => isPost ? h(PostCard, { item: item }) : h(ThoughtCard, { item: item, linked: true })))))),
270
272
  });
271
273
  }
272
274
  function PostNavigation({ item, posts }) {
273
275
  const index = posts.findIndex((post) => post.slug === item.slug);
274
276
  const older = index >= 0 ? posts[index + 1] : undefined;
275
277
  const newer = index > 0 ? posts[index - 1] : undefined;
276
- return (h("nav", { className: "post-nav", "aria-label": "\u6587\u7AE0\u5BFC\u822A" },
278
+ return (h("nav", { className: "post-nav", "aria-label": "Post navigation" },
277
279
  older ? (h("a", { href: itemUrl(older) },
278
- h("span", { className: "label" }, "\u2190 \u4E0A\u4E00\u7BC7\uFF08\u66F4\u65E9\uFF09"),
280
+ h("span", { className: "label" }, "\u2190 Previous post (older)"),
279
281
  older.title)) : (h("span", null)),
280
282
  newer ? (h("a", { className: "next", href: itemUrl(newer) },
281
- h("span", { className: "label" }, "\u4E0B\u4E00\u7BC7\uFF08\u66F4\u65B0\uFF09\u2192"),
283
+ h("span", { className: "label" }, "Next post (newer) \u2192"),
282
284
  newer.title)) : (h("span", { className: "next" },
283
- h("span", { className: "label" }, "\u4E0B\u4E00\u7BC7\uFF08\u66F4\u65B0\uFF09\u2192"),
284
- "\u6CA1\u6709\u4E86\uFF0C\u8FD9\u662F\u6700\u65B0\u7684\u4E00\u7BC7"))));
285
+ h("span", { className: "label" }, "Next post (newer) \u2192"),
286
+ "Nothing newer \u2014 this is the latest post."))));
285
287
  }
286
288
  function RelatedThoughts({ item, thoughts, }) {
287
289
  const related = thoughts.filter((thought) => thought.dateKey === item.dateKey).slice(0, 3);
288
290
  if (related.length === 0)
289
291
  return null;
290
292
  return (h("aside", { className: "related-thoughts" },
291
- h("h2", null, "\u540C\u4E00\u5929\u7684\u60F3\u6CD5"),
293
+ h("h2", null, "Thoughts from the same day"),
292
294
  related.map((thought) => (h(ThoughtCard, { item: thought, linked: true })))));
293
295
  }
294
296
  export function postPage(item, posts, thoughts, theme = blogTheme, site = DEFAULT_SITE) {
295
- const category = typeof item.metadata.category === "string" ? item.metadata.category : "文章";
297
+ const category = typeof item.metadata.category === "string" ? item.metadata.category : "Post";
296
298
  return pageHtml({
297
299
  site,
298
300
  theme,
@@ -307,11 +309,11 @@ export function postPage(item, posts, thoughts, theme = blogTheme, site = DEFAUL
307
309
  h("h1", null, item.title),
308
310
  h("div", { className: "meta" },
309
311
  item.dateKey,
310
- " \u00B7 \u7EA6 ",
312
+ " \u00B7 about ",
311
313
  item.readingMinutes,
312
- " \u5206\u949F \u00B7 ",
314
+ " min \u00B7 ",
313
315
  item.characterCount,
314
- " \u5B57")),
316
+ " characters")),
315
317
  h("div", { className: "prose", dangerouslySetInnerHTML: { __html: item.html } }),
316
318
  h(RelatedThoughts, { item: item, thoughts: thoughts }),
317
319
  h(PostNavigation, { item: item, posts: posts })))),
@@ -328,7 +330,7 @@ export function thoughtPage(item, theme = blogTheme, site = DEFAULT_SITE) {
328
330
  children: (h("main", null,
329
331
  h("article", null,
330
332
  h("header", { className: "post-head" },
331
- h("span", { className: "kind" }, "\u60F3\u6CD5"),
333
+ h("span", { className: "kind" }, "Thought"),
332
334
  h("h1", null, item.title),
333
335
  h("div", { className: "meta" },
334
336
  item.dateKey,
@@ -341,7 +343,7 @@ export function aboutPage(theme = blogTheme, site = DEFAULT_SITE) {
341
343
  return pageHtml({
342
344
  site,
343
345
  theme,
344
- title: "关于",
346
+ title: "About",
345
347
  activePath: "/about/",
346
348
  styleHref: "../blog-theme.css",
347
349
  children: (h("main", { className: "about" },
@@ -350,7 +352,7 @@ export function aboutPage(theme = blogTheme, site = DEFAULT_SITE) {
350
352
  h("h1", null, about.heading),
351
353
  about.paragraphs.map((paragraph) => (h("p", null, paragraph))),
352
354
  about.links && about.links.length > 0 ? (h(Fragment, null,
353
- h("h2", null, about.linksHeading ?? "找到我"),
355
+ h("h2", null, about.linksHeading ?? "Find me"),
354
356
  about.links.map((link) => (h("a", { className: "github-link", href: link.href, target: "_blank", rel: "me noopener noreferrer" },
355
357
  h(DoodleGithubIcon, null),
356
358
  h("span", { className: "github-copy" },
@@ -371,17 +373,17 @@ function SkillCard({ skill, site }) {
371
373
  return (h("a", { className: `skill-card${skill.scope === "project" ? " project-skill" : ""}`, href: skillUrl(skill) },
372
374
  h("span", { className: "skill-card-source" },
373
375
  h("span", { className: "skill-card-path" }, skill.scope === "public" ? skillInstallCommand(site, skill) : skill.sourceBasePath),
374
- skill.scope === "project" ? h("span", { className: "skill-scope-badge" }, "\u9879\u76EE Skill") : null),
376
+ skill.scope === "project" ? (h("span", { className: "skill-scope-badge" }, "Project Skill")) : null),
375
377
  h("span", { className: "skill-card-main" },
376
378
  h("strong", null, skill.name),
377
379
  h("span", null, skill.description)),
378
380
  h("span", { className: "skill-card-foot" },
379
381
  h("span", null,
380
382
  skill.files.length,
381
- " \u4E2A Markdown \u00B7 ",
383
+ " Markdown files \u00B7 ",
382
384
  skill.relations.length,
383
- " \u6761\u5F15\u7528"),
384
- h("span", { className: "skill-open" }, "\u6253\u5F00\u76EE\u5F55\u00A0 \u2192"))));
385
+ " references"),
386
+ h("span", { className: "skill-open" }, "Open directory\u00A0 \u2192"))));
385
387
  }
386
388
  function skillTree(files) {
387
389
  const root = { name: "", children: [] };
@@ -410,14 +412,14 @@ function SkillTreeNodes({ nodes, activePath, }) {
410
412
  h("button", { type: "button", className: node.path === activePath ? "active" : "", "data-skill-file": node.path, "aria-pressed": node.path === activePath ? "true" : "false" }, node.name))))));
411
413
  }
412
414
  function SkillFileTree({ skill, activePath }) {
413
- return (h("nav", { className: "skill-files", "aria-label": `${skill.name} 文件目录` },
415
+ return (h("nav", { className: "skill-files", "aria-label": `${skill.name} file tree` },
414
416
  h("span", { className: "skill-files-label" }, "Files"),
415
417
  h(SkillTreeNodes, { nodes: skillTree(skill.files), activePath: activePath })));
416
418
  }
417
419
  function SkillGraphNodeView({ node }) {
418
420
  const width = node.width;
419
421
  const height = node.height;
420
- return (h("a", { className: `skill-graph-node${node.external ? " external" : ""}${node.kind ? ` ${node.kind}` : ""}`, href: node.external ? "#relations" : `#${encodeURIComponent(node.path)}`, "data-map-path": node.path, "data-map-file": node.external ? undefined : node.path, "data-map-detail": node.detail, "aria-label": `${node.name},${node.role}` },
422
+ return (h("a", { className: `skill-graph-node${node.external ? " external" : ""}${node.kind ? ` ${node.kind}` : ""}`, href: node.external ? "#relations" : `#${encodeURIComponent(node.path)}`, "data-map-path": node.path, "data-map-file": node.external ? undefined : node.path, "data-map-detail": node.detail, "aria-label": `${node.name}; ${node.role}` },
421
423
  h("rect", { x: node.x - width / 2, y: node.y - height / 2, width: width, height: height, rx: "9" }),
422
424
  h("text", { className: "skill-graph-node-name", x: node.x, y: node.y - 4 }, node.name),
423
425
  h("text", { className: "skill-graph-node-role", x: node.x, y: node.y + 17 }, node.role)));
@@ -425,7 +427,7 @@ function SkillGraphNodeView({ node }) {
425
427
  function SkillRelationGraph({ skill, direction }) {
426
428
  const graph = layoutSkillGraph(skill, direction);
427
429
  const markerId = `skill-arrow-${skill.slug}-${direction.toLowerCase()}`;
428
- return (h("svg", { className: `skill-graph-svg skill-graph-${direction.toLowerCase()}`, viewBox: `0 0 ${graph.width} ${graph.height}`, "aria-label": `${skill.name} 文件引用关系` },
430
+ return (h("svg", { className: `skill-graph-svg skill-graph-${direction.toLowerCase()}`, viewBox: `0 0 ${graph.width} ${graph.height}`, "aria-label": `${skill.name} file reference graph` },
429
431
  h("defs", null,
430
432
  h("marker", { id: markerId, viewBox: "0 0 10 10", refX: "8", refY: "5", markerWidth: "5", markerHeight: "5", orient: "auto-start-reverse" },
431
433
  h("path", { className: "skill-graph-arrow", d: "M 0 0 L 10 5 L 0 10 z" }))),
@@ -448,28 +450,28 @@ function SkillRelations({ skill }) {
448
450
  const hasRelations = skill.relations.length > 0;
449
451
  const compactGraph = skill.files.length + skill.externalNodes.length <= 3;
450
452
  return (h("section", { className: "skill-relations", "data-skill-view-panel": "relations", hidden: true },
451
- h("div", { className: "skill-reading-summary", "aria-label": "\u9605\u8BFB\u7ED3\u6784\u6458\u8981" },
453
+ h("div", { className: "skill-reading-summary", "aria-label": "Reading structure summary" },
452
454
  h("span", null,
453
455
  h("strong", null,
454
456
  reachableFiles,
455
457
  "/",
456
458
  skill.files.length),
457
- "\u53EF\u8FBE\u6587\u6863"),
459
+ "reachable docs"),
458
460
  h("span", null,
459
461
  h("strong", null, skill.relations.length),
460
- "\u5F15\u7528\u5173\u7CFB"),
462
+ " references"),
461
463
  h("span", null,
462
464
  h("strong", null, maxDepth),
463
- "\u6700\u6DF1\u5C42\u7EA7"),
465
+ " max depth"),
464
466
  h("span", { className: missingNodes.length > 0 ? "has-issue" : "" },
465
467
  h("strong", null, missingNodes.length),
466
- "\u7F3A\u5931\u76EE\u6807")),
468
+ " missing targets")),
467
469
  hasRelations ? (h(Fragment, null,
468
470
  h("div", { className: `skill-graph-canvas${compactGraph ? " compact" : ""}` },
469
471
  h(SkillRelationGraph, { skill: skill, direction: "LR" }),
470
472
  h(SkillRelationGraph, { skill: skill, direction: "TB" })),
471
473
  h("section", { className: "skill-reading-paths", "aria-labelledby": `${skill.slug}-paths` },
472
- h("h3", { id: `${skill.slug}-paths` }, "\u5F15\u7528\u53D1\u751F\u5728\u54EA\u91CC"),
474
+ h("h3", { id: `${skill.slug}-paths` }, "Where references happen"),
473
475
  h("ol", null, skill.relations.map((relation) => {
474
476
  const sourceFile = skill.files.find((file) => file.path === relation.source);
475
477
  return (h("li", { className: sourceFile?.reachable ? "" : "unreachable" },
@@ -479,27 +481,29 @@ function SkillRelations({ skill }) {
479
481
  h("code", { title: relation.target }, relation.target)),
480
482
  h("span", { className: "skill-reading-context" }, relation.contexts.map((context) => (h("span", null,
481
483
  context.section,
482
- context.line ? ` · 第 ${context.line} 行` : "",
483
- context.linkText !== relation.label ? ` · “${context.linkText}”` : "",
484
- !sourceFile?.reachable ? " · 入口不可达" : ""))))));
484
+ context.line ? ` · line ${context.line}` : "",
485
+ context.linkText !== relation.label ? ` · "${context.linkText}"` : "",
486
+ !sourceFile?.reachable ? " · entry unreachable" : ""))))));
485
487
  }))))) : (h("div", { className: "skill-reading-empty" },
486
- h("strong", null, "\u6CA1\u6709\u8DE8\u6587\u4EF6\u9605\u8BFB\u8DEF\u5F84"),
488
+ h("strong", null, "No cross-file reading paths"),
487
489
  h("p", null,
488
- "Agent \u8FDB\u5165\u540E\u53EA\u4F1A\u8BFB\u53D6 ",
490
+ "Once the Agent enters, it only reads ",
489
491
  h("code", null, "SKILL.md"),
490
- "\u3002\u5982\u679C\u8FD8\u6709\u5FC5\u987B\u9605\u8BFB\u7684\u53C2\u8003\u6750\u6599\uFF0C\u9700\u8981\u4ECE\u76F8\u5173\u7AE0\u8282\u7528 Markdown \u94FE\u63A5\u660E\u786E\u5F15\u51FA\u3002"))),
491
- unreferencedFiles.length > 0 || missingNodes.length > 0 ? (h("aside", { className: "skill-reading-issues", "aria-label": "\u4FE1\u606F\u7ED3\u6784\u95EE\u9898" },
492
- h("strong", null, "\u9700\u8981\u7559\u610F"),
492
+ ". If other reference material must be read, link it explicitly from the relevant sections with Markdown links."))),
493
+ unreferencedFiles.length > 0 || missingNodes.length > 0 ? (h("aside", { className: "skill-reading-issues", "aria-label": "Information structure issues" },
494
+ h("strong", null, "Needs attention"),
493
495
  unreferencedFiles.length > 0 ? (h("p", null,
494
- "\u5165\u53E3\u65E0\u6CD5\u5230\u8FBE\uFF1A",
496
+ "Unreachable from the entry:",
495
497
  unreferencedFiles.map((file) => (h("code", null, file.path))))) : null,
496
498
  missingNodes.length > 0 ? (h("p", null,
497
- "\u94FE\u63A5\u76EE\u6807\u4E0D\u5B58\u5728\uFF1A",
499
+ "Missing link targets:",
498
500
  missingNodes.map((node) => (h("code", null, node.path))))) : null)) : null,
499
501
  hasRelations ? (h("div", { className: "skill-graph-status", "data-map-status": true, "aria-live": "polite" },
500
- "\u70B9\u51FB\u56FE\u4E2D\u7684\u8282\u70B9\u67E5\u770B\u5B83\u5728\u9605\u8BFB\u94FE\u8DEF\u4E2D\u7684\u4F5C\u7528",
501
- externalNodes.length > 0 ? `;当前有 ${externalNodes.length} 个 Skill 外部目标` : "",
502
- "\u3002")) : null));
502
+ "Select a node in the graph to see its role in the reading chain",
503
+ externalNodes.length > 0
504
+ ? `; ${externalNodes.length} targets outside the Skill currently`
505
+ : "",
506
+ ".")) : null));
503
507
  }
504
508
  const SKILL_BROWSER_SCRIPT = `(() => {
505
509
  document.querySelectorAll('[data-skill-browser]').forEach((browser) => {
@@ -585,8 +589,8 @@ const SKILL_BROWSER_SCRIPT = `(() => {
585
589
  const command = copyButton.dataset.copyCommand;
586
590
  if (!command) return;
587
591
  await navigator.clipboard.writeText(command);
588
- copyButton.textContent = '已复制';
589
- window.setTimeout(() => { copyButton.textContent = '复制'; }, 1400);
592
+ copyButton.textContent = 'Copied';
593
+ window.setTimeout(() => { copyButton.textContent = 'Copy'; }, 1400);
590
594
  });
591
595
  });
592
596
  })();`;
@@ -597,27 +601,27 @@ export function skillsIndexPage(skills, theme = blogTheme, site = DEFAULT_SITE)
597
601
  site,
598
602
  theme,
599
603
  title: "Skills",
600
- description: "可以交给 Agent 使用的方法与工作约定。",
604
+ description: "Methods and working conventions that can be handed to an Agent.",
601
605
  activePath: "/skills/",
602
606
  styleHref: "../blog-theme.css",
603
607
  children: (h("main", { className: "skills-index" },
604
608
  h("header", { className: "skills-head" },
605
609
  h("span", { className: "skill-path" }, "~/skills"),
606
610
  h("h1", null, "Skills"),
607
- h("p", null, "\u516C\u5F00\u5206\u4EAB\u3001\u53EF\u4EE5\u76F4\u63A5\u4EA4\u7ED9 Agent \u4F7F\u7528\u7684\u65B9\u6CD5\u3002")),
611
+ h("p", null, "Methods shared publicly and usable directly by an Agent.")),
608
612
  h("section", { className: "skill-group", "aria-labelledby": "public-skills-heading" },
609
613
  h("header", { className: "skill-group-head" },
610
- h("h2", { id: "public-skills-heading" }, "\u516C\u5F00 Skills"),
611
- h("span", null, "\u516C\u5F00\u5185\u5BB9")),
612
- publicSkills.length > 0 ? (h("div", { className: "skill-list" }, publicSkills.map((skill) => (h(SkillCard, { skill: skill, site: site }))))) : (h("p", { className: "skill-group-empty" }, "\u516C\u5F00 Skills \u76EE\u524D\u8FD8\u6CA1\u6709\u5185\u5BB9\u3002"))),
614
+ h("h2", { id: "public-skills-heading" }, "Public Skills"),
615
+ h("span", null, "Public content")),
616
+ publicSkills.length > 0 ? (h("div", { className: "skill-list" }, publicSkills.map((skill) => (h(SkillCard, { skill: skill, site: site }))))) : (h("p", { className: "skill-group-empty" }, "Public Skills have no content yet."))),
613
617
  projectSkills.length > 0 ? (h("section", { className: "skill-group project-skills", "aria-labelledby": "project-skills-heading" },
614
618
  h("header", { className: "skill-group-head" },
615
619
  h("div", null,
616
- h("h2", { id: "project-skills-heading" }, "\u9879\u76EE Skills"),
617
- h("small", null, "\u672C\u9879\u76EE\u5185\u90E8\u4F7F\u7528\u7684\u5F00\u53D1\u4E0E\u5185\u5BB9\u5DE5\u4F5C\u6D41")),
620
+ h("h2", { id: "project-skills-heading" }, "Project Skills"),
621
+ h("small", null, "Development and content workflows used inside this project")),
618
622
  h("span", null, ".agents/skills/")),
619
623
  h("div", { className: "skill-list" }, projectSkills.map((skill) => (h(SkillCard, { skill: skill, site: site })))))) : null,
620
- h("p", { className: "skills-prototype-note" }, "\u5F15\u7528\u5173\u7CFB\u56FE\u4ECE SKILL.md \u51FA\u53D1\uFF0C\u6839\u636E Markdown \u94FE\u63A5\u5728\u6784\u5EFA\u65F6\u81EA\u52A8\u751F\u6210\u3002"))),
624
+ h("p", { className: "skills-prototype-note" }, "The reference graph starts from SKILL.md and is generated at build time from Markdown links."))),
621
625
  });
622
626
  }
623
627
  export function skillPage(skill, theme = blogTheme, site = DEFAULT_SITE) {
@@ -631,18 +635,18 @@ export function skillPage(skill, theme = blogTheme, site = DEFAULT_SITE) {
631
635
  activePath: "/skills/",
632
636
  styleHref: skill.scope === "public" ? "../../blog-theme.css" : "../../../blog-theme.css",
633
637
  children: (h("main", { className: "skill-page" },
634
- h("a", { className: "skill-back", href: "/skills/" }, "\u2190 \u6240\u6709 Skills"),
638
+ h("a", { className: "skill-back", href: "/skills/" }, "\u2190 All Skills"),
635
639
  h("header", { className: "skill-browser-head" },
636
640
  h("span", { className: "skill-command" },
637
- skill.scope === "project" ? (h("span", { className: "skill-scope-badge" }, "\u9879\u76EE Skill \u00B7 \u5185\u90E8")) : null,
641
+ skill.scope === "project" ? (h("span", { className: "skill-scope-badge" }, "Project Skill \u00B7 Internal")) : null,
638
642
  h("code", null, command)),
639
643
  h("span", { className: "skill-browser-actions" },
640
- h("button", { type: "button", "data-copy-command": command }, skill.scope === "public" ? "复制" : "复制路径"),
644
+ h("button", { type: "button", "data-copy-command": command }, skill.scope === "public" ? "Copy" : "Copy path"),
641
645
  site.repositorySourceUrl ? (h("a", { href: `${site.repositorySourceUrl}/${skill.sourceBasePath}`, target: "_blank", rel: "noopener noreferrer" }, "GitHub \u2197")) : null)),
642
646
  h("div", { className: "skill-stage", "data-skill-browser": true },
643
- h("nav", { className: "skill-view-tabs", "aria-label": "Skill \u6D4F\u89C8\u65B9\u5F0F" },
644
- h("button", { type: "button", "data-skill-view": "files", "aria-pressed": "true" }, "\u6587\u4EF6\u6D4F\u89C8"),
645
- h("button", { type: "button", "data-skill-view": "relations", "aria-pressed": "false" }, "\u5F15\u7528\u5173\u7CFB\u56FE")),
647
+ h("nav", { className: "skill-view-tabs", "aria-label": "Skill view mode" },
648
+ h("button", { type: "button", "data-skill-view": "files", "aria-pressed": "true" }, "File browser"),
649
+ h("button", { type: "button", "data-skill-view": "relations", "aria-pressed": "false" }, "Reference graph")),
646
650
  h("div", { className: "skill-browser", "data-skill-view-panel": "files" },
647
651
  h(SkillFileTree, { skill: skill, activePath: firstFile.path }),
648
652
  h("section", { className: "skill-viewer", "aria-live": "polite" },
@@ -660,27 +664,27 @@ export function agentMarkdown(posts, thoughts, site = DEFAULT_SITE) {
660
664
  const lines = [
661
665
  `# ${site.name}`,
662
666
  "",
663
- "> 给 Agent 读取的站点索引与内容约定。",
667
+ "> Site index and content conventions for Agents to read.",
664
668
  "",
665
669
  "## Site map",
666
670
  "",
667
- "- [首页](/)",
668
- "- [文章](/posts/)",
669
- "- [想法](/thoughts/)",
670
- "- [Skills](/skills/)(可浏览文件与自动生成的 Markdown 引用关系)",
671
- "- [关于](/about/)",
671
+ "- [Home](/)",
672
+ "- [Posts](/posts/)",
673
+ "- [Thoughts](/thoughts/)",
674
+ "- [Skills](/skills/) (browse files and the auto-generated Markdown reference graph)",
675
+ "- [About](/about/)",
672
676
  "",
673
677
  "## Content model",
674
678
  "",
675
- `- \`${site.contentDirectory}/thoughts/\` 保存经过剪裁、可直接展示的短想法。`,
676
- `- \`${site.contentDirectory}/posts/\` 保存完整文章;文件名或路径组件以 \`_\` 开头的文件是 draft,不公开、不渲染。`,
677
- "- 内容文件支持 `.md` 和 `.mdx`,开头可使用 YAML Frontmatter。",
678
- "- 目前 Frontmatter 没有强制字段;`title`、`date`、`created_at`、`category`、`tags` 会被站点识别。",
679
+ `- \`${site.contentDirectory}/thoughts/\` stores trimmed, directly presentable short thoughts.`,
680
+ `- \`${site.contentDirectory}/posts/\` stores full posts; files whose name or path segment starts with \`_\` are drafts and are not published or rendered.`,
681
+ "- Content files support `.md` and `.mdx`, and may start with YAML frontmatter.",
682
+ "- Frontmatter currently has no required fields; `title`, `date`, `created_at`, `category` and `tags` are recognized by the site.",
679
683
  "",
680
684
  "## Public content",
681
685
  "",
682
- `公开文章:${posts.length} 篇。`,
683
- `公开想法:${thoughts.length} 条。`,
686
+ `Public posts: ${posts.length}.`,
687
+ `Public thoughts: ${thoughts.length}.`,
684
688
  "",
685
689
  "### Posts",
686
690
  "",
@@ -699,11 +703,11 @@ export function llmText(posts, thoughts, site = DEFAULT_SITE) {
699
703
  `> ${site.description}`,
700
704
  "",
701
705
  "## Pages",
702
- "- 首页: /",
703
- "- 文章: /posts/",
704
- "- 想法: /thoughts/",
706
+ "- Home: /",
707
+ "- Posts: /posts/",
708
+ "- Thoughts: /thoughts/",
705
709
  "- Skills: /skills/",
706
- "- 关于: /about/",
710
+ "- About: /about/",
707
711
  "- Agent Markdown: /agents.md",
708
712
  "",
709
713
  "## Posts",
@@ -713,7 +717,7 @@ export function llmText(posts, thoughts, site = DEFAULT_SITE) {
713
717
  ...thoughts.map((thought) => `- ${thought.title}: ${itemUrl(thought)}`),
714
718
  "",
715
719
  "## Rules",
716
- "- 只把公开构建产物视为可展示内容。",
717
- "- posts 中以 _ 开头的 draft 不公开、不渲染。",
720
+ "- Only the public build output is considered presentable content.",
721
+ "- Drafts whose names start with _ under posts are not published or rendered.",
718
722
  ].join("\n");
719
723
  }
@@ -44,7 +44,7 @@ function markdownLinks(source) {
44
44
  }
45
45
  if (url) {
46
46
  links.push({
47
- label: nodeText(node).replaceAll(/\s+/g, " ").trim() || "打开",
47
+ label: nodeText(node).replaceAll(/\s+/g, " ").trim() || "Open",
48
48
  url,
49
49
  section,
50
50
  line: node.position?.start?.line,
@@ -53,7 +53,7 @@ function markdownLinks(source) {
53
53
  }
54
54
  node.children?.forEach((child) => collectLinks(child, section));
55
55
  };
56
- let section = "文档开头";
56
+ let section = "Beginning of document";
57
57
  for (const node of tree.children ?? []) {
58
58
  if (node.type === "heading") {
59
59
  section = nodeText(node).replaceAll(/\s+/g, " ").trim() || section;
@@ -79,7 +79,7 @@ function inferredDescription(body) {
79
79
  .split(/\r?\n\s*\r?\n/)
80
80
  .map(plainText)
81
81
  .find(Boolean);
82
- return (paragraph ?? "一个可以交给 Agent 使用的 Skill。").slice(0, 180);
82
+ return (paragraph ?? "A skill that can be handed to an Agent.").slice(0, 180);
83
83
  }
84
84
  async function collectFiles(directory) {
85
85
  const entries = await readdir(directory, { withFileTypes: true });
@@ -107,16 +107,16 @@ function isExternalUrl(url) {
107
107
  function externalDetail(url) {
108
108
  try {
109
109
  const parsed = new URL(url);
110
- return `Agent 会离开 Skill,继续读取 ${parsed.hostname}。`;
110
+ return `The Agent leaves the Skill and continues to ${parsed.hostname}.`;
111
111
  }
112
112
  catch {
113
- return "指向 Skill 目录之外的输入或资料。";
113
+ return "Points to input or material outside the Skill directory.";
114
114
  }
115
115
  }
116
116
  function relationLabel(label, target) {
117
117
  const targetName = target.endsWith("/") ? target : (target.split("/").at(-1) ?? target);
118
118
  if (label === target || label === targetName)
119
- return "引用";
119
+ return "Reference";
120
120
  return label.length > 16 ? `${label.slice(0, 15)}…` : label;
121
121
  }
122
122
  function compactGraphLabel(label) {
@@ -209,7 +209,7 @@ async function loadSkill(directory, sourceBasePath, scope) {
209
209
  target = link.url;
210
210
  externalNodes.set(target, {
211
211
  path: target,
212
- role: "外部链接",
212
+ role: "External link",
213
213
  detail: externalDetail(target),
214
214
  kind: "external",
215
215
  });
@@ -223,15 +223,15 @@ async function loadSkill(directory, sourceBasePath, scope) {
223
223
  externalNodes.set(target, {
224
224
  path: target,
225
225
  role: resolved.kind === "asset"
226
- ? "本地资源"
226
+ ? "Local asset"
227
227
  : resolved.kind === "outside"
228
- ? "Skill 外部"
229
- : "缺失引用",
228
+ ? "Outside the Skill"
229
+ : "Missing reference",
230
230
  detail: resolved.kind === "asset"
231
- ? "Markdown 明确链接到这个非文本资源。"
231
+ ? "The Markdown explicitly links to this non-text asset."
232
232
  : resolved.kind === "outside"
233
- ? "链接指向 Skill 目录之外,Agent 会离开当前 Skill 继续读取。"
234
- : "Markdown 中存在此链接,但 Skill 目录内没有对应文件。",
233
+ ? "The link points outside the Skill directory; the Agent leaves the current Skill and continues reading."
234
+ : "The link exists in the Markdown, but there is no corresponding file in the Skill directory.",
235
235
  kind: resolved.kind === "outside" ? "external" : resolved.kind,
236
236
  });
237
237
  }
@@ -253,7 +253,7 @@ async function loadSkill(directory, sourceBasePath, scope) {
253
253
  return {
254
254
  source,
255
255
  target,
256
- label: compactGraphLabel(sections[0] === "文档开头" ? labels.join(" / ") : sections.join(" / ")),
256
+ label: compactGraphLabel(sections[0] === "Beginning of document" ? labels.join(" / ") : sections.join(" / ")),
257
257
  contexts,
258
258
  };
259
259
  });
@@ -272,12 +272,12 @@ async function loadSkill(directory, sourceBasePath, scope) {
272
272
  const reachable = depth !== undefined;
273
273
  return {
274
274
  path,
275
- role: path === "SKILL.md" ? "入口" : reachable ? `${depth} 级引用` : "未被引用",
275
+ role: path === "SKILL.md" ? "Entry" : reachable ? `${depth}-level reference` : "Not referenced",
276
276
  detail: path === "SKILL.md"
277
- ? "Agent 从这里开始读取这个 Skill。"
277
+ ? "The Agent starts reading this Skill here."
278
278
  : reachable
279
- ? `从 SKILL.md 经过 ${depth} 次链接可以读到这里。`
280
- : "不在从 SKILL.md 出发的链接链路中,Agent 不会自然读到这里。",
279
+ ? `Reachable from SKILL.md through ${depth} links.`
280
+ : "Not on the link chain from SKILL.md, so the Agent will not naturally read this.",
281
281
  content: documents.get(path).body,
282
282
  reachable,
283
283
  depth,
package/dist/src/theme.js CHANGED
@@ -71,7 +71,7 @@ const styles = css `
71
71
  text-rendering: optimizeLegibility;
72
72
  }
73
73
 
74
- /* 顶栏:保留秩序,但不再像刊头。 */
74
+ /* Top bar: keep the order, but stop looking like a masthead. */
75
75
  header.site {
76
76
  display: flex;
77
77
  align-items: center;
@@ -255,7 +255,7 @@ const styles = css `
255
255
  pointer-events: none;
256
256
  }
257
257
 
258
- /* 首页内容流:日期只是呼吸点,不再承担机械时间轴。 */
258
+ /* Home feed: dates are breathing points, not a mechanical timeline. */
259
259
  .feed {
260
260
  position: relative;
261
261
  padding: 8px 0 48px;
@@ -385,7 +385,7 @@ const styles = css `
385
385
  letter-spacing: 0.06em;
386
386
  }
387
387
 
388
- /* 两类内容都像桌上的纸,但保留各自的重量。 */
388
+ /* Both content kinds look like paper on a desk, but keep their own weight. */
389
389
  .post-card,
390
390
  .thought {
391
391
  background-color: ${blogTokens.card};
@@ -548,7 +548,7 @@ const styles = css `
548
548
  outline: none;
549
549
  }
550
550
 
551
- /* 过滤器是轻量控制,不再像出版物图例。 */
551
+ /* Filters are lightweight controls, not publication legends. */
552
552
  .tag-filter {
553
553
  display: flex;
554
554
  flex-wrap: wrap;
@@ -598,7 +598,7 @@ const styles = css `
598
598
  transform: translateY(1px);
599
599
  }
600
600
 
601
- /* 文章与想法详情。 */
601
+ /* Post and thought detail. */
602
602
  .post-head {
603
603
  padding: 68px 0 37px;
604
604
  border-bottom: 1px solid ${blogTokens.line};
@@ -892,7 +892,7 @@ const styles = css `
892
892
  text-align: right;
893
893
  }
894
894
 
895
- /* 索引页与关于页。 */
895
+ /* Index and about pages. */
896
896
  .listing,
897
897
  .about,
898
898
  .skills-index,
@@ -1009,7 +1009,7 @@ const styles = css `
1009
1009
  letter-spacing: 0.06em;
1010
1010
  }
1011
1011
 
1012
- /* Skills:用目录和文档的语义区分内容,不把它做成产品陈列。 */
1012
+ /* Skills: separate content by catalog and document semantics instead of displaying it as a product. */
1013
1013
  .skills-head {
1014
1014
  margin-bottom: 33px;
1015
1015
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meowpress",
3
- "version": "0.1.1-alpha.0",
3
+ "version": "0.1.1-alpha.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {