Skip to content

Commit bd428f6

Browse files
committed
Initial commit
1 parent 854f310 commit bd428f6

15 files changed

Lines changed: 2185 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
node-version: [20, 22]
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-node@v4
18+
with:
19+
node-version: ${{ matrix.node-version }}
20+
- run: npm ci
21+
- run: npm run typecheck
22+
- run: npm run build

.github/workflows/release.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: read
13+
id-token: write
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: 22
19+
registry-url: https://registry.npmjs.org
20+
- run: npm ci
21+
- run: npm run build
22+
- run: npm publish --provenance --access public
23+
env:
24+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
lib/
3+
*.tsbuildinfo
4+
.DS_Store

README.md

Lines changed: 264 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,264 @@
1-
# node-sdk
2-
The official node sdk
1+
<h1 align="center">
2+
<code>@onecli/sdk</code>
3+
</h1>
4+
5+
<p align="center">
6+
Official Node.js SDK for <a href="https://onecli.sh">OneCLI</a>. Connect AI agents to external services via plugins.
7+
</p>
8+
9+
<p align="center">
10+
<a href="https://onecli.sh/docs">Documentation</a> &nbsp;|&nbsp;
11+
<a href="https://onecli.sh">Website</a> &nbsp;|&nbsp;
12+
<a href="https://github.com/onecli/onecli-sdk">GitHub</a>
13+
</p>
14+
15+
<p align="center">
16+
<a href="https://www.npmjs.com/package/@onecli/sdk">
17+
<img src="https://img.shields.io/npm/v/@onecli/sdk.svg" alt="npm version" />
18+
</a>
19+
<a href="https://github.com/onecli/onecli-sdk/blob/main/LICENSE">
20+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License" />
21+
</a>
22+
<a href="https://www.npmjs.com/package/@onecli/sdk">
23+
<img src="https://img.shields.io/node/v/@onecli/sdk.svg" alt="Node.js version" />
24+
</a>
25+
</p>
26+
27+
---
28+
29+
## What is OneCLI?
30+
31+
**OneCLI** (`oc`) is a thin, agent-first CLI that connects AI agents to external services via plugins. The SDK provides a programmatic interface for Node.js applications to interact with OneCLI's proxy, allowing containerized agents to access external APIs without exposing credentials.
32+
33+
## Installation
34+
35+
```bash
36+
npm install @onecli/sdk
37+
```
38+
39+
```bash
40+
pnpm add @onecli/sdk
41+
```
42+
43+
```bash
44+
yarn add @onecli/sdk
45+
```
46+
47+
## Requirements
48+
49+
| SDK version | Node.js version |
50+
| ----------- | --------------- |
51+
| >= 0.1.0 | >= 20 |
52+
53+
## Quick Start
54+
55+
### Standalone function
56+
57+
The simplest way to use the SDK. A single function that configures Docker containers to use the OneCLI proxy:
58+
59+
```typescript
60+
import { applyProxyConfig } from "@onecli/sdk";
61+
62+
const args = ["run", "-i", "--rm", "--name", "my-agent"];
63+
64+
// Fetches proxy config and pushes -e / -v flags onto args
65+
const proxyActive = await applyProxyConfig(args, "http://localhost:18080");
66+
67+
// args now contains proxy env vars and volume mounts
68+
console.log(proxyActive); // true if proxy was reachable
69+
```
70+
71+
### Class-based client
72+
73+
For more control, use the `OneCLI` client class:
74+
75+
```typescript
76+
import { OneCLI } from "@onecli/sdk";
77+
78+
const oc = new OneCLI({
79+
proxyUrl: "http://localhost:18080",
80+
});
81+
82+
// Get raw container configuration
83+
const config = await oc.proxy().getContainerConfig();
84+
console.log(config.env); // { HTTPS_PROXY: "...", NODE_EXTRA_CA_CERTS: "...", ... }
85+
console.log(config.mounts); // [{ hostPath: "...", containerPath: "...", readonly: true }]
86+
87+
// Or apply directly to Docker run args
88+
const args = ["run", "-i", "--rm", "my-image"];
89+
const active = await oc.proxy().applyContainerConfig(args);
90+
```
91+
92+
### Environment variable
93+
94+
Instead of passing `proxyUrl` explicitly, set the `ONECLI_PROXY_URL` environment variable:
95+
96+
```bash
97+
export ONECLI_PROXY_URL=http://localhost:18080
98+
```
99+
100+
```typescript
101+
import { OneCLI } from "@onecli/sdk";
102+
103+
// Automatically reads from ONECLI_PROXY_URL
104+
const oc = new OneCLI();
105+
const active = await oc.proxy().applyContainerConfig(args);
106+
```
107+
108+
## API Reference
109+
110+
### `OneCLI`
111+
112+
Main SDK client.
113+
114+
```typescript
115+
new OneCLI(options?: OneCLIOptions)
116+
```
117+
118+
| Option | Type | Default | Description |
119+
| ---------- | -------- | -------------------------------- | ------------------------------- |
120+
| `proxyUrl` | `string` | `process.env.ONECLI_PROXY_URL` | Base URL of the OneCLI proxy |
121+
| `timeout` | `number` | `5000` | Request timeout in milliseconds |
122+
123+
#### `oc.proxy()`
124+
125+
Returns the `ProxyClient` for container configuration. Throws `OneCLIError` if no proxy URL is configured.
126+
127+
---
128+
129+
### `ProxyClient`
130+
131+
Manages communication with the OneCLI proxy's `/container-config` endpoint.
132+
133+
#### `proxyClient.getContainerConfig()`
134+
135+
Fetch the raw container configuration from the proxy.
136+
137+
```typescript
138+
const config = await oc.proxy().getContainerConfig();
139+
// Returns: { env: Record<string, string>, mounts: ContainerMount[] }
140+
```
141+
142+
**Throws** `OneCLIRequestError` if the proxy returns a non-200 response.
143+
144+
#### `proxyClient.applyContainerConfig(args, options?)`
145+
146+
Fetch the proxy config and push Docker flags onto the `args` array. Returns `true` if config was applied, `false` if the proxy was unreachable.
147+
148+
```typescript
149+
const active = await oc.proxy().applyContainerConfig(args, {
150+
combineCaBundle: true, // Merge system + proxy CAs (default: true)
151+
addHostMapping: true, // Add --add-host on Linux (default: true)
152+
});
153+
```
154+
155+
| Option | Type | Default | Description |
156+
| ---------------- | --------- | ------- | ----------------------------------------------------- |
157+
| `combineCaBundle`| `boolean` | `true` | Build combined CA bundle for system-wide proxy trust |
158+
| `addHostMapping` | `boolean` | `true` | Add `host.docker.internal` mapping on Linux |
159+
160+
**What it does:**
161+
1. Fetches `/container-config` from the proxy
162+
2. Pushes `-e KEY=VALUE` for each environment variable
163+
3. Pushes `-v host:container[:ro]` for each mount
164+
4. Builds a combined CA bundle (system CAs + proxy CA) so all tools trust the proxy
165+
5. Adds `--add-host host.docker.internal:host-gateway` on Linux
166+
167+
---
168+
169+
### `applyProxyConfig(args, proxyUrl?)`
170+
171+
Standalone convenience function. Equivalent to creating a `ProxyClient` and calling `applyContainerConfig`.
172+
173+
```typescript
174+
import { applyProxyConfig } from "@onecli/sdk";
175+
176+
const active = await applyProxyConfig(args, "http://localhost:18080");
177+
// Pass undefined/null to skip (returns false immediately)
178+
```
179+
180+
---
181+
182+
### Error Classes
183+
184+
#### `OneCLIError`
185+
186+
General SDK error.
187+
188+
```typescript
189+
import { OneCLIError } from "@onecli/sdk";
190+
191+
try {
192+
oc.proxy(); // throws if no proxy URL configured
193+
} catch (error) {
194+
if (error instanceof OneCLIError) {
195+
console.error(error.message);
196+
}
197+
}
198+
```
199+
200+
#### `OneCLIRequestError`
201+
202+
HTTP request error with context.
203+
204+
```typescript
205+
import { OneCLIRequestError } from "@onecli/sdk";
206+
207+
try {
208+
await oc.proxy().getContainerConfig();
209+
} catch (error) {
210+
if (error instanceof OneCLIRequestError) {
211+
console.error(error.url); // Request URL
212+
console.error(error.statusCode); // HTTP status code
213+
console.error(error.message); // [URL=...] [StatusCode=...] ...
214+
}
215+
}
216+
```
217+
218+
---
219+
220+
### Types
221+
222+
All types are exported for use in your own code:
223+
224+
```typescript
225+
import type {
226+
OneCLIOptions,
227+
ContainerConfig,
228+
ContainerMount,
229+
ApplyContainerConfigOptions,
230+
} from "@onecli/sdk";
231+
```
232+
233+
## How It Works
234+
235+
The OneCLI proxy runs on the host machine and acts as a MITM proxy for containerized agents. When a container makes HTTPS requests to intercepted domains (e.g. `api.anthropic.com`), the proxy:
236+
237+
1. Terminates TLS using a local CA certificate
238+
2. Inspects the request and injects real credentials (replacing placeholder tokens)
239+
3. Forwards the request to the upstream service
240+
4. Returns the response to the container
241+
242+
This means **containers never see real API keys**. They only have placeholder tokens that the proxy swaps out transparently.
243+
244+
The SDK configures containers with the right environment variables (`HTTPS_PROXY`, `NODE_EXTRA_CA_CERTS`) and volume mounts (proxy CA certificate) so this works automatically.
245+
246+
## Development
247+
248+
```bash
249+
# Install dependencies
250+
npm install
251+
252+
# Build
253+
npm run build
254+
255+
# Type-check without emitting
256+
npm run typecheck
257+
258+
# Watch mode
259+
npm run dev
260+
```
261+
262+
## License
263+
264+
MIT

0 commit comments

Comments
 (0)