diff --git a/.github/workflows/build-binaries.yml b/.github/workflows/build-binaries.yml new file mode 100644 index 00000000..d9b38c27 --- /dev/null +++ b/.github/workflows/build-binaries.yml @@ -0,0 +1,99 @@ +name: Build Binaries + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Setup Bun + uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1 + + - name: Setup Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: npm ci + + - name: Build + run: | + cd packages/coding-agent + npm run build + + - name: Build binaries for all platforms + run: | + cd packages/coding-agent + + # Create output directory + mkdir -p binaries + + # Build for each platform + declare -a targets=( + "bun-darwin-arm64:pi-darwin-arm64" + "bun-darwin-x64:pi-darwin-x64" + "bun-linux-x64:pi-linux-x64" + "bun-linux-arm64:pi-linux-arm64" + "bun-windows-x64:pi-windows-x64.exe" + ) + + for target_pair in "${targets[@]}"; do + IFS=':' read -r target outfile <<< "$target_pair" + echo "Building for $target..." + bun build --compile --target="$target" ./dist/cli.js --outfile "binaries/$outfile" + done + + - name: Create release archives + run: | + cd packages/coding-agent + + # Files to include with each binary + cp package.json binaries/ + cp README.md binaries/ + cp CHANGELOG.md binaries/ + mkdir -p binaries/theme + cp dist/theme/*.json binaries/theme/ + + # Create archives for each platform + cd binaries + + # macOS arm64 + tar -czf pi-darwin-arm64.tar.gz pi-darwin-arm64 package.json README.md CHANGELOG.md theme/ + + # macOS x64 + tar -czf pi-darwin-x64.tar.gz pi-darwin-x64 package.json README.md CHANGELOG.md theme/ + + # Linux x64 + tar -czf pi-linux-x64.tar.gz pi-linux-x64 package.json README.md CHANGELOG.md theme/ + + # Linux arm64 + tar -czf pi-linux-arm64.tar.gz pi-linux-arm64 package.json README.md CHANGELOG.md theme/ + + # Windows x64 (zip) + zip -r pi-windows-x64.zip pi-windows-x64.exe package.json README.md CHANGELOG.md theme/ + + - name: Upload to GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd packages/coding-agent/binaries + + # Upload all archives to the release + gh release upload "${{ github.ref_name }}" \ + pi-darwin-arm64.tar.gz \ + pi-darwin-x64.tar.gz \ + pi-linux-x64.tar.gz \ + pi-linux-arm64.tar.gz \ + pi-windows-x64.zip \ + --clobber diff --git a/package-lock.json b/package-lock.json index 193e02aa..6daef393 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6074,11 +6074,11 @@ }, "packages/agent": { "name": "@mariozechner/pi-agent-core", - "version": "0.11.6", + "version": "0.12.0", "license": "MIT", "dependencies": { - "@mariozechner/pi-ai": "^0.11.5", - "@mariozechner/pi-tui": "^0.11.5" + "@mariozechner/pi-ai": "^0.11.6", + "@mariozechner/pi-tui": "^0.11.6" }, "devDependencies": { "@types/node": "^24.3.0", @@ -6089,6 +6089,42 @@ "node": ">=20.0.0" } }, + "packages/agent/node_modules/@mariozechner/pi-ai": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.11.6.tgz", + "integrity": "sha512-E96GATRiarbLtvukx69VruA8E2szGkmNbT86SHTFnOg1Nl1Y78hVcYggUFhTTHuuOZznbwG68iBzK6roKybysw==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.61.0", + "@google/genai": "^1.30.0", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "5.21.0", + "partial-json": "^0.1.7", + "zod-to-json-schema": "^3.24.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/agent/node_modules/@mariozechner/pi-tui": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.11.6.tgz", + "integrity": "sha512-tiYPbZ3ZlGYDqZk9nZ/pckFGbUfhfc35O/933QxX11ObPOgGFuj92pDFrPACfPX6rYvG909p1CBvZeGS7Szd+w==", + "license": "MIT", + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/agent/node_modules/@types/node": { "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", @@ -6099,6 +6135,31 @@ "undici-types": "~7.16.0" } }, + "packages/agent/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "packages/agent/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "packages/agent/node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -6108,7 +6169,7 @@ }, "packages/ai": { "name": "@mariozechner/pi-ai", - "version": "0.11.6", + "version": "0.12.0", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "^0.61.0", @@ -6149,12 +6210,12 @@ }, "packages/coding-agent": { "name": "@mariozechner/pi-coding-agent", - "version": "0.11.6", + "version": "0.12.0", "license": "MIT", "dependencies": { - "@mariozechner/pi-agent-core": "^0.11.5", - "@mariozechner/pi-ai": "^0.11.5", - "@mariozechner/pi-tui": "^0.11.5", + "@mariozechner/pi-agent-core": "^0.11.6", + "@mariozechner/pi-ai": "^0.11.6", + "@mariozechner/pi-tui": "^0.11.6", "chalk": "^5.5.0", "diff": "^8.0.2", "glob": "^11.0.3" @@ -6172,6 +6233,55 @@ "node": ">=20.0.0" } }, + "packages/coding-agent/node_modules/@mariozechner/pi-agent-core": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-agent-core/-/pi-agent-core-0.11.6.tgz", + "integrity": "sha512-NnfZlEyXBitBVzyRsakOfvRcI0AoIpInADDUWgtGefrf/9Vv3QAmN7oDd7Zq5rZUbfMY5rVHUuogvEyZBMpwxQ==", + "license": "MIT", + "dependencies": { + "@mariozechner/pi-ai": "^0.11.6", + "@mariozechner/pi-tui": "^0.11.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/coding-agent/node_modules/@mariozechner/pi-ai": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.11.6.tgz", + "integrity": "sha512-E96GATRiarbLtvukx69VruA8E2szGkmNbT86SHTFnOg1Nl1Y78hVcYggUFhTTHuuOZznbwG68iBzK6roKybysw==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.61.0", + "@google/genai": "^1.30.0", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "5.21.0", + "partial-json": "^0.1.7", + "zod-to-json-schema": "^3.24.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/coding-agent/node_modules/@mariozechner/pi-tui": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.11.6.tgz", + "integrity": "sha512-tiYPbZ3ZlGYDqZk9nZ/pckFGbUfhfc35O/933QxX11ObPOgGFuj92pDFrPACfPX6rYvG909p1CBvZeGS7Szd+w==", + "license": "MIT", + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/coding-agent/node_modules/@types/node": { "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", @@ -6182,6 +6292,31 @@ "undici-types": "~7.16.0" } }, + "packages/coding-agent/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "packages/coding-agent/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "packages/coding-agent/node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -6191,12 +6326,12 @@ }, "packages/mom": { "name": "@mariozechner/pi-mom", - "version": "0.11.6", + "version": "0.12.0", "license": "MIT", "dependencies": { "@anthropic-ai/sandbox-runtime": "^0.0.16", - "@mariozechner/pi-agent-core": "^0.11.5", - "@mariozechner/pi-ai": "^0.11.5", + "@mariozechner/pi-agent-core": "^0.11.6", + "@mariozechner/pi-ai": "^0.11.6", "@sinclair/typebox": "^0.34.0", "@slack/socket-mode": "^2.0.0", "@slack/web-api": "^7.0.0", @@ -6215,6 +6350,55 @@ "node": ">=20.0.0" } }, + "packages/mom/node_modules/@mariozechner/pi-agent-core": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-agent-core/-/pi-agent-core-0.11.6.tgz", + "integrity": "sha512-NnfZlEyXBitBVzyRsakOfvRcI0AoIpInADDUWgtGefrf/9Vv3QAmN7oDd7Zq5rZUbfMY5rVHUuogvEyZBMpwxQ==", + "license": "MIT", + "dependencies": { + "@mariozechner/pi-ai": "^0.11.6", + "@mariozechner/pi-tui": "^0.11.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/mom/node_modules/@mariozechner/pi-ai": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.11.6.tgz", + "integrity": "sha512-E96GATRiarbLtvukx69VruA8E2szGkmNbT86SHTFnOg1Nl1Y78hVcYggUFhTTHuuOZznbwG68iBzK6roKybysw==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.61.0", + "@google/genai": "^1.30.0", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "5.21.0", + "partial-json": "^0.1.7", + "zod-to-json-schema": "^3.24.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/mom/node_modules/@mariozechner/pi-tui": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.11.6.tgz", + "integrity": "sha512-tiYPbZ3ZlGYDqZk9nZ/pckFGbUfhfc35O/933QxX11ObPOgGFuj92pDFrPACfPX6rYvG909p1CBvZeGS7Szd+w==", + "license": "MIT", + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "packages/mom/node_modules/@types/node": { "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", @@ -6225,6 +6409,31 @@ "undici-types": "~7.16.0" } }, + "packages/mom/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "packages/mom/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "packages/mom/node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -6234,10 +6443,10 @@ }, "packages/pods": { "name": "@mariozechner/pi", - "version": "0.11.6", + "version": "0.12.0", "license": "MIT", "dependencies": { - "@mariozechner/pi-agent-core": "^0.11.5", + "@mariozechner/pi-agent-core": "^0.11.6", "chalk": "^5.5.0" }, "bin": { @@ -6248,9 +6457,83 @@ "node": ">=20.0.0" } }, + "packages/pods/node_modules/@mariozechner/pi-agent-core": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-agent-core/-/pi-agent-core-0.11.6.tgz", + "integrity": "sha512-NnfZlEyXBitBVzyRsakOfvRcI0AoIpInADDUWgtGefrf/9Vv3QAmN7oDd7Zq5rZUbfMY5rVHUuogvEyZBMpwxQ==", + "license": "MIT", + "dependencies": { + "@mariozechner/pi-ai": "^0.11.6", + "@mariozechner/pi-tui": "^0.11.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/pods/node_modules/@mariozechner/pi-ai": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.11.6.tgz", + "integrity": "sha512-E96GATRiarbLtvukx69VruA8E2szGkmNbT86SHTFnOg1Nl1Y78hVcYggUFhTTHuuOZznbwG68iBzK6roKybysw==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.61.0", + "@google/genai": "^1.30.0", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "5.21.0", + "partial-json": "^0.1.7", + "zod-to-json-schema": "^3.24.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/pods/node_modules/@mariozechner/pi-tui": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.11.6.tgz", + "integrity": "sha512-tiYPbZ3ZlGYDqZk9nZ/pckFGbUfhfc35O/933QxX11ObPOgGFuj92pDFrPACfPX6rYvG909p1CBvZeGS7Szd+w==", + "license": "MIT", + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/pods/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "packages/pods/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "packages/proxy": { "name": "@mariozechner/pi-proxy", - "version": "0.11.6", + "version": "0.12.0", "dependencies": { "@hono/node-server": "^1.14.0", "hono": "^4.6.16" @@ -6266,7 +6549,7 @@ }, "packages/tui": { "name": "@mariozechner/pi-tui", - "version": "0.11.6", + "version": "0.12.0", "license": "MIT", "dependencies": { "@types/mime-types": "^2.1.4", @@ -6310,12 +6593,12 @@ }, "packages/web-ui": { "name": "@mariozechner/pi-web-ui", - "version": "0.11.6", + "version": "0.12.0", "license": "MIT", "dependencies": { "@lmstudio/sdk": "^1.5.0", - "@mariozechner/pi-ai": "^0.11.5", - "@mariozechner/pi-tui": "^0.11.5", + "@mariozechner/pi-ai": "^0.11.6", + "@mariozechner/pi-tui": "^0.11.6", "docx-preview": "^0.3.7", "jszip": "^3.10.1", "lucide": "^0.544.0", @@ -6333,6 +6616,67 @@ "@mariozechner/mini-lit": "^0.2.0", "lit": "^3.3.1" } + }, + "packages/web-ui/node_modules/@mariozechner/pi-ai": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.11.6.tgz", + "integrity": "sha512-E96GATRiarbLtvukx69VruA8E2szGkmNbT86SHTFnOg1Nl1Y78hVcYggUFhTTHuuOZznbwG68iBzK6roKybysw==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.61.0", + "@google/genai": "^1.30.0", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "5.21.0", + "partial-json": "^0.1.7", + "zod-to-json-schema": "^3.24.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/web-ui/node_modules/@mariozechner/pi-tui": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.11.6.tgz", + "integrity": "sha512-tiYPbZ3ZlGYDqZk9nZ/pckFGbUfhfc35O/933QxX11ObPOgGFuj92pDFrPACfPX6rYvG909p1CBvZeGS7Szd+w==", + "license": "MIT", + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/web-ui/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "packages/web-ui/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } } } } diff --git a/packages/agent/package.json b/packages/agent/package.json index b51be6b0..baec3e3c 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi-agent-core", - "version": "0.11.6", + "version": "0.12.0", "description": "General-purpose agent with transport abstraction, state management, and attachment support", "type": "module", "main": "./dist/index.js", @@ -18,8 +18,8 @@ "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { - "@mariozechner/pi-ai": "^0.11.6", - "@mariozechner/pi-tui": "^0.11.6" + "@mariozechner/pi-ai": "^0.12.0", + "@mariozechner/pi-tui": "^0.12.0" }, "keywords": [ "ai", diff --git a/packages/ai/package.json b/packages/ai/package.json index 210f2a40..ba7bd425 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi-ai", - "version": "0.11.6", + "version": "0.12.0", "description": "Unified LLM API with automatic model discovery and provider configuration", "type": "module", "main": "./dist/index.js", diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 5adeaa63..1f239d53 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased] +## [0.12.0] - 2025-12-02 + +### Added + +- **Standalone Binary Support**: Build a self-contained binary using Bun with `npm run build:binary`. Pre-built binaries for macOS (arm64/x64), Linux (x64/arm64), and Windows (x64) are available on GitHub Releases. Based on [#89](https://github.com/badlogic/pi-mono/pull/89) by [@steipete](https://github.com/steipete), extended with cross-platform path resolution and GitHub Actions for automated release builds. + ## [0.11.6] - 2025-12-02 ### Added diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index 8724e07d..95a897ff 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -31,10 +31,51 @@ Works on Linux, macOS, and Windows (barely tested, needs Git Bash running in the ## Installation +### npm (recommended) + ```bash npm install -g @mariozechner/pi-coding-agent ``` +### Standalone Binary + +Pre-built binaries are available on the [GitHub Releases](https://github.com/badlogic/pi-mono/releases) page. Download the archive for your platform: + +- `pi-darwin-arm64.tar.gz` - macOS Apple Silicon +- `pi-darwin-x64.tar.gz` - macOS Intel +- `pi-linux-x64.tar.gz` - Linux x64 +- `pi-linux-arm64.tar.gz` - Linux ARM64 +- `pi-windows-x64.zip` - Windows x64 + +Extract and run: + +```bash +# macOS/Linux +tar -xzf pi-darwin-arm64.tar.gz +./pi-darwin-arm64 + +# Windows +unzip pi-windows-x64.zip +pi-windows-x64.exe +``` + +The archive includes the binary plus supporting files (README, CHANGELOG, themes). Keep them together in the same directory. + +### Build Binary from Source + +Requires [Bun](https://bun.sh) 1.0+: + +```bash +git clone https://github.com/badlogic/pi-mono.git +cd pi-mono +npm install +cd packages/coding-agent +npm run build:binary + +# Binary and supporting files are in dist/ +./dist/pi +``` + ## Quick Start ```bash @@ -1093,6 +1134,23 @@ Things that might happen eventually: - Switch to a model with bigger context (e.g., Gemini) using `/model` and either continue with that model, or let it summarize the session to a .md file to be loaded in a new session - **Better RPC mode docs**: It works, you'll figure it out (see `test/rpc-example.ts`) +## Development + +### Path Resolution + +The codebase supports three execution modes: +- **npm**: Running via `node dist/cli.js` after npm install +- **Bun binary**: Standalone compiled binary with files alongside +- **tsx**: Running directly from source via `npx tsx src/cli.ts` + +All path resolution for package assets (package.json, README.md, CHANGELOG.md, themes) must go through `src/paths.ts`: + +```typescript +import { getPackageDir, getThemeDir, getPackageJsonPath, getReadmePath, getChangelogPath } from "./paths.js"; +``` + +**Never use `__dirname` directly** for resolving package assets. The `paths.ts` module handles the differences between execution modes automatically. + ## License MIT diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index 73a6d78d..16451edb 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi-coding-agent", - "version": "0.11.6", + "version": "0.12.0", "description": "Coding agent CLI with read, bash, edit, write tools and session management", "type": "module", "bin": { @@ -14,18 +14,19 @@ ], "scripts": { "clean": "rm -rf dist", - "build": "tsgo -p tsconfig.build.json && chmod +x dist/cli.js && npm run copy-theme-assets", - "build:binary": "command -v bun >/dev/null 2>&1 || { echo 'Error: Bun is required for building the binary. Install it from https://bun.sh'; exit 1; } && npm run build && bun build --compile --bytecode ./dist/cli.js --outfile dist/pi", - "copy-theme-assets": "cp src/theme/*.json dist/theme/", + "build": "tsgo -p tsconfig.build.json && chmod +x dist/cli.js && npm run copy-assets", + "build:binary": "command -v bun >/dev/null 2>&1 || { echo 'Error: Bun is required for building the binary. Install it from https://bun.sh'; exit 1; } && npm run build && bun build --compile ./dist/cli.js --outfile dist/pi && npm run copy-binary-assets", + "copy-assets": "cp src/theme/*.json dist/theme/", + "copy-binary-assets": "cp package.json dist/ && cp README.md dist/ && cp CHANGELOG.md dist/", "dev": "tsgo -p tsconfig.build.json --watch --preserveWatchOutput", "check": "tsgo --noEmit", "test": "vitest --run", "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { - "@mariozechner/pi-agent-core": "^0.11.6", - "@mariozechner/pi-ai": "^0.11.6", - "@mariozechner/pi-tui": "^0.11.6", + "@mariozechner/pi-agent-core": "^0.12.0", + "@mariozechner/pi-ai": "^0.12.0", + "@mariozechner/pi-tui": "^0.12.0", "chalk": "^5.5.0", "diff": "^8.0.2", "glob": "^11.0.3" diff --git a/packages/coding-agent/src/changelog.ts b/packages/coding-agent/src/changelog.ts index 4813856a..32eb2997 100644 --- a/packages/coding-agent/src/changelog.ts +++ b/packages/coding-agent/src/changelog.ts @@ -1,6 +1,4 @@ import { existsSync, readFileSync } from "fs"; -import { dirname, join } from "path"; -import { fileURLToPath } from "url"; export interface ChangelogEntry { major: number; @@ -97,11 +95,5 @@ export function getNewEntries(entries: ChangelogEntry[], lastVersion: string): C return entries.filter((entry) => compareVersions(entry, last) > 0); } -/** - * Get the path to the CHANGELOG.md file - */ -export function getChangelogPath(): string { - const __filename = fileURLToPath(import.meta.url); - const __dirname = dirname(__filename); - return join(__dirname, "../CHANGELOG.md"); -} +// Re-export getChangelogPath from paths.ts for convenience +export { getChangelogPath } from "./paths.js"; diff --git a/packages/coding-agent/src/export-html.ts b/packages/coding-agent/src/export-html.ts index 470f2518..43078341 100644 --- a/packages/coding-agent/src/export-html.ts +++ b/packages/coding-agent/src/export-html.ts @@ -2,14 +2,12 @@ import type { AgentState } from "@mariozechner/pi-agent-core"; import type { AssistantMessage, Message, ToolResultMessage, UserMessage } from "@mariozechner/pi-ai"; import { existsSync, readFileSync, writeFileSync } from "fs"; import { homedir } from "os"; -import { basename, dirname, join } from "path"; -import { fileURLToPath } from "url"; +import { basename } from "path"; +import { getPackageJsonPath } from "./paths.js"; import type { SessionManager } from "./session-manager.js"; // Get version from package.json -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")); +const packageJson = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8")); const VERSION = packageJson.version; /** diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index 456ddee2..2b199435 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -4,11 +4,11 @@ import { ProcessTerminal, TUI } from "@mariozechner/pi-tui"; import chalk from "chalk"; import { existsSync, readFileSync, statSync } from "fs"; import { homedir } from "os"; -import { dirname, extname, join, resolve } from "path"; -import { fileURLToPath } from "url"; +import { extname, join, resolve } from "path"; import { getChangelogPath, getNewEntries, parseChangelog } from "./changelog.js"; import { exportFromFile } from "./export-html.js"; import { findModel, getApiKeyForModel, getAvailableModels } from "./model-config.js"; +import { getPackageJsonPath, getReadmePath } from "./paths.js"; import { SessionManager } from "./session-manager.js"; import { SettingsManager } from "./settings-manager.js"; import { expandSlashCommand, loadSlashCommands } from "./slash-commands.js"; @@ -19,9 +19,7 @@ import { SessionSelectorComponent } from "./tui/session-selector.js"; import { TuiRenderer } from "./tui/tui-renderer.js"; // Get version from package.json -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")); +const packageJson = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8")); const VERSION = packageJson.version; const defaultModelPerProvider: Record = { @@ -374,7 +372,7 @@ function buildSystemPrompt(customPrompt?: string, selectedTools?: ToolName[]): s }); // Get absolute path to README.md - const readmePath = resolve(join(__dirname, "../README.md")); + const readmePath = getReadmePath(); // Build tools list based on selected tools const tools = selectedTools || (["read", "bash", "edit", "write"] as ToolName[]); diff --git a/packages/coding-agent/src/paths.ts b/packages/coding-agent/src/paths.ts new file mode 100644 index 00000000..d9ff0846 --- /dev/null +++ b/packages/coding-agent/src/paths.ts @@ -0,0 +1,66 @@ +import { existsSync } from "fs"; +import { dirname, join, resolve } from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** + * Detect if we're running as a Bun compiled binary. + * Bun binaries have import.meta.url starting with "file:///$bunfs/" + */ +export const isBunBinary = import.meta.url.startsWith("file:///$bunfs/"); + +/** + * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md). + * - For Bun binary: returns the directory containing the executable + * - For Node.js (dist/): returns __dirname (the dist/ directory) + * - For tsx (src/): returns parent directory (the package root) + */ +export function getPackageDir(): string { + if (isBunBinary) { + // Bun binary: resolve relative to the executable + return dirname(process.execPath); + } + // Node.js: check if package.json exists in __dirname (dist/) or parent (src/ case) + if (existsSync(join(__dirname, "package.json"))) { + return __dirname; + } + // Running from src/ via tsx - go up one level to package root + return dirname(__dirname); +} + +/** + * Get path to the theme directory + * - For Bun binary: dist/theme/ next to executable + * - For Node.js (dist/): dist/theme/ + * - For tsx (src/): src/theme/ + */ +export function getThemeDir(): string { + if (isBunBinary) { + return join(dirname(process.execPath), "theme"); + } + // __dirname is either dist/ or src/ - theme is always a subdirectory + return join(__dirname, "theme"); +} + +/** + * Get path to package.json + */ +export function getPackageJsonPath(): string { + return join(getPackageDir(), "package.json"); +} + +/** + * Get path to README.md + */ +export function getReadmePath(): string { + return resolve(join(getPackageDir(), "README.md")); +} + +/** + * Get path to CHANGELOG.md + */ +export function getChangelogPath(): string { + return resolve(join(getPackageDir(), "CHANGELOG.md")); +} diff --git a/packages/coding-agent/src/theme/theme.ts b/packages/coding-agent/src/theme/theme.ts index 85a5f2e2..17e52042 100644 --- a/packages/coding-agent/src/theme/theme.ts +++ b/packages/coding-agent/src/theme/theme.ts @@ -1,13 +1,11 @@ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; -import { fileURLToPath } from "node:url"; import type { EditorTheme, MarkdownTheme, SelectListTheme } from "@mariozechner/pi-tui"; import { type Static, Type } from "@sinclair/typebox"; import { TypeCompiler } from "@sinclair/typebox/compiler"; import chalk from "chalk"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); +import { getThemeDir } from "../paths.js"; // ============================================================================ // Types & Schema @@ -321,8 +319,9 @@ let BUILTIN_THEMES: Record | undefined; function getBuiltinThemes(): Record { if (!BUILTIN_THEMES) { - const darkPath = path.join(__dirname, "dark.json"); - const lightPath = path.join(__dirname, "light.json"); + const themeDir = getThemeDir(); + const darkPath = path.join(themeDir, "dark.json"); + const lightPath = path.join(themeDir, "light.json"); BUILTIN_THEMES = { dark: JSON.parse(fs.readFileSync(darkPath, "utf-8")) as ThemeJson, light: JSON.parse(fs.readFileSync(lightPath, "utf-8")) as ThemeJson, diff --git a/packages/mom/package.json b/packages/mom/package.json index 890f5e19..183cd37e 100644 --- a/packages/mom/package.json +++ b/packages/mom/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi-mom", - "version": "0.11.6", + "version": "0.12.0", "description": "Slack bot that delegates messages to the pi coding agent", "type": "module", "bin": { @@ -21,8 +21,8 @@ }, "dependencies": { "@anthropic-ai/sandbox-runtime": "^0.0.16", - "@mariozechner/pi-agent-core": "^0.11.6", - "@mariozechner/pi-ai": "^0.11.6", + "@mariozechner/pi-agent-core": "^0.12.0", + "@mariozechner/pi-ai": "^0.12.0", "@sinclair/typebox": "^0.34.0", "@slack/socket-mode": "^2.0.0", "@slack/web-api": "^7.0.0", diff --git a/packages/pods/package.json b/packages/pods/package.json index 01159eff..2bc5f12e 100644 --- a/packages/pods/package.json +++ b/packages/pods/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi", - "version": "0.11.6", + "version": "0.12.0", "description": "CLI tool for managing vLLM deployments on GPU pods", "type": "module", "bin": { @@ -34,7 +34,7 @@ "node": ">=20.0.0" }, "dependencies": { - "@mariozechner/pi-agent-core": "^0.11.6", + "@mariozechner/pi-agent-core": "^0.12.0", "chalk": "^5.5.0" }, "devDependencies": {} diff --git a/packages/proxy/package.json b/packages/proxy/package.json index 51c17c5e..141b0e8c 100644 --- a/packages/proxy/package.json +++ b/packages/proxy/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi-proxy", - "version": "0.11.6", + "version": "0.12.0", "type": "module", "description": "CORS and authentication proxy for pi-ai", "main": "dist/index.js", diff --git a/packages/tui/package.json b/packages/tui/package.json index 16f64dcf..c95389d9 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi-tui", - "version": "0.11.6", + "version": "0.12.0", "description": "Terminal User Interface library with differential rendering for efficient text-based applications", "type": "module", "main": "dist/index.js", diff --git a/packages/web-ui/package.json b/packages/web-ui/package.json index 51a24b21..55f654d5 100644 --- a/packages/web-ui/package.json +++ b/packages/web-ui/package.json @@ -1,6 +1,6 @@ { "name": "@mariozechner/pi-web-ui", - "version": "0.11.6", + "version": "0.12.0", "description": "Reusable web UI components for AI chat interfaces powered by @mariozechner/pi-ai", "type": "module", "main": "dist/index.js", @@ -18,8 +18,8 @@ }, "dependencies": { "@lmstudio/sdk": "^1.5.0", - "@mariozechner/pi-ai": "^0.11.6", - "@mariozechner/pi-tui": "^0.11.6", + "@mariozechner/pi-ai": "^0.12.0", + "@mariozechner/pi-tui": "^0.12.0", "docx-preview": "^0.3.7", "jszip": "^3.10.1", "lucide": "^0.544.0",