printing-press-import
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese/printing-press-import
/printing-press-import
Bring a published CLI from the public library
()
into the internal library at so it matches
the form the generator would produce. Manuscripts ride along.
mvanhorn/printing-press-library~/printing-press/library/bash
/printing-press-import notion
/printing-press-import cal.com
/printing-press-import allrecipes --from-clone ~/Code/printing-press-libraryThe internal library is the working copy; the public library is the
durable artifact. After import, the CLI is ready for polish, emboss, or
re-publish — the publish step will re-apply the module path rewrites.
将公共库()中已发布的CLI导入到内部库,使其与生成器生成的格式完全一致,同时导入相关文稿。
mvanhorn/printing-press-library~/printing-press/library/bash
/printing-press-import notion
/printing-press-import cal.com
/printing-press-import allrecipes --from-clone ~/Code/printing-press-library内部库是工作副本,公共库是持久化的成品。导入完成后,该CLI即可进行polish、emboss或重新发布操作——发布步骤会重新应用模块路径重写。
When to run
运行时机
- The public library has a CLI you don't have locally
- The internal copy is broken, lost, or out of sync
- You want a clean baseline before running polish on a published CLI
If the user is asking to polish a CLI and mentions "in/from the public
library" or "from the repo", suggest running this skill first.
- 公共库中有你本地未拥有的CLI
- 内部副本损坏、丢失或不同步
- 你希望在对已发布的CLI执行polish操作前获得一个干净的基准版本
如果用户要求polish某个CLI,且提到“来自公共库”或“来自仓库”,建议先运行此skill。
Setup
配置
bash
PRESS_HOME="$HOME/printing-press"
PRESS_LIBRARY="$PRESS_HOME/library"
PRESS_MANUSCRIPTS="$PRESS_HOME/manuscripts"
SCRIPTS_DIR="$(dirname "${BASH_SOURCE[0]:-$0}")/references"The four reference scripts live alongside this SKILL.md under
:
references/import-fetch.sh <library-path> <staging> [--clone <path>]- (prints zip path on stdout)
import-backup.sh <api-slug> import-rewrite.sh <staging> <api-slug>import-place.sh <staging> <api-slug>
bash
PRESS_HOME="$HOME/printing-press"
PRESS_LIBRARY="$PRESS_HOME/library"
PRESS_MANUSCRIPTS="$PRESS_HOME/manuscripts"
SCRIPTS_DIR="$(dirname "${BASH_SOURCE[0]:-$0}")/references"四个参考脚本与本SKILL.md文件一同存放在目录下:
references/import-fetch.sh <library-path> <staging> [--clone <path>]- (在标准输出打印压缩包路径)
import-backup.sh <api-slug> import-rewrite.sh <staging> <api-slug>import-place.sh <staging> <api-slug>
Phase 1 — Resolve the CLI
阶段1 — 解析CLI
The argument can be anything natural: an API slug (), a brand
name (), an old CLI name (), or close enough
(). Resolve via the public library's —
which carries , , , , and for
every entry, in one fetch.
notioncal.comnotion-pp-cliAllrecipesregistry.jsonnamecategoryapidescriptionpathbash
REGISTRY=$(mktemp)
gh api -H "Accept: application/vnd.github.v3.raw" \
repos/mvanhorn/printing-press-library/contents/registry.json \
> "$REGISTRY"Match in this order:
- Exact match —
namejq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY" - Normalized exact — strip suffix, lowercase, dot→hyphen, then exact match
-pp-cli - Substring on or
name— case-insensitive containsdescription
bash
undefined参数可以是任意自然表述:API slug(如)、品牌名称(如)、旧CLI名称(如),或近似名称(如)。通过公共库的进行解析——该文件包含每个条目的、、、和信息,只需一次获取即可。
notioncal.comnotion-pp-cliAllrecipesregistry.jsonnamecategoryapidescriptionpathbash
REGISTRY=$(mktemp)
gh api -H "Accept: application/vnd.github.v3.raw" \
repos/mvanhorn/printing-press-library/contents/registry.json \
> "$REGISTRY"按以下顺序进行匹配:
- 精确匹配—
namejq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY" - 标准化精确匹配 — 去除后缀、转为小写、将点替换为连字符,然后进行精确匹配
-pp-cli - 或
name子串匹配 — 不区分大小写的包含匹配description
bash
undefinedExact:
精确匹配:
jq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY"
jq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY"
Normalized exact (after $ARG2 = lowercase, dot→hyphen, suffix-stripped):
标准化精确匹配($ARG2为小写、点转连字符、去除后缀后的参数):
jq --arg q "$ARG2" '.entries[] | select(.name == $q)' "$REGISTRY"
jq --arg q "$ARG2" '.entries[] | select(.name == $q)' "$REGISTRY"
Fuzzy (substring on name or description):
模糊匹配(name或description的子串):
jq --arg q "$ARG2" '.entries[]
| select((.name | ascii_downcase | contains($q | ascii_downcase))
or (.description | ascii_downcase | contains($q | ascii_downcase)))
' "$REGISTRY"
If you get one match: use it. If multiple: present at most 4 to the user
via `AskUserQuestion` showing `name` + `description` per candidate. If
zero: tell the user the public library doesn't have that CLI.
The matched entry gives you everything you need:
- `LIB_PATH` from `.path` (e.g., `library/productivity/cal-com`)
- `API_SLUG` from `.name`
- `CATEGORY` from `.category`
**Don't slurp whole files** when reasoning over candidates. The fields
above are enough; if you genuinely need more, the per-CLI manifest is
just `<LIB_PATH>/manifest.json` and the description there can be pulled
the same way (`gh api -H "Accept: ... raw" .../manifest.json | jq -r '.description'`).jq --arg q "$ARG2" '.entries[]
| select((.name | ascii_downcase | contains($q | ascii_downcase))
or (.description | ascii_downcase | contains($q | ascii_downcase)))
' "$REGISTRY"
如果匹配到一个结果:直接使用。如果匹配到多个:最多向用户展示4个候选结果,通过`AskUserQuestion`显示每个候选的`name` + `description`。如果没有匹配结果:告知用户公共库中没有该CLI。
匹配到的条目包含所需的全部信息:
- 从`.path`获取`LIB_PATH`(例如`library/productivity/cal-com`)
- 从`.name`获取`API_SLUG`
- 从`.category`获取`CATEGORY`
**不要读取整个文件**来筛选候选结果。以上字段已足够;如果确实需要更多信息,每个CLI的清单文件为`<LIB_PATH>/manifest.json`,其中的描述信息可以通过同样方式获取(`gh api -H "Accept: ... raw" .../manifest.json | jq -r '.description'`)。Phase 2 — Decide on overwrite
阶段2 — 决定是否覆盖
Check whether the internal library already has this CLI:
bash
LIB_TARGET="$PRESS_LIBRARY/$API_SLUG"
MAN_TARGET="$PRESS_MANUSCRIPTS/$API_SLUG"If neither exists: straightforward import — proceed to Phase 3.
If either exists: read provenance from both sides to decide whether
to overwrite. Don't read whole files — pull just
the fields that matter:
.printing-press.jsonbash
undefined检查内部库中是否已存在该CLI:
bash
LIB_TARGET="$PRESS_LIBRARY/$API_SLUG"
MAN_TARGET="$PRESS_MANUSCRIPTS/$API_SLUG"如果两者都不存在: 直接导入,进入阶段3。
如果其中任意一个存在: 读取双方的溯源信息来决定是否覆盖。不要读取整个文件——只需提取关键字段:
.printing-press.jsonbash
undefinedInternal provenance (if present):
内部溯源信息(如果存在):
jq '{run_id, generated_at, printing_press_version, spec_checksum}'
"$LIB_TARGET/.printing-press.json" 2>/dev/null
"$LIB_TARGET/.printing-press.json" 2>/dev/null
jq '{run_id, generated_at, printing_press_version, spec_checksum}'
"$LIB_TARGET/.printing-press.json" 2>/dev/null
"$LIB_TARGET/.printing-press.json" 2>/dev/null
Public provenance (one-shot via raw):
公共溯源信息(通过raw方式一次性获取):
gh api -H "Accept: application/vnd.github.v3.raw"
repos/mvanhorn/printing-press-library/contents/$LIB_PATH/.printing-press.json
| jq '{run_id, generated_at, printing_press_version, spec_checksum}'
repos/mvanhorn/printing-press-library/contents/$LIB_PATH/.printing-press.json
| jq '{run_id, generated_at, printing_press_version, spec_checksum}'
Reason over the diff:
- **Same `run_id`** — public is the same generation as internal. Likely
no-op; ask before clobbering. If the user wants to import anyway
(e.g., to recover from a broken internal copy), proceed.
- **Public newer `generated_at`** — public has changes the internal
doesn't. Importing is the safe move; ask the user to confirm.
- **Internal newer `generated_at`** — internal has work the public
doesn't (in-progress polish, manual fixes). Importing would clobber
that. Stop and surface this to the user — they likely want to publish
the internal changes first.
- **Either side missing `.printing-press.json`** — older or hand-imported.
Ask the user.
When the user confirms overwrite, the backup step in Phase 3 captures
the current internal state.gh api -H "Accept: application/vnd.github.v3.raw"
repos/mvanhorn/printing-press-library/contents/$LIB_PATH/.printing-press.json
| jq '{run_id, generated_at, printing_press_version, spec_checksum}'
repos/mvanhorn/printing-press-library/contents/$LIB_PATH/.printing-press.json
| jq '{run_id, generated_at, printing_press_version, spec_checksum}'
根据差异进行判断:
- **`run_id`相同** — 公共库版本与内部版本属于同一生成批次。通常无需操作;覆盖前需询问用户。如果用户仍希望导入(例如恢复损坏的内部副本),则继续执行。
- **公共库的`generated_at`更新** — 公共库包含内部版本没有的变更。导入是安全操作;需请用户确认。
- **内部版本的`generated_at`更新** — 内部版本包含公共库没有的工作内容(正在进行的polish操作、手动修复)。导入会覆盖这些内容。停止操作并告知用户——他们可能需要先发布内部的变更。
- **任意一方缺少`.printing-press.json`** — 版本较旧或手动导入。询问用户。
当用户确认覆盖后,阶段3中的备份步骤会保存当前内部版本的状态。Phase 3 — Import
阶段3 — 导入
bash
STAGING=$(mktemp -d)bash
STAGING=$(mktemp -d)Fetch (remote unless --from-clone was passed)
获取(远程获取,除非传入--from-clone参数)
if [[ -n "${CLONE_PATH:-}" ]]; then
bash "$SCRIPTS_DIR/import-fetch.sh" "$LIB_PATH" "$STAGING" --clone "$CLONE_PATH"
else
bash "$SCRIPTS_DIR/import-fetch.sh" "$LIB_PATH" "$STAGING"
fi
if [[ -n "${CLONE_PATH:-}" ]]; then
bash "$SCRIPTS_DIR/import-fetch.sh" "$LIB_PATH" "$STAGING" --clone "$CLONE_PATH"
else
bash "$SCRIPTS_DIR/import-fetch.sh" "$LIB_PATH" "$STAGING"
fi
Backup if anything is being clobbered. Prints zip path on stdout.
如果有内容将被覆盖,则进行备份。在标准输出打印压缩包路径。
if [[ -d "$LIB_TARGET" || -d "$MAN_TARGET" ]]; then
BACKUP_ZIP=$(bash "$SCRIPTS_DIR/import-backup.sh" "$API_SLUG")
echo "Backed up to: $BACKUP_ZIP"
fi
if [[ -d "$LIB_TARGET" || -d "$MAN_TARGET" ]]; then
BACKUP_ZIP=$(bash "$SCRIPTS_DIR/import-backup.sh" "$API_SLUG")
echo "已备份至: $BACKUP_ZIP"
fi
Reverse the publish-step module path rewrites.
撤销发布步骤中的模块路径重写。
bash "$SCRIPTS_DIR/import-rewrite.sh" "$STAGING" "$API_SLUG"
bash "$SCRIPTS_DIR/import-rewrite.sh" "$STAGING" "$API_SLUG"
Atomically move staging into place.
原子性地将临时目录中的内容移动到目标位置。
bash "$SCRIPTS_DIR/import-place.sh" "$STAGING" "$API_SLUG"
undefinedbash "$SCRIPTS_DIR/import-place.sh" "$STAGING" "$API_SLUG"
undefinedPhase 4 — Verify internal consistency
阶段4 — 验证内部一致性
After the move, confirm the imported CLI builds and is structurally
intact. Treat any failure as a real problem — don't paper over it.
bash
cd "$LIB_TARGET"移动完成后,确认导入的CLI可以构建且结构完整。任何失败都视为实际问题——不要忽略。
bash
cd "$LIB_TARGET"Module path is local form
模块路径为本地格式
grep -q "^module ${API_SLUG}-pp-cli$" go.mod
|| { echo "FAIL: go.mod still on public module path"; exit 1; }
|| { echo "FAIL: go.mod still on public module path"; exit 1; }
grep -q "^module ${API_SLUG}-pp-cli$" go.mod
|| { echo "失败: go.mod仍使用公共模块路径"; exit 1; }
|| { echo "失败: go.mod仍使用公共模块路径"; exit 1; }
No public module path leaked into source
源码中未出现公共模块路径
if grep -rq "github.com/mvanhorn/printing-press-library/library"
--include='.go' --include='.yaml' --include='*.yml' .; then echo "FAIL: source still references public module path" exit 1 fi
--include='.go' --include='.yaml' --include='*.yml' .; then echo "FAIL: source still references public module path" exit 1 fi
if grep -rq "github.com/mvanhorn/printing-press-library/library"
--include='.go' --include='.yaml' --include='*.yml' .; then echo "失败: 源码仍引用公共模块路径" exit 1 fi
--include='.go' --include='.yaml' --include='*.yml' .; then echo "失败: 源码仍引用公共模块路径" exit 1 fi
Build
构建
go build ./...
|| { echo "FAIL: go build"; exit 1; }
|| { echo "FAIL: go build"; exit 1; }
go build ./...
|| { echo "失败: go build"; exit 1; }
|| { echo "失败: go build"; exit 1; }
Doctor (self-check)
自检(self-check)
make doctor 2>/dev/null
|| ./bin/${API_SLUG}-pp-cli doctor 2>/dev/null
|| true # best-effort; not all CLIs have doctor wired the same way
|| ./bin/${API_SLUG}-pp-cli doctor 2>/dev/null
|| true # best-effort; not all CLIs have doctor wired the same way
Report the import outcome:
- Source path (from registry: `<category>/<api-slug>`)
- Run ID (from `.printing-press.json`)
- Manuscripts run-ids placed (count + names)
- Backup zip path (if any)
- Build statusmake doctor 2>/dev/null
|| ./bin/${API_SLUG}-pp-cli doctor 2>/dev/null
|| true # 尽力而为;并非所有CLI都以相同方式连接doctor功能
|| ./bin/${API_SLUG}-pp-cli doctor 2>/dev/null
|| true # 尽力而为;并非所有CLI都以相同方式连接doctor功能
报告导入结果:
- 源路径(来自registry:`<category>/<api-slug>`)
- Run ID(来自`.printing-press.json`)
- 导入的文稿run-id数量及名称
- 备份压缩包路径(如有)
- 构建状态Polish-side hint
Polish操作提示
If the user's request to import was triggered by a polish ask (e.g.,
they said "polish notion in the public library"), suggest:
Imported $API_SLUG. To polish: /printing-press-polish $API_SLUGThe polish skill operates on the internal library, so import-then-polish
is the right flow when starting from a published CLI.
如果用户的导入请求是由polish需求触发的(例如他们说“polish公共库中的notion”),建议:
已导入$API_SLUG。如需执行polish操作:/printing-press-polish $API_SLUGpolish skill基于内部库操作,因此当从已发布的CLI开始时,正确流程是先导入再执行polish。