Skip to content

Commit ce5e956

Browse files
committed
feat(npm): publish scoped packages
1 parent 33df418 commit ce5e956

14 files changed

Lines changed: 86 additions & 205 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@ jobs:
1515
- uses: ./.github/actions/setup-bun
1616
- name: Validate version
1717
run: test "v$(node -p \"require('./packages/miaopan-code/package.json').version\")" = "$GITHUB_REF_NAME"
18+
- name: Set release version
19+
run: echo "MIAOPAN_CODE_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
1820
- name: Build CLI
1921
run: bun --cwd packages/miaopan-code run build
2022
env:
21-
MIAOPAN_CODE_VERSION: ${{ github.ref_name }}
22-
MIAOPAN_CODE_CHANNEL: release
23+
MIAOPAN_CODE_CHANNEL: latest
24+
- name: Publish npm packages
25+
run: bun --cwd packages/miaopan-code run script/publish.ts
26+
env:
27+
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
2328
- name: Build VSIX
2429
working-directory: sdks/vscode
2530
run: npx @vscode/vsce package --no-git-tag-version --no-update-package-json --no-dependencies -o dist/miaopan-code.vsix

‎README.zh.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<p align="center">开源的 AI Coding Agent。</p>
1111
<p align="center">
1212
<a href="https://github.com/miaopan607/miaopan-code/discord"><img alt="Discord" src="https://img.shields.io/discord/1391832426048651334?style=flat-square&label=discord" /></a>
13-
<a href="https://www.npmjs.com/package/miaopan-code-ai"><img alt="npm" src="https://img.shields.io/npm/v/miaopan-code-ai?style=flat-square" /></a>
13+
<a href="https://www.npmjs.com/package/@miaopan/code"><img alt="npm" src="https://img.shields.io/npm/v/@miaopan/code?style=flat-square" /></a>
1414
<a href="https://github.com/miaopan607/miaopan-code/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/miaopan607/miaopan-code/publish.yml?style=flat-square&branch=dev" /></a>
1515
</p>
1616

@@ -50,7 +50,7 @@
5050
curl -fsSL https://github.com/miaopan607/miaopan-code/install | bash
5151

5252
# 软件包管理器
53-
npm i -g miaopan-code-ai@latest # 也可使用 bun/pnpm/yarn
53+
npm i -g @miaopan/code@latest # 也可使用 bun/pnpm/yarn
5454
scoop install miaopan-code # Windows
5555
choco install miaopan-code # Windows
5656
brew install anomalyco/tap/miaopan-code # macOS 和 Linux(推荐,始终保持最新)

‎packages/miaopan-code/script/build.ts‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ const targets = singleFlag
137137
await $`rm -rf dist`
138138

