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
17 changes: 8 additions & 9 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,31 @@ env:

jobs:
verify:
name: Verify (${{ matrix.os }}, Node ${{ matrix.node-version }})
name: Verify (${{ matrix.os }}, Bun ${{ matrix.bun-version }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [18, 20, 24]
bun-version: [latest]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
node-version: ${{ matrix.node-version }}
cache: npm
bun-version: ${{ matrix.bun-version }}

- name: Install dependencies
run: npm ci
run: bun install

- name: Run tests
run: npm test
run: bun test

- name: Type-check
run: npm run build
run: bun run build

build-and-push-image:
if: github.event_name != 'pull_request'
Expand Down
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM node:24-alpine
FROM oven/bun:alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY src/ src/
USER node
ENTRYPOINT ["npx", "tsx", "src/index.ts"]
USER bun
ENTRYPOINT ["bun", "src/index.ts"]
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ After installing, the SessionStart hook (at `hooks/session-start.mjs`) will auto
```bash
git clone https://github.com/orkait/hyperstack.git
cd hyperstack
npm install
node bin/hyperstack.mjs # same entrypoint the published bin uses
npm start # runs via tsx, no build step
npm run dev # watch mode
npm run build # tsc --noEmit (type-check only, no dist output)
bun install
bun bin/hyperstack.mjs # same entrypoint the published bin uses
bun start # no build step
bun dev # watch mode
bun run build # tsc --noEmit (type-check only, no dist output)
```

Node 18+ required.
Expand Down
25 changes: 18 additions & 7 deletions bin/hyperstack.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,25 @@ import { fileURLToPath } from "node:url";
const binDir = dirname(fileURLToPath(import.meta.url));
const rootDir = resolve(binDir, "..");
const entrypoint = resolve(rootDir, "src/index.ts");
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
const tsxLoaderArgs = nodeMajor >= 20 ? ["--import", "tsx"] : ["--loader", "tsx"];

const child = spawn(process.execPath, [...tsxLoaderArgs, entrypoint, ...process.argv.slice(2)], {
cwd: rootDir,
env: process.env,
stdio: "inherit",
});
const isBun = !!process.versions.bun;

let child;
if (isBun) {
child = spawn(process.execPath, [entrypoint, ...process.argv.slice(2)], {
cwd: rootDir,
env: process.env,
stdio: "inherit",
});
} else {
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "0", 10);
const tsxLoaderArgs = nodeMajor >= 20 ? ["--import", "tsx"] : ["--loader", "tsx"];
child = spawn(process.execPath, [...tsxLoaderArgs, entrypoint, ...process.argv.slice(2)], {
cwd: rootDir,
env: process.env,
stdio: "inherit",
});
}

const forwardSignal = (signal) => {
if (!child.killed) {
Expand Down
269 changes: 269 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

15 changes: 8 additions & 7 deletions install.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,27 @@ If Docker is available, add the following configuration to the appropriate MCP c

The `--memory=256m` and `--cpus=0.5` flags are intentional resource limits. Do not remove them. The server runs fine within these constraints.

### Option B: Local Node (Fallback)
### Option B: Local Bun (Fallback)

If Docker is NOT available, run the server locally using Node 18+:
If Docker is NOT available, run the server locally using Bun:

1. Navigate to the directory where you cloned the repository (e.g., `~/.claude/skills/hyperstack`)
2. Run `npm install` in that directory
3. Add the following to the user's MCP config file, replacing `/absolute/path/to/...` with the actual clone path:
1. [Install Bun](https://bun.sh) if not already available (`curl -fsSL https://bun.sh/install | bash`)
2. Navigate to the directory where you cloned the repository (e.g., `~/.claude/skills/hyperstack`)
3. Run `bun install` in that directory
4. Add the following to the user's MCP config file, replacing `/absolute/path/to/...` with the actual clone path:

```json
{
"mcpServers": {
"hyperstack": {
"command": "node",
"command": "bun",
"args": ["/absolute/path/to/hyperstack/bin/hyperstack.mjs"]
}
}
}
```

There is no build step. The wrapper starts the server directly from source via `tsx`.
There is no build step. Bun runs TypeScript directly from source.

## Step 4: Verify Installation

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
"type": "module",
"scripts": {
"build": "tsc --noEmit",
"test": "tsx --test tests/**/*.test.ts",
"start": "tsx src/index.ts",
"dev": "tsx watch src/index.ts"
"test": "bun test",
"start": "bun src/index.ts",
"dev": "bun --watch src/index.ts"
},
"author": "Orkait",
"license": "MIT",
Expand Down
10 changes: 3 additions & 7 deletions tests/workflow-behaviour.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { readFile } from "node:fs/promises";
import { resolve } from "node:path";
import test from "node:test";

test("publish workflow verifies the package across the supported OS and Node matrix before publishing", async () => {
const workflow = await readFile(resolve(".github/workflows/publish.yml"), "utf8");
test("publish workflow verifies the package across the supported OS and Bun matrix before publishing", async () => {
const workflow = (await readFile(resolve(".github/workflows/publish.yml"), "utf8")).replace(/\r\n/g, "\n");

assert.match(workflow, /pull_request:/, "workflow should validate on pull requests");
assert.match(workflow, /strategy:\s*\n(?:\s+.*\n)*?\s+matrix:/, "workflow should define a matrix strategy");
Expand All @@ -13,11 +13,7 @@ test("publish workflow verifies the package across the supported OS and Node mat
/os:\s*\[ubuntu-latest,\s*macos-latest,\s*windows-latest\]/,
"workflow should verify on ubuntu, macOS, and Windows",
);
assert.match(
workflow,
/node-version:\s*\[18,\s*20,\s*24\]/,
"workflow should verify on Node 18, 20, and 24",
);
assert.match(workflow, /bun-version:/, "workflow should verify with Bun");
assert.match(workflow, /needs:\s*verify/, "publish job should wait for the verification matrix");
assert.match(
workflow,
Expand Down
Loading