@aipper/zentao-mcp-server 0.1.9 → 0.1.11

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.
@@ -1,481 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- usage() {
5
- cat <<'EOF'
6
- release-npm.sh (zentao-mcp-server)
7
-
8
- Default mode is dry-run: run checks + npm pack --dry-run, no npm publish.
9
-
10
- Usage:
11
- bash scripts/release-npm.sh
12
- bash scripts/release-npm.sh --publish
13
-
14
- Options:
15
- --release <tag> Set package version from tag (vX.Y.Z), then commit + tag
16
- --bump <level> Auto bump version: patch | minor | major, then commit + tag
17
- --publish Run npm publish after checks (defaults to --bump patch)
18
- --yes Skip interactive confirmation
19
- --require-tag Require a semver git tag on HEAD matching package version
20
- --skip-secrets-scan Skip ripgrep-based secrets scan
21
- --skip-whoami Skip npm whoami check
22
- --no-git-clean-check Skip clean-worktree check (not recommended)
23
- -h, --help Show help
24
-
25
- Environment:
26
- ZENTAO_NPM_CACHE_DIR Override npm cache dir used by this script
27
- EOF
28
- }
29
-
30
- PUBLISH=0
31
- YES=0
32
- REQUIRE_TAG=0
33
- RELEASE_TAG=""
34
- BUMP_LEVEL=""
35
- SKIP_SECRETS_SCAN=0
36
- SKIP_WHOAMI=0
37
- SKIP_GIT_CLEAN_CHECK=0
38
-
39
- while [[ $# -gt 0 ]]; do
40
- case "$1" in
41
- --release)
42
- shift
43
- if [[ $# -lt 1 ]]; then
44
- echo "error: --release requires <tag> (e.g. v0.1.0)" >&2
45
- usage
46
- exit 2
47
- fi
48
- RELEASE_TAG="$1"
49
- ;;
50
- --bump)
51
- shift
52
- if [[ $# -lt 1 ]]; then
53
- echo "error: --bump requires <level> (patch|minor|major)" >&2
54
- usage
55
- exit 2
56
- fi
57
- BUMP_LEVEL="$1"
58
- ;;
59
- --publish) PUBLISH=1 ;;
60
- --yes) YES=1 ;;
61
- --require-tag) REQUIRE_TAG=1 ;;
62
- --skip-secrets-scan) SKIP_SECRETS_SCAN=1 ;;
63
- --skip-whoami) SKIP_WHOAMI=1 ;;
64
- --no-git-clean-check) SKIP_GIT_CLEAN_CHECK=1 ;;
65
- -h|--help) usage; exit 0 ;;
66
- *) echo "error: unknown arg: $1" >&2; usage; exit 2 ;;
67
- esac
68
- shift
69
- done
70
-
71
- log() { echo "info: $*"; }
72
- warn() { echo "warn: $*" >&2; }
73
- die() { echo "error: $*" >&2; exit 2; }
74
-
75
- repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
76
- cd "$repo_root"
77
-
78
- command -v node >/dev/null 2>&1 || die "node is required"
79
- command -v npm >/dev/null 2>&1 || die "npm is required"
80
-
81
- DEFAULT_NPM_CACHE_DIR="${ZENTAO_NPM_CACHE_DIR:-/tmp/zentao-npm-cache}"
82
-
83
- maybe_use_safe_npm_cache() {
84
- if [[ -z "${npm_config_cache:-}" && -z "${NPM_CONFIG_CACHE:-}" ]]; then
85
- export npm_config_cache="$DEFAULT_NPM_CACHE_DIR"
86
- fi
87
- local cache_dir="${npm_config_cache:-${NPM_CONFIG_CACHE:-}}"
88
- if [[ -n "${cache_dir:-}" ]]; then
89
- mkdir -p "$cache_dir" 2>/dev/null || true
90
- log "npm_cache=$cache_dir"
91
- fi
92
- }
93
-
94
- maybe_use_safe_npm_cache
95
-
96
- pkg_name=""
97
- pkg_version=""
98
- pkg_private=""
99
- release_version=""
100
- release_tag_name=""
101
- release_tmpdir=""
102
- release_restore_on_exit=0
103
-
104
- cleanup_release() {
105
- if [[ "${release_restore_on_exit:-0}" == "1" && -n "${release_tmpdir:-}" ]]; then
106
- cp "$release_tmpdir/package.json" package.json 2>/dev/null || true
107
- fi
108
- if [[ -n "${release_tmpdir:-}" ]]; then
109
- rm -rf "$release_tmpdir" 2>/dev/null || true
110
- fi
111
- }
112
- trap cleanup_release EXIT
113
-
114
- is_semver() {
115
- printf '%s' "$1" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([-.+].+)?$'
116
- }
117
-
118
- normalize_release_tag() {
119
- local input="$1"
120
- if [[ "$input" == v* ]]; then
121
- release_tag_name="$input"
122
- release_version="${input#v}"
123
- else
124
- release_tag_name="v$input"
125
- release_version="$input"
126
- fi
127
- if ! is_semver "$release_version"; then
128
- die "--release requires semver tag (vX.Y.Z); got: $input"
129
- fi
130
- }
131
-
132
- calc_bumped_version() {
133
- local current="$1"
134
- local level="$2"
135
- ZENTAO_CURRENT_VERSION="$current" ZENTAO_BUMP_LEVEL="$level" node - <<'NODE'
136
- const current = process.env.ZENTAO_CURRENT_VERSION || "";
137
- const level = process.env.ZENTAO_BUMP_LEVEL || "";
138
- const m = current.match(/^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/);
139
- if (!m) {
140
- console.error(`error: current version is not semver-like: ${current}`);
141
- process.exit(2);
142
- }
143
- let major = Number(m[1]);
144
- let minor = Number(m[2]);
145
- let patch = Number(m[3]);
146
- if (level === "patch") {
147
- patch += 1;
148
- } else if (level === "minor") {
149
- minor += 1;
150
- patch = 0;
151
- } else if (level === "major") {
152
- major += 1;
153
- minor = 0;
154
- patch = 0;
155
- } else {
156
- console.error(`error: unsupported bump level: ${level} (expected patch|minor|major)`);
157
- process.exit(2);
158
- }
159
- process.stdout.write(`${major}.${minor}.${patch}`);
160
- NODE
161
- }
162
-
163
- read_pkg() {
164
- pkg_name="$(node -p "require('./package.json').name")"
165
- pkg_version="$(node -p "require('./package.json').version")"
166
- pkg_private="$(node -p "Boolean(require('./package.json').private)")"
167
- }
168
-
169
- write_version() {
170
- local v="$1"
171
- ZENTAO_RELEASE_VERSION="$v" node - <<'NODE'
172
- const fs = require("node:fs");
173
- const file = "package.json";
174
- const v = process.env.ZENTAO_RELEASE_VERSION;
175
- if (!v) {
176
- console.error("missing ZENTAO_RELEASE_VERSION");
177
- process.exit(2);
178
- }
179
- const src = fs.readFileSync(file, "utf8");
180
- const pkg = JSON.parse(src);
181
- pkg.version = v;
182
- fs.writeFileSync(file, JSON.stringify(pkg, null, 2) + "\n");
183
- NODE
184
- }
185
-
186
- backup_package_for_restore() {
187
- release_tmpdir="$(mktemp -d)"
188
- cp package.json "$release_tmpdir/package.json"
189
- release_restore_on_exit=1
190
- }
191
-
192
- check_publish_ownership() {
193
- local npm_user="$1"
194
- local package_name="$2"
195
-
196
- local view_out=""
197
- local view_code=0
198
- set +e
199
- view_out="$(npm view "$package_name" name 2>&1)"
200
- view_code=$?
201
- set -e
202
-
203
- if [[ "$view_code" != "0" ]]; then
204
- if echo "$view_out" | grep -Eqi "(E404|404|not found|not in this registry)"; then
205
- log "publish ownership precheck: package not found on registry ($package_name), treated as first publish"
206
- return 0
207
- fi
208
- warn "publish ownership precheck skipped: cannot query package metadata"
209
- return 0
210
- fi
211
-
212
- local owners_out=""
213
- local owners_code=0
214
- set +e
215
- owners_out="$(npm owner ls "$package_name" 2>&1)"
216
- owners_code=$?
217
- set -e
218
-
219
- if [[ "$owners_code" != "0" ]]; then
220
- warn "publish ownership precheck skipped: cannot query package owners"
221
- return 0
222
- fi
223
-
224
- if echo "$owners_out" | grep -Eiq "^${npm_user}[[:space:]]"; then
225
- log "publish ownership precheck: ok ($npm_user owns $package_name)"
226
- return 0
227
- fi
228
-
229
- die "npm user '$npm_user' is not an owner of '$package_name' (likely 403). Use a scoped name like '@$npm_user/zentao-mcp-server' or ask current owner to add you."
230
- }
231
-
232
- read_pkg
233
-
234
- # Default behavior: publishing without explicit release/bump will auto-bump patch.
235
- if [[ "$PUBLISH" == "1" && -z "${RELEASE_TAG:-}" && -z "${BUMP_LEVEL:-}" ]]; then
236
- BUMP_LEVEL="patch"
237
- log "publish requested without version args; defaulting to --bump patch"
238
- fi
239
-
240
- log "repo_root=$repo_root"
241
- log "package=$pkg_name"
242
- log "version=$pkg_version"
243
- log "mode=$(
244
- if [[ "$PUBLISH" == "1" ]]; then
245
- echo publish
246
- elif [[ -n "${RELEASE_TAG:-}" || -n "${BUMP_LEVEL:-}" ]]; then
247
- echo prepare
248
- else
249
- echo dry-run
250
- fi
251
- )"
252
-
253
- if [[ -n "${RELEASE_TAG:-}" && -n "${BUMP_LEVEL:-}" ]]; then
254
- die "cannot combine --release and --bump"
255
- fi
256
-
257
- VERSION_UPDATE=0
258
- if [[ -n "${RELEASE_TAG:-}" ]]; then
259
- normalize_release_tag "$RELEASE_TAG"
260
- VERSION_UPDATE=1
261
- fi
262
- if [[ -n "${BUMP_LEVEL:-}" ]]; then
263
- release_version="$(calc_bumped_version "$pkg_version" "$BUMP_LEVEL")"
264
- release_tag_name="v$release_version"
265
- VERSION_UPDATE=1
266
- log "bump_level=$BUMP_LEVEL"
267
- fi
268
-
269
- if [[ "$VERSION_UPDATE" == "1" && "$REQUIRE_TAG" == "1" ]]; then
270
- die "cannot combine --release/--bump with --require-tag (release flow creates a tag)"
271
- fi
272
-
273
- if [[ "$VERSION_UPDATE" == "1" ]]; then
274
- command -v git >/dev/null 2>&1 || die "--release/--bump requires git"
275
- log "release_tag=$release_tag_name"
276
- log "release_version=$release_version"
277
-
278
- if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
279
- die "--release requires running inside a git repository"
280
- fi
281
-
282
- if git rev-parse -q --verify "refs/tags/$release_tag_name" >/dev/null 2>&1; then
283
- die "--release tag already exists: $release_tag_name"
284
- fi
285
-
286
- if [[ "$SKIP_GIT_CLEAN_CHECK" != "1" ]]; then
287
- dirty="$(git status --porcelain || true)"
288
- if [[ -n "${dirty:-}" ]]; then
289
- die "--release requires a clean git working tree; commit or stash changes first"
290
- fi
291
- fi
292
-
293
- backup_package_for_restore
294
- write_version "$release_version"
295
- read_pkg
296
- log "(after release) version=$pkg_version"
297
- fi
298
-
299
- if [[ "$REQUIRE_TAG" == "1" ]]; then
300
- if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
301
- die "--require-tag requires running inside a git repository"
302
- fi
303
- git_tag="$(git describe --tags --exact-match 2>/dev/null || true)"
304
- if [[ -z "${git_tag:-}" ]]; then
305
- die "--require-tag expected a semver tag on HEAD (e.g. v$pkg_version); found none"
306
- fi
307
- tag_version="${git_tag#v}"
308
- if ! is_semver "$tag_version"; then
309
- die "--require-tag expected tag in vX.Y.Z (or X.Y.Z) form; got: $git_tag"
310
- fi
311
- if [[ "$tag_version" != "$pkg_version" ]]; then
312
- die "--require-tag tag version mismatch: tag=$git_tag (=> $tag_version) but package version=$pkg_version"
313
- fi
314
- log "git_tag=$git_tag"
315
- fi
316
-
317
- if [[ "$PUBLISH" == "1" && "$pkg_version" == "0.0.0" ]]; then
318
- die "refusing to publish version 0.0.0; bump version first"
319
- fi
320
-
321
- if [[ "$VERSION_UPDATE" != "1" ]]; then
322
- if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
323
- if [[ "$SKIP_GIT_CLEAN_CHECK" != "1" ]]; then
324
- dirty="$(git status --porcelain || true)"
325
- if [[ -n "${dirty:-}" ]]; then
326
- if [[ "$PUBLISH" == "1" ]]; then
327
- die "git working tree is not clean; commit or stash changes before publishing"
328
- fi
329
- warn "git working tree is not clean (ok for dry-run):"
330
- echo "$dirty" | sed -n '1,20p'
331
- if [[ "$(echo "$dirty" | wc -l | tr -d ' ')" -gt 20 ]]; then
332
- warn "(truncated)"
333
- fi
334
- fi
335
- fi
336
- else
337
- warn "not a git repository; skip git clean check"
338
- fi
339
- fi
340
-
341
- if [[ "$SKIP_SECRETS_SCAN" != "1" ]]; then
342
- if command -v rg >/dev/null 2>&1; then
343
- log "secrets scan (filenames only):"
344
- secret_re='(_authToken\\s*=\\s*[^\\s#]{16,}|sk-[A-Za-z0-9]{20,}|ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{20,}|npm_[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|AIzaSy[A-Za-z0-9_-]{35}|-----BEGIN [A-Z ]*PRIVATE KEY-----|Authorization:\\s*Bearer\\s+[^\\s<]{20,}|Bearer\\s+[A-Za-z0-9._-]{20,}|(api[_-]?key|token|password|secret)\\s*[:=]\\s*[\\x27\\\"][^\\x27\\\"<]{12,}[\\x27\\\"])'
345
- matches="$(rg -i -l "$secret_re" . --glob '!node_modules/**' --glob '!.git/**' --glob '!dist/**' --glob '!.env' --glob '!.env.*' || true)"
346
- if [[ -n "${matches:-}" ]]; then
347
- if [[ "$PUBLISH" == "1" ]]; then
348
- echo "$matches"
349
- die "potential secret-like patterns found; inspect files above before publishing"
350
- fi
351
- warn "potential secret-like patterns found (dry-run continues):"
352
- echo "$matches"
353
- else
354
- log "secrets scan: ok"
355
- fi
356
- else
357
- warn "rg not found; skip secrets scan"
358
- fi
359
- fi
360
-
361
- if [[ "$SKIP_WHOAMI" == "1" ]]; then
362
- warn "npm whoami skipped (--skip-whoami)"
363
- else
364
- set +e
365
- whoami_out="$(npm whoami 2>&1)"
366
- whoami_code=$?
367
- set -e
368
- if [[ "$whoami_code" == "0" ]]; then
369
- npm_user="$(printf '%s' "$whoami_out" | tr -d '\r\n')"
370
- log "npm whoami: ok ($npm_user)"
371
- else
372
- warn "npm whoami failed:"
373
- echo "$whoami_out" >&2
374
- if [[ "$PUBLISH" == "1" ]]; then
375
- warn "continue publish flow despite whoami failure; final publish result will be authoritative"
376
- fi
377
- fi
378
- fi
379
-
380
- if [[ "$PUBLISH" == "1" ]]; then
381
- if [[ "$SKIP_WHOAMI" == "1" ]]; then
382
- warn "publish ownership precheck skipped because --skip-whoami is enabled"
383
- else
384
- if [[ -z "${npm_user:-}" ]]; then
385
- warn "publish ownership precheck skipped: npm username unavailable"
386
- else
387
- check_publish_ownership "$npm_user" "$pkg_name"
388
- fi
389
- fi
390
- fi
391
-
392
- log "pack preview: npm pack --dry-run"
393
- pack_out=""
394
- set +e
395
- pack_out="$(npm pack --dry-run 2>&1)"
396
- pack_code=$?
397
- set -e
398
- if [[ "$pack_code" != "0" ]]; then
399
- if echo "$pack_out" | grep -Eqi "(EPERM|EACCES)" && [[ "${npm_config_cache:-${NPM_CONFIG_CACHE:-}}" != "$DEFAULT_NPM_CACHE_DIR" ]]; then
400
- warn "npm pack failed with EPERM/EACCES; retry with npm_config_cache=$DEFAULT_NPM_CACHE_DIR"
401
- export npm_config_cache="$DEFAULT_NPM_CACHE_DIR"
402
- mkdir -p "$DEFAULT_NPM_CACHE_DIR" 2>/dev/null || true
403
- npm pack --dry-run >/dev/null
404
- else
405
- echo "$pack_out" >&2
406
- exit "$pack_code"
407
- fi
408
- fi
409
- log "pack preview: ok"
410
-
411
- publish_cmd=(npm publish)
412
- if [[ "$pkg_name" == @*/* ]]; then
413
- publish_cmd=(npm publish --access public)
414
- fi
415
- log "publish command: ${publish_cmd[*]}"
416
-
417
- if [[ "$PUBLISH" != "1" ]]; then
418
- if [[ "$VERSION_UPDATE" == "1" ]]; then
419
- if [[ "$YES" != "1" ]]; then
420
- echo ""
421
- echo "About to prepare git release:"
422
- echo " - set version to $release_version"
423
- echo " - git commit: chore(release): $release_tag_name"
424
- echo " - git tag: $release_tag_name"
425
- echo ""
426
- read -r -p "Type 'release' to continue: " confirm_release
427
- if [[ "${confirm_release:-}" != "release" ]]; then
428
- die "aborted"
429
- fi
430
- fi
431
- if ! git diff --quiet -- package.json; then
432
- git add package.json
433
- git commit -m "chore(release): $release_tag_name"
434
- else
435
- log "release: no version changes to commit"
436
- fi
437
- git tag "$release_tag_name"
438
- log "release: created git tag $release_tag_name"
439
- release_restore_on_exit=0
440
- log "prepare complete (no npm publish performed)"
441
- exit 0
442
- fi
443
- log "dry-run complete (no publish performed)"
444
- exit 0
445
- fi
446
-
447
- if [[ "$pkg_private" == "true" ]]; then
448
- die "package.json has private=true; set private=false before publishing"
449
- fi
450
-
451
- if [[ "$YES" != "1" ]]; then
452
- echo ""
453
- echo "About to publish to npm:"
454
- echo " - $pkg_name@$pkg_version"
455
- if [[ "$VERSION_UPDATE" == "1" ]]; then
456
- echo ""
457
- echo "And prepare git release:"
458
- echo " - git commit: chore(release): $release_tag_name"
459
- echo " - git tag: $release_tag_name"
460
- fi
461
- echo ""
462
- read -r -p "Type 'publish' to continue: " confirm_publish
463
- if [[ "${confirm_publish:-}" != "publish" ]]; then
464
- die "aborted"
465
- fi
466
- fi
467
-
468
- if [[ "$VERSION_UPDATE" == "1" ]]; then
469
- if ! git diff --quiet -- package.json; then
470
- git add package.json
471
- git commit -m "chore(release): $release_tag_name"
472
- else
473
- log "release: no version changes to commit"
474
- fi
475
- git tag "$release_tag_name"
476
- log "release: created git tag $release_tag_name"
477
- release_restore_on_exit=0
478
- fi
479
-
480
- "${publish_cmd[@]}"
481
- log "publish complete"