Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 264 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
on:
push:
branches:
- main

permissions:
contents: write
pull-requests: write

name: release-please

jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}

- uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4.4.1
id: release
with:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

# release-please bumps package.json but does not know about bun.lock.
# A version-only bump usually leaves bun.lock unchanged, but a release PR
# can also carry dependency updates — re-resolve and commit the lockfile
# into the release PR so the tagged commit always installs cleanly with
# `bun install --frozen-lockfile`. Only commits when bun.lock changes.
- name: Checkout release PR branch
if: ${{ steps.release.outputs.pr }}
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
token: ${{ steps.app-token.outputs.token }}
ref: ${{ fromJson(steps.release.outputs.pr).headBranchName }}

- name: Setup Bun
if: ${{ steps.release.outputs.pr }}
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.10

- name: Sync bun.lock
if: ${{ steps.release.outputs.pr }}
run: |
bun install --lockfile-only
if git diff --quiet bun.lock; then
echo "bun.lock already in sync"
else
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add bun.lock
git commit -m "chore: sync bun.lock"
git push origin HEAD:${{ fromJson(steps.release.outputs.pr).headBranchName }}
fi

build-binaries:
needs: release-please
if: ${{ needs.release-please.outputs.release_created }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# csp embeds platform-specific native addons (onnxruntime-node,
# @kreuzberg/tree-sitter-language-pack). `bun build --compile` bundles
# the *host* platform's .node files, so each target MUST build on a
# native runner — cross-compiling with `--target` produces a binary
# with the wrong-arch addons ("bad CPU type in executable").
include:
- os: macos-13 # Intel
target: darwin-x64
- os: macos-14 # Apple Silicon
target: darwin-arm64
- os: ubuntu-latest # x64
target: linux-x64
- os: ubuntu-24.04-arm # arm64
target: linux-arm64

steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.10

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Build binary (native target)
run: |
bun build src/cli.ts --compile --outfile csp-${{ matrix.target }}

- name: Smoke test binary
run: |
./csp-${{ matrix.target }} --version

- name: Generate checksum
run: |
shasum -a 256 csp-${{ matrix.target }} > csp-${{ matrix.target }}.sha256

- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: csp-${{ matrix.target }}
path: |
csp-${{ matrix.target }}
csp-${{ matrix.target }}.sha256

upload-release-assets:
needs: [release-please, build-binaries]
if: ${{ needs.release-please.outputs.release_created }}
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- name: Download all artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: artifacts

- name: Prepare release assets
run: |
mkdir -p release
find artifacts -type f -exec cp {} release/ \;
ls -lh release/

- name: Upload release artifacts
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release upload ${{ needs.release-please.outputs.tag_name }} \
release/* \
--clobber

update-homebrew-formula:
needs: [release-please, upload-release-assets]
if: ${{ needs.release-please.outputs.release_created }}
runs-on: ubuntu-latest

steps:
- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
repositories: |
code-search
homebrew-tap

- name: Checkout homebrew-tap repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
repository: pleaseai/homebrew-tap
token: ${{ steps.app-token.outputs.token }}
path: homebrew-tap

- name: Configure git
run: |
cd homebrew-tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Update Formula
run: |
VERSION=${{ needs.release-please.outputs.tag_name }}
VERSION_NO_V=${VERSION#v}

# Download checksums
curl -L -o darwin-x64.sha256 \
"https://github.com/${{ github.repository }}/releases/download/${VERSION}/csp-darwin-x64.sha256"
curl -L -o darwin-arm64.sha256 \
"https://github.com/${{ github.repository }}/releases/download/${VERSION}/csp-darwin-arm64.sha256"
curl -L -o linux-x64.sha256 \
"https://github.com/${{ github.repository }}/releases/download/${VERSION}/csp-linux-x64.sha256"
curl -L -o linux-arm64.sha256 \
"https://github.com/${{ github.repository }}/releases/download/${VERSION}/csp-linux-arm64.sha256"

# Extract checksums
DARWIN_X64_SHA256=$(cat darwin-x64.sha256 | awk '{print $1}')
DARWIN_ARM64_SHA256=$(cat darwin-arm64.sha256 | awk '{print $1}')
LINUX_X64_SHA256=$(cat linux-x64.sha256 | awk '{print $1}')
LINUX_ARM64_SHA256=$(cat linux-arm64.sha256 | awk '{print $1}')

# Create or update Formula
cd homebrew-tap
cat > csp.rb << 'FORMULA_EOF'
class Csp < Formula
desc "Fast and accurate hybrid code search for agents"
homepage "https://github.com/pleaseai/code-search"
version "VERSION_PLACEHOLDER"
license "MIT"

on_macos do
if Hardware::CPU.arm?
url "https://github.com/pleaseai/code-search/releases/download/vVERSION_PLACEHOLDER/csp-darwin-arm64"
sha256 "SHA256_DARWIN_ARM64_PLACEHOLDER"
else
url "https://github.com/pleaseai/code-search/releases/download/vVERSION_PLACEHOLDER/csp-darwin-x64"
sha256 "SHA256_DARWIN_X64_PLACEHOLDER"
end
end

on_linux do
if Hardware::CPU.arm?
url "https://github.com/pleaseai/code-search/releases/download/vVERSION_PLACEHOLDER/csp-linux-arm64"
sha256 "SHA256_LINUX_ARM64_PLACEHOLDER"
else
url "https://github.com/pleaseai/code-search/releases/download/vVERSION_PLACEHOLDER/csp-linux-x64"
sha256 "SHA256_LINUX_X64_PLACEHOLDER"
end
end

def install
if OS.mac?
if Hardware::CPU.arm?
bin.install "csp-darwin-arm64" => "csp"
else
bin.install "csp-darwin-x64" => "csp"
end
else
if Hardware::CPU.arm?
bin.install "csp-linux-arm64" => "csp"
else
bin.install "csp-linux-x64" => "csp"
end
end
end

test do
assert_match version.to_s, shell_output("#{bin}/csp --version")
end
end
FORMULA_EOF

# Replace placeholders
sed -i "s/VERSION_PLACEHOLDER/${VERSION_NO_V}/g" csp.rb
sed -i "s/SHA256_DARWIN_X64_PLACEHOLDER/${DARWIN_X64_SHA256}/" csp.rb
sed -i "s/SHA256_DARWIN_ARM64_PLACEHOLDER/${DARWIN_ARM64_SHA256}/" csp.rb
sed -i "s/SHA256_LINUX_X64_PLACEHOLDER/${LINUX_X64_SHA256}/" csp.rb
sed -i "s/SHA256_LINUX_ARM64_PLACEHOLDER/${LINUX_ARM64_SHA256}/" csp.rb

# Check if there are changes
if git diff --quiet csp.rb 2>/dev/null; then
echo "No changes to Formula"
exit 0
fi

# Commit and push
git add csp.rb
git commit -m "chore: update csp to ${VERSION}"
git push origin main
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "0.0.0"
}
6 changes: 6 additions & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,17 @@ codex plugin add csp@pleaseai
에이전트의 컨텍스트에 `csp` 사용법을 추가해 언제 어떻게 CLI를 호출할지 알 수 있도록 합니다. 먼저 `csp` CLI를 설치한 뒤, 아래 스니펫을 `AGENTS.md` 또는 `CLAUDE.md`에 추가하세요.

```bash
# Homebrew (macOS / Linux) — Node/Bun 없이 동작하는 독립 실행 바이너리
brew install pleaseai/tap/csp

# 또는 JavaScript 패키지 매니저로 설치 (PATH에 Bun 또는 Node 22+ 필요)
bun add -g @pleaseai/csp # bun으로 설치 (권장)
npm install -g @pleaseai/csp # 또는 npm
pnpm add -g @pleaseai/csp # 또는 pnpm
```

> Homebrew formula는 `bun build --compile`로 만든 자체 완결형 바이너리를 제공합니다(tree-sitter·임베딩 런타임 내장). 인덱스는 `~/.csp/`에 캐시됩니다([ADR 0002](.please/docs/decisions/0002-index-storage-cache-model.md) 참고).

<details>
<summary>AGENTS.md / CLAUDE.md 스니펫</summary>

Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,17 @@ It bundles the `csp` MCP server (`search`, `find_related`) plus a `csp-search` s
Add `csp` usage instructions to your agent's context so it knows when and how to call the CLI. Install the `csp` CLI, then add the snippet below to your `AGENTS.md` or `CLAUDE.md`:

```bash
bun add -g @pleaseai/csp # Install with bun (recommended)
# Homebrew (macOS / Linux) — standalone binary, no Node/Bun required
brew install pleaseai/tap/csp

# Or via a JavaScript package manager (needs Bun or Node 22+ on your PATH)
bun add -g @pleaseai/csp # Install with bun (recommended)
npm install -g @pleaseai/csp # Or with npm
pnpm add -g @pleaseai/csp # Or with pnpm
```

> The Homebrew formula ships a self-contained binary built with `bun build --compile` (tree-sitter and embedding runtimes are bundled). Indexes are cached under `~/.csp/` (see [ADR 0002](.please/docs/decisions/0002-index-storage-cache-model.md)).

<details>
<summary>AGENTS.md / CLAUDE.md snippet</summary>

Expand Down
30 changes: 30 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"packages": {
".": {
"release-type": "node",
"package-name": "@pleaseai/csp",
"include-component-in-tag": false,
"include-v-in-tag": true,
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance Improvements" },
{ "type": "revert", "section": "Reverts" },
{ "type": "docs", "section": "Documentation" },
{ "type": "style", "section": "Styles", "hidden": true },
{ "type": "chore", "section": "Miscellaneous Chores", "hidden": true },
{ "type": "refactor", "section": "Code Refactoring", "hidden": true },
{ "type": "test", "section": "Tests", "hidden": true },
{ "type": "build", "section": "Build System", "hidden": true },
{ "type": "ci", "section": "Continuous Integration", "hidden": true }
],
"extra-files": [
{
"type": "generic",
"path": "src/version.ts"
}
]
}
}
}
6 changes: 6 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { serve } from './mcp/server.ts'
import { clearSavings, formatSavingsReport } from './stats.ts'
import { ContentType } from './types.ts'
import { formatResults, isGitUrl, resolveChunk } from './utils.ts'
import { version } from './version.ts'

export enum Agent {
Antigravity = 'antigravity',
Expand Down Expand Up @@ -375,6 +376,11 @@ export async function runCli(argv: string[], options: RunOptions = {}): Promise<
return 0
}

if (argv[0] === '-V' || argv[0] === '--version') {
process.stdout.write(`csp ${version}\n`)
return 0
}

try {
const { command, positional, flags } = parseArgs(argv)

Expand Down
3 changes: 2 additions & 1 deletion src/mcp/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { loadOrBuildIndex } from '../indexing/cache.ts'
import { CspIndex, loadModel } from '../indexing/index.ts'
import { ContentType } from '../types.ts'
import { formatResults, isGitUrl, resolveChunk } from '../utils.ts'
import { version } from '../version.ts'

const REPO_DESCRIPTION
= 'https:// or http:// git URL (e.g. https://github.com/org/repo) or local directory path to index and search. '
Expand Down Expand Up @@ -497,7 +498,7 @@ export async function createServer(
}

const underlying = new McpServer(
{ name: 'csp', version: '0.0.0' },
{ name: 'csp', version },
{ instructions: SERVER_INSTRUCTIONS },
)

Expand Down
7 changes: 4 additions & 3 deletions src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// * `package.json#version` is the source of truth for npm publishing.
// * Bun/tsdown don't read Python-style triples; reconstructing one would
// just be dead code.
// A future integration PR will keep this in sync with `package.json#version`
// (e.g. via a generated file or a build-time replacement).
export const version = '0.0.0'
// Kept in sync with `package.json#version` by release-please via the
// `x-release-please-version` annotation below (see release-please-config.json
// `extra-files`).
export const version = '0.0.0' // x-release-please-version