Parcourir la source

refactor: 重构 weapp-publish 技能,符合 skill-creator 规范

- SKILL.md 从 358 行精简到 51 行
- 添加 scripts/publish-weapp.js 可执行脚本
- 添加 references/ 目录存放配置、FAQ、使用示例
- 改进 description,添加详细触发场景
- 移除 YAML frontmatter 中的 license 字段

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname il y a 1 jour
Parent
commit
de1e44feb4

+ 18 - 325
.claude/skills/weapp-publish/SKILL.md

@@ -1,357 +1,50 @@
 ---
 name: weapp-publish
-description: 微信小程序发布工具。用于发布企业小程序和人才小程序的开发版和体验版,支持自动化构建、上传和预览流程。
-license: MIT
+description: 微信小程序自动化发布工具。支持企业小程序和人才小程序的开发版和体验版发布。当用户需要:发布小程序到微信平台、上传体验版、生成开发版预览二维码、配置小程序发布环境时触发。使用 scripts/publish-weapp.js 脚本执行发布流程。
 ---
 
-# 微信小程序发布 Skill
+# 微信小程序发布
 
-本 Skill 专门用于本项目的企业小程序和人才小程序的自动化发布流程
+本项目包含两个小程序:**企业小程序**(用人方)和 **人才小程序**(求职者)
 
 ---
 
