关于 printing-press-amend
将 dogfood 会话中的使用障碍或用户明确提出的需求转为 PR,以修改公共库中的打印版 CLI。支持从会话记录提取问题、直接输入需求,或合并两种来源。
主要功能
- 01从会话记录提取使用障碍
- 02接收明确的 CLI 修改需求
- 03将发现分类为缺陷或功能
- 04按名称或路径指定 CLI
- 05为公共库 CLI 创建补丁
适用场景
- 01将会话中的错误转为 CLI 修复
- 02添加指定的命令或订阅源
- 03合并 dogfood 发现与直接需求
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mvanhorn/ cli-printing-press --skill printing-press-amend安装后在 Claude Code 中输入/printing-press-amend确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/.gitkeepdirect-input-parsing.mdlibrary-pr-plumbing.mdpii-scrubbing.mdtranscript-parsing.md详细介绍
/printing-press-amend
将一次内部试用会话转化为公共库中已发布 CLI 的 PR。
/printing-press-amend # auto-detect target CLI from session
/printing-press-amend superhuman # explicit short name
/printing-press-amend superhuman-pp-cli
/printing-press-amend "$PRESS_LIBRARY/superhuman"
此技能位于此仓库(机器)中,用于处理公共库中已发布的 CLI。它与 /printing-press-publish(添加新的 CLI)、/printing-press-polish(发布前改进 CLI)以及 /printing-press-retro(反思机器本身)互为同级。这些技能都不涵盖由真实会话中的摩擦问题驱动的发布后 CLI 修改。
此技能产出的成果在语义上是一个“补丁”(在 git/PR 意义上),由公共库的 .printing-press-patches/ 目录跟踪(每个补丁一个文件)。当内联 // PATCH(...) 源代码注释有助于更轻松地在定制站点中搜索时,可将其用作可选导航辅助。斜杠技能名称为 amend,以区别于现有的 cli-printing-press patch 二进制子命令(该命令通过 AST 注入预定义功能——机制不同,意图也不同)。
设置
开始任何操作之前:
# min-binary-version: 4.0.0
# Derive scope first — needed for local build detection
_scope_dir="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"
_scope_dir="$(cd "$_scope_dir" && pwd -P)"
# Prefer local build when running from inside the printing-press repo.
_press_repo=false
if [ -x "$_scope_dir/cli-printing-press" ] && [ -d "$_scope_dir/cmd/cli-printing-press" ]; then
_press_repo=true
export PATH="$_scope_dir:$PATH"
echo "Using local build: $_scope_dir/cli-printing-press"
elif ! command -v cli-printing-press >/dev/null 2>&1; then
if [ -x "$HOME/go/bin/cli-printing-press" ]; then
echo "cli-printing-press found at ~/go/bin/cli-printing-press but not on PATH."
echo "Add GOPATH/bin to your PATH: export PATH=\"\$HOME/go/bin:\$PATH\""
else
echo "cli-printing-press binary not found."
echo "Install with: go install github.com/mvanhorn/cli-printing-press/v4/cmd/cli-printing-press@latest"
fi
return 1 2>/dev/null || exit 1
fi
# Resolve and emit the absolute path the agent must use for every later
# `cli-printing-press` invocation. `export PATH` above only affects this one
# Bash tool call; subsequent calls open a fresh shell and resolve bare
# `cli-printing-press` against the user's default PATH, where a stale global
# can silently shadow the local build. The agent captures this marker and
# substitutes the absolute path into every later invocation.
if [ "$_press_repo" = "true" ]; then
PRINTING_PRESS_BIN="$_scope_dir/cli-printing-press"
else
PRINTING_PRESS_BIN="$(command -v cli-printing-press 2>/dev/null || true)"
fi
if ! command -v go >/dev/null 2>&1; then
echo ""
echo "[setup-error] Go toolchain not found."
echo ""
echo "This Printing Press flow runs Go-based build or validation commands."
echo "Install Go 1.26.10 or newer from https://go.dev/dl/, then verify with:"
echo " go version"
echo "Then re-run this skill."
echo ""
return 1 2>/dev/null || exit 1
fi
echo "PRINTING_PRESS_BIN=$PRINTING_PRESS_BIN"
_pp_semver_lt() {
if [ -z "${PP_SEMVER_A:-}" ] || [ -z "${PP_SEMVER_B:-}" ]; then
echo "[setup-error] semver comparison inputs are missing." >&2
return 2
fi
awk -v a="${PP_SEMVER_A:-}" -v b="${PP_SEMVER_B:-}" 'BEGIN {
split(a, x, "."); split(b, y, ".")
for (i = 1; i <= 3; i++) {
if ((x[i] + 0) < (y[i] + 0)) exit 0
if ((x[i] + 0) > (y[i] + 0)) exit 1
}
exit 1
}'
}
_pp_go_version_norm() {
printf '%s\n' "${PP_GO_VERSION_INPUT:-}" | sed -nE 's/.*go([0-9]+)\.([0-9]+)(\.([0-9]+))?.*/\1.\2.\4/p' | sed -E 's/\.$/.0/'
}
_pp_check_go_currency() {
_pp_go_installed="$(PP_GO_VERSION_INPUT="$(go env GOVERSION 2>/dev/null)" _pp_go_version_norm)"
_pp_go_required="$(PP_GO_VERSION_INPUT="$(go version "$PRINTING_PRESS_BIN" 2>/dev/null)" _pp_go_version_norm)"
PP_SEMVER_A="$_pp_go_installed"
PP_SEMVER_B="$_pp_go_required"
if [ -z "$_pp_go_installed" ] || [ -z "$_pp_go_required" ] || ! _pp_semver_lt; then
return 0
fi
echo ""
if [ "${GOTOOLCHAIN:-auto}" = "local" ]; then
echo "[setup-error] Go $_pp_go_required or newer is required by this cli-printing-press binary (installed: $_pp_go_installed)."
echo "GOTOOLCHAIN=local disables automatic toolchain downloads, so later Go quality gates would fail."
echo "Install Go $_pp_go_required or newer from https://go.dev/dl/, or unset GOTOOLCHAIN."
echo ""
return 1
fi
echo "[go-toolchain-old] Go $_pp_go_required or newer is required by this cli-printing-press binary (installed: $_pp_go_installed)."
echo "PRESS_GO_INSTALLED=$_pp_go_installed"
echo "PRESS_GO_REQUIRED=$_pp_go_required"
echo "Default GOTOOLCHAIN behavior may download the required toolchain during Go commands."
echo ""
return 0
}
_pp_check_go_currency || { return 1 2>/dev/null || exit 1; }
PRESS_BASE="$(basename "$_scope_dir" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9_-]/-/g; s/^-+//; s/-+$//')"
if [ -z "$PRESS_BASE" ]; then
PRESS_BASE="workspace"
fi
PRESS_SCOPE="$PRESS_BASE-$(printf '%s' "$_scope_dir" | shasum -a 256 | cut -c1-8)"
PRESS_HOME="${PRINTING_PRESS_HOME:-$HOME/printing-press}"
PRESS_RUNSTATE="$PRESS_HOME/.runstate/$PRESS_SCOPE"
PRESS_LIBRARY="$PRESS_HOME/library"
PRESS_MANUSCRIPTS="$PRESS_HOME/manuscripts"
PRESS_CURRENT="$PRESS_RUNSTATE/current"
_pp_check_disk_space() {
_pp_disk_warn_kb="${PRINTING_PRESS_DISK_WARN_KB:-3145728}"
_pp_disk_fail_kb="${PRINTING_PRESS_DISK_FAIL_KB:-524288}"
case "$_pp_disk_warn_kb$_pp_disk_fail_kb" in
""|*[!0-9]*) return 0 ;;
esac
_pp_disk_path="$PRESS_HOME"
while [ ! -e "$_pp_disk_path" ] && [ "$_pp_disk_path" != "/" ]; do
_pp_disk_path="$(dirname "$_pp_disk_path")"
done
_pp_disk_avail_kb="$(df -Pk "$_pp_disk_path" 2>/dev/null | awk 'BEGIN {
if ((getline header) <= 0 || (getline record) <= 0) exit
field_count = split(record, fields)
if (field_count >= 4) print fields[4]
}')"
case "$_pp_disk_avail_kb" in
""|*[!0-9]*) return 0 ;;
esac
if [ "$_pp_disk_avail_kb" -lt "$_pp_disk_fail_kb" ]; then
echo ""
echo "[setup-error] Critically low disk space on the Printing Press workspace volume."
echo "PRESS_DISK_PATH=$_pp_disk_path"
echo "PRESS_DISK_AVAIL_KB=$_pp_disk_avail_kb"
echo "PRESS_DISK_FAIL_KB=$_pp_disk_fail_kb"
echo "Free disk space or set PRINTING_PRESS_HOME to a volume with more room, then re-run this skill."
echo ""
return 1
fi
if [ "$_pp_disk_avail_kb" -lt "$_pp_disk_warn_kb" ]; then
echo ""
echo "[low-disk] Printing Press workspace volume is low on free space."
echo "PRESS_DISK_PATH=$_pp_disk_path"
echo "PRESS_DISK_AVAIL_KB=$_pp_disk_avail_kb"
echo "PRESS_DISK_WARN_KB=$_pp_disk_warn_kb"
echo "This flow may need several GiB for generated files, Go build cache, module downloads, or repository clones."
echo ""
fi
}
_pp_check_disk_space || { return 1 2>/dev/null || exit 1; }
mkdir -p "$PRESS_RUNSTATE" "$PRESS_LIBRARY" "$PRESS_MANUSCRIPTS" "$PRESS_CURRENT"
# --- Currency-floor check (standalone, fail-open) ---
# Hard-stop on binaries below the published supported floor so amend does not
# regenerate CLIs with since-fixed bugs. Repo checkouts build from source and
# are exempt. The floor is clamped to <= latest so a bad value cannot brick
# every install. Fetched fresh each run rather than reusing the printing-press
# preflight's TTL cache: amend is low-frequency, so the bounded curl + go-list
# cost is not worth its own cache here.
if [ "$_press_repo" != "true" ] && command -v curl >/dev/null 2>&1; then
_semver_lt() {
if [ -z "${PP_SEMVER_A:-}" ] || [ -z "${PP_SEMVER_B:-}" ]; then
echo "[setup-error] semver comparison inputs are missing." >&2
return 2
fi
awk -v a="${PP_SEMVER_A:-}" -v b="${PP_SEMVER_B:-}" 'BEGIN {
split(a, x, "."); split(b, y, ".")
for (i = 1; i <= 3; i++) {
if ((x[i] + 0) < (y[i] + 0)) exit 0
if ((x[i] + 0) > (y[i] + 0)) exit 1
}
exit 1
}'
}
_floor_installed=$("$PRINTING_PRESS_BIN" version --json 2>/dev/null | sed -nE 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p')
_floor_doc=$(curl -fsSL --max-time 5 \
https://raw.githubusercontent.com/mvanhorn/cli-printing-press/main/supported-versions.txt 2>/dev/null || true)
_floor_min=$(printf '%s\n' "$_floor_doc" | sed -nE 's/^min_supported=//p' | head -n 1)
_floor_reason=$(printf '%s\n' "$_floor_doc" | sed -nE 's/^reason=//p' | head -n 1)
_floor_latest=""
if command -v go >/dev/null 2>&1; then
_floor_latest=$(go list -m -json github.com/mvanhorn/cli-printing-press/v4@latest 2>/dev/null | sed -nE 's/^[[:space:]]*"Version":[[:space:]]*"v?([^"]+)".*/\1/p' | head -n 1)
fi
if [ -n "$_floor_min" ] && [ -n "$_floor_installed" ] && [ -n "$_floor_latest" ] &&
PP_SEMVER_A="$_floor_installed" PP_SEMVER_B="$_floor_min" _semver_lt &&
! PP_SEMVER_A="$_floor_latest" PP_SEMVER_B="$_floor_min" _semver_lt; then
echo ""
echo "[upgrade-required] printing-press v$_floor_min is the minimum supported version (you have v$_floor_installed)"
echo "PRESS_REQUIRED_MIN=$_floor_min"
echo "PRESS_REQUIRED_INSTALLED=$_floor_installed"
echo "PRESS_REQUIRED_REASON=$_floor_reason"
echo ""
fi
fi
运行设置约定后,从标准输出中捕获 PRINTING_PRESS_BIN=<abs-path> 行。此技能中后续每次调用 cli-printing-press ... 时,都必须使用该绝对路径(替换为对应值,而不是字面上的 $PRINTING_PRESS_BIN 标记)——上面的 export PATH 只影响它所运行的单次 Bash 工具调用,因此后续调用会启动新的 shell,此时裸命令 cli-printing-press 会根据用户的默认 PATH 解析,过时的全局版本可能会遮蔽本地构建版本。
如果设置输出了 [go-toolchain-old] 或 [low-disk],请向用户提示该警告并继续,除非设置同时输出了 [setup-error]。[go-toolchain-old] 表示后续 Go 命令可能会下载所需工具链,或在下载受阻时失败;[low-disk] 表示本次运行可能需要数 GiB 空间,用于生成文件、Go 构建缓存、模块下载或仓库克隆。
捕获二进制文件路径后,检查二进制版本兼容性。读取此技能 YAML 前置元数据中的 min-binary-version 字段。运行 <PRINTING_PRESS_BIN> version --json 并从输出中解析版本。按照 semver 规则将其与 min-binary-version 比较。如果已安装的二进制版本低于最低要求,请立即停止并告知用户:“cli-printing-press 二进制版本 vX.Y.Z 低于最低要求 vA.B.C。请运行 go install github.com/mvanhorn/cli-printing-press/v4/cmd/cli-printing-press@latest 进行更新。”
如果设置约定输出了 [upgrade-required] 块,则表示已安装的二进制版本低于已发布的版本下限(PRESS_REQUIRED_MIN)——较旧版本重新生成 CLI 时会带有已修复的问题(PRESS_REQUIRED_REASON)。这是一个不同于 min-binary-version 的硬性门槛:不得使用该二进制版本进行修改或重新生成。通过 AskUserQuestion 提供一键升级选项——是 — 立即升级(运行 go install github.com/mvanhorn/cli-printing-press/v4/cmd/cli-printing-press@latest,重新捕获 PRINTING_PRESS_BIN,然后继续)或 取消(停止本次运行)。不得跳过并继续;低于版本下限时,只能升级或中止。如果升级命令失败,请说明情况并停止。
阶段 0 — 输入模式检测
此技能接受两种用于后续补丁所用发现事项列表的输入来源:Claude Code 会话记录(内部试用模式,当前行为)和斜杠命令提示词中的用户自定义需求(直接输入模式,v0.2 中新增)。两种模式仅在阶段 1 存在差异;从阶段 2 开始与模式无关,使用形状完全相同的类型化发现事项列表。
在阶段 1 运行前确定模式。
检测标准
阅读对话上下文中的斜杠命令提示词正文和紧接着的调用轮次。分为以下四种情况:
-
MODE=direct— 提示词包含具体的 CLI 名称,且至少有一种直接输入信号:- 针对 CLI 的动作动词:
rename、add、remove、fix、sniff、discover - 用户希望添加的明确 URL(例如:
https://example.com/feed/x) - 列举的订阅源、命令、端点或功能
- 类似“这些想法”“这些功能”“包含以下内容”的措辞
- 针对 CLI 的动作动词:
-
MODE=dogfood— 提示词为空,或提到某个 CLI 但没有任何要求(“修改 superhuman CLI”),或明确提及当前会话(“我刚才试用的内容”“本次会话中的阻碍”“根据我今天的会话”) -
MODE=both— 提示词明确同时提及会话和具体要求(“我试用了本次会话,也想添加功能 X”“除了我遇到的阻碍,请再添加命令 Y”) -
有歧义 — 只出现一种信号(提到 CLI 但没有动词,或有动词但没有指定目标 CLI,或提出的要求可能是阻碍反馈,也可能是新增需求)。通过
AskUserQuestion询问用户:"有两种方式可以为此次修改获取发现结果。哪种方式适合?
- 挖掘当前会话记录(dogfood 模式)
- 使用我刚才输入的要求(direct-input 模式)
- 两者都用——结合会话中的阻碍和我的要求"
如果完全没有斜杠命令提示词,则默认使用 MODE=dogfood。这样可保留标准体验——仅输入 /printing-press-amend 时,仍与 v0.1 中的行为完全一致。
持久化模式
将解析出的模式写入 $PRESS_RUNSTATE/current/mode.txt,供后续阶段(以及恢复运行时)读取:
echo "$MODE" > "$PRESS_RUNSTATE/current/mode.txt"
输出
阶段 0 向阶段 1 输出一行:
mode: <dogfood|direct|both>
阶段 1 根据此值进行分支:dogfood 发现结果通过 ### 1a 处理,direct-input 发现结果通过 ### 1b 处理,组合运行则依次执行这两个小节。从阶段 2 开始完全忽略该模式——发现结果列表就是约定。
阶段 1 — 捕获
此阶段会生成类型化的发现结果列表。所有模式下的列表结构相同:每条发现结果都包含 id、kind、category、classification(bug 或 feature)、evidence、target_cli、rationale 和 provenance(dogfood 对应 transcript,direct 对应 user-ask,sniff 衍生结果对应 sniff)。阶段 2 将原样使用该列表。
当 MODE=dogfood 时,仅运行 ### 1a。当 MODE=direct 时,仅运行 ### 1b。当 MODE=both 时,先运行 ### 1a,再运行 ### 1b,并合并两个发现结果列表,确保 ID 不重复(1b 从 1a 结束的编号继续)。
1a. Dogfood 模式(MODE=dogfood)
完整流程请阅读 references/transcript-parsing.md。本小节的工作概述:
-
解析当前活动会话的 transcript 文件 — 根据当前工作目录推导
<project-dir-slug>,按 mtime 列出~/.claude/projects/<slug>/*.jsonl,选择最近修改的文件。读取前,务必通过AskUserQuestion向用户确认解析出的路径——选错文件会导致从错误的会话中摄取摩擦信号。 -
遍历 transcript 并提取摩擦信号 — 非零退出码、错误消息、手写 API 请求负载(例如本应使用 CLI 命令,却直接通过
curlPOST)、失败后重试模式、Agent 评论(如“X 不存在”/“X 返回 400”)、对缺少标志的提及、静默返回 null、身份验证方面的困惑。每个信号都包含时间戳、类别、原文证据以及它引用的<slug>-pp-cli。 -
将每个信号分类为 bug 或 feature,并提供一句话理由。Bug = CLI 行为有误;feature = CLI 缺少相应行为。分类是 Agent 的最佳判断;用户会在 U4 范围检查点确认或修改。
-
自动检测目标 CLI — 统计信号中每个
<slug>-pp-cli的出现次数,建议出现次数最多的 CLI 作为默认选项。通过AskUserQuestion确认(只有一个 CLI:简单的是/否确认;多个 CLI 次数接近:从列表中选择)。如果用户传入了明确的<cli-name-or-path>参数,则跳过自动检测。 -
解析目标路径并确定发布状态 — 接受短名称、全名或绝对路径(参见 R4)。将输入规范化为纯 CLI slug,然后通过在公共库中查找该 slug 来确定发布状态(本地有克隆时查找
~/printing-press-library/library/*/<slug>,否则通过gh api查询相同路径)。不要根据本地工作副本的 git 远程仓库推断发布状态,也不要将缺少$PRESS_LIBRARY/<slug>工作副本视为未发布。如果在公共库中找到该 slug,则记录target_category、published_status: published,并通过托管克隆的上游 PR 流程处理本次运行。只有当公共库中不存在该 slug 时,才使用published_status: local-only。U7 的 PR 创建阶段需要此类别;在此处记录可避免重新推导。
1a 输出的每个发现都带有 provenance: transcript。输出将作为结构化发现列表流入 Phase 2,格式详见 references/transcript-parsing.md。
1b. 直接输入模式(MODE=direct)
完整流程请参阅 references/direct-input-parsing.md(v0.2 引入)。本小节的功能概要:
-
读取斜杠命令提示词正文,以及触发该技能的紧接着的 Agent 消息轮次——其中包含用户的原话请求(例如:“将 Digg 1000 重命名为 Digg,添加以下四个 Feed:……,探查新端点”)。没有对话记录可供确认;跳过 1a 中使用的 U1 对话记录路径模态框。
-
确定目标 CLI——遵循与 1a 步骤 4-5 相同的名称解析规则(依据 R4),但 CLI 通常已在提示词中命名。通过正则表达式提取(
<slug>-pp-cli或“the CLI”);如果没有,则询问用户。 -
使用
references/direct-input-parsing.md中的规则,将请求解析为结构化发现项。每个请求对应一个带有类型化kind字段的发现项:rename— “rename X to Y” / “call it X instead of Y” →classification: featureadd-command— “add command X” / “add subcommand X” →classification: featureadd-feed— “add feed ” / 用户希望添加的 URL 列表(每个 URL 对应一个发现项)→classification: featureadd-endpoint— “add endpoint ” / 明确的 API 路径 →classification: featurefix-bug— “fix X” / “X is broken” / “X returns null” →classification: bugsniff— “sniff for new APIs” / “find new endpoints” / “discover more” → 转至### 1b.i中的探查子程序
-
每个发现项都会在
evidence中记录用户的原话,以便 U4 范围确认模态框向用户展示他们实际写下的内容。 -
边缘情况——涉及多个 CLI 的请求拆分为两次独立运行(超出 v0.2 的范围;请用户选择一个)。含义模糊的动词(例如未说明具体内容的
update X)会触发AskUserQuestion澄清,而不是进行猜测。
1b 生成的每个发现项都带有 provenance: user-ask(由探查子程序生成的发现项则为 provenance: sniff)。输出将传入第 2 阶段,采用与 1a 相同的结构化发现项列表格式。
1b.i. 嗅探子程序
当解析规则将任何 1b 请求标记为 kind: sniff 时触发(例如“嗅探新 API”“查找新端点”“在 中发现更多端点”等表述)。嗅探需要在每次运行中选择启用——除非用户明确提出,否则绝不调用。如果没有嗅探发现请求,则完全跳过此子程序。
步骤 1 — 确定目标来源 URL。 读取目标 CLI 已发布的清单 ~/printing-press-library/library/<category>/<slug>/.printing-press.json,并提取 source_url(若无,则使用 spec_url)。类别已在 1b 步骤 2 中确定。
如果这两个字段都未设置,请直接询问用户:
“嗅探需要目标 URL——请粘贴要嗅探的来源网站,或者跳过本次运行的嗅探请求?”
如果用户跳过,则从活动列表中移除该嗅探请求,并继续处理其他 1b 发现项。如果用户粘贴了 URL,则在步骤 2–3 中使用该 URL。
步骤 2 — 先运行 crowd-sniff(快速,无需浏览器)。 将 <PRINTING_PRESS_BIN> 替换为设置时记录的绝对路径:
<PRINTING_PRESS_BIN> crowd-sniff --site "$SOURCE_URL" --json > /tmp/amend-sniff-crowd.json
crowd_exit=$?
crowd-sniff 会查询 npm SDK 和 GitHub 代码搜索,以发现候选端点——无需浏览器。通常运行时间不到一分钟。
步骤 3 — 可选的 browser-sniff(仅当用户选择深入嗅探时)。 当用户的请求明确提到基于浏览器的发现(“使用浏览器嗅探”“进行深度嗅探”),且已有捕获的 HAR 时,运行:
<PRINTING_PRESS_BIN> browser-sniff --har "$HAR_PATH" --json > /tmp/amend-sniff-browser.json
browser_exit=$?
此技能在 v0.2 中不会协调 HAR 捕获——捕获由用户驱动(用户在 Chrome 中打开来源网站、导出 HAR,并将其提供给技能),否则会附注说明并跳过深度嗅探。v0.3 可能会扩展此技能,通过 claude-in-chrome MCP 驱动捕获;这不在 v0.2 的范围内。
步骤 4 — 将发现结果转换为发现项。 对于嗅探输出中的每个候选端点,将一个发现项追加到 1b 发现项列表中:
id: F<n>(解析出的请求之后的下一个可用编号)kind: add-endpointclassification: featureevidence: "通过 crowd-sniff 发现:<endpoint-path>"(适用时使用browser-sniff)target_cli: <slug>-pp-clirationale: <嗅探输出中的单行摘要(若有),否则为 "嗅探候选项,待用户确认">provenance: sniff
默认在第 3 阶段将这些项目划为第 3 层级(优化/架构)——用户审核后,可将个别条目提升至第 2 层级(如果优先级较高)。
步骤 5 — 降级处理路径。
| 条件 | 行为 |
|---|---|
.printing-press.json 缺少 source_url,且用户在被询问时选择跳过 | 移除嗅探请求;继续处理其他 1b 发现项;记录“已跳过嗅探——没有来源 URL”。 |
crowd-sniff 以非零状态退出 | 记录错误;跳过嗅探发现项;继续处理其他 1b 发现项。不要中止修改运行。 |
crowd-sniff 返回零个候选端点 | 在延后发现项列表中添加一条记录(“已运行嗅探,未发现新端点”),而不是不添加任何内容——为用户保留记录。 |
| 用户请求 Browser-sniff,但没有可用的 HAR | 记录日志;仅使用 crowd-sniff 结果。 |
步骤 6 — 向用户显示来源信息。 在第 3 阶段的范围确认弹窗中,来源于嗅探的发现项会按 (sniff) 来源标签进行视觉分组,方便用户决定是否整组保留,例如:
Tier 3 — Polish / architecture (5)
F8 add-endpoint /v1/feeds/stars (sniff)
F9 add-endpoint /v1/feeds/new (sniff)
F10 add-endpoint /v1/feeds/activity (sniff)
...
第 2 阶段 — 检查点前防护
在用户看到范围菜单之前,会运行两项防护。任一项都可能抑制发现项或中止运行。
2a. PR 交叉引用(抑制重复提案)
对于 Phase 1 中的每项发现,请在 mvanhorn/printing-press-library 中搜索未关闭和近期已合并的 PR,查找匹配项。重复检测标准(按优先级排序):(1)目标 CLI 的目录路径与 PR 的已更改文件列表有重叠;(2)发现类别和理由中的关键词与 PR 标题或正文匹配。
# Replace <PRINTING_PRESS_BIN> use with the absolute path captured at setup.
# This phase uses gh, not the press binary.
# Open PRs touching this CLI
gh pr list --repo mvanhorn/printing-press-library \
--search "in:title,body <slug>" --state open --limit 20 \
--json number,title,state,headRefName,files
# Recently merged PRs (last 90 days) touching this CLI.
# Compute "90 days ago" portably — `date -v-90d` is BSD/macOS only, `date -d`
# is GNU/Linux only. Try GNU first, fall back to BSD, then to python3. If
# every form fails, abort with an explicit error rather than letting the
# dedup guard silently drop out with an empty `merged:>` qualifier.
ninety_days_ago=$(date -u -d '90 days ago' +%Y-%m-%d 2>/dev/null \
|| date -u -v-90d +%Y-%m-%d 2>/dev/null \
|| python3 -c 'import datetime; print((datetime.datetime.now(datetime.UTC).date() - datetime.timedelta(days=90)).isoformat())' 2>/dev/null)
if [ -z "$ninety_days_ago" ]; then
echo "ERROR: cannot compute 90-days-ago date — no GNU date, BSD date, or python3 available."
exit 1
fi
gh pr list --repo mvanhorn/printing-press-library \
--search "in:title,body <slug> merged:>$ninety_days_ago" \
--state merged --limit 20 \
--json number,title,state,mergedAt,headRefName,files
对于存在可能重复匹配项的每项发现,内联显示:
“发现
F<n>(<category>)可能已由 PR # —<title>(,)解决。要跳过这项发现吗?”
用户选项:跳过(移至 deferred)、保留,或“查看 PR #”(打开 gh pr view <num> --repo mvanhorn/printing-press-library --web)。对于明确已合并的匹配项,默认选择“跳过”;对于未关闭的 PR,默认选择“保留”(用户可能想将内容添加到正在处理的 PR,而不是新开一个 PR)。
此检查旨在避免 2026-05-15 dogfood 中出现的典型失败情况:某个 Printing Press CLI 已有类似 PR 在几小时前于另一个 CLI 上合并,却仍提议添加自动刷新功能。误跳过的代价较低(用户可在 U4 通过自定义选择重新添加);漏掉重复项的代价则是 PR 被拒绝并耗费审核者时间。
2b. 过期二进制检查(如果 dogfood 使用的二进制版本落后于已发布版本,则中止)
读取公共库中目标 CLI 的 .printing-press.json,找到已发布版本。将其与本地打印的 CLI 二进制报告的版本进行比较。
# Read published version (managed clone if available, else gh api)
if [ -f "$HOME/printing-press-library/library/<category>/<slug>/.printing-press.json" ]; then
published=$(jq -r '.version // empty' "$HOME/printing-press-library/library/<category>/<slug>/.printing-press.json")
else
published=$(gh api repos/mvanhorn/printing-press-library/contents/library/<category>/<slug>/.printing-press.json \
--jq '.content' | base64 -d | jq -r '.version // empty')
fi
# Read local binary version (if installed; the user dogfooded with this binary)
local_ver=$(<slug>-pp-cli version --json 2>/dev/null | jq -r '.version // empty' || echo "")
如果 local_ver 早于 published(按 semver 比较),则正常中止:
“你用于 dogfood 的
<slug>-pp-cli二进制版本为 v<local_ver>,但库中已发布的版本为 v<published>。你遇到的问题可能已在已发布版本中修复。请运行:go install github.com/mvanhorn/<slug>-pp-cli@latest……然后重新进行 dogfood,再运行
/printing-press-amend。本次运行已中止。”
边缘情况:如果 .printing-press.json 缺失或没有 version 字段,则跳过过期检查并附上说明。如果 CLI 仅在本地使用(尚未发布),则跳过检查。
输出
Phase 2 将(可能经过精简的)发现列表传递给 Phase 3:
findings_kept:
- <finding from Phase 1>
findings_suppressed:
- id: F3
reason: "Duplicate of PR #571 (merged 2026-05-13)"
target_binary_check: { local: "1.0.0", published: "1.0.0", status: "current" }
published_status: published
Phase 3 — 范围确认检查点(用户参与环节 #1)
这是两个用户检查点中的第一个。到目前为止,所有操作都是只读探索;此检查点将确定范围。
为剩余发现划分层级
将发现分为三个层级:
- Tier 1 — Bug — 所有
classification: bug的发现。CLI 行为有误;修复可恢复正确性。 - Tier 2 — 解决当前会话痛点的缺失功能 — 与用户在会话期间实际编写的临时变通方案相关的
classification: feature发现(即用户现在明确需要该功能,而非仅仅认为它在理论上有用)。 - Tier 3 — 润色 / 架构 — 其余
classification: feature发现;这些属于可选改进或架构优化,且会话期间没有对应的临时变通方案。
在提问前内联显示分层后的列表:
Friction found for <slug>-pp-cli (12 signals, 2 suppressed as duplicates):
Tier 1 — Bugs (4)
F1 drafts list returns 400 silently
F4 messages query returns data: null
F7 refresh-token expiry not surfaced in errors
F11 ai --query returns code 500
Tier 2 — Missing features that solve session pain (4)
F2 no `drafts new` command (user hand-rolled writeMessage payload)
F5 no `--type sent` for threads list (user worked around with messages query)
F8 no `--remind-in <duration>` flag for send (user manually re-flagged drafts)
F10 no `bootstrap` to local SQLite (user did 50+ thread API calls)
Tier 3 — Polish / architecture (2)
F12 `auth status` doesn't link to `auth login` when refresh expired
F13 doctor doesn't surface stale-binary warning vs. published version
通过 AskUserQuestion 选择范围
Which scope should this patch cover?
1. Bugs only (Tier 1) — 4 findings
2. Bugs + immediate features (Tier 1 + Tier 2) — 8 findings
3. All tiers (Tier 1 + Tier 2 + Tier 3) — 10 findings
4. Custom selection — pick individual findings
AskUserQuestion 选项必须自包含(每个标签都必须能独立说明其作用,不依赖描述文本——有些 harness 会隐藏描述)。
对于自定义选择路径:显示一个多选列表,每项包含发现的 id、类别和一行理由;继续之前,先确认用户勾选的子集。
持久化未纳入范围的发现
对于每项未纳入已确认范围的发现,将其追加到以下路径的延后列表 Markdown 文件中:
$PRESS_MANUSCRIPTS/<api-slug>/<run-id>/proofs/<timestamp>-amend-<cli-name>-deferred.md
<run-id> 是本次修订运行的全新时间戳 ID(例如 amend-2026-05-15T1432)。将延后文件格式设为 YAML 前置元数据 + 按发现分节的 Markdown 正文,以便未来在同一 CLI 上运行 /printing-press-amend 时重新展示这些条目。
---
date: 2026-05-15
target_cli: superhuman-pp-cli
amend_run_id: amend-2026-05-15T1432
deferred_count: 2
---
然后,为每项延后的发现建立一个分节,包含:id、category、classification、rationale、evidence、reason-deferred(例如「用户仅选择了 Tier 1」)以及 still_relevant: unknown。
后续运行 /printing-press-amend 时,Phase 3 应在 $PRESS_MANUSCRIPTS/<api-slug>/ 中查找最新的 *-deferred.md,并询问用户是否要将仍与本次运行范围相关的条目纳入本次运行。(实现说明:此重新展示逻辑将在 v0.1 中发布;不得静默地重新加入——务必先展示并确认。)
边界情况:无事可做
如果 Phase 2 抑制了所有发现(全部为重复项),Phase 3 应清楚地报告结果并退出,不打开菜单:
“本次会话中的所有发现均已由现有 PR 处理。未发现新的补丁。”
输出
Phase 3 向 Phase 4 输出:
published_status: published
scope_tier: bugs+features # or bugs|all|custom
findings_active: [...] # the user-confirmed subset
findings_deferred_path: <path> # where the deferred file landed
Phase 4 — 规划 + 执行 + 验证(自主运行)
此阶段在检查点 1 和 2 之间无人值守运行。用户不会看到逐项修复的详情;他们将在 Phase 6 的 PR 草稿检查点审阅最终差异。
步骤 1 — 设置受管克隆
根据计划中的实施前决策:此技能直接操作 mvanhorn/printing-press-library 的受管克隆,而不是 $PRESS_LIBRARY/<slug>/。受管克隆位于:
$PRESS_HOME/.publish-repo-$PRESS_SCOPE
这是 /printing-press-publish 使用的同一克隆(该技能的步骤 5)。复用它:
PUBLISH_REPO_DIR="$PRESS_HOME/.publish-repo-$PRESS_SCOPE"
PUBLISH_CONFIG="$PRESS_HOME/.publish-config-$PRESS_SCOPE.json"
if [ ! -d "$PUBLISH_REPO_DIR/.git" ]; then
# First-time setup: see references/library-pr-plumbing.md for the full
# detection (push-vs-fork access via gh api .../permissions.push,
# SSH-vs-HTTPS protocol detection, scoped-clone cleanup loop).
echo "Managed clone not present — bootstrapping..."
# ... (see library-pr-plumbing.md)
else
# Refresh from upstream. -f on checkout discards any local edits left behind
# by a prior run that aborted between Phase 4's edits and Phase 7's commit —
# without -f, those uncommitted changes block the checkout and the subsequent
# reset --hard never runs.
cd "$PUBLISH_REPO_DIR"
git fetch upstream main
git checkout -f main
git reset --hard upstream/main
fi
CLI 在受管克隆中的目录为 $PUBLISH_REPO_DIR/library/<category>/<slug>/。类别已在 Phase 1 中确定(也可通过 find "$PUBLISH_REPO_DIR/library" -maxdepth 2 -name "<slug>" -type d 查找)。
CLI_DIR="$PUBLISH_REPO_DIR/library/<category>/<slug>"
此阶段的所有编辑都在 $CLI_DIR 内进行。切勿触碰 $PRESS_LIBRARY/<slug>/——那是另一个工作副本,编辑它不会反映到 PR 中。
步骤 2 — 编写本次运行的计划文档
在编辑代码之前,将计划写入以下路径的 Markdown 文件:
$PRESS_MANUSCRIPTS/<slug>/<run-id>/proofs/<timestamp>-amend-<cli-name>.md
同时复制到 /tmp/printing-press/amend/,以便快速查阅。计划文档包含:
- Frontmatter:
date、target_cli、amend_run_id、scope_tier、findings_count - 每项活跃发现一个分节:id、category、classification、rationale、目标文件(
$CLI_DIR/...路径)、预期行为变更,以及该发现的测试场景 - 风险和发现之间的依赖关系(如有)
计划文档应体现决策结构,而非执行结构——实施时的排序将在步骤 3 中确定。
步骤 3 — 执行计划(遵循补丁约定)
按依赖顺序处理每项发现:
-
编辑
$CLI_DIR/下的目标文件。遵守 AGENTS.md 中禁止重新实现的规则(不得手写响应构造器;新命令必须调用真实端点,或通过// pp:client-call/// pp:novel-static-reference例外标记从本地存储读取,但仅限确有正当理由的情况)。 -
可选:在修改位置添加
// PATCH(<short reason>)源代码注释,便于后续 Agent 快速找到自定义内容。格式示例:// PATCH(amend-2026-05-15: surface refresh-token expiry to user) — was silently retrying func (c *Client) Refresh(ctx context.Context) error { ... } -
创建一个补丁文件
$CLI_DIR/.printing-press-patches/<id>.json(文件名 = 补丁id)。每个文件都是一个完整独立的补丁对象,每个补丁单独一个文件,这样并发的 amend PR 不会在补丁元数据上发生冲突:{ "schema_version": 2, "id": "<api-slug>-refresh-token-expiry", "applied_at": "<YYYY-MM-DD>", "base_run_id": "<copy from .printing-press.json>", "base_printing_press_version": "<copy from .printing-press.json>", "summary": "fix(superhuman): surface refresh-token expiry; add drafts new + --type sent", "reason": "The generated CLI hid an expired refresh token and omitted a workflow flag needed by the live API.", "files": [ "internal/auth/refresh.go", "internal/cli/drafts.go", "internal/cli/threads.go" ], "call_sites": ["printRefreshTokenExpiry("], "validated_outcome": "publish validate passed; focused drafts and refresh-token checks pass", "findings_addressed": ["F1", "F2", "F5", "F7"] }如果 CLI 仍包含旧版的单数组
.printing-press-patches.json(来自尚未规范化的旧版印刷构建),仍要将条目写入新的.printing-press-patches/<id>.json文件;公共库的 normalize-patches 工作流会在合并后合并这两者。不要追加到旧数组中。如果添加了
// PATCH(...)注释,也可以包含patch_count字段,方便审阅者查看。未添加源代码注释时,不要添加patch_count。对于具有未来替代路径的临时补丁,请在同一补丁条目中包含上游交接字段:
{ "deferred_to_upstream": [ { "feature": "Generator or upstream API capability this printed-CLI patch should eventually supersede", "reason": "Why the local patch is intentionally temporary or API-specific." } ], "upstream_issue": "https://github.com/mvanhorn/cli-printing-press/issues/<n>" }代码级自定义必须创建
.printing-press-patches/<id>.json补丁文件。行内// PATCH(...)源代码注释是可选的导航辅助;公共库验证器不再强制要求标记与注释成对出现。如果自定义内容中起关键作用的调用可能消失,但文件仍然存在,请在call_sites或markers(或marker)中声明该调用,并确保这些检索标记位于files[]中,以便其消失时 regen 和publish validate能够 fail closed。每个检索标记都必须有对应的files[];这些文件之外残留的匹配项不计入。仅当补丁有意保留未来替代路径时,才使用
deferred_to_upstream:目前缺少公共 API 端点;命令依赖非官方主机或备用身份验证来源;实时响应结构与生成器假设不符;或者 Printing Press 学会该模式后便不再需要此修复。在这些情况下,先搜索mvanhorn/cli-printing-press的 issues;复用匹配的 issue,或在提交库 PR 前新建一个 issue,然后将该 URL 设为upstream_issue。不要只在 PR 正文中说明对机器层面或 API 发布流程的依赖。 -
机器层面与印刷版 CLI 的判断(依据 AGENTS.md):如果某项发现的修复适用于所有印刷版 CLI(例如“生成器应为任何 threads list 命令生成
--type sent”),请将其作为边界情况提出:“发现 F5(缺少
--type sent)看起来属于机器层面修复——生成器模板internal/generator/templates/threads.go.tmpl应为每个具有此端点结构的 CLI 生成该参数,而不只是<slug>-pp-cli。是延后到/printing-press-retro跟进处理,还是仅针对 CLI 修复?”若决定延后,将其归入延后列表并标记为
machine-level。若因印刷版 CLI 现在需要局部修复而决定保留,并且补丁仍保留未来替代路径,则须在开启库 PR 前创建或复用上游 Printing Press issue,将 issue URL 添加到补丁的.printing-press-patches/<id>.json中,并添加一项deferred_to_upstream,说明应取代本地补丁的机器层面或上游 API 条件。
步骤 4 — 验证
所有编辑完成后,运行整合验证器(将 <PRINTING_PRESS_BIN> 替换为设置时记录的绝对路径):
<PRINTING_PRESS_BIN> publish validate --dir "$CLI_DIR" --json > /tmp/amend-validate.json
exit_code=$?
publish validate 会运行 manifest、phase5、govulncheck(限定为此 CLI 的模块)、go vet、go build、--help 和 --version。退出码为 0 表示验证通过。
步骤 5 — 失败时重试(最多 3 轮)
如果 publish validate 报告失败,请从 JSON 中解析错误类别,尝试有针对性的修复,然后重新运行 validate。总共最多重试 3 轮。第 3 轮后:
# Save the in-progress plan + diff to a holding location
HELD_PATH="$PRESS_MANUSCRIPTS/<slug>/<run-id>/proofs/<timestamp>-amend-<cli-name>-INCOMPLETE.md"
git -C "$PUBLISH_REPO_DIR" diff > "${HELD_PATH%.md}.diff"
cp "$PLAN_PATH" "$HELD_PATH"
将最终错误日志展示给用户,不要自动打开 PR,然后退出。用户可以通过再次调用此技能来继续(Phase 1 会检测到暂存的计划,并提供继续选项)。
步骤 6 — 检查补丁清单
此 amend 运行必须至少记录一个补丁——.printing-press-patches/ 下的一个 <id>.json(目录布局);或者,仅当 CLI 尚未规范化时,旧版 .printing-press-patches.json 中的 patches[] 非空。
dir_count=0
if [ -d "$CLI_DIR/.printing-press-patches" ]; then
dir_count=$(find "$CLI_DIR/.printing-press-patches" -maxdepth 1 -name '*.json' ! -name '_meta.json' | wc -l | tr -d ' ')
fi
legacy_count=0
if [ -f "$CLI_DIR/.printing-press-patches.json" ]; then
legacy_count=$(jq '(.patches // []) | length' "$CLI_DIR/.printing-press-patches.json")
fi
if [ "$dir_count" -eq 0 ] && [ "$legacy_count" -eq 0 ]; then
echo "ERROR: this amend run must record at least one patch under .printing-press-patches/ (or the legacy .printing-press-patches.json)."
exit 1
fi
补丁清单缺失或为空 → 请先在本地修复,再继续。
步骤 6 — 文档更新检查点
在 Phase 4 输出通过结果之前,检查已确认的发现和最终 diff,查看所有新增、重命名或更改的面向用户的命令、标志、工作流、运行模式或 MCP 可见操作。每项此类更改都必须在同一个公共库 PR 中附带文档:
- 在
SKILL.md和README.md中新增或更新 cookbook 配方。 - 新增或更新对应的 Unique Features / Unique Capabilities 条目,使生成的文档和面向 Agent 的摘要都能说明更改后的工作流。
- 确保示例准确:命令、标志、位置参数和输出片段必须与
$CLI_DIR中现有的代码一致。 - 如果存在该路径,请从公共库检出目录运行
python3 .github/scripts/verify-skill/verify_skill.py --dir "$CLI_DIR";否则运行检出目录中可用的打包版验证器等效命令,并记录该命令。
如果缺少任何必需的文档修改或验证器结果,请停止并提供阻塞检查清单。该清单需列出相关命令以及缺失的 README/SKILL/Unique Features 内容。清单清空前,不要进入 PR 草稿检查点。如果 amend 仅修复内部问题,没有面向用户的行为变更,请在 Phase 4 输出中记录 documentation_checkpoint: no-user-facing-doc-change。
输出
Phase 4 向 Phase 5 输出:
plan_doc_path: <path>
managed_clone_dir: <path>
cli_dir_in_clone: <path>
findings_addressed: [...]
build_status: PASS|FAIL
test_status: PASS|FAIL
dogfood_status: PASS|FAIL|N/A # PASS|FAIL when MODE=dogfood (or "both"); always N/A when MODE=direct
validate_iterations: <n>
patch_entry_count: <n>
documentation_checkpoint: PASS|no-user-facing-doc-change
每种模式的 dogfood_status。 当 MODE=dogfood 时,该值反映使用基于转录内容的发现进行的 dogfood 验证步骤的结果(如果运行产生了干净的修复,则为 PASS;如果发现了回归,则为 FAIL)。当 MODE=direct 时,没有可用于 dogfood 验证的转录内容——设置 dogfood_status=N/A。当 MODE=both 时,仍需针对发现中基于转录内容的部分运行 dogfood 验证;相应地设置 PASS/FAIL。最迟必须在 Phase 4 结束时设置此默认值,以确保 Phase 7 的 PR 正文和 Phase 8 的 RESULT 区块不会输出空值。
阶段 5 — PII 清理
阅读 references/pii-scrubbing.md,了解完整流程。概要如下:
清理分为三个层次,每层都在临时暂存副本上操作(不会处理用户的会话记录或正在编写的源代码):
- 凭证 — 复用
skills/printing-press-retro/references/secret-scrubbing.md中的正则表达式模式(Stripe、GitHub PAT、Bearer 令牌、AWS 密钥等),并针对从会话记录中引用的手工编写 API 负载中的Authorization/Cookie/X-API-Key标头,添加 amend 专用规则。 - 实体 — 将公司、人员和电子邮件与用户维护的停用列表
~/.printing-press/amend-config.yaml匹配。替换为保留形态的标记(<company-1>、<person-1>、<email-1>),并在所有产物中保持标识一致,以便审阅者仍能理解意图。 - 首次提及防护 — 检查每个产物,找出看起来像专有名词、首字母大写且未列入停用列表的词组。在阶段 6 显示 PR 草稿前,将其直接展示给用户:“发现
Esper Labs(计划文档中出现 3 次,PR 正文中出现 1 次)——要添加到停用列表并清理,还是接受?”
目标按优先级排序:PR 标题/正文草稿、单次运行计划文档、延后处理的问题列表,以及新添加到 $CLI_DIR 的任何测试固件或示例输出。清理每个目标前,先复制为 <path>.pre-pii-scrub,以便用户审查更改内容。
纵深防御:检查 $CLI_DIR 中的每个 *.go 文件是否包含停用列表中的内容。若发现任何匹配项,则视为阻塞问题——暂停并要求用户在进入阶段 6 前解决。Agent 不应在 Go 源代码中引入 PII;此检查用于捕获 Agent 的错误。
创建停用列表:如果 ~/.printing-press/amend-config.yaml 不存在,此技能会创建默认文件,其中包含初始列表和格式说明注释。验证文件模式(对所有者以外用户可写时发出警告;文件由非当前用户拥有时中止)。
清理报告写入 $PRESS_MANUSCRIPTS/<slug>/<run-id>/scrub-report.json(不提交;供用户审查)。阶段结束时向用户显示的摘要:“已在 Y 个产物中替换 X 个标记。”
阶段 6 — PR 草稿审查检查点(用户参与点 #2)
这是第二个也是最后一个用户检查点。之后的所有操作均在无人值守的情况下进行(推送 + 打开 PR + 添加标签 + RESULT 块)。在执行任何 gh 命令前,向用户展示即将发布的所有内容。
在此次审查中加入阶段 4 的文档检查结果,确保未记录的面向用户的更改不会混入 PR。
组装草稿
在内存中撰写 PR 标题、正文、标签和差异摘要。标题格式遵循公共库约定:
- 当范围仅包含错误修复时,使用
fix(<api-slug>): <one-line summary> - 当范围包含功能时,使用
feat(<api-slug>): <one-line summary> - 当范围混合时(功能的契约变更更大),使用
feat(<api-slug>): <one-line summary>
<one-line summary> 由最重要的 1–3 项发现组成(例如:surface refresh-token expiry; add drafts new + --type sent)。
PR 正文部分(依据源 R27):
- 摘要 — 用 1–3 句话说明用户痛点和修复方案
- 发现 — 包含 ID、类别、类型(错误/功能)、理由的表格
- 变更 —
git diff --stat upstream/main..HEAD的输出 - 验证 — 第 4 阶段的构建/测试/dogfood/验证状态,以及文档检查点结果
- 证据 — 指向本次运行计划文档和 PR 的 HEAD SHA 对应的
.printing-press-patches/目录的完整 GitHub URL(在推送后获取,以免链接返回 404) - 如果在
library-pr-plumbing.md的第 6 步找到匹配的问题,添加Closes #N页脚
标签:始终建议使用 comp:<api-slug>;仅错误修复时使用 priority:P1,错误修复加功能时使用 priority:P2,覆盖所有层级时使用 priority:P3。将标签应用到上游库 PR 之前,先用 gh label list --repo mvanhorn/printing-press-library --json name --jq '.[].name' 查询目标仓库,并仅应用仓库中存在的标签。如果缺少建议的标签,则跳过,并在 PR 正文或最终运行日志中注明;不要让缺少单 CLI 或优先级标签导致 amend 流程失败。
gh 执行前先展示
向用户展示标题、正文、标签列表和 git diff --stat。如果第 5 阶段发现了用户确认属于合法内容、但未识别的首字母大写短语,现在要在对应句子中重新展示这些短语:
“提醒:PR 正文中提到了
<phrase>(你在第 5 阶段已确认其合法)。请在创建 PR 前确认。”
AskUserQuestion:打开 / 编辑 / 暂缓 / 中止
PR draft ready. What now?
1. Open PR as drafted (recommended)
2. Edit then open — drop into an interactive review of title/body
3. Hold — save plan + diff for later resume; nothing pushed
4. Abort — discard everything, no record kept
对于编辑后打开:将标题和正文分别作为可编辑区块呈现,接受用户修改,重新展示完整草稿,并在继续前确认。
对于暂缓:将计划和差异保存到 $PRESS_MANUSCRIPTS/<slug>/<run-id>/proofs/<timestamp>-amend-<cli-name>-HELD.md 和 ${path%.md}.diff。输出一个 RESULT 区块,包含 status: held 和恢复路径。之后运行 /printing-press-amend 时,可以检测到暂缓文件并询问是否恢复。
对于中止:输出简短确认。U5 中的计划文档仍会保留(在 frontmatter 中写入 status: aborted),以便用户留存发现记录,但不会保留其他内容。托管克隆会在下次运行时重置。
第 7 阶段 — 创建 PR(自主执行)
如果用户选择打开或编辑后打开,则运行 references/library-pr-plumbing.md 的第 5–7 步:
- 第 5 步 —
git add "$CLI_DIR"+ 使用约定式提交信息和发现列表进行提交 - 第 6 步 — 搜索与这些发现匹配的现有问题;关联该问题或新建问题;尽力自行分配
- 第 7 步 — 推送分支(推送还是 fork 访问模式由第 1 步决定),使用
gh pr create和--body-file创建 PR,捕获 HEAD_SHA,应用标签
fork/访问权限检测、分支冲突处理和托管克隆刷新模式均已在 references/library-pr-plumbing.md 中详细说明。不要在此处重复这些模式——该参考文档是权威来源。
PR 创建后,在面向用户的摘要中展示 URL 和 Greptile 提示:
“PR 已创建:
Greptile 将在约 2 分钟内进行审查。查看行内评论:
gh api repos/mvanhorn/printing-press-library/pulls/<N>/comments在请求人工审查前,建议先处理 P0/P1 级发现。”
第 8 阶段 — 输出
完成后输出结构化的 ---PATCH-RESULT--- 区块。格式:
---PATCH-RESULT---
pr_url: <url>
pr_number: <n>
branch_name: <name>
api_slug: <slug>
scope_tier: <bugs|bugs+features|all|custom>
files_changed:
- <file>
build_status: <PASS|FAIL>
test_status: <PASS|FAIL>
dogfood_status: <PASS|FAIL|N/A>
pii_scrub_summary: <N tokens replaced across M artifacts>
findings_addressed:
- <one-line-summary>
findings_deferred:
- <one-line-summary>
deferred_list_path: <path>
plan_doc_path: <path>
---END-PATCH-RESULT---
对此技能本身的验证
此 SKILL.md 的静态 lint 检查通过以下命令运行:
<PRINTING_PRESS_BIN> verify-internal-skill --dir skills/printing-press-amend
(请参阅 internal/cli/verify_internal_skill.go 和对应的测试文件。设置契约一致性检查作为 Go 测试在 internal/pipeline/contracts_test.go 中运行,即 TestSkillSetupBlocksMatchWorkspaceContract。)