hd-garden 0.10.3 → 0.10.4

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.en.md CHANGED
@@ -17,9 +17,46 @@ npm install
17
17
  make dev
18
18
  ```
19
19
 
20
- The published npm package is `hd-garden`; once installed inside a site, you can run `npx garden` (do not run `npx garden init` directly, as `garden` on npm is an unrelated package). Running `make dev` for the first time creates `.env.local`, installs the three AI skills under `.agents/skills/`, installs the pre-commit check in `.git/hooks/pre-commit`, and starts the dev server at `http://localhost:3000` (with the built-in handbook at `http://localhost:3000/garden/en`).
20
+ The published npm package is `hd-garden`; once installed inside a site, you can run `npx garden` (do not run `npx garden init` directly, as `garden` on npm is an unrelated package). `init` copies the VS Code / Cursor and Typora Intelligent UI plugins into the site and, in an interactive terminal, asks whether to install each one (see the next section). Running `make dev` for the first time creates `.env.local`, installs the three AI skills under `.agents/skills/`, installs the pre-commit check in `.git/hooks/pre-commit`, and starts the dev server at `http://localhost:3000` (with the built-in handbook at `http://localhost:3000/garden/en`).
21
21
 
22
- ## 2. Describe components in plain language (humans and Agents share the same CLI)
22
+ ## 2. Write interactives in VS Code, Cursor, and Typora
23
+
24
+ The Intelligent UI plugins ship inside `hd-garden`. You do not compile them in the site. They insert a one-sentence idea, preview the rendered component in the editor, open the component catalog, and hand the post to the `garden-ui` skill to compile.
25
+
26
+ `npx hd-garden init` copies the files to `.garden/editors/` (a `.vsix` for VS Code / Cursor, and the Typora plugin). In an interactive terminal it asks about VS Code / Cursor first, then Typora. The first `npx garden sync` (`make dev` syncs first) asks again if that prompt has not happened yet. `y` installs; pressing Enter skips.
27
+
28
+ With no TTY (a pipe or a CI log), with `CI=1`, or with `GARDEN_SKIP_EDITORS=1`, the command does not wait for input. It prints the install command below. You can run it later, and running it again is safe:
29
+
30
+ ```bash
31
+ npx garden editors install # Ask again about VS Code and Typora
32
+ npx garden editors install --yes # Install both, without asking
33
+ npx garden editors install --vscode # VS Code / Cursor only
34
+ npx garden editors install --typora # Typora only
35
+ ```
36
+
37
+ ### VS Code / Cursor
38
+
39
+ - **Insert an idea**: `Cmd+Alt+I` on macOS, `Ctrl+Alt+I` on Windows and Linux. The Command Palette and the editor context menu have the same Garden command. It inserts a plain `garden` fence: a short brief for the `garden-ui` skill, which compiles it later. In Typora, type `/` and choose `/garden`; the next list gives each component a small preview image.
40
+ - **Preview**: Open the Markdown preview. A `ui` fence renders the same component as the blog. An `intent` fence renders as an idea card. The extension reads sidecar data files next to the post.
41
+ - **Check**: Errors show up in the Problems panel and as squiggles in the source. A CodeLens above each block says whether it is ok, broken, stale, or not compiled yet.
42
+ - **Catalog**: The Garden catalog command inserts a recipe at the cursor when you choose to start from it. The same catalog from the terminal is `npx garden ui catalog` (it writes `.garden/ui-catalog.html`).
43
+ - **Compile**: Copy the compile prompt. On an English site (`locale: en_US`) it is `Compile this post:` plus the path. Paste that to an Agent that has the `garden-ui` skill. The skill runs `npx garden ui scan`, reads `npx garden ui prompt`, and writes the fence back with `npx garden ui apply`. The plugin does not call a model and does not store a key.
44
+
45
+ When `code` or `cursor` is on `PATH`, `garden editors install` runs `--install-extension`. If both commands exist, it installs into both. Without a CLI, open the Extensions view, choose the `...` menu, then **Install from VSIX**, and select the file under `.garden/editors/vscode/`.
46
+
47
+ ### Typora
48
+
49
+ Typora has no official plugin API. Install [typora-community-plugin](https://github.com/typora-community-plugin/typora-community-plugin/blob/main/docs/en-us/user-guide/1a-installation.md) first (on macOS it patches `index.html` inside `Typora.app`). `garden editors install` looks in the usual locations. If the framework is missing, it still copies the plugin and prints that prerequisite.
50
+
51
+ The plugin is copied to `~/.typora/community-plugins/plugins/hedon954.garden-intelligent-ui/`. On macOS it is also copied to `~/Library/Application Support/abnerworks.Typora/plugins/plugins/hedon954.garden-intelligent-ui/`, which is the directory the Installed Plugins list reads. Open Typora and enable Garden Intelligent UI under Settings, Installed plugins.
52
+
53
+ Use it the same way as VS Code: leaving a fence previews `ui` / `intent` (as with Mermaid, click into the fence to edit the source; clicks on sliders and buttons stay in the preview). Type `/`, choose `/garden`, or use the insert command (`Ctrl+Alt+I` on Windows and Linux; on macOS, Option rewrites the key, so record a shortcut under Settings, Keyboard Shortcuts). Copy compile prompt hands the post to the `garden-ui` skill.
54
+
55
+ A Typora upgrade overwrites the community framework inside the app. Reinstall typora-community-plugin, then enable this plugin again. The fences stay in the Markdown, and `make dev` still previews them.
56
+
57
+ The Obsidian plugin is not installed by this command.
58
+
59
+ ## 3. Describe components in plain language (humans and Agents share the same CLI)
23
60
 
24
61
  Where you want a component or interactive calculation, write an unnamed `garden` fence describing what the reader should adjust and see:
25
62
 
@@ -31,7 +68,7 @@ Where you want a component or interactive calculation, write an unnamed `garden`
31
68
 
32
69
  Ask your Agent to compile the post using the bundled `garden-ui` skill: it runs `npx garden ui scan` to locate uncompiled or broken blocks, reads the component catalog from `npx garden ui prompt`, generates a `garden interactive` block (or `card`, `stat`, `compare`, `timeline`, `chart`, `figure`, `html`, `file`, `relations`, `list`, `choice`, or a `diff` block right below a code snippet), and writes only that fence back via `npx garden ui apply`. If you run `git commit` before compiling, the pre-commit hook runs `npx --no-install garden ui check --staged --quiet`, stops the commit, and prints a ready-to-paste fix prompt for your AI.
33
70
 
34
- ## 3. Common commands
71
+ ## 4. Common commands
35
72
 
36
73
  ```bash
37
74
  make new SLUG=writing-pace TITLE="Writing Pace" # Create a draft post in content/posts/
@@ -42,9 +79,10 @@ make update MESSAGE="Add writing-pace post" # Check, commit, and push to ori
42
79
  npx garden check content/posts/writing-pace.md # Validate front matter, components, and assets
43
80
  npx garden ui check --staged # Check staged posts for uncompiled ideas or UI errors
44
81
  npx garden ui catalog # Generate an offline component gallery at .garden/ui-catalog.html
82
+ npx garden editors install --yes # Install the Intelligent UI plugins into VS Code / Cursor and Typora
45
83
  ```
46
84
 
47
- ## 4. Excalidraw
85
+ ## 5. Excalidraw
48
86
 
49
87
  Point a Markdown image at the `.excalidraw` source. `garden build` exports one light flat SVG beside that file, with a transparent background, and embeds that SVG in the article so its text can be selected. No separate export command.
50
88
 
@@ -54,7 +92,7 @@ Point a Markdown image at the `.excalidraw` source. `garden build` exports one l
54
92
 
55
93
  The first page that references `.excalidraw` downloads the exporter (Chromium is not required; fonts are embedded in the SVG). See [Local Image](docs/handbook/en/components/image.md).
56
94
 
57
- ## 5. Handbook and reference docs
95
+ ## 6. Handbook and reference docs
58
96
 
59
97
  Start `make dev` and open `/garden/en` (Chinese at `/garden`), or read the markdown sources directly:
60
98
 
package/README.md CHANGED
@@ -17,11 +17,48 @@ npm install
17
17
  make dev
18
18
  ```
19
19
 
20
- 公开包名是 `hd-garden`,装进站点后可使用 `npx garden`(不要直接运行未安装的 `npx garden init`,npm 上的 `garden` 是另一个包)。首次运行 `make dev` 会生成 `.env.local`、补齐 `.agents/skills/` 下的三个 AI skill,并在 `.git/hooks/pre-commit` 安装提交前检查,默认预览地址是 `http://localhost:3000`(使用说明在 `http://localhost:3000/garden`)。
20
+ 公开包名是 `hd-garden`,装进站点后可使用 `npx garden`(不要直接运行未安装的 `npx garden init`,npm 上的 `garden` 是另一个包)。`init` 会把 VS Code / Cursor 与 Typora 的 Intelligent UI 插件放进站点,并在交互终端里分别询问要不要装上(见下一节)。首次运行 `make dev` 会生成 `.env.local`、补齐 `.agents/skills/` 下的三个 AI skill,并在 `.git/hooks/pre-commit` 安装提交前检查,默认预览地址是 `http://localhost:3000`(使用说明在 `http://localhost:3000/garden`)。
21
21
 
22
22
  如果在本地使用了 npm 镜像,请把 `registry` 留在 `~/.npmrc`,不要让镜像域名写进 `package-lock.json`(提交前可运行 `node node_modules/hd-garden/scripts/check-lockfile-registry.mjs` 检查)。
23
23
 
24
- ## 2. 用一句话写组件(人和 Agent 用同一套工具)
24
+ ## 2. 在 VS Code、Cursor 和 Typora 里写交互
25
+
26
+ Intelligent UI 插件随 `hd-garden` 一起发布,不用在站点里编译源码。它做四件事:插入一句想法、在编辑器里预览画好的组件、打开组件清单,以及把「编译这篇」交给 `garden-ui` skill。
27
+
28
+ `npx hd-garden init` 把产物复制到站点的 `.garden/editors/`(VS Code 的 `.vsix`,以及 Typora 插件目录)。终端可交互时,会先问要不要装进 VS Code / Cursor,再问要不要装进 Typora。第一次 `npx garden sync`(`make dev` 会先同步)如果还没问过,会再问一次。回答 `y` 才会安装;直接回车是不装。
29
+
30
+ 没有 TTY(管道或 CI 日志)、`CI=1`,或设置了 `GARDEN_SKIP_EDITORS=1` 时,命令不会停下来等输入,只打印下面这条安装命令。之后随时可以装,重复执行也安全:
31
+
32
+ ```bash
33
+ npx garden editors install # 再问一次 VS Code 和 Typora
34
+ npx garden editors install --yes # 两个都装,不再询问
35
+ npx garden editors install --vscode # 只装 VS Code / Cursor
36
+ npx garden editors install --typora # 只装 Typora
37
+ ```
38
+
39
+ ### VS Code / Cursor
40
+
41
+ - **插入想法**:macOS 用 `Cmd+Alt+I`,Windows / Linux 用 `Ctrl+Alt+I`,或命令「插入 Garden 块」。插入的是不带组件名的 `garden` 围栏,正文用中文告诉你要写什么,交给 `garden-ui` skill 编译。Typora 里先输入 `/` 选 `/garden`,再从带小预览图的列表里选组件。
42
+ - **预览**:打开 Markdown 预览。`ui` 围栏画成和博客一样的组件,`intent` 围栏显示成想法卡片。同名目录里的数据文件由扩展读取。
43
+ - **检查**:错误进「问题」面板,并在源码上画波浪线。每个块上方的 CodeLens 标出正常、有错、过期或未编译。
44
+ - **组件清单**:命令「查看组件清单」。点「用它开始」把配方插进当前稿件。终端里的同一份清单是 `npx garden ui catalog`(生成 `.garden/ui-catalog.html`)。
45
+ - **编译**:命令「复制编译提示词」。中文站点复制 `编译这篇:<相对路径>`,英文站点(`locale: en_US`)复制 `Compile this post: <相对路径>`。把这句话发给装了 `garden-ui` skill 的 Agent,由它 `npx garden ui scan`、读 `npx garden ui prompt`、再 `npx garden ui apply`。插件不调用模型,也不保存密钥。
46
+
47
+ 本机有 `code` 或 `cursor` 命令时,`garden editors install` 会执行 `--install-extension`。两个命令都在时,会各装一次。没有命令行时,打开扩展视图,点右上角「…」,选 **Install from VSIX**(从 VSIX 安装),文件在 `.garden/editors/vscode/`。
48
+
49
+ ### Typora
50
+
51
+ Typora 没有官方插件接口。先按 [typora-community-plugin 的安装说明](https://github.com/typora-community-plugin/typora-community-plugin/blob/main/docs/en-us/user-guide/1a-installation.md) 装上社区框架(macOS 上它会修改 `Typora.app` 里的 `index.html`)。`garden editors install` 会检查常见安装位置;没找到时仍会复制插件,并打印这个前提。
52
+
53
+ 插件文件复制到 `~/.typora/community-plugins/plugins/hedon954.garden-intelligent-ui/`。macOS 同时写到 `~/Library/Application Support/abnerworks.Typora/plugins/plugins/hedon954.garden-intelligent-ui/`。打开 Typora,在「设置 → 已安装插件」里勾选 Garden Intelligent UI。
54
+
55
+ 用法和 VS Code 同一套:光标离开围栏时预览 `ui` / `intent`(和 Mermaid 一样,点进围栏编辑源码;点滑杆或按钮不会跳进源码);先输入 `/` 再选 `/garden`,或用命令「插入 Garden 块」,都会插入想法围栏(Windows / Linux 默认 `Ctrl+Alt+I`,macOS 的 Option 会改写按键,请到「设置 → 快捷键」里自己录);「Garden:复制编译提示词」交给 `garden-ui` skill。
56
+
57
+ 升级 Typora 会覆盖社区框架改过的程序文件,插件跟着失效。需要重新安装 typora-community-plugin,再勾选本插件。稿件里的围栏原文还在,也可以用 `make dev` 预览。
58
+
59
+ Obsidian 插件这一轮不随包安装。
60
+
61
+ ## 3. 用一句话写组件(人和 Agent 用同一套工具)
25
62
 
26
63
  在正文想放组件的位置写一个不带名字的 `garden` 围栏,只描述想让读者做什么、看到什么:
27
64
 
@@ -33,7 +70,7 @@ make dev
33
70
 
34
71
  让 Agent 按站点里的 `garden-ui` skill 处理这篇稿件:Agent 先用 `npx garden ui scan` 读取待编译块的哈希,再读 `npx garden ui prompt` 的组件规则,生成 `garden interactive`(或 `card`、`stat`、`compare`、`timeline`、`chart`、`figure`、`html`、`file`、`relations`、`list`、`choice` 等内置组件,或在完整代码下方生成 `diff`),最后用 `npx garden ui apply` 只替换该围栏。如果你在编译前直接 `git commit`,pre-commit 钩子会运行同一条 `npx --no-install garden ui check --staged --quiet` 拦下提交,并打印一段可直接粘贴给 AI 的修复提示词。
35
72
 
36
- ## 3. 常用命令
73
+ ## 4. 常用命令
37
74
 
38
75
  ```bash
39
76
  make new SLUG=writing-pace TITLE="慢慢写" # 在 content/posts/ 下创建文章草稿
@@ -44,9 +81,10 @@ make update MESSAGE="新增一篇文章" # 检查通过后提交并
44
81
  npx garden check content/posts/writing-pace.md # 单独检查一篇文章的标题、组件与资源路径
45
82
  npx garden ui check --staged # 检查暂存区稿件中的想法块与交互组件
46
83
  npx garden ui catalog # 在 .garden/ui-catalog.html 生成离线组件清单
84
+ npx garden editors install --yes # 把 Intelligent UI 插件装进 VS Code / Cursor 与 Typora
47
85
  ```
48
86
 
49
- ## 4. Excalidraw
87
+ ## 5. Excalidraw
50
88
 
51
89
  正文用 Markdown 图片指向 `.excalidraw` 源文件。`garden build` 会在同目录导出一张浅色扁平 SVG,画布背景透明,并把这张 SVG 嵌进正文,图里的文字可以选中。不需要单独的导出命令。
52
90
 
@@ -56,7 +94,7 @@ npx garden ui catalog # 在 .garden/ui-catalog.html 生
56
94
 
57
95
  页面里第一次出现 `.excalidraw` 时,构建会下载导出程序(不需要 Chromium;字体写进 SVG)。说明见[本地图片](docs/handbook/components/image.md)。
58
96
 
59
- ## 5. 使用说明与深入文档
97
+ ## 6. 使用说明与深入文档
60
98
 
61
99
  本地运行 `make dev` 后访问 `/garden`(英文版在 `/garden/en`),或直接阅读仓库内的文档:
62
100
 
package/bin/garden.mjs CHANGED
@@ -4,6 +4,7 @@ import { spawnSync } from "node:child_process";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import { createRequire } from "node:module";
7
+ import { editorsInstall, offerEditorsOnce } from "../scripts/editors-kit.mjs";
7
8
  import { gardenPackageRoot, gardenSiteRoot } from "../scripts/garden-paths.mjs";
8
9
  import { langOf, siteCliLang } from "../ui/core/cli-locale.mjs";
9
10
 
@@ -196,29 +197,30 @@ function copyIfMissing(from, to) {
196
197
  return true;
197
198
  }
198
199
 
199
- function ensureSiteKit(destinationRoot = siteRoot) {
200
- if (samePath(destinationRoot, gardenPackageRoot)) return;
200
+ async function ensureSiteKit(destinationRoot = siteRoot) {
201
201
  const lang = siteCliLang(destinationRoot);
202
+ if (!samePath(destinationRoot, gardenPackageRoot)) {
203
+ const added = [];
204
+ if (
205
+ copyIfMissing(
206
+ path.join(gardenPackageRoot, "templates", "site", lang === "en" ? "Makefile.en" : "Makefile"),
207
+ path.join(destinationRoot, "Makefile"),
208
+ )
209
+ ) {
210
+ added.push("Makefile");
211
+ }
212
+ if (added.length) {
213
+ process.stdout.write(
214
+ lang === "en"
215
+ ? `Added missing site files: ${added.join(", ")}\n`
216
+ : `已补齐站点文件:${added.join("、")}\n`,
217
+ );
218
+ }
202
219
 
203
- const added = [];
204
- if (
205
- copyIfMissing(
206
- path.join(gardenPackageRoot, "templates", "site", lang === "en" ? "Makefile.en" : "Makefile"),
207
- path.join(destinationRoot, "Makefile"),
208
- )
209
- ) {
210
- added.push("Makefile");
220
+ installSkill(destinationRoot, { onlyMissing: true, lang });
221
+ if (process.env.GARDEN_SKIP_HOOKS !== "1") installHook(destinationRoot, { quiet: true, lang });
211
222
  }
212
- if (added.length) {
213
- process.stdout.write(
214
- lang === "en"
215
- ? `Added missing site files: ${added.join(", ")}\n`
216
- : `已补齐站点文件:${added.join("、")}\n`,
217
- );
218
- }
219
-
220
- installSkill(destinationRoot, { onlyMissing: true, lang });
221
- if (process.env.GARDEN_SKIP_HOOKS !== "1") installHook(destinationRoot, { quiet: true, lang });
223
+ await offerEditorsOnce(destinationRoot, lang);
222
224
  }
223
225
 
224
226
  const HOOK_MARKER = "# garden: ui check";
@@ -272,19 +274,19 @@ function installHook(destinationRoot = siteRoot, { quiet = false, force = false,
272
274
  );
273
275
  }
274
276
 
275
- function prepare() {
277
+ async function prepare() {
276
278
  ensureEnv();
277
279
  ensurePublic();
278
280
  fs.mkdirSync(path.join(siteRoot, "content", "posts"), { recursive: true });
279
281
  fs.mkdirSync(path.join(siteRoot, "content", "thoughts"), { recursive: true });
280
- ensureSiteKit();
282
+ await ensureSiteKit();
281
283
  }
282
284
 
283
- function sync() {
285
+ async function sync() {
284
286
  if (!fs.existsSync(path.join(siteRoot, "site.config.yaml"))) {
285
287
  fail(`当前目录不是 Garden 站点(缺少 site.config.yaml):${siteRoot}`);
286
288
  }
287
- prepare();
289
+ await prepare();
288
290
  runNode("scripts/build-content.mjs");
289
291
  }
290
292
 
@@ -313,8 +315,8 @@ function ensureDevGitHubLogin() {
313
315
  fs.writeFileSync(local, text.endsWith("\n") ? text : `${text}\n`);
314
316
  }
315
317
 
316
- function runVinext(vinextArgs, { copyDist = false } = {}) {
317
- sync();
318
+ async function runVinext(vinextArgs, { copyDist = false } = {}) {
319
+ await sync();
318
320
  const cwd = vinextRoot();
319
321
  const result = spawnSync(process.execPath, [resolveVinext(), ...vinextArgs], {
320
322
  cwd,
@@ -378,7 +380,7 @@ function writeEngineDependency(destination) {
378
380
  fs.writeFileSync(sitePkgPath, `${JSON.stringify(sitePkg, null, 2)}\n`);
379
381
  }
380
382
 
381
- function initSite() {
383
+ async function initSite() {
382
384
  const { destination, lang } = parseInitArgs(rest);
383
385
  const template = path.join(gardenPackageRoot, "templates", "site");
384
386
  if (!fs.existsSync(template)) fail("Garden 包里缺少 templates/site。");
@@ -405,9 +407,10 @@ function initSite() {
405
407
  }
406
408
  }
407
409
  writeEngineDependency(destination);
410
+ process.stdout.write(lang === "en" ? `Created site: ${destination}\n` : `已创建站点:${destination}\n`);
411
+ installSkill(destination, { lang });
412
+ await offerEditorsOnce(destination, lang);
408
413
  if (lang === "en") {
409
- process.stdout.write(`Created site: ${destination}\n`);
410
- installSkill(destination, { lang });
411
414
  process.stdout.write("Next steps:\n");
412
415
  process.stdout.write(` cd ${destination}\n`);
413
416
  process.stdout.write(" npm install\n");
@@ -417,8 +420,6 @@ function initSite() {
417
420
  printGiscusGuide("en");
418
421
  return;
419
422
  }
420
- process.stdout.write(`已创建站点:${destination}\n`);
421
- installSkill(destination);
422
423
  process.stdout.write("下一步:\n");
423
424
  process.stdout.write(` cd ${destination}\n`);
424
425
  process.stdout.write(" npm install\n");
@@ -428,6 +429,35 @@ function initSite() {
428
429
  printGiscusGuide("zh");
429
430
  }
430
431
 
432
+ function editorInstallFlags(argv) {
433
+ const known = new Set(["--vscode", "--typora", "--yes"]);
434
+ for (const arg of argv) {
435
+ if (!known.has(arg)) {
436
+ const lang = siteCliLang(siteRoot);
437
+ fail(lang === "en" ? `Unknown option: ${arg}` : `未知参数:${arg}`);
438
+ }
439
+ }
440
+ return {
441
+ vscode: argv.includes("--vscode"),
442
+ typora: argv.includes("--typora"),
443
+ yes: argv.includes("--yes"),
444
+ };
445
+ }
446
+
447
+ async function editorsCommand(argv) {
448
+ const lang = siteCliLang(siteRoot);
449
+ const sub = argv[0];
450
+ if (sub !== "install") {
451
+ fail(
452
+ lang === "en"
453
+ ? "Usage: garden editors install [--vscode] [--typora] [--yes]"
454
+ : "用法:garden editors install [--vscode] [--typora] [--yes]",
455
+ );
456
+ }
457
+ const status = await editorsInstall(siteRoot, lang, editorInstallFlags(argv.slice(1)));
458
+ if (status) process.exit(status);
459
+ }
460
+
431
461
  function packagedSkills() {
432
462
  const root = path.join(gardenPackageRoot, ".agents", "skills");
433
463
  if (!fs.existsSync(root)) return [];
@@ -473,6 +503,7 @@ function help() {
473
503
  garden check <文章.md> 检查一篇博文的硬性结构
474
504
  garden ui <子命令> Intelligent UI:scan、check、apply、prompt、schema、catalog
475
505
  garden hooks 安装提交前检查(检查暂存稿件里的 ui 块)
506
+ garden editors install 安装 Intelligent UI 插件到 VS Code / Cursor 与 Typora(--vscode、--typora、--yes)
476
507
  garden skill 把引擎自带的 skill 装进当前站点
477
508
  garden pages:validate 检查 dist/client
478
509
  garden pages:prepare 写入公开产物仓库
@@ -480,85 +511,92 @@ function help() {
480
511
  `);
481
512
  }
482
513
 
483
- switch (command) {
484
- case "help":
485
- case "--help":
486
- case "-h":
487
- help();
488
- break;
489
- case "sync":
490
- sync();
491
- break;
492
- case "dev":
493
- ensureDevGitHubLogin();
494
- runVinext(["dev", ...rest]);
495
- break;
496
- case "build":
497
- // Favicons are refetched on every build; failures fall back to link-assets.json.
498
- if (process.env.GARDEN_OFFLINE !== "1") runNode("scripts/link-assets.mjs");
499
- // Remote image sizes: only new images are probed; the rest come from image-sizes.json.
500
- if (process.env.GARDEN_OFFLINE !== "1") runNode("scripts/image-sizes.mjs");
501
- // Sizes of remote files in garden file blocks; failures fall back to file-sizes.json.
502
- if (process.env.GARDEN_OFFLINE !== "1") runNode("scripts/file-sizes.mjs");
503
- runVinext(["build", ...rest], { copyDist: true });
504
- // /favicon.ico from the site's own icon (brand.favicon).
505
- runNode("scripts/favicon-ico.mjs");
506
- // Pages for old addresses listed under redirects in site.config.yaml (static export only).
507
- if (process.env.STATIC_EXPORT === "1") {
508
- // What the export wrote for empty dynamic routes (ui/garden/static-params.mjs).
509
- runNode("scripts/static-placeholders.mjs");
510
- runNode("scripts/redirects.mjs");
511
- // <html lang="en"> on the English handbook pages.
512
- runNode("scripts/html-lang.mjs");
513
- // 404.html also under basePath when the host serves that folder alone.
514
- runNode("scripts/static-404.mjs");
515
- }
516
- break;
517
- case "links":
518
- runNode("scripts/link-assets.mjs");
519
- break;
520
- case "images":
521
- runNode("scripts/image-sizes.mjs");
522
- break;
523
- case "files":
524
- runNode("scripts/file-sizes.mjs");
525
- break;
526
- case "start":
527
- runVinext(["start", ...rest]);
528
- break;
529
- case "new":
530
- runNode("scripts/new-post.mjs", rest);
531
- break;
532
- case "embed":
533
- runNode("scripts/fetch-embed.mjs", rest);
534
- break;
535
- case "check":
536
- runNode("scripts/check-post.mjs", rest);
537
- break;
538
- case "ui":
539
- runNode("scripts/ui-cli.mjs", rest, { cwd: process.cwd() });
540
- break;
541
- case "hooks":
542
- installHook(siteRoot, { force: rest.includes("--force") });
543
- break;
544
- case "init":
545
- initSite();
546
- break;
547
- case "skill":
548
- case "skills":
549
- installSkill();
550
- break;
551
- case "pages:validate":
552
- runNode("scripts/prepare-pages-output.mjs", [
553
- rest[0] ?? path.join(siteRoot, "dist", "client"),
554
- ]);
555
- break;
556
- case "pages:prepare":
557
- runNode("scripts/prepare-pages-output.mjs", rest);
558
- break;
559
- case "webmentions":
560
- runNode("scripts/send-webmentions.mjs", rest);
561
- break;
562
- default:
563
- fail(`未知命令:${command}`);
514
+ async function main() {
515
+ switch (command) {
516
+ case "help":
517
+ case "--help":
518
+ case "-h":
519
+ help();
520
+ break;
521
+ case "sync":
522
+ await sync();
523
+ break;
524
+ case "dev":
525
+ ensureDevGitHubLogin();
526
+ await runVinext(["dev", ...rest]);
527
+ break;
528
+ case "build":
529
+ // Favicons are refetched on every build; failures fall back to link-assets.json.
530
+ if (process.env.GARDEN_OFFLINE !== "1") runNode("scripts/link-assets.mjs");
531
+ // Remote image sizes: only new images are probed; the rest come from image-sizes.json.
532
+ if (process.env.GARDEN_OFFLINE !== "1") runNode("scripts/image-sizes.mjs");
533
+ // Sizes of remote files in garden file blocks; failures fall back to file-sizes.json.
534
+ if (process.env.GARDEN_OFFLINE !== "1") runNode("scripts/file-sizes.mjs");
535
+ await runVinext(["build", ...rest], { copyDist: true });
536
+ // /favicon.ico from the site's own icon (brand.favicon).
537
+ runNode("scripts/favicon-ico.mjs");
538
+ // Pages for old addresses listed under redirects in site.config.yaml (static export only).
539
+ if (process.env.STATIC_EXPORT === "1") {
540
+ // What the export wrote for empty dynamic routes (ui/garden/static-params.mjs).
541
+ runNode("scripts/static-placeholders.mjs");
542
+ runNode("scripts/redirects.mjs");
543
+ // <html lang="en"> on the English handbook pages.
544
+ runNode("scripts/html-lang.mjs");
545
+ // 404.html also under basePath when the host serves that folder alone.
546
+ runNode("scripts/static-404.mjs");
547
+ }
548
+ break;
549
+ case "links":
550
+ runNode("scripts/link-assets.mjs");
551
+ break;
552
+ case "images":
553
+ runNode("scripts/image-sizes.mjs");
554
+ break;
555
+ case "files":
556
+ runNode("scripts/file-sizes.mjs");
557
+ break;
558
+ case "start":
559
+ await runVinext(["start", ...rest]);
560
+ break;
561
+ case "new":
562
+ runNode("scripts/new-post.mjs", rest);
563
+ break;
564
+ case "embed":
565
+ runNode("scripts/fetch-embed.mjs", rest);
566
+ break;
567
+ case "check":
568
+ runNode("scripts/check-post.mjs", rest);
569
+ break;
570
+ case "ui":
571
+ runNode("scripts/ui-cli.mjs", rest, { cwd: process.cwd() });
572
+ break;
573
+ case "hooks":
574
+ installHook(siteRoot, { force: rest.includes("--force") });
575
+ break;
576
+ case "editors":
577
+ await editorsCommand(rest);
578
+ break;
579
+ case "init":
580
+ await initSite();
581
+ break;
582
+ case "skill":
583
+ case "skills":
584
+ installSkill();
585
+ break;
586
+ case "pages:validate":
587
+ runNode("scripts/prepare-pages-output.mjs", [
588
+ rest[0] ?? path.join(siteRoot, "dist", "client"),
589
+ ]);
590
+ break;
591
+ case "pages:prepare":
592
+ runNode("scripts/prepare-pages-output.mjs", rest);
593
+ break;
594
+ case "webmentions":
595
+ runNode("scripts/send-webmentions.mjs", rest);
596
+ break;
597
+ default:
598
+ fail(`未知命令:${command}`);
599
+ }
564
600
  }
601
+
602
+ await main();
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: 用 AI 写作
3
3
  navTitle: 用 AI 写作
4
- description: 用一句话描述想要的组件,交给 Agent 生成;提交前由同一个脚本检查,失败时打印可粘贴给 AI 的修复提示词。
4
+ description: 用编辑器插件插入想法并预览,交给 Agent 编译;提交前由同一个脚本检查。
5
5
  section: getting-started
6
6
  order: 2
7
7
  ---
@@ -82,15 +82,41 @@ pages:
82
82
 
83
83
  Agent 按 `garden-ui` skill 会把这个想法块替换成一段紧挨着完整代码的 `diff` 围栏。页面渲染时会把完整代码和 `diff` 合成一个带「代码 / 对比上一版」切换按钮的代码框,手写 `diff` 的规则见 [写文章与随想](/garden/writing)。
84
84
 
85
- ## 6. 不使用 Agent 时的快捷输入
85
+ ## 6. 在编辑器里插入、预览,再交给 skill 编译
86
+
87
+ VS Code、Cursor 和 Typora 的 Intelligent UI 插件把上面的流程放到写稿的地方。插件随 `hd-garden` 发布。`npx hd-garden init` 把产物复制到 `.garden/editors/`,并在交互终端里询问要不要安装。第一次 `npx garden sync` 如果还没问过,会再问一次。非交互环境、`CI=1` 或 `GARDEN_SKIP_EDITORS=1` 只打印提示,不阻塞。手动安装:
88
+
89
+ ```bash
90
+ npx garden editors install
91
+ npx garden editors install --yes
92
+ npx garden editors install --vscode
93
+ npx garden editors install --typora
94
+ ```
95
+
96
+ 装好之后,一篇组件通常是这四步:
97
+
98
+ 1. **插入想法。** 在要放组件的位置运行「插入 Garden 块」(VS Code / Cursor 的快捷键是 macOS `Cmd+Alt+I`,Windows / Linux `Ctrl+Alt+I`)。Typora 里输入 `/` 后选 `/garden`,下一层列表每一项有一张小预览图;命令的快捷键在 Windows / Linux 是 `Ctrl+Alt+I`,macOS 需要在「设置 → 快捷键」里自己录。插入的是给 `garden-ui` skill 编译的想法围栏,例如选「资源卡」得到:
99
+
100
+ ````markdown
101
+ ```garden
102
+ 做成资源卡。一篇论文、一个仓库或一本书,读者需要标题、链接和一句说明。请写上链接、标题、一句说明。
103
+ ```
104
+ ````
105
+ 2. **预览。** 打开 Markdown 预览,或在 Typora 里把光标移出围栏。`intent` 显示成想法卡片;skill 写回 `ui` 之后,预览画成和博客一样的组件。错误会标在源码上(VS Code / Cursor 的「问题」面板和 CodeLens)。
106
+ 3. **看清单。** 命令「查看组件清单」,或在终端运行 `npx garden ui catalog` 打开 `.garden/ui-catalog.html`。清单里的「用它开始」把配方插进当前稿件,适合已经知道要用哪一种组件的时候。
107
+ 4. **编译。** 「复制编译提示词」。中文站点得到 `编译这篇:<相对路径>`,英文站点得到 `Compile this post: <相对路径>`。把这句话发给 `garden-ui` skill。Agent 用 `npx garden ui scan` 定位,用 `npx garden ui prompt` 读规则,用 `npx garden ui apply` 写回。插件不调用模型。
108
+
109
+ **Typora 的前提。** 先安装 [typora-community-plugin](https://github.com/typora-community-plugin/typora-community-plugin/blob/main/docs/en-us/user-guide/1a-installation.md)。`npx garden editors install --typora` 把插件复制到 `~/.typora/community-plugins/plugins/hedon954.garden-intelligent-ui/`(macOS 同时写到 `~/Library/Application Support/abnerworks.Typora/plugins/plugins/hedon954.garden-intelligent-ui/`),然后在「设置 → 已安装插件」里勾选 Garden Intelligent UI。升级 Typora 会覆盖社区框架,需要重装框架后再勾选。没找到 `code` 或 `cursor` 时,用扩展视图的 Install from VSIX 选择 `.garden/editors/vscode/` 里的文件。安装细节见 [语法检查与快捷输入](/garden/workflow)。
110
+
111
+ ## 7. 不使用 Agent 时的快捷输入
86
112
 
87
113
  不借助 AI 手写组件时,可以直接使用包内自带的模板与代码片段:
88
114
 
89
115
  - `make new` 创建的草稿底部自带一段 `<!-- 组件速查 ... -->` 注释,包含想法块和 12 个组件的示例,写完可直接删掉。
90
116
  - `templates/garden-blocks.md` 汇总了想法块与 12 个组件的适用场景(`when` / `whenNot`)和可复制示例;macOS 与 Typora / Alfred 用户可导入 `templates/garden-snippets.plist`,输入 `;gidea`(或 `;garden想法`)、`;gcard`、`;gstat`、`;gcompare`、`;gtimeline`、`;gchart`、`;gfigure`、`;ghtml`、`;ginteractive`、`;gfile`、`;grel`、`;glist`、`;gchoice` 即可展开对应围栏。
91
- - 引擎仓库的 `editors/vscode`、`editors/typora` 与 `editors/obsidian` 目录提供了对应的编辑器片段与插件支持,运行 `npx garden ui catalog` 则可在本地生成 `.garden/ui-catalog.html` 离线组件画廊。
117
+ - 编辑器插件的用法见上一节。`npx garden ui catalog` 在本地生成 `.garden/ui-catalog.html` 离线组件画廊。
92
118
 
93
- ## 7. 可选的独立管理后台
119
+ ## 8. 可选的独立管理后台
94
120
 
95
121
  Garden 引擎仓库内置了可选的 `/admin` 管理后台(位于 `app/admin` 与 `worker/`),可通过 `npm run admin:local`、`npm run admin:cloudflare` 或 Docker 单独部署。配置环境变量后,后台提供以下网页端功能:
96
122
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: Writing with AI
3
3
  navTitle: Writing with AI
4
- description: Describe components in one sentence for an Agent to compile, and validate staged files with the same CLI in the pre-commit hook.
4
+ description: Insert and preview ideas with the editor plugins, let an Agent compile them, and validate staged files with the same CLI.
5
5
  section: getting-started
6
6
  order: 2
7
7
  ---
@@ -82,15 +82,35 @@ Compared with the previous version: split the title into two lines with " | " in
82
82
 
83
83
  Following the `garden-ui` skill, the Agent replaces that idea fence with a `diff` fence right below the code block. The page merges the adjacent code and `diff` fences into a single code frame with a toggle between the full code and the diff; see [Writing Posts & Thoughts](/garden/en/writing) for the hand-written `diff` format.
84
84
 
85
- ## 6. Templates and Snippets Without an Agent
85
+ ## 6. Insert, Preview, and Compile from the Editor
86
+
87
+ The VS Code, Cursor, and Typora Intelligent UI plugins put the flow above in the editor. They ship inside `hd-garden`. `npx hd-garden init` copies them to `.garden/editors/` and asks whether to install them when the terminal is interactive. The first `npx garden sync` asks again if that prompt has not happened yet. A non-interactive shell, `CI=1`, or `GARDEN_SKIP_EDITORS=1` prints the hint and does not block. Install later with:
88
+
89
+ ```bash
90
+ npx garden editors install
91
+ npx garden editors install --yes
92
+ npx garden editors install --vscode
93
+ npx garden editors install --typora
94
+ ```
95
+
96
+ A component then takes four steps:
97
+
98
+ 1. **Insert an idea.** Where the component should go, run the Garden insert command (`Cmd+Alt+I` on macOS, `Ctrl+Alt+I` on Windows and Linux in VS Code / Cursor). In Typora, type `/` and choose `/garden` to open a picker with a small preview image on each row; the command shortcut is `Ctrl+Alt+I` on Windows and Linux, and macOS needs a shortcut recorded under Settings, Keyboard Shortcuts. The insertion is a plain `garden` fence whose body tells the `garden-ui` skill which component to compile and which facts to include.
99
+ 2. **Preview.** Open the Markdown preview, or in Typora move the cursor out of the fence. An `intent` block shows as an idea card. After the skill writes a `ui` block, the preview matches the blog. VS Code / Cursor also report errors in Problems and in the CodeLens above the block.
100
+ 3. **Open the catalog.** Use the catalog command, or run `npx garden ui catalog` and open `.garden/ui-catalog.html`. Starting from a recipe inserts it at the cursor when you already know which component you want.
101
+ 4. **Compile.** Copy the compile prompt. On an English site the clipboard text is `Compile this post:` plus the post path. Paste it to the `garden-ui` skill. The Agent locates the block with `npx garden ui scan`, reads the rules with `npx garden ui prompt`, and writes it back with `npx garden ui apply`. The plugin does not call a model.
102
+
103
+ **Typora prerequisite.** Install [typora-community-plugin](https://github.com/typora-community-plugin/typora-community-plugin/blob/main/docs/en-us/user-guide/1a-installation.md) first. `npx garden editors install --typora` copies the plugin to `~/.typora/community-plugins/plugins/hedon954.garden-intelligent-ui/`. On macOS it also copies to `~/Library/Application Support/abnerworks.Typora/plugins/plugins/hedon954.garden-intelligent-ui/`. Enable Garden Intelligent UI under Settings, Installed plugins. A Typora upgrade overwrites the community framework; reinstall the framework, then enable the plugin again. If `code` or `cursor` is not on `PATH`, use Install from VSIX in the Extensions view and select the file under `.garden/editors/vscode/`. Install details are in [Checks & Shortcuts](/garden/en/workflow).
104
+
105
+ ## 7. Templates and Snippets Without an Agent
86
106
 
87
107
  When writing components by hand without AI, you can use the templates and snippets shipped in the package:
88
108
 
89
109
  - Every draft created by `make new` includes an HTML comment at the bottom with copy-ready examples for idea fences and all 12 components; delete the comment whenever you are done.
90
110
  - `templates/garden-blocks.md` lists `when` / `whenNot` guidance and copyable templates for every block; macOS, Typora, and Alfred users can import `templates/garden-snippets.plist` to expand `;gidea`, `;gcard`, `;gstat`, `;gcompare`, `;gtimeline`, `;gchart`, `;gfigure`, `;ghtml`, `;ginteractive`, `;gfile`, `;grel`, `;glist`, and `;gchoice`.
91
- - The engine repository also ships editor integrations under `editors/vscode`, `editors/typora`, and `editors/obsidian`, and `npx garden ui catalog` generates an offline component catalog at `.garden/ui-catalog.html`.
111
+ - Editor plugin usage is in the previous section. `npx garden ui catalog` writes an offline component catalog at `.garden/ui-catalog.html`.
92
112
 
93
- ## 7. Optional Standalone Admin
113
+ ## 8. Optional Standalone Admin
94
114
 
95
115
  The Garden engine includes an optional `/admin` console (under `app/admin` and `worker/`) that can be deployed separately with `npm run admin:local`, `npm run admin:cloudflare`, or Docker. Once configured via environment variables, it provides:
96
116
 
@@ -187,6 +187,7 @@ make dev
187
187
  Run `make update` when a post is ready; it runs the full check and build before committing and pushing. Read the chapters for details:
188
188
 
189
189
  - **[Quick Start](/garden/en/start)**: Directory layout, creating posts with `make new`, previewing drafts, and daily commands.
190
+ - **[Writing with AI](/garden/en/ai-writing)** and **[Checks & Shortcuts](/garden/en/workflow)**: Insert an idea, preview the component, and open the catalog in VS Code, Cursor, or Typora, and install the plugins with `npx garden editors install`.
190
191
  - **[Site & Column Config](/garden/en/config)**: Every field in `site.config.yaml`, custom SVG icons, and ordering series in `content/columns.yaml`.
191
192
  - **[Deploy to GitHub Pages](/garden/en/deploy)**: A single GitHub Actions workflow that supports both one public repository and a private source repo paired with a public Pages repo.
192
193
  - **[Writing Posts & Thoughts](/garden/en/writing)** and **[How the Reading Layout Works](/garden/en/design)**: Front Matter fields, three-tier adaptive widths, and color tokens. Link cards, source chips, and local images are on [Components Overview](/garden/en/components).