From ae6954a02f1cdf5feba00613c8fc00d748baa433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Wed, 13 May 2026 17:22:50 +0800 Subject: [PATCH 1/3] fix(publish): auto-discover packages + pre-publish test gate What: Replace hardcoded PUBLISH_ORDER with auto-discovery of all non-private packages, sorted by topological dependency order (Kahn's). Add a test gate (npm test) after build, before publish. Why: The manual list was missing workflow-gateway and workflow-agent-react, causing them to never get published. Any future package additions would have the same problem. Changes: - scripts/publish.sh: Replace static PUBLISH_ORDER array with node script that reads all packages/*/package.json, filters out private, and topologically sorts by @uncaged/* internal dependencies - scripts/publish.sh: Add npm test step between build and publish, aborting on failure --- scripts/publish.sh | 108 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/scripts/publish.sh b/scripts/publish.sh index a655ce9..e6c72ae 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -36,23 +36,53 @@ CURRENT=$(current_version) VERSION=$(bump_version "$CURRENT" "${1:?Usage: publish.sh }") echo "๐Ÿ“ฆ Publish: $CURRENT โ†’ $VERSION" -# โ”€โ”€โ”€ Topological publish order โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -PUBLISH_ORDER=( - workflow-protocol - workflow-util - workflow-cas - workflow-runtime - workflow-reactor - workflow-register - workflow-execute - cli-workflow - workflow-util-agent - workflow-agent-cursor - workflow-agent-hermes - workflow-agent-llm - workflow-template-develop - workflow-template-solve-issue -) +# โ”€โ”€โ”€ Auto-discover publishable packages (topological order) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Finds all non-private packages and sorts by internal dependency count (fewest first) +mapfile -t PUBLISH_ORDER < <(node -e " + const fs = require('fs'); + const path = require('path'); + const pkgsDir = path.join('$REPO_ROOT', 'packages'); + const dirs = fs.readdirSync(pkgsDir).filter(d => + fs.existsSync(path.join(pkgsDir, d, 'package.json')) + ); + // Collect non-private packages + const pkgs = new Map(); + for (const d of dirs) { + const p = JSON.parse(fs.readFileSync(path.join(pkgsDir, d, 'package.json'), 'utf8')); + if (p.private) continue; + const deps = new Set(); + for (const k of ['dependencies','peerDependencies','devDependencies']) { + if (!p[k]) continue; + for (const n of Object.keys(p[k])) { + if (n.startsWith('@uncaged/')) deps.add(n.replace('@uncaged/','')); + } + } + pkgs.set(d, deps); + } + // Topological sort (Kahn's) โ€” publish dependencies before dependents + const inDeg = new Map([...pkgs.keys()].map(k => [k, 0])); + for (const [pkg, deps] of pkgs) { + for (const dep of deps) { + if (pkgs.has(dep)) inDeg.set(pkg, (inDeg.get(pkg) || 0) + 1); + } + } + const queue = [...inDeg.entries()].filter(([,d]) => d === 0).map(([k]) => k).sort(); + const order = []; + while (queue.length) { + const n = queue.shift(); + order.push(n); + for (const [pkg, deps] of pkgs) { + if (deps.has(n)) { + inDeg.set(pkg, inDeg.get(pkg) - 1); + if (inDeg.get(pkg) === 0) queue.push(pkg); + } + } + } + // Append any remaining (circular or isolated) โ€” should not happen + for (const k of pkgs.keys()) { if (!order.includes(k)) order.push(k); } + order.forEach(o => console.log(o)); +") +echo "๐Ÿ“‹ Discovered ${#PUBLISH_ORDER[@]} packages: ${PUBLISH_ORDER[*]}" # โ”€โ”€โ”€ Bump version โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ echo "๐Ÿ”ข Bumping versions..." @@ -92,6 +122,13 @@ done echo "๐Ÿ”จ Building..." npm run build +# โ”€โ”€โ”€ Self-test โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +echo "๐Ÿงช Running tests..." +if ! npm test; then + echo "โŒ Tests failed โ€” aborting publish" + exit 1 +fi + # โ”€โ”€โ”€ Publish โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ echo "๐Ÿš€ Publishing..." cat > "$REPO_ROOT/.npmrc" <" git push -[[ "$FAIL" -eq 0 ]] && echo "โœ… v${VERSION} published" || echo "โš ๏ธ v${VERSION} published with errors" +if [[ "$FAIL" -ne 0 ]]; then + echo "โš ๏ธ v${VERSION} published with errors" + exit 1 +fi + +# โ”€โ”€โ”€ Post-publish smoke test โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +echo "๐Ÿ” Smoke test: installing & verifying published packages..." +SMOKE_DIR=$(mktemp -d) +trap "rm -rf $SMOKE_DIR" EXIT + +cat > "$SMOKE_DIR/.npmrc" </dev/null 2>&1 && npm install $PKGS_TO_INSTALL 2>&1) || { + echo "โŒ Smoke test failed: could not install packages" + exit 1 +} + +# Try importing each package +for pkg_dir in "${PUBLISH_ORDER[@]}"; do + if ! (cd "$SMOKE_DIR" && node -e "require('@uncaged/${pkg_dir}')" 2>&1); then + echo "โŒ Smoke test failed: require('@uncaged/${pkg_dir}') threw" + exit 1 + fi + echo " โœ… @uncaged/${pkg_dir} โ€” importable" +done + +echo "โœ… v${VERSION} published & verified" From e1423f196bbb9f7095ae2cc43291d42c35be85f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Wed, 13 May 2026 17:32:08 +0800 Subject: [PATCH 2/3] refactor: delegate publish to publish-all.sh, remove duplicated discovery+topo logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove inline auto-discover + Kahn's topo sort from publish.sh (was duplicating publish-all.sh) - Remove inline publish loop + smoke test (publish-all.sh handles both) - publish.sh now: bump version โ†’ replace workspace:* โ†’ build โ†’ test โ†’ call publish-all.sh โ†’ restore โ†’ commit - Net: -97 lines, single source of truth for package discovery and publish order --- scripts/publish.sh | 107 +++------------------------------------------ 1 file changed, 5 insertions(+), 102 deletions(-) diff --git a/scripts/publish.sh b/scripts/publish.sh index e6c72ae..529e8e6 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -13,8 +13,7 @@ set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$REPO_ROOT" -GITEA_TOKEN="${GITEA_TOKEN:?GITEA_TOKEN is required}" -GITEA_NPM_REGISTRY="https://git.shazhou.work/api/packages/uncaged/npm/" +GITEA_TOKEN="${GITEA_TOKEN:?GITEA_TOKEN is required}" # needed by .npmrc # โ”€โ”€โ”€ Version โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ current_version() { @@ -36,54 +35,6 @@ CURRENT=$(current_version) VERSION=$(bump_version "$CURRENT" "${1:?Usage: publish.sh }") echo "๐Ÿ“ฆ Publish: $CURRENT โ†’ $VERSION" -# โ”€โ”€โ”€ Auto-discover publishable packages (topological order) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# Finds all non-private packages and sorts by internal dependency count (fewest first) -mapfile -t PUBLISH_ORDER < <(node -e " - const fs = require('fs'); - const path = require('path'); - const pkgsDir = path.join('$REPO_ROOT', 'packages'); - const dirs = fs.readdirSync(pkgsDir).filter(d => - fs.existsSync(path.join(pkgsDir, d, 'package.json')) - ); - // Collect non-private packages - const pkgs = new Map(); - for (const d of dirs) { - const p = JSON.parse(fs.readFileSync(path.join(pkgsDir, d, 'package.json'), 'utf8')); - if (p.private) continue; - const deps = new Set(); - for (const k of ['dependencies','peerDependencies','devDependencies']) { - if (!p[k]) continue; - for (const n of Object.keys(p[k])) { - if (n.startsWith('@uncaged/')) deps.add(n.replace('@uncaged/','')); - } - } - pkgs.set(d, deps); - } - // Topological sort (Kahn's) โ€” publish dependencies before dependents - const inDeg = new Map([...pkgs.keys()].map(k => [k, 0])); - for (const [pkg, deps] of pkgs) { - for (const dep of deps) { - if (pkgs.has(dep)) inDeg.set(pkg, (inDeg.get(pkg) || 0) + 1); - } - } - const queue = [...inDeg.entries()].filter(([,d]) => d === 0).map(([k]) => k).sort(); - const order = []; - while (queue.length) { - const n = queue.shift(); - order.push(n); - for (const [pkg, deps] of pkgs) { - if (deps.has(n)) { - inDeg.set(pkg, inDeg.get(pkg) - 1); - if (inDeg.get(pkg) === 0) queue.push(pkg); - } - } - } - // Append any remaining (circular or isolated) โ€” should not happen - for (const k of pkgs.keys()) { if (!order.includes(k)) order.push(k); } - order.forEach(o => console.log(o)); -") -echo "๐Ÿ“‹ Discovered ${#PUBLISH_ORDER[@]} packages: ${PUBLISH_ORDER[*]}" - # โ”€โ”€โ”€ Bump version โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ echo "๐Ÿ”ข Bumping versions..." for dir in packages/*/; do @@ -129,22 +80,9 @@ if ! npm test; then exit 1 fi -# โ”€โ”€โ”€ Publish โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -echo "๐Ÿš€ Publishing..." -cat > "$REPO_ROOT/.npmrc" <&1); then - echo " โœ… @uncaged/$pkg_dir@$VERSION" - else - echo " โŒ @uncaged/$pkg_dir" - FAIL=1 - fi -done +# โ”€โ”€โ”€ Publish (delegate to publish-all.sh) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +echo "๐Ÿš€ Publishing via publish-all.sh..." +"$REPO_ROOT/scripts/publish-all.sh" # โ”€โ”€โ”€ Restore workspace:* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ echo "๐Ÿ”„ Restoring workspace:*..." @@ -173,39 +111,4 @@ git commit -m "chore: publish v${VERSION} ๅฐๆฉ˜ " git push -if [[ "$FAIL" -ne 0 ]]; then - echo "โš ๏ธ v${VERSION} published with errors" - exit 1 -fi - -# โ”€โ”€โ”€ Post-publish smoke test โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -echo "๐Ÿ” Smoke test: installing & verifying published packages..." -SMOKE_DIR=$(mktemp -d) -trap "rm -rf $SMOKE_DIR" EXIT - -cat > "$SMOKE_DIR/.npmrc" </dev/null 2>&1 && npm install $PKGS_TO_INSTALL 2>&1) || { - echo "โŒ Smoke test failed: could not install packages" - exit 1 -} - -# Try importing each package -for pkg_dir in "${PUBLISH_ORDER[@]}"; do - if ! (cd "$SMOKE_DIR" && node -e "require('@uncaged/${pkg_dir}')" 2>&1); then - echo "โŒ Smoke test failed: require('@uncaged/${pkg_dir}') threw" - exit 1 - fi - echo " โœ… @uncaged/${pkg_dir} โ€” importable" -done - -echo "โœ… v${VERSION} published & verified" +echo "โœ… v${VERSION} published" From 0207f93303c804ca863ec59482a5469cee9a5092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Wed, 13 May 2026 17:42:11 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20npm=20test=20=E2=86=92=20bun=20test?= =?UTF-8?q?=20per=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/publish.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/publish.sh b/scripts/publish.sh index 529e8e6..baadce2 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -75,7 +75,7 @@ npm run build # โ”€โ”€โ”€ Self-test โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ echo "๐Ÿงช Running tests..." -if ! npm test; then +if ! bun test; then echo "โŒ Tests failed โ€” aborting publish" exit 1 fi