-## 支持的小程序
-
-| 小程序 | 目录 | AppID | 说明 |
-|--------|------|-------|------|
-| **企业小程序** | `mini/` | `wx1e791ed2e0229eb8` | 用人方小程序(企业管理端) |
-| **人才小程序** | `mini-talent/` | `wx3c47dbce1ea7d43c` | 人才小程序(求职者端) |
-
----
-
-## 发布前准备
-
-### 1. 安装 miniprogram-ci
-
-```bash
-pnpm add -D miniprogram-ci
-# 或全局安装
-pnpm add -g miniprogram-ci
-```
-
-### 2. 获取上传密钥
-
-使用小程序管理员身份访问"微信公众平台 > 开发 > 开发设置",下载代码上传密钥。
-
-**企业小程序密钥文件**: `mini/certs/private.upload.key`
-**人才小程序密钥文件**: `mini-talent/certs/private.upload.key`
-
-> 密钥文件已存在于各自小程序目录的 `certs/` 目录下。
-
-### 3. 配置 IP 白名单
-
-在微信公众平台配置服务器的 IP 白名单。
-
----
-
-## 发布流程
-
-### 完整发布步骤
-
-1. **构建项目**: 运行 Taro 构建命令生成小程序代码
-2. **上传代码**: 使用 miniprogram-ci 发布到微信服务器
-3. **设置体验版**(可选): 在小程序后台将上传的版本设置为体验版
+## 快速开始
 
 ### 发布命令
 
 ```bash
 # 企业小程序 - 体验版上传
-pnpm run publish:enterprise:dev
+pnpm run publish:enterprise
 
 # 企业小程序 - 开发版生成二维码
-pnpm run publish:enterprise:prod
+pnpm run publish:enterprise:dev
 
 # 人才小程序 - 体验版上传
-pnpm run publish:talent:dev
+pnpm run publish:talent
 
 # 人才小程序 - 开发版生成二维码
-pnpm run publish:talent:prod
-```
-
----
-
-## 脚本实现
-
-### 创建发布脚本
-
-在项目根目录创建 `scripts/publish-weapp.js`:
-
-```javascript
-const ci = require('miniprogram-ci')
-const path = require('path')
-const { execSync } = require('child_process')
-
-// 小程序配置
-const MINI_CONFIGS = {
-  enterprise: {
-    name: '企业小程序',
-    appid: 'wx1e791ed2e0229eb8',
-    projectPath: path.resolve(__dirname, '../mini'),
-    privateKeyPath: path.resolve(__dirname, '../mini/certs/private.upload.key'),
-    buildCmd: 'cd mini && pnpm build:weapp',
-    distPath: 'dist/weapp',
-  },
-  talent: {
-    name: '人才小程序',
-    appid: 'wx3c47dbce1ea7d43c',
-    projectPath: path.resolve(__dirname, '../mini-talent'),
-    privateKeyPath: path.resolve(__dirname, '../mini-talent/certs/private.upload.key'),
-    buildCmd: 'cd mini-talent && pnpm build:weapp',
-    distPath: 'dist/weapp',
-  },
-}
-
-/**
- * 构建小程序
- */
-function buildMiniProject(config) {
-  console.log(`\n🔨 正在构建 ${config.name}...`)
-  try {
-    execSync(config.buildCmd, { stdio: 'inherit' })
-    console.log(`✅ ${config.name} 构建完成`)
-  } catch (error) {
-    console.error(`❌ ${config.name} 构建失败`)
-    throw error
-  }
-}
-
-/**
- * 上传小程序到微信服务器
- */
-async function uploadExperienceProject(config, options) {
-  const { version, desc, robot = 1 } = options
-
-  console.log(`\n📤 正在发布体验版 ${config.name}...`)
-  console.log(`   版本: ${version}`)
-  console.log(`   描述: ${desc}`)
-
-  const project = new ci.Project({
-    appid: config.appid,
-    type: 'miniProgram',
-    projectPath: config.projectPath,
-    privateKeyPath: config.privateKeyPath,
-    ignores: ['node_modules/**/*'],
-  })
-
-  try {
-    const result = await ci.experience({
-      project,
-      version,
-      desc,
-      setting: {
-        useProjectConfig: true,
-        es7: true,
-        minify: true,
-        minifyJS: true,
-        minifyWXML: true,
-        minifyWXSS: true,
-        autoPrefixWXSS: true,
-      },
-      onProgressUpdate: (progress) => {
-        process.stdout.write('\r   上传进度: ' + progress + '%')
-      },
-      robot,
-    })
-
-    console.log(`\n✅ ${config.name} 发布成功!`)
-    console.log(`   时间: ${result.time}`)
-    console.log(`   版本: ${result.version}`)
-    console.log(`   请前往小程序后台查看: https://mp.weixin.qq.com/`)
-  } catch (error) {
-    console.error(`\n❌ ${config.name} 发布失败`)
-    console.error(error.message)
-    throw error
-  }
-}
-
-/**
- * 预览小程序(生成二维码)
- */
-async function previewDevProject(config, options) {
-  const { desc, qrcodePath, robot = 1 } = options
-
-  console.log(`\n👀 正在生成 ${config.name} 预览二维码...`)
-
-  const project = new ci.Project({
-    appid: config.appid,
-    type: 'miniProgram',
-    projectPath: config.projectPath,
-    privateKeyPath: config.privateKeyPath,
-    ignores: ['node_modules/**/*'],
-  })
-
-  try {
-    const result = await ci.dev({
-      project,
-      desc,
-      setting: { useProjectConfig: true },
-      qrcodeFormat: 'image',
-      qrcodeOutputDest: qrcodePath,
-      onProgressUpdate: (progress) => {
-        process.stdout.write('\r   生成进度: ' + progress + '%')
-      },
-      robot,
-    })
-
-    console.log(`\n✅ 预览二维码已生成: ${qrcodePath}`)
-  } catch (error) {
-    console.error(`\n❌ 预览二维码生成失败`)
-    console.error(error.message)
-    throw error
-  }
-}
-
-/**
- * 主函数
- */
-async function main() {
-  const args = process.argv.slice(2)
-  const [miniType, action = 'experience'] = args
-
-  // 解析参数
-  const options = {
-    version: process.env.VERSION || '1.0.0',
-    desc: process.env.DESC || '自动化发布',
-    robot: parseInt(process.env.ROBOT || '1'),
-  }
-
-  if (!miniType || !MINI_CONFIGS[miniType]) {
-    console.error('❌ 请指定小程序类型: enterprise 或 talent')
-    console.error('示例: pnpm run publish:enterprise')
-    process.exit(1)
-  }
-
-  const config = MINI_CONFIGS[miniType]
-
-  try {
-    // 构建项目
-    buildMiniProject(config)
-
-    // 执行操作
-    if (action === 'experience') {
-      await uploadExperienceProject(config, options)
-    } else if (action === 'dev') {
-      await previewDevProject(config, {
-        desc: options.desc,
-        qrcodePath: path.resolve(__dirname, `../qrcode-${miniType}.jpg`),
-        robot: options.robot,
-      })
-    } else {
-      console.error(`❌ 未知操作: ${action}`)
-      process.exit(1)
-    }
-  } catch (error) {
-    process.exit(1)
-  }
-}
-
-main()
-```
-
----
-
-## package.json 配置
-
-在根目录 `package.json` 中添加以下脚本:
-
-```json
-{
-  "scripts": {
-    "publish:enterprise": "node scripts/publish-weapp.js enterprise experience",
-    "publish:enterprise:dev": "node scripts/publish-weapp.js enterprise dev",
-    "publish:talent": "node scripts/publish-weapp.js talent experience",
-    "publish:talent:dev": "node scripts/publish-weapp.js talent dev"
-  }
-}
-```
-
----
-
-## 环境变量配置
-
-创建 `.env.local` 文件:
-
-```bash
-# 发布版本号
-VERSION=1.0.0
-
-# 发布描述
-DESC=修复了一些问题并优化了用户体验
-
-# CI 机器人编号 (1-30)
-ROBOT=1
-```
-
----
-
-## 使用示例
-
-### 发布企业小程序
-
-```bash
-# 使用默认版本号和描述
-pnpm run publish:enterprise
-
-# 自定义版本号和描述
-VERSION=1.2.0 DESC="新增订单管理功能" pnpm run publish:enterprise
-
-# 生成预览二维码
-pnpm run publish:enterprise:dev
+pnpm run publish:talent:dev
 ```
 
-### 发布人才小程序
+### 自定义版本和描述
 
 ```bash