139139
const binaries: Record<string, string> = {}
140+
const binaryDirs: string[] = []
140141
if (!skipInstall) {
141142
await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}`
142143
await $`bun install --os="*" --cpu="*" @parcel/watcher@${pkg.dependencies["@parcel/watcher"]}`
@@ -212,11 +213,15 @@ for (const item of targets) {
212213
}
213214

214215
await $`rm -rf ./dist/${name}/bin/tui`
216+
await Bun.file(`dist/${name}/LICENSE`).write(await Bun.file("../../LICENSE").text())
217+
await Bun.file(`dist/${name}/NOTICE`).write(await Bun.file("../../NOTICE").text())
218+
const packageName = `@miaopan/${name.replace("miaopan-code", "code")}`
215219
await Bun.file(`dist/${name}/package.json`).write(
216220
JSON.stringify(
217221
{
218-
name,
222+
name: packageName,
219223
version: Script.version,
224+
license: pkg.license,
220225
preferUnplugged: true,
221226
os: [item.os],
222227
cpu: [item.arch],
@@ -226,15 +231,16 @@ for (const item of targets) {
226231
2,
227232
),
228233
)
229-
binaries[name] = Script.version
234+
binaries[packageName] = Script.version
235+
binaryDirs.push(name)
230236
}
231237

232238
if (Script.release) {
233-
for (const key of Object.keys(binaries)) {
234-
if (key.includes("linux")) {
235-
await $`tar -czf ../../${key}.tar.gz *`.cwd(`dist/${key}/bin`)
239+
for (const name of binaryDirs) {
240+
if (name.includes("linux")) {
241+
await $`tar -czf ../../${name}.tar.gz *`.cwd(`dist/${name}/bin`)
236242
} else {
237-
await $`zip -r ../../${key}.zip *`.cwd(`dist/${key}/bin`)
243+
await $`zip -r ../../${name}.zip *`.cwd(`dist/${name}/bin`)
238244
}
239245
}
240246
await $`gh release upload v${Script.version} ./dist/*.zip ./dist/*.tar.gz --clobber --repo ${process.env.GH_REPO}`

‎packages/miaopan-code/script/postinstall.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const archMap = {
2424

2525
const platform = platformMap[os.platform()] ?? os.platform()
2626
const arch = archMap[os.arch()] ?? os.arch()
27-
const base = `miaopanCode-${platform}-${arch}`
27+
const base = `@miaopan/code-${platform}-${arch}`
2828
const sourceBinary = platform === "windows" ? "miaopanCode.exe" : "miaopan-code"
2929
const targetBinary = path.join(__dirname, "bin", "miaopanCode.exe")
3030

‎packages/miaopan-code/script/publish.ts‎

Lines changed: 33 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -5,209 +5,79 @@ import { Script } from "@miaopan-code/script"
55
import { fileURLToPath } from "url"
66

77
const dir = fileURLToPath(new URL("..", import.meta.url))
8+
const packageName = "@miaopan/code"
9+
const dryRun = process.argv.includes("--dry-run")
810
process.chdir(dir)
911

1012
async function published(name: string, version: string) {
1113
return (await $`npm view ${name}@${version} version`.nothrow()).exitCode === 0
1214
}
1315

1416
async function publish(dir: string, name: string, version: string) {
15-
// GitHub artifact downloads can drop the executable bit, and Docker uses the
16-
// unpacked dist binaries directly rather than the published tarball.
1717
if (process.platform !== "win32") await $`chmod -R 755 .`.cwd(dir)
1818
if (await published(name, version)) {
1919
console.log(`already published ${name}@${version}`)
2020
return
2121
}
22+
await $`find . -maxdepth 1 -type f -name '*.tgz' -delete`.cwd(dir)
2223
await $`bun pm pack`.cwd(dir)
23-
await $`npm publish *.tgz --access public --tag ${Script.channel}`.cwd(dir)
24+
if (dryRun) {
25+
await $`bun publish *.tgz --access public --tag ${Script.channel} --dry-run`.cwd(dir)
26+
return
27+
}
28+
await $`bun publish *.tgz --access public --tag ${Script.channel}`.cwd(dir)
2429
}
2530

26-
const binaries: Record<string, string> = {}
27-
for (const filepath of new Bun.Glob("*/package.json").scanSync({ cwd: "./dist" })) {
28-
const pkg = await Bun.file(`./dist/${filepath}`).json()
29-
binaries[pkg.name] = pkg.version
30-
}
31-
console.log("binaries", binaries)
32-
const version = Object.values(binaries)[0]
31+
const binaries = await Array.fromAsync(new Bun.Glob("*/package.json").scan({ cwd: "./dist" }))
32+
.then((files) => files.filter((file) => file !== `${pkg.name}/package.json`))
33+
.then(async (files) =>
34+
Promise.all(
35+
files.map(async (file) => {
36+
const binary = await Bun.file(`./dist/${file}`).json()
37+
return { dir: file.replace("/package.json", ""), name: binary.name, version: binary.version }
38+
}),
39+
),
40+
)
41+
if (binaries.length === 0) throw new Error("No platform packages found. Run the build first.")
42+
43+
const version = binaries[0].version
44+
if (binaries.some((binary) => binary.version !== version)) throw new Error("Platform package versions must match.")
3345

