diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7dfa1c5..b7fb2d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -333,21 +333,36 @@ jobs: tmp="$(mktemp -d)" if [ "$ext" = "zip" ]; then - unzip -q "$archive" -d "$tmp" + # PowerShell `Compress-Archive` writes ZIP entries with backslash + # separators; Info-ZIP `unzip` flattens those into a literal + # filename so the binary can't be found by path. `7z` (preinstalled + # on ubuntu-latest) normalizes backslashes into real directories. + 7z x -y -o"$tmp" "$archive" >/dev/null else tar -xf "$archive" -C "$tmp" fi pkgdir="stage/${key}" mkdir -p "$pkgdir/bin" + # Prefer the expected layout (`/`), then fall back to + # a recursive search so the step is robust to archive quirks. if [ -f "$tmp/${stem}/${binname}" ]; then - cp "$tmp/${stem}/${binname}" "$pkgdir/bin/${binname}" + src="$tmp/${stem}/${binname}" elif [ -f "$tmp/${binname}" ]; then - cp "$tmp/${binname}" "$pkgdir/bin/${binname}" + src="$tmp/${binname}" else + # Exact match, then suffix match — the latter catches a + # backslash-flattened basename like `\kimetsu.exe` if some + # extractor still mangles the Windows archive. + src="$(find "$tmp" -type f -name "${binname}" | head -n1)" + [ -z "$src" ] && src="$(find "$tmp" -type f -name "*${binname}" | head -n1)" + fi + if [ -z "${src:-}" ] || [ ! -f "$src" ]; then echo "::error::binary ${binname} not found inside ${archive}" + echo "::error::extracted tree:"; find "$tmp" -maxdepth 3 -print exit 1 fi + cp "$src" "$pkgdir/bin/${binname}" [ "$ext" = "zip" ] || chmod +x "$pkgdir/bin/${binname}" node -e ' @@ -365,8 +380,14 @@ jobs: }, null, 2) + "\n"); ' "$pkgdir" "@kimetsu-ai/${key}" "$VERSION" "$osv" "$cpuv" - echo "publishing @kimetsu-ai/${key}@${VERSION}" - ( cd "$pkgdir" && npm publish --access public ) + # Idempotent: skip if this exact version is already on npm, so a + # re-run after a partial failure doesn't choke on EPUBLISHCONFLICT. + if npm view "@kimetsu-ai/${key}@${VERSION}" version >/dev/null 2>&1; then + echo "skip: @kimetsu-ai/${key}@${VERSION} already published" + else + echo "publishing @kimetsu-ai/${key}@${VERSION}" + ( cd "$pkgdir" && npm publish --access public ) + fi done - name: stamp + publish main package @@ -386,8 +407,12 @@ jobs: } fs.writeFileSync(p, JSON.stringify(j, null, 2) + "\n"); ' "$VERSION" - echo "publishing kimetsu-ai@${VERSION}" - ( cd npm/kimetsu && npm publish --access public ) + if npm view "kimetsu-ai@${VERSION}" version >/dev/null 2>&1; then + echo "skip: kimetsu-ai@${VERSION} already published" + else + echo "publishing kimetsu-ai@${VERSION}" + ( cd npm/kimetsu && npm publish --access public ) + fi - name: summary run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 93d16f4..9b0452b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ follow [SemVer](https://semver.org/spec/v2.0.0.html) with the caveat that pre-1.0 minor bumps may include breaking changes (documented in the release notes). -## v0.8.2 — npm distribution +## v0.8.3 — npm distribution ADDED * **npm distribution.** Kimetsu now publishes to npm — `npm install -g kimetsu-ai` @@ -22,12 +22,19 @@ ADDED live in [`npm/`](npm/). Installs the `kimetsu` command (also available as `kimetsu-ai`). -## v0.8.1 - -Release-engineering release. The `publish-npm` pipeline first landed here, but -the npm packages themselves ship in v0.8.2 (npm registry naming: the project -lives under the `@kimetsu-ai` scope / `kimetsu-ai` package). crates.io and the -prebuilt binaries released as usual. +FIXED + * **Windows npm package.** The `publish-npm` job now extracts the Windows + archive with `7z` instead of `unzip` (PowerShell `Compress-Archive` uses + backslash path separators that `unzip` flattens), and publishing is + idempotent so a re-run after a partial failure skips already-published + versions. + +## v0.8.1, v0.8.2 + +Release-engineering releases on the road to the npm channel. crates.io and the +prebuilt binaries shipped as usual in both. npm naming settled on the +`@kimetsu-ai` scope / `kimetsu-ai` package (v0.8.1), and the complete, working +npm packages — including Windows — ship in v0.8.3. ## v0.8.0 — proactive recall, selectable embedding model, full MCP control diff --git a/Cargo.lock b/Cargo.lock index 3ad0411..a2b7a27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1483,7 +1483,7 @@ dependencies = [ [[package]] name = "kimetsu-agent" -version = "0.8.2" +version = "0.8.3" dependencies = [ "blake3", "kimetsu-brain", @@ -1499,7 +1499,7 @@ dependencies = [ [[package]] name = "kimetsu-brain" -version = "0.8.2" +version = "0.8.3" dependencies = [ "blake3", "fastembed", @@ -1515,7 +1515,7 @@ dependencies = [ [[package]] name = "kimetsu-chat" -version = "0.8.2" +version = "0.8.3" dependencies = [ "base64 0.22.1", "crossterm", @@ -1530,7 +1530,7 @@ dependencies = [ [[package]] name = "kimetsu-cli" -version = "0.8.2" +version = "0.8.3" dependencies = [ "clap", "kimetsu-agent", @@ -1546,7 +1546,7 @@ dependencies = [ [[package]] name = "kimetsu-core" -version = "0.8.2" +version = "0.8.3" dependencies = [ "serde", "serde_json", @@ -1557,7 +1557,7 @@ dependencies = [ [[package]] name = "kimetsu-e2e" -version = "0.8.2" +version = "0.8.3" dependencies = [ "kimetsu-agent", "kimetsu-brain", diff --git a/Cargo.toml b/Cargo.toml index 741eb2a..b3f545a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ resolver = "3" # everything below except the per-crate `description`, `keywords`, # and `categories` which live in each `[package]` block since # crates.io enforces them per crate. -version = "0.8.2" +version = "0.8.3" edition = "2024" # Rust ecosystem dual-license (matches tokio, serde, fastembed-rs, # etc.). UNLICENSED would block crates.io entirely.