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
32 changes: 32 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI

on:
push:
branches: [main, ts]
pull_request:
branches: [main]

jobs:
test:
name: Test (Node ${{ matrix.node-version }})
runs-on: ubuntu-latest
strategy:
matrix:
# 20 = engines floor (>=20.10, import attributes), 22 = current LTS
node-version: [20, 22]
steps:
- uses: actions/checkout@v5
- name: Set up pnpm
uses: pnpm/action-setup@v4
# version is taken from the packageManager field in package.json
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm build
- name: Run tests
run: pnpm test
22 changes: 22 additions & 0 deletions .github/workflows/lint-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: "Lint PR"

on:
pull_request_target:
types:
- opened
- edited
- reopened

jobs:
lint-pr:
name: Validate PR title
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
subjectPattern: ^[a-zA-Z0-9!-_@#=*`.|+,\s]+$
subjectPatternError: "The subject \"{subject}\" found in the pr title \"{title}\" didn't match the configured pattern. Can only chars, numbers and symbols !-_@#=*`|+."
40 changes: 40 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Release

on:
release:
types: [published]
workflow_dispatch:

permissions:
contents: read
id-token: write

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up pnpm
uses: pnpm/action-setup@v4
# version is taken from the packageManager field in package.json
- name: Use Node.js 22
uses: actions/setup-node@v5
with:
node-version: 22
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm build
- name: Run tests
run: pnpm test
- name: Publish to npm
# npm (not pnpm) publish: pnpm's packer does not honor the "!"
# negation patterns in the files field, which keeps .d.ts and
# source maps out of the tarball. prepublishOnly re-runs clean,
# build, and tests as a final gate inside publish.
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Agents that register every MCP tool upfront pay for it in context: hundreds of s
## Install

```bash
npm install -g @happyvibing/agentcli
pnpm add -g @happyvibing/agentcli # or: npm install -g @happyvibing/agentcli
```

Requires Node >= 20. Or run from source: `git clone && npm install && npm link`.
Requires Node >= 20.10. Or run from source: `git clone && pnpm install && pnpm build && pnpm link --global`.

## Quick start

Expand Down
2 changes: 1 addition & 1 deletion bin/agentcli.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env node
import { run } from "../src/index.js";
import { run } from "../dist/src/index.js";

run(process.argv.slice(2));
16 changes: 8 additions & 8 deletions fixtures/echo-server.mjs → fixtures/echo-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,29 +52,29 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
}));

server.setRequestHandler(CallToolRequestSchema, async (req) => {
const a = req.params.arguments || {};
switch (req.params.name) {
const a = (req.params as { arguments?: Record<string, unknown> }).arguments || {};
switch ((req.params as { name: string }).name) {
case "echo": {
let m = a.message;
let m = a.message as string;
if (a.upper) m = m.toUpperCase();
if (a.mode === "shout") m = m.toUpperCase() + "!!!";
const times = Math.max(1, a.times ?? 1);
const times = Math.max(1, (a.times as number) ?? 1);
return { content: [{ type: "text", text: Array(times).fill(m).join(" ") }] };
}
case "complex":
return { content: [{ type: "text", text: JSON.stringify({ received: a.spec, receivedTags: a.tags }) }] };
case "fail":
return { isError: true, content: [{ type: "text", text: "boom: intentional failure" }] };
case "slow":
await new Promise((r) => setTimeout(r, a.ms ?? 1000));
await new Promise<void>((r) => setTimeout(r, (a.ms as number) ?? 1000));
return { content: [{ type: "text", text: "done" }] };
case "double": {
const payload = [{ id: a.n ?? 1 }, { id: (a.n ?? 1) + 1 }];
const payload = [{ id: (a.n as number) ?? 1 }, { id: ((a.n as number) ?? 1) + 1 }];
return { content: [{ type: "text", text: JSON.stringify(JSON.stringify(payload)) }] };
}
default:
return { isError: true, content: [{ type: "text", text: "unknown tool: " + req.params.name }] };
return { isError: true, content: [{ type: "text", text: "unknown tool: " + (req.params as { name: string }).name }] };
}
});

await server.connect(new StdioServerTransport());
await server.connect(new StdioServerTransport());
Loading
Loading