34-
await $`mkdir -p ./dist/${pkg.name}`
3546
await $`mkdir -p ./dist/${pkg.name}/bin`
3647
await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs`
3748
await Bun.file(`./dist/${pkg.name}/LICENSE`).write(await Bun.file("../../LICENSE").text())
49+
await Bun.file(`./dist/${pkg.name}/NOTICE`).write(await Bun.file("../../NOTICE").text())
3850
await Bun.file(`./dist/${pkg.name}/bin/${pkg.name}.exe`).write(
3951
[
40-
`echo "Error: ${pkg.name}-ai's postinstall script was not run." >&2`,
52+
`echo "Error: ${packageName}'s postinstall script was not run." >&2`,
4153
'echo "" >&2',
4254
'echo "This occurs when using --ignore-scripts during installation, or when using a" >&2',
4355
'echo "package manager like pnpm that does not run postinstall scripts by default." >&2',
4456
'echo "" >&2',
4557
'echo "To fix this, run the postinstall script manually:" >&2',
46-
`echo " cd node_modules/${pkg.name}-ai && node postinstall.mjs" >&2`,
58+
`echo " cd node_modules/${packageName} && node postinstall.mjs" >&2`,
4759
'echo "" >&2',
48-
`echo "Or reinstall ${pkg.name}-ai without the --ignore-scripts flag." >&2`,
60+
`echo "Or reinstall ${packageName} without the --ignore-scripts flag." >&2`,
4961
"exit 1",
5062
"",
5163
].join("\n"),
5264
)
53-
5465
await Bun.file(`./dist/${pkg.name}/package.json`).write(
5566
JSON.stringify(
5667
{
57-
name: pkg.name + "-ai",
58-
bin: {
59-
[pkg.name]: `./bin/${pkg.name}.exe`,
60-
},
61-
scripts: {
62-
postinstall: "node ./postinstall.mjs",
63-
},
64-
version: version,
68+
name: packageName,
69+
bin: { [pkg.name]: `./bin/${pkg.name}.exe` },
70+
scripts: { postinstall: "node ./postinstall.mjs" },
71+
version,
6572
license: pkg.license,
6673
os: ["darwin", "linux", "win32"],
6774
cpu: ["arm64", "x64"],
68-
optionalDependencies: binaries,
75+
optionalDependencies: Object.fromEntries(binaries.map((binary) => [binary.name, binary.version])),
6976
},
7077
null,
7178
2,
7279
),
7380
)
7481

75-
const tasks = Object.entries(binaries).map(async ([name]) => {
76-
await publish(`./dist/${name}`, name, binaries[name])
77-
})
78-
await Promise.all(tasks)
79-
await publish(`./dist/${pkg.name}`, `${pkg.name}-ai`, version)
80-
81-
const image = "ghcr.io/miaopan607/miaopan-code"
82-
const platforms = "linux/amd64,linux/arm64"
83-
const tags = [`${image}:${version}`, `${image}:${Script.channel}`]
84-
const tagFlags = tags.flatMap((t) => ["-t", t])
85-
86-
// registries
87-
if (!Script.preview) {
88-
await $`docker buildx build --platform ${platforms} ${tagFlags} --push .`
89-
// Calculate SHA values
90-
const arm64Sha = await $`sha256sum ./dist/miaopanCode-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
91-
const x64Sha = await $`sha256sum ./dist/miaopanCode-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
92-
const macX64Sha = await $`sha256sum ./dist/miaopanCode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
93-
const macArm64Sha = await $`sha256sum ./dist/miaopanCode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim())
94-
95-
const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2)
96-
97-
// arch
98-
const binaryPkgbuild = [
99-
"# Maintainer: dax",
100-
"# Maintainer: adam",
101-
"",
102-
"pkgname='miaopanCode-bin'",
103-
`pkgver=${pkgver}`,
104-
`_subver=${_subver}`,
105-
"options=('!debug' '!strip')",
106-
"pkgrel=1",
107-
"pkgdesc='The AI coding agent built for the terminal.'",
108-
"url='https://github.com/miaopan607/miaopan-code'",
109-
"arch=('aarch64' 'x86_64')",
110-
"license=('MIT')",
111-
"provides=('miaopan-code')",
112-
"conflicts=('miaopan-code')",
113-
"depends=('ripgrep')",
114-
"",
115-
`source_aarch64=("\${pkgname}_\${pkgver}_aarch64.tar.gz::https://github.com/miaopan607/miaopan-code/releases/download/v\${pkgver}\${_subver}/miaopanCode-linux-arm64.tar.gz")`,
116-
`sha256sums_aarch64=('${arm64Sha}')`,
117-
118-
`source_x86_64=("\${pkgname}_\${pkgver}_x86_64.tar.gz::https://github.com/miaopan607/miaopan-code/releases/download/v\${pkgver}\${_subver}/miaopanCode-linux-x64.tar.gz")`,
119-
`sha256sums_x86_64=('${x64Sha}')`,
120-
"",
121-
"package() {",
122-
' install -Dm755 ./miaopanCode "${pkgdir}/usr/bin/miaopanCode"',
123-
"}",
124-
"",
125-
].join("\n")
126-
127-
for (const [pkg, pkgbuild] of [["miaopanCode-bin", binaryPkgbuild]]) {
128-
for (let i = 0; i < 30; i++) {
129-
try {
130-
await $`rm -rf ./dist/aur-${pkg}`
131-
await $`git clone ssh://aur@aur.archlinux.org/${pkg}.git ./dist/aur-${pkg}`
132-
await $`cd ./dist/aur-${pkg} && git checkout master`
133-
await Bun.file(`./dist/aur-${pkg}/PKGBUILD`).write(pkgbuild)
134-
await $`cd ./dist/aur-${pkg} && makepkg --printsrcinfo > .SRCINFO`
135-
await $`cd ./dist/aur-${pkg} && git add PKGBUILD .SRCINFO`
136-
if ((await $`cd ./dist/aur-${pkg} && git diff --cached --quiet`.nothrow()).exitCode === 0) break
137-
await $`cd ./dist/aur-${pkg} && git commit -m "Update to v${Script.version}"`
138-
await $`cd ./dist/aur-${pkg} && git push`
139-
break
140-
} catch {
141-
continue
142-
}
143-
}
144-
}
145-
146-
// Homebrew formula
147-
const homebrewFormula = [
148-
"# typed: false",
149-
"# frozen_string_literal: true",
150-
"",
151-
"# This file was generated by GoReleaser. DO NOT EDIT.",
152-
"class MiaopanCode < Formula",
153-
` desc "The AI coding agent built for the terminal."`,
154-
` homepage "https://github.com/miaopan607/miaopan-code"`,
155-
` version "${Script.version.split("-")[0]}"`,
156-
"",
157-
` depends_on "ripgrep"`,
158-
"",
159-
" on_macos do",
160-
" if Hardware::CPU.intel?",
161-
` url "https://github.com/miaopan607/miaopan-code/releases/download/v${Script.version}/miaopanCode-darwin-x64.zip"`,
162-
` sha256 "${macX64Sha}"`,
163-
"",
164-
" def install",
165-
' bin.install "miaopan-code"',
166-
" end",
167-
" end",
168-
" if Hardware::CPU.arm?",
169-
` url "https://github.com/miaopan607/miaopan-code/releases/download/v${Script.version}/miaopanCode-darwin-arm64.zip"`,
170-
` sha256 "${macArm64Sha}"`,
171-
"",
172-
" def install",
173-
' bin.install "miaopan-code"',
174-
" end",
175-
" end",
176-
" end",
177-
"",
178-
" on_linux do",
179-
" if Hardware::CPU.intel? and Hardware::CPU.is_64_bit?",
180-
` url "https://github.com/miaopan607/miaopan-code/releases/download/v${Script.version}/miaopanCode-linux-x64.tar.gz"`,
181-
` sha256 "${x64Sha}"`,
182-
" def install",
183-
' bin.install "miaopan-code"',
184-
" end",
185-
" end",
186-
" if Hardware::CPU.arm? and Hardware::CPU.is_64_bit?",
187-
` url "https://github.com/miaopan607/miaopan-code/releases/download/v${Script.version}/miaopanCode-linux-arm64.tar.gz"`,
188-
` sha256 "${arm64Sha}"`,
189-
" def install",
190-
' bin.install "miaopan-code"',
191-
" end",
192-
" end",
193-
" end",
194-
"end",
195-
"",
196-
"",
197-
].join("\n")
198-
199-
const token = process.env.GITHUB_TOKEN
200-
if (!token) {
201-
console.error("GITHUB_TOKEN is required to update homebrew tap")
202-
process.exit(1)
203-
}
204-
const tap = `https://x-access-token:${token}@github.com/anomalyco/homebrew-tap.git`
205-
await $`rm -rf ./dist/homebrew-tap`
206-
await $`git clone ${tap} ./dist/homebrew-tap`
207-
await Bun.file("./dist/homebrew-tap/miaopanCode.rb").write(homebrewFormula)
208-
await $`cd ./dist/homebrew-tap && git add miaopanCode.rb`
209-
if ((await $`cd ./dist/homebrew-tap && git diff --cached --quiet`.nothrow()).exitCode !== 0) {
210-
await $`cd ./dist/homebrew-tap && git commit -m "Update to v${Script.version}"`
211-
await $`cd ./dist/homebrew-tap && git push`
212-
}
213-
}
82+
await Promise.all(binaries.map((binary) => publish(`./dist/${binary.dir}`, binary.name, binary.version)))
83+
await publish(`./dist/${pkg.name}`, packageName, version)

