@wdyy/skills 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,6 +25,7 @@ description: 基于标准五段根 .env,为无 CI/CD 的多项目 Linux 服务
25
25
  - 宿主机 Nginx 只监听根 `.env` 的 `PROJECT_HTTP_PORT`,`/api/` 代理活动后端,其他请求代理活动前端。
26
26
  - 所有容器只把项目根 `./logs` 挂载到 `/app/logs`;日志文件直接位于 `logs/`,不得创建服务、颜色或日期子目录。
27
27
  - 根 `.env` 原样复制到 `deploy/.env` 并人工上传,但必须被 `.dockerignore` 排除,且不得进入版本目录或任一镜像。
28
+ - `FRONTEND_BASE_IMAGE` 与 `BACKEND_BASE_IMAGE` 使用非空 Docker 镜像引用;可直接使用本地带标签镜像。相同标签在不同时间重新构建时可能对应不同基础镜像内容,但已导出的项目成品镜像仍按版本确定部署。
28
29
  - 环境文件固定按“前端、后端、数据库、API、部署”排列;部署生成器保留前四段和已有值,只扩充部署段。
29
30
  - `DATABASE_MIGRATION_MODE=manual` 时只打包迁移与执行脚本;`none` 时不要求数据库文件。任何部署命令都不得自动访问数据库。
30
31
  - 相同输入生成的 deploy.sh、Compose、Nginx 配置必须字节一致;版本指针、镜像归档和 manifest 可随发布变化。
@@ -40,14 +40,14 @@ FRONTEND_BLUE_PORT=19091
40
40
  FRONTEND_GREEN_PORT=19092
41
41
  BACKEND_BLUE_PORT=19093
42
42
  BACKEND_GREEN_PORT=19094
43
- FRONTEND_BASE_IMAGE=nginx:1.29-alpine@sha256:<confirmed-digest>
44
- BACKEND_BASE_IMAGE=node:24-bookworm-slim@sha256:<confirmed-digest>
43
+ FRONTEND_BASE_IMAGE=nginx:stable
44
+ BACKEND_BASE_IMAGE=node:24-alpine3.24
45
45
  DATABASE_MIGRATION_MODE=none
46
46
  ```
47
47
 
48
48
  `FRONTEND_URL`、`FRONTEND_PORT`、`BACKEND_URL`、`BACKEND_PORT` 是应用监听的唯一来源;容器、蓝绿和项目入口的健康/版本 URL 必须由对应主机、端口与固定路径确定性构造。不得增加 `FRONTEND_CONTAINER_PORT`、`BACKEND_CONTAINER_PORT`、`BACKEND_LISTEN_HOST`、`*_HEALTH_URL` 或 `*_VERSION_URL`。通配监听地址 `0.0.0.0` 仅在主动本机探测时转换为 `127.0.0.1`。
49
49
 
50
- 部署示例值只说明字段,生成目标项目后必须由工程师确认 `.env` 实际值,不得保留占位符或示例部署端口。`PROJECT_NAME` 只允许 `^[a-z][a-z0-9_]*$`。所有宿主机端口必须互不相同且在 1–65535;基础镜像必须使用 digest 固定。数据库连接键允许为空,但项目使用数据库时必须填写真实值。
50
+ 部署示例值只说明字段,生成目标项目后必须由工程师确认 `.env` 实际值,不得保留占位符或示例部署端口。`PROJECT_NAME` 只允许 `^[a-z][a-z0-9_]*$`。所有宿主机端口必须互不相同且在 1–65535;两个基础镜像必须是非空 Docker 镜像引用,可使用本地带标签镜像。相同标签在不同时间重新构建时可能解析为不同基础镜像内容;成功构建后导出的项目成品镜像仍用于服务器端确定部署。数据库连接键允许为空,但项目使用数据库时必须填写真实值。
51
51
 
52
52
  `.env` 权限必须为 `0600` 或只读的 `0400`。部署脚本只把明确的部署键载入自身环境;数据库密码、JWT 等其他应用键保留在文件中供 Compose 注入容器,不得改变脚本的 `PATH`、Shell 选项或命令行为。
53
53
 
@@ -129,9 +129,6 @@ if (!/^\/.+[^/]$/.test(env.get('SERVER_PROJECTS_ROOT'))) throw new Error('Invali
129
129
  for (const key of ['FRONTEND_URL', 'BACKEND_URL', 'DOCKER_BIND_IP']) {
130
130
  if (!/^[A-Za-z0-9:.%-]+$/.test(env.get(key))) throw new Error(`${key} contains unsafe characters`);
131
131
  }
132
- for (const key of ['FRONTEND_BASE_IMAGE', 'BACKEND_BASE_IMAGE']) {
133
- if (!/@sha256:[0-9a-f]{64}$/.test(env.get(key))) throw new Error(`${key} must be pinned by digest`);
134
- }
135
132
  const migrationMode = env.get('DATABASE_MIGRATION_MODE');
136
133
  if (!['manual', 'none'].includes(migrationMode)) throw new Error('DATABASE_MIGRATION_MODE must be manual or none');
137
134
  if (env.has('LOG_DIR') || env.has('HOST_LOG_DIR')) throw new Error('Root .env must not configure log directories');
@@ -60,8 +60,8 @@ FRONTEND_BLUE_PORT=19091
60
60
  FRONTEND_GREEN_PORT=19092
61
61
  BACKEND_BLUE_PORT=19093
62
62
  BACKEND_GREEN_PORT=19094
63
- FRONTEND_BASE_IMAGE=nginx@sha256:${'0'.repeat(64)}
64
- BACKEND_BASE_IMAGE=node@sha256:${'1'.repeat(64)}
63
+ FRONTEND_BASE_IMAGE=nginx:stable
64
+ BACKEND_BASE_IMAGE=node:24-alpine3.24
65
65
  DATABASE_MIGRATION_MODE=${mode}
66
66
  ${extra}`;
