Wizard wizard 是一个 bash 脚本,它一步一步引导人完成一项手动流程:这类流程手动做很繁琐,每次重新向 AI 解释一遍也很繁琐。它会打开每个 URL,准确说明该点什么、该复制什么,捕获这些值,把它们写到该去的地方( 、GitHub secrets),在每个阶段确认,并显示还剩多少个阶段。它可能用于配置第三方服务、运行一次性 migration,或把项目从一种状态迁移到另一种状态。 出色的 UX 已经由 template.sh 解决:逐阶段的进度、confirmation gates、跨平台 URL 打开(含 WSL)、隐藏的 secret 输入、幂等的 upserts、 / 写入,以及收尾 summary。 你的工作只是确定流程范围并编写它的各个 stage。 标记之上的 library 在每个 wizard 中都完全相同;这种一致性正是重点:永远不要手动编辑它。 Wizard 默认是临时的:为单次运行而构建,保存到 scratch 或 路径,任务完成后删除。只有当用户想要一条应留在 repo 中的可重复 setup 路径时,才 commit 它。 流程 1. 界定流程范围 梳理出人必须执行的每一个手动步骤,以及沿途捕获的每一个值。先读 repo,不要凭空发问: - 对于 setup: 、 、 、 、 、framework config,以及 (每一处 / 引用都…

\\001' e=

Wizard wizard 是一个 bash 脚本,它一步一步引导人完成一项手动流程:这类流程手动做很繁琐,每次重新向 AI 解释一遍也很繁琐。它会打开每个 URL,准确说明该点什么、该复制什么,捕获这些值,把它们写到该去的地方( 、GitHub secrets),在每个阶段确认,并显示还剩多少个阶段。它可能用于配置第三方服务、运行一次性 migration,或把项目从一种状态迁移到另一种状态。 出色的 UX 已经由 template.sh 解决:逐阶段的进度、confirmation gates、跨平台 URL 打开(含 WSL)、隐藏的 secret 输入、幂等的 upserts、 / 写入,以及收尾 summary。 你的工作只是确定流程范围并编写它的各个 stage。 标记之上的 library 在每个 wizard 中都完全相同;这种一致性正是重点:永远不要手动编辑它。 Wizard 默认是临时的:为单次运行而构建,保存到 scratch 或 路径,任务完成后删除。只有当用户想要一条应留在 repo 中的可重复 setup 路径时,才 commit 它。 流程 1. 界定流程范围 梳理出人必须执行的每一个手动步骤,以及沿途捕获的每一个值。先读 repo,不要凭空发问: - 对于 setup: 、 、 、 、 、framework config,以及 (每一处 / 引用都…

\\002' p rc=0\n current=$(_existing \"$key\" || true)\n # Readline needs the colour codes wrapped in \\001..\\002 to place the cursor.\n p=\" $s$BOLD$e$prompt$s$RESET$e \"\n [[ -n \"$current\" ]] && p+=\"$s$DIM$e[Enter keeps current]$s$RESET$e \"\n read -e -r -p \"$p\" input || rc=1\n if (( rc )) && [[ -z \"$input\" ]]; then return 1; fi\n [[ -z \"$input\" && -n \"$current\" ]] && input=\"$current\"\n printf -v \"$key\" '%s' \"$input\"\n}\n\n# ask_secret KEY \"Prompt\" is like ask, but input is hidden.\nask_secret() {\n local key=\"$1\" prompt=\"$2\" current input rc=0\n current=$(_existing \"$key\" || true)\n if [[ -n \"$current\" ]]; then\n printf ' %s%s%s %s[Enter keeps current]%s ' \"$BOLD\" \"$prompt\" \"$RESET\" \"$DIM\" \"$RESET\"\n else\n printf ' %s%s%s ' \"$BOLD\" \"$prompt\" \"$RESET\"\n fi\n read -rs input || rc=1\n printf '\\n'\n if (( rc )) && [[ -z \"$input\" ]]; then return 1; fi\n [[ -z \"$input\" && -n \"$current\" ]] && input=\"$current\"\n printf -v \"$key\" '%s' \"$input\"\n}\n\n# write_env KEY VALUE upserts KEY='VALUE' into ENV_FILE (replaces any existing\n# line) and sets $KEY. Idempotent. Creates ENV_FILE at mode 0600; writes through\n# a symlink and keeps an existing file's mode.\nwrite_env() {\n local key=\"$1\" value=\"$2\" tmp sq=\"'\\\\''\"\n [[ -e \"$ENV_FILE\" ]] || (umask 077 && : > \"$ENV_FILE\")\n tmp=$(mktemp)\n grep -vE \"^${key}=\" \"$ENV_FILE\" > \"$tmp\" || true\n printf \"%s='%s'\\n\" \"$key\" \"${value//\\'/$sq}\" >> \"$tmp\"\n cat \"$tmp\" > \"$ENV_FILE\"\n rm -f \"$tmp\"\n printf -v \"$key\" '%s' \"$value\"\n WRITTEN_ENV+=(\"$key\")\n printf ' %s✓ wrote%s %s → %s\\n' \"$GREEN\" \"$RESET\" \"$key\" \"$ENV_FILE\"\n}\n\n# set_secret NAME VALUE sets a GitHub Actions repo secret via gh. Falls back\n# to a warning (and records it) if gh is unavailable or unauthenticated.\nset_secret() {\n local name=\"$1\" value=\"$2\"\n if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then\n if printf '%s' \"$value\" | gh secret set \"$name\" >/dev/null 2>&1; then\n WRITTEN_SECRET+=(\"$name\")\n printf ' %s✓ set%s GitHub secret %s\\n' \"$GREEN\" \"$RESET\" \"$name\"\n return\n fi\n fi\n SKIPPED+=(\"GitHub secret $name (set it manually: gh secret set $name)\")\n warn \"skipped GitHub secret $name: gh not ready; set it later\"\n}\n\n# set_var NAME VALUE sets a GitHub Actions repo variable (non-secret).\nset_var() {\n local name=\"$1\" value=\"$2\"\n if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then\n if gh variable set \"$name\" --body \"$value\" >/dev/null 2>&1; then\n printf ' %s✓ set%s GitHub variable %s\\n' \"$GREEN\" \"$RESET\" \"$name\"\n return\n fi\n fi\n SKIPPED+=(\"GitHub variable $name\")\n warn \"skipped GitHub variable $name, gh not ready; set it later\"\n}\n\n# finish clears, then shows a closing summary of everything configured.\nfinish() {\n _clear\n printf '\\n%s%s ✓ Setup complete%s\\n' \"$BOLD\" \"$GREEN\" \"$RESET\"\n (( ${#WRITTEN_ENV[@]} )) && note \"wrote ${#WRITTEN_ENV[@]} value(s) to $ENV_FILE: ${WRITTEN_ENV[*]}\"\n (( ${#WRITTEN_SECRET[@]} )) && note \"set ${#WRITTEN_SECRET[@]} GitHub secret(s): ${WRITTEN_SECRET[*]}\"\n if (( ${#SKIPPED[@]} )); then\n printf '\\n'; warn \"still to do by hand:\"\n for s in \"${SKIPPED[@]}\"; do note \" - $s\"; done\n fi\n printf '\\n'\n}\n\n# ──────────────────────────────────────────────────────────────────────────\n# STAGES: author this section. One stage() per step the human takes.\n# Replace the example below. Set TOTAL_STAGES to match the stages you write.\n# Keep every stage inside run_wizard and the last line as is: bash then parses\n# the whole file before the first prompt, so an edit mid-run can't break it.\n# ──────────────────────────────────────────────────────────────────────────\n\nrun_wizard() {\n\nTOTAL_STAGES=1\n\nbanner \"Stripe setup\"\n\n# ── Example stage: replace with your real steps ───────────────────────────\nstage \"Stripe: API keys\"\nsay \"We'll grab your Stripe test keys and store them for local dev + CI.\"\nopen_url \"https://dashboard.stripe.com/test/apikeys\"\nstep \"On the API keys page, copy the Publishable key (starts pk_test_).\"\nask STRIPE_PUBLISHABLE_KEY \"Paste the publishable key:\"\nstep \"Click 'Reveal test key' on the Secret key row, then copy it.\"\nask_secret STRIPE_SECRET_KEY \"Paste the secret key:\"\nwrite_env STRIPE_PUBLISHABLE_KEY \"$STRIPE_PUBLISHABLE_KEY\"\nwrite_env STRIPE_SECRET_KEY \"$STRIPE_SECRET_KEY\"\nset_secret STRIPE_SECRET_KEY \"$STRIPE_SECRET_KEY\" # CI needs this one\n# ──────────────────────────────────────────────────────────────────────────\n\nfinish\n}\n\nrun_wizard \"$@\"; exit\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":9498,"content_sha256":"6566f147299bc6f1d941e64591ed04385416d543e11f96f564c7228f5018d0ed"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Wizard","type":"text"}]},{"type":"paragraph","content":[{"text":"wizard","type":"text","marks":[{"type":"strong"}]},{"text":" 是一个 bash 脚本,它一步一步引导人完成一项手动流程:这类流程手动做很繁琐,每次重新向 AI 解释一遍也很繁琐。它会打开每个 URL,准确说明该点什么、该复制什么,捕获这些值,把它们写到该去的地方(","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":"、GitHub secrets),在每个阶段确认,并显示还剩多少个阶段。它可能用于配置第三方服务、运行一次性 migration,或把项目从一种状态迁移到另一种状态。","type":"text"}]},{"type":"paragraph","content":[{"text":"出色的 UX 已经由 ","type":"text"},{"text":"template.sh","type":"text","marks":[{"type":"link","attrs":{"href":"template.sh","title":null}}]},{"text":" 解决:逐阶段的进度、confirmation gates、跨平台 URL 打开(含 WSL)、隐藏的 secret 输入、幂等的 ","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":" upserts、","type":"text"},{"text":"gh secret","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"gh variable","type":"text","marks":[{"type":"code_inline"}]},{"text":" 写入,以及收尾 summary。","type":"text"},{"text":"你的工作只是确定流程范围并编写它的各个 stage。","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"STAGES","type":"text","marks":[{"type":"code_inline"}]},{"text":" 标记之上的 library 在每个 wizard 中都完全相同;这种一致性正是重点:永远不要手动编辑它。","type":"text"}]},{"type":"paragraph","content":[{"text":"Wizard 默认是临时的:为单次运行而构建,保存到 scratch 或 ","type":"text"},{"text":"scripts/","type":"text","marks":[{"type":"code_inline"}]},{"text":" 路径,任务完成后删除。只有当用户想要一条应留在 repo 中的可重复 setup 路径时,才 commit 它。","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"流程","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. 界定流程范围","type":"text"}]},{"type":"paragraph","content":[{"text":"梳理出人必须执行的每一个手动步骤,以及沿途捕获的每一个值。先读 repo,不要凭空发问:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"对于 setup:","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":".env.example","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":".env.*","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"README","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"docker-compose*","type":"text","marks":[{"type":"code_inline"}]},{"text":"、framework config,以及 ","type":"text"},{"text":".github/workflows/*","type":"text","marks":[{"type":"code_inline"}]},{"text":"(每一处 ","type":"text"},{"text":"secrets.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"vars.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" 引用都是 wizard 必须产出的一个值)。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"对于 migration 或 transition:当前状态、目标状态,以及两者之间不可逆的操作。","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"然后向用户展示有序的 stages 列表以及每个 stage 产出的值,并确认:他们可能增删或重新排序。","type":"text"}]},{"type":"paragraph","content":[{"text":"Done when:","type":"text","marks":[{"type":"strong"}]},{"text":" 每个 stage 都按顺序命名,并且对于每个捕获的值,你知道 (a) 人从哪里获取它,(b) 它写到哪里(","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":"、一个 GitHub secret、两者,或都不写;有些 stage 是纯操作),以及 (c) 它是 secret(隐藏输入)还是 public。","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. 描绘每个 stage 的路径","type":"text"}]},{"type":"paragraph","content":[{"text":"对于每个 stage,写出人遵循的精确路径:打开哪个 URL、在那里做什么、值在哪里显示、它填充哪个变量,例如 \"Dashboard → Developers → API keys → Reveal test key → copy\"。在你确实不知道当前 UI 或确切命令的地方,如实说明并询问用户或查阅文档:永远不要编造可能不存在的步骤。","type":"text"}]},{"type":"paragraph","content":[{"text":"Done when:","type":"text","marks":[{"type":"strong"}]},{"text":" 每个 stage 都能追溯到陌生人也能照做的具体指令。","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. 编写 wizard","type":"text"}]},{"type":"paragraph","content":[{"text":"把 ","type":"text"},{"text":"template.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" 复制到目标路径。用每个步骤一个 ","type":"text"},{"text":"stage","type":"text","marks":[{"type":"code_inline"}]},{"text":" 替换示例 stage,按依赖顺序排列。使用 library helpers(","type":"text"},{"text":"stage","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"say","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"step","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"open_url","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"ask","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"ask_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"write_env","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"set_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"set_var","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"pause","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"confirm","type":"text","marks":[{"type":"code_inline"}]},{"text":"),并把 ","type":"text"},{"text":"TOTAL_STAGES","type":"text","marks":[{"type":"code_inline"}]},{"text":" 设为你编写的 stage 数量。","type":"text"}]},{"type":"paragraph","content":[{"text":"守住 template 设定的标准:在索取某个 URL 的值之前先打开它,对任何 secret 使用 ","type":"text"},{"text":"ask_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":",对每个持久化的值使用 ","type":"text"},{"text":"write_env","type":"text","marks":[{"type":"code_inline"}]},{"text":",只对 CI 确实需要的值使用 ","type":"text"},{"text":"set_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":",并在任何不可逆操作之前 ","type":"text"},{"text":"confirm","type":"text","marks":[{"type":"code_inline"}]},{"text":"。每个 ","type":"text"},{"text":"stage","type":"text","marks":[{"type":"code_inline"}]},{"text":" 都会清屏,因此只显示当前步骤:让一个 stage 只聚焦一项任务,这样人需要的内容就不会滚出视野。不要触碰标记之上的 library。","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. 验证并交接","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"bash -n \u003cscript>","type":"text","marks":[{"type":"code_inline"}]},{"text":";如果可用则运行 ","type":"text"},{"text":"shellcheck","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"chmod +x \u003cscript>","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不要自己端到端运行它:它会打开浏览器并阻塞在人的输入上。改为静态追踪:step 1 中的每个值都被捕获并落到 step 1 所说的位置,并且每个 ","type":"text"},{"text":"set_secret","type":"text","marks":[{"type":"code_inline"}]},{"text":" 名称都与 CI 中的某处 ","type":"text"},{"text":"secrets.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" 引用精确匹配。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"告诉用户如何运行它。如果它是一条可重复的 setup 路径,就 commit 它并从 README 链接过去,让下一个人运行脚本而不是询问 AI。","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"wizard","author":"@skillopedia","source":{"stars":5497,"repo_name":"mattpocock-skills-zh-CN","origin_url":"https://github.com/vinvcn/mattpocock-skills-zh-CN/blob/HEAD/skills/engineering/wizard/SKILL.md","repo_owner":"vinvcn","body_sha256":"83adec32ce566812b63818a840048dceb2f81a26f2e0da9406a4d2cda7859657","cluster_key":"8c0a3d211cbb70767da500bda0a7bff791fd776e803c1c5c402aeee2368802b6","clean_bundle":{"format":"clean-skill-bundle-v1","source":"vinvcn/mattpocock-skills-zh-CN/skills/engineering/wizard/SKILL.md","text_bytes":9585,"source_commit":"5b57718666917f8a6a0ff3066ae8d5ec386baef4","skills_sh_rank":6252,"attachment_count":2,"text_attachments":2,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/engineering/wizard/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"devops-infrastructure","import_tag":"skills-sh-top20k-2026-11","description":"生成一个交互式 bash wizard,逐步引导人完成只有他们能执行的手动流程。用于 provisioning 基础设施、设置 credentials 或 CI secrets、走查不熟悉的第三方 dashboard,或运行一次性 migration 或 cutover。对于 agent 自己就能执行的步骤,不要调用它。"}},"renderedAt":1793661669852}

Wizard wizard 是一个 bash 脚本,它一步一步引导人完成一项手动流程:这类流程手动做很繁琐,每次重新向 AI 解释一遍也很繁琐。它会打开每个 URL,准确说明该点什么、该复制什么,捕获这些值,把它们写到该去的地方( 、GitHub secrets),在每个阶段确认,并显示还剩多少个阶段。它可能用于配置第三方服务、运行一次性 migration,或把项目从一种状态迁移到另一种状态。 出色的 UX 已经由 template.sh 解决:逐阶段的进度、confirmation gates、跨平台 URL 打开(含 WSL)、隐藏的 secret 输入、幂等的 upserts、 / 写入,以及收尾 summary。 你的工作只是确定流程范围并编写它的各个 stage。 标记之上的 library 在每个 wizard 中都完全相同;这种一致性正是重点:永远不要手动编辑它。 Wizard 默认是临时的:为单次运行而构建,保存到 scratch 或 路径,任务完成后删除。只有当用户想要一条应留在 repo 中的可重复 setup 路径时,才 commit 它。 流程 1. 界定流程范围 梳理出人必须执行的每一个手动步骤,以及沿途捕获的每一个值。先读 repo,不要凭空发问: - 对于 setup: 、 、 、 、 、framework config,以及 (每一处 / 引用都…