‎packages/miaopan-code/src/cli/cmd/uninstall.ts‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ async function showRemovalSummary(targets: RemovalTargets, method: Installation.
129129

130130
if (method !== "curl" && method !== "unknown") {
131131
const cmds: Record<string, string> = {
132-
npm: "npm uninstall -g miaopan-code-ai",
133-
pnpm: "pnpm uninstall -g miaopan-code-ai",
134-
bun: "bun remove -g miaopan-code-ai",
135-
yarn: "yarn global remove miaopan-code-ai",
132+
npm: "npm uninstall -g @miaopan/code",
133+
pnpm: "pnpm uninstall -g @miaopan/code",
134+
bun: "bun remove -g @miaopan/code",
135+
yarn: "yarn global remove @miaopan/code",
136136
brew: "brew uninstall miaopanCode",
137137
choco: "choco uninstall miaopanCode",
138138
scoop: "scoop uninstall miaopanCode",
@@ -180,10 +180,10 @@ async function executeUninstall(method: Installation.Method, targets: RemovalTar
180180

181181
if (method !== "curl" && method !== "unknown") {
182182
const cmds: Record<string, string[]> = {
183-
npm: ["npm", "uninstall", "-g", "miaopan-code-ai"],
184-
pnpm: ["pnpm", "uninstall", "-g", "miaopan-code-ai"],
185-
bun: ["bun", "remove", "-g", "miaopan-code-ai"],
186-
yarn: ["yarn", "global", "remove", "miaopan-code-ai"],
183+
npm: ["npm", "uninstall", "-g", "@miaopan/code"],
184+
pnpm: ["pnpm", "uninstall", "-g", "@miaopan/code"],
185+
bun: ["bun", "remove", "-g", "@miaopan/code"],
186+
yarn: ["yarn", "global", "remove", "@miaopan/code"],
187187
brew: ["brew", "uninstall", "miaopan-code"],
188188
choco: ["choco", "uninstall", "miaopan-code"],
189189
scoop: ["scoop", "uninstall", "miaopan-code"],

0 commit comments

Comments
 (0)