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 (
mvanhorn/printing-press-library
) into the internal library at
~/printing-press/library/
so it matches the form the generator would produce. Manuscripts ride along.
bash
/printing-press-import notion
/printing-press-import cal.com
/printing-press-import allrecipes --from-clone ~/Code/printing-press-library
The 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.
将公共库(
mvanhorn/printing-press-library
)中已发布的CLI导入到内部库
~/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>]
  • import-backup.sh <api-slug>
    (prints zip path on stdout)
  • 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 (
notion
), a brand name (
cal.com
), an old CLI name (
notion-pp-cli
), or close enough (
Allrecipes
). Resolve via the public library's
registry.json
— which carries
name
,
category
,
api
,
description
, and
path
for every entry, in one fetch.
bash
REGISTRY=$(mktemp)
gh api -H "Accept: application/vnd.github.v3.raw" \
  repos/mvanhorn/printing-press-library/contents/registry.json \
  > "$REGISTRY"
Match in this order:
  1. Exact
    name
    match
    jq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY"
  2. Normalized exact — strip
    -pp-cli
    suffix, lowercase, dot→hyphen, then exact match
  3. Substring on
    name
    or
    description
    — case-insensitive contains
bash
undefined
参数可以是任意自然表述:API slug(如
notion
)、品牌名称(如
cal.com
)、旧CLI名称(如
notion-pp-cli
),或近似名称(如
Allrecipes
)。通过公共库的
registry.json
进行解析——该文件包含每个条目的
name
category
api
description
path
信息,只需一次获取即可。
bash
REGISTRY=$(mktemp)
gh api -H "Accept: application/vnd.github.v3.raw" \
  repos/mvanhorn/printing-press-library/contents/registry.json \
  > "$REGISTRY"
按以下顺序进行匹配:
  1. 精确匹配
    name
    jq --arg q "$ARG" '.entries[] | select(.name == $q)' "$REGISTRY"
  2. 标准化精确匹配 — 去除
    -pp-cli
    后缀、转为小写、将点替换为连字符,然后进行精确匹配
  3. name
    description
    子串匹配
    — 不区分大小写的包含匹配
bash
undefined

Exact:

精确匹配:

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
.printing-press.json
files — pull just the fields that matter:
bash
undefined
检查内部库中是否已存在该CLI:
bash
LIB_TARGET="$PRESS_LIBRARY/$API_SLUG"
MAN_TARGET="$PRESS_MANUSCRIPTS/$API_SLUG"
如果两者都不存在: 直接导入,进入阶段3。
如果其中任意一个存在: 读取双方的溯源信息来决定是否覆盖。不要读取整个
.printing-press.json
文件——只需提取关键字段:
bash
undefined

Internal provenance (if present):

内部溯源信息(如果存在):

jq '{run_id, generated_at, printing_press_version, spec_checksum}'
"$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

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}'

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}'

根据差异进行判断:

- **`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"
undefined
bash "$SCRIPTS_DIR/import-place.sh" "$STAGING" "$API_SLUG"
undefined

Phase 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; }
grep -q "^module ${API_SLUG}-pp-cli$" go.mod
|| { 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
if grep -rq "github.com/mvanhorn/printing-press-library/library"
--include='.go' --include='.yaml' --include='*.yml' .; then echo "失败: 源码仍引用公共模块路径" exit 1 fi

Build

构建

go build ./...
|| { echo "FAIL: go build"; exit 1; }
go build ./...
|| { 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

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 status
make doctor 2>/dev/null
|| ./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_SLUG
The 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_SLUG
polish skill基于内部库操作,因此当从已发布的CLI开始时,正确流程是先导入再执行polish。