-# 使用默认版本号和描述
-pnpm run publish:talent
-
-# 自定义版本号和描述
-VERSION=2.0.0 DESC="全新改版,优化求职流程" pnpm run publish:talent
-
-# 生成预览二维码
-pnpm run publish:talent:dev
+VERSION=1.2.0 DESC="新增功能" pnpm run publish:enterprise
 ```
 
 ---
 
-## 快捷命令建议
-
-用户可以直接询问 Claude 执行以下操作:
-
-| 用户指令 | Claude 行为 |
-|----------|-------------|
-| "发布企业小程序" | 运行 `pnpm run publish:enterprise` |
-| "发布人才小程序" | 运行 `pnpm run publish:talent` |
-| "生成企业小程序预览二维码" | 运行 `pnpm run publish:enterprise:dev` |
-| "发布两个小程序" | 依次运行企业小程序和人才小程序的发布命令 |
-
----
-
-## 注意事项
-
-1. **密钥安全**: 上传密钥拥有预览、上传权限,请勿提交到代码仓库
-2. **构建依赖**: 发布前确保项目依赖已安装 (`pnpm install`)
-3. **版本管理**: 建议使用语义化版本号 (Semantic Versioning)
-4. **IP 白名单**: 确保服务器 IP 已在微信公众平台配置白名单
-5. **机器人编号**: 多个 CI 并发时使用不同的 robot 编号 (1-30)
-
----
-
-## 常见问题
-
-### Q: 发布失败提示 IP 不在白名单
-**A**: 请在微信公众平台"开发 > 开发设置"中添加服务器 IP 到白名单。
-
-### Q: 构建成功但发布失败
-**A**: 检查密钥文件路径是否正确,密钥是否匹配对应的 AppID。
+## 发布流程
 
-### Q: 如何设置体验版
-**A**: 发布成功后,登录小程序后台"版本管理",将指定版本设置为体验版。
+1. 构建项目(Taro 编译)
+2. 上传到微信服务器
+3. 生成体验版或预览二维码
 
 ---
 
-## 相关资源
+## 参考文档
 
-- [miniprogram-ci 官方文档](https://www.npmjs.com/package/miniprogram-ci)
-- [微信公众平台](https://mp.weixin.qq.com/)
-- [miniprogram-ci Skill](.claude/skills/miniprogram-ci/SKILL.md)
+- **配置说明**: [config.md](references/config.md) - 小程序信息、package.json 配置、环境变量
+- **常见问题**: [faq.md](references/faq.md) - 故障排查、注意事项
+- **使用示例**: [usage.md](references/usage.md) - 完整使用示例、快捷命令

+ 67 - 0
.claude/skills/weapp-publish/references/config.md

@@ -0,0 +1,67 @@
+# 配置参考
+
+## 支持的小程序
+
+| 小程序 | 目录 | AppID | 说明 |
+|--------|------|-------|------|
+| **企业小程序** | `mini/` | `wx1e791ed2e0229eb8` | 用人方小程序(企业管理端) |
+| **人才小程序** | `mini-talent/` | `wx3c47dbce1ea7d43c` | 人才小程序(求职者端) |
+
+---
+
+## package.json 配置
+
+在根目录 `package.json` 中添加以下脚本:
+
+```json
+{
+  "scripts": {
+    "publish:enterprise": "node .claude/skills/weapp-publish/scripts/publish-weapp.js enterprise experience",
+    "publish:enterprise:dev": "node .claude/skills/weapp-publish/scripts/publish-weapp.js enterprise dev",
+    "publish:talent": "node .claude/skills/weapp-publish/scripts/publish-weapp.js talent experience",
+    "publish:talent:dev": "node .claude/skills/weapp-publish/scripts/publish-weapp.js talent dev"
+  }
+}
+```
+
+---
+
+## 环境变量配置
+
+创建 `.env.local` 文件:
+
+```bash
+# 发布版本号
+VERSION=1.0.0
+
+# 发布描述
+DESC=修复了一些问题并优化了用户体验
+
+# CI 机器人编号 (1-30)
+ROBOT=1
+```
+
+---
+
+## 发布前准备
+
+### 1. 安装 miniprogram-ci
+
+```bash
+pnpm add -D miniprogram-ci
+# 或全局安装
+pnpm add -g miniprogram-ci
+```
+
+### 2. 获取上传密钥
+
+使用小程序管理员身份访问"微信公众平台 > 开发 > 开发设置",下载代码上传密钥。
+
+**企业小程序密钥文件**: `mini/certs/private.upload.key`
+**人才小程序密钥文件**: `mini-talent/certs/private.upload.key`
+
+> 密钥文件已存在于各自小程序目录的 `certs/` 目录下。
+
+### 3. 配置 IP 白名单
+
+在微信公众平台配置服务器的 IP 白名单。

+ 23 - 0
.claude/skills/weapp-publish/references/faq.md

@@ -0,0 +1,23 @@
+# 常见问题
+
+### Q: 发布失败提示 IP 不在白名单
+
+**A**: 请在微信公众平台"开发 > 开发设置"中添加服务器 IP 到白名单。
+
+### Q: 构建成功但发布失败
+
+**A**: 检查密钥文件路径是否正确,密钥是否匹配对应的 AppID。
+
+### Q: 如何设置体验版
+
+**A**: 发布成功后,登录小程序后台"版本管理",将指定版本设置为体验版。
+
+---
+
+## 注意事项
+
+1. **密钥安全**: 上传密钥拥有预览、上传权限,请勿提交到代码仓库
+2. **构建依赖**: 发布前确保项目依赖已安装 (`pnpm install`)
+3. **版本管理**: 建议使用语义化版本号 (Semantic Versioning)
+4. **IP 白名单**: 确保服务器 IP 已在微信公众平台配置白名单
+5. **机器人编号**: 多个 CI 并发时使用不同的 robot 编号 (1-30)

+ 46 - 0
.claude/skills/weapp-publish/references/usage.md

@@ -0,0 +1,46 @@
+# 使用示例
+
+## 发布企业小程序
+
+```bash
+# 使用默认版本号和描述
+pnpm run publish:enterprise
+
+# 自定义版本号和描述
+VERSION=1.2.0 DESC="新增订单管理功能" pnpm run publish:enterprise
+
+# 生成预览二维码
+pnpm run publish:enterprise:dev
+```
+
+## 发布人才小程序
+
+```bash
+# 使用默认版本号和描述
+pnpm run publish:talent
+
+# 自定义版本号和描述
+VERSION=2.0.0 DESC="全新改版,优化求职流程" pnpm run publish:talent
+
+# 生成预览二维码
+pnpm run publish:talent:dev
+```
+
+---
+
+## 快捷命令参考
+
+| 用户指令 | Claude 行为 |
+|----------|-------------|
+| "发布企业小程序" | 运行 `pnpm run publish:enterprise` |
+| "发布人才小程序" | 运行 `pnpm run publish:talent` |
+| "生成企业小程序预览二维码" | 运行 `pnpm run publish:enterprise:dev` |
+| "发布两个小程序" | 依次运行企业小程序和人才小程序的发布命令 |
+
+---
+
+## 相关资源
+
+- [miniprogram-ci 官方文档](https://www.npmjs.com/package/miniprogram-ci)
+- [微信公众平台](https://mp.weixin.qq.com/)
+- [miniprogram-ci Skill](.claude/skills/miniprogram-ci/SKILL.md)

+ 154 - 0
.claude/skills/weapp-publish/scripts/publish-weapp.js

@@ -0,0 +1,154 @@
+const ci = require('miniprogram-ci')
+const path = require('path')
+const { execSync } = require('child_process')
+
+// 小程序配置
+const MINI_CONFIGS = {
+  enterprise: {
+    name: '企业小程序',
+    appid: 'wx1e791ed2e0229eb8',
+    projectPath: path.resolve(__dirname, '../../mini'),
+    privateKeyPath: path.resolve(__dirname, '../../mini/certs/private.upload.key'),
+    buildCmd: 'cd mini && pnpm build:weapp',
+    distPath: 'dist/weapp',
+  },
+  talent: {
+    name: '人才小程序',
+    appid: 'wx3c47dbce1ea7d43c',
+    projectPath: path.resolve(__dirname, '../../mini-talent'),
+    privateKeyPath: path.resolve(__dirname, '../../mini-talent/certs/private.upload.key'),
+    buildCmd: 'cd mini-talent && pnpm build:weapp',
+    distPath: 'dist/weapp',
+  },
+}
+
+function buildMiniProject(config) {
+  console.log(`\n🔨 正在构建 ${config.name}...`)
+  try {
+    execSync(config.buildCmd, { stdio: 'inherit' })
+    console.log(`✅ ${config.name} 构建完成`)
+  } catch (error) {
+    console.error(`❌ ${config.name} 构建失败`)
+    throw error
+  }
+}
+
+async function uploadExperienceProject(config, options) {
+  const { version, desc, robot = 1 } = options
+
+  console.log(`\n📤 正在发布体验版 ${config.name}...`)
+  console.log(`   版本: ${version}`)
+  console.log(`   描述: ${desc}`)
+
+  const project = new ci.Project({
+    appid: config.appid,
+    type: 'miniProgram',
+    projectPath: config.projectPath,
+    privateKeyPath: config.privateKeyPath,
+    ignores: ['node_modules/**/*'],
+  })
+
+  try {
+    const result = await ci.experience({
+      project,
+      version,
+      desc,
+      setting: {
+        useProjectConfig: true,
+        es7: true,
+        minify: true,
+        minifyJS: true,
+        minifyWXML: true,
+        minifyWXSS: true,
+        autoPrefixWXSS: true,
+      },
+      onProgressUpdate: (progress) => {
+        process.stdout.write('\r   上传进度: ' + progress + '%')
+      },
+      robot,
+    })
+
+    console.log(`\n✅ ${config.name} 发布成功!`)
+    console.log(`   时间: ${result.time}`)
+    console.log(`   版本: ${result.version}`)
+    console.log(`   请前往小程序后台查看: https://mp.weixin.qq.com/`)
+  } catch (error) {
+    console.error(`\n❌ ${config.name} 发布失败`)
+    console.error(error.message)
+    throw error
+  }
+}
+
+async function previewDevProject(config, options) {
+  const { desc, qrcodePath, robot = 1 } = options
+
+  console.log(`\n👀 正在生成 ${config.name} 预览二维码...`)
+
+  const project = new ci.Project({
+    appid: config.appid,
+    type: 'miniProgram',
+    projectPath: config.projectPath,
+    privateKeyPath: config.privateKeyPath,
+    ignores: ['node_modules/**/*'],
+  })
+
+  try {
+    await ci.dev({
+      project,
+      desc,
+      setting: { useProjectConfig: true },
+      qrcodeFormat: 'image',
+      qrcodeOutputDest: qrcodePath,
+      onProgressUpdate: (progress) => {
+        process.stdout.write('\r   生成进度: ' + progress + '%')
+      },
+      robot,
+    })
+
+    console.log(`\n✅ 预览二维码已生成: ${qrcodePath}`)
+  } catch (error) {
+    console.error(`\n❌ 预览二维码生成失败`)
+    console.error(error.message)
+    throw error
+  }
+}
+
+async function main() {
+  const args = process.argv.slice(2)
+  const [miniType, action = 'experience'] = args
+
+  const options = {
+    version: process.env.VERSION || '1.0.0',
+    desc: process.env.DESC || '自动化发布',
+    robot: parseInt(process.env.ROBOT || '1'),
+  }
+
+  if (!miniType || !MINI_CONFIGS[miniType]) {
+    console.error('❌ 请指定小程序类型: enterprise 或 talent')
+    console.error('示例: pnpm run publish:enterprise')
+    process.exit(1)
+  }
+
+  const config = MINI_CONFIGS[miniType]
+
+  try {
+    buildMiniProject(config)
+
+    if (action === 'experience') {
+      await uploadExperienceProject(config, options)
+    } else if (action === 'dev') {
+      await previewDevProject(config, {
+        desc: options.desc,
+        qrcodePath: path.resolve(__dirname, `../../qrcode-${miniType}.jpg`),
+        robot: options.robot,
+      })
+    } else {
+      console.error(`❌ 未知操作: ${action}`)
+      process.exit(1)
+    }
+  } catch {
+    process.exit(1)
+  }
+}
+
+main()