67
67
  }
@@ -319,12 +319,11 @@ test('dotenv 被作为数据解析,不执行命令替换或覆盖脚本 PATH',
319
319
  await assert.rejects(access(join(fixture.root, 'should-not-exist')));
320
320
  });
321
321
 
322
- test('build 拒绝重复键、漂移基础镜像和额外版本参数', async () => {
322
+ test('build 接受带标签基础镜像并拒绝重复键和额外版本参数', async () => {
323
323
  const duplicate = await createFixture({ extraEnv: 'PROJECT_NAME=duplicate\n' });
324
324
  assert.notEqual(runBuild(duplicate).status, 0);
325
- const mutable = await createFixture();
326
- await writeFile(join(mutable.root, '.env'), (await readFile(join(mutable.root, '.env'), 'utf8')).replace(/nginx@sha256:[0-9a-f]+/, 'nginx:latest'));
327
- assert.notEqual(runBuild(mutable).status, 0);
325
+ const tagged = await createFixture();
326
+ assert.equal(runBuild(tagged).status, 0);
328
327
  const extra = await createFixture();
329
328
  assert.equal(runBuild(extra, {}, '20260808-001').status, 2);
330
329
  const logDirectory = await createFixture({ extraEnv: 'LOG_DIR=/tmp/logs\n' });
@@ -132,10 +132,6 @@ validate_configuration() {
132
132
  [[ "$seen" != *" $port "* ]] || fail "host ports must be unique; duplicate value: $port"
133
133
  seen+="$port "
134
134
  done
135
- [[ "$FRONTEND_BASE_IMAGE" =~ @sha256:[0-9a-f]{64}$ ]] ||
136
- fail "FRONTEND_BASE_IMAGE must be pinned by sha256 digest"
137
- [[ "$BACKEND_BASE_IMAGE" =~ @sha256:[0-9a-f]{64}$ ]] ||
138
- fail "BACKEND_BASE_IMAGE must be pinned by sha256 digest"
139
135
  [[ "$DATABASE_MIGRATION_MODE" == manual || "$DATABASE_MIGRATION_MODE" == none ]] ||
140
136
  fail "DATABASE_MIGRATION_MODE must be manual or none"
141
137
  }
@@ -25,6 +25,6 @@ FRONTEND_BLUE_PORT=
25
25
  FRONTEND_GREEN_PORT=
26
26
  BACKEND_BLUE_PORT=
27
27
  BACKEND_GREEN_PORT=
28
- FRONTEND_BASE_IMAGE=
29
- BACKEND_BASE_IMAGE=
28
+ FRONTEND_BASE_IMAGE=nginx:stable
29
+ BACKEND_BASE_IMAGE=node:24-alpine3.24
30
30
  DATABASE_MIGRATION_MODE=
package/README.md CHANGED
@@ -60,7 +60,51 @@ wdyy update-skill --all
60
60
 
61
61
  ## 发布到 npm
62
62
 
63
- 发布包名为 `@wdyy/skills`,命令行入口为 `wdyy`。发布前不得跳过验证:
63
+ 发布包名为 `@wdyy/skills`,命令行入口为 `wdyy`。以下流程适用于首次发布和后续发版;同一包名与版本只能发布一次。
64
+
65
+ ### 使用发布脚本
66
+
67
+ 推荐从项目根目录手动运行 `release_npm.sh`。脚本会检查工作区、组织权限、项目测试、lint 与打包内容,自动执行 `npm version <patch|minor|major>`、`npm publish --access public`,并核验 registry 版本。它不会执行登录、浏览器认证或处理认证凭据。
68
+
69
+ 首次运行或登录失效时,先手工登录;脚本检测到未登录也会提示并退出:
70
+
71
+ ```bash
72
+ npm login
73
+ ./release_npm.sh patch
74
+ ```
75
+
76
+ 可按变更范围选择版本级别:
77
+
78
+ ```bash
79
+ ./release_npm.sh patch # 修复或小幅调整
80
+ ./release_npm.sh minor # 向后兼容的新功能
81
+ ./release_npm.sh major # 不兼容变更
82
+ ```
83
+
84
+ 脚本在 `npm publish` 成功前不会推送 Git 提交或标签;若 `npm version` 已完成而后续发布失败,工程师必须根据 npm 与 Git 的实际状态处理,不得重复发布相同版本。
85
+
86
+ ### 手工执行的发布流程
87
+
88
+ 当需要排查发布问题时,可按以下步骤手工执行。发布前确认当前工作区只包含准备发布的内容,并查看将要发布的版本:
89
+
90
+ ### 1. 准备发布内容
91
+
92
+ ```bash
93
+ git status --short
94
+ node -p "require('./package.json').version"
95
+ ```
96
+
97
+ 后续发版先选择符合变更范围的版本级别。`npm version` 会更新 `package.json`,并在 Git 工作区满足其要求时创建提交和标签:
98
+
99
+ ```bash
100
+ npm version patch # 修复或小幅调整
101
+ # npm version minor # 向后兼容的新功能
102
+ # npm version major # 不兼容变更
103
+ ```
104
+
105
+ ### 2. 执行发布前校验
106
+
107
+ 版本确定后,必须完整执行以下校验,不得跳过:
64
108
 
65
109
  ```bash
66
110
  npm test
@@ -69,27 +113,31 @@ node --test $(find .well-known/skills -path '*/scripts/*.test.mjs' -print)
69
113
  npm pack --dry-run
70
114
  ```
71
115
 
72
- 首次发布前,登录拥有 `wdyy` 组织 owner 或发布权限的 npm 账号,并在 npm 账户设置中配置安全密钥 2FA(WebAuthn,例如 macOS Touch ID 或硬件安全密钥)。npm 已不支持通过 CLI 新增 TOTP 认证器;不得在仓库、终端历史或文档中记录 access token、验证码或恢复码。
116
+ 其中 `npm pack --dry-run` 用于确认包内容;应包含 `bin`、`lib`、`.well-known/skills` `README.md`,且不应包含本地环境文件或其他无关文件。
73
117
 
74
- 确认身份与组织权限后,发布公开包:
118
+ ### 3. 登录并核对组织权限
119
+
120
+ 首次发布前,在 npm 账户设置中配置安全密钥 2FA(WebAuthn,例如 macOS Touch ID 或硬件安全密钥)。npm 已不支持通过 CLI 新增 TOTP 认证器。使用拥有 `wdyy` 组织 Owner 或发布权限的账号登录,并核对身份和组织成员资格:
75
121
 
76
122
  ```bash
77
123
  npm login
78
124
  npm whoami
79
125
  npm org ls wdyy
80
- npm publish --access public
81
126
  ```
82
127
 
83
- `npm whoami` 返回 `E401` 表示当前 CLI 没有有效登录态,应重新执行 `npm login` 后再发布。已成功登录但 `npm publish --access public` 仍返回 `E404` 时,通常表示当前账号没有 `@wdyy` 组织的包创建或发布权限;请由该组织的 Owner 授予权限后重试。不要通过在命令行中传入 access token、验证码或恢复码来规避认证。
128
+ 不得在仓库、终端历史或文档中记录 access token、验证码或恢复码。
84
129
 
85
- 同一包名和版本只能发布一次。后续发布必须先升级版本,再重新执行全部发布前验证:
130
+ ### 4. 发布公开包
131
+
132
+ 完成校验且确认登录态、组织权限和版本号无误后,执行:
86
133
 
87
134
  ```bash
88
- npm version patch
89
135
  npm publish --access public
90
136
  ```
91
137
 
92
- 发布后核验 registry 中的版本,并在干净的目标项目中验证全局安装与初始化:
138
+ ### 5. 发布后验收
139
+
140
+ 核对 registry 已出现目标版本;然后在干净的目标项目中安装并验证初始化:
93
141
 
94
142
  ```bash
95
143
  npm view @wdyy/skills version
@@ -97,6 +145,14 @@ npm install -g @wdyy/skills
97
145
  wdyy init
98
146
  ```
99
147
 
148
+ ### 常见问题
149
+
150
+ - `npm whoami` 返回 `E401`:当前 CLI 没有有效登录态,重新执行 `npm login` 后再继续。
151
+ - 已成功登录但 `npm publish --access public` 返回 `E404`:通常是当前账号没有 `@wdyy` 组织的包创建或发布权限;请组织 Owner 授权后重试。
152
+ - 发布提示版本已存在:版本不可覆盖,先通过 `npm version patch`、`minor` 或 `major` 生成新版本,再从“执行发布前校验”重新开始。
153
+
154
+ 不得通过在命令行中传入 access token、验证码或恢复码来规避认证或权限问题。
155
+
100
156
  ## 验证
101
157
 
102
158
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdyy/skills",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "企业内部开发 Skill 与项目初始化命令",
5
5
  "type": "module",
6
6
  "bin": {