@sx4im/skillcheck 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -48
- package/dist/bin/skillcheck.js +2 -2
- package/dist/bin/skillcheck.js.map +1 -1
- package/dist/src/adapters/nvidia-nim.js +5 -2
- package/dist/src/adapters/nvidia-nim.js.map +1 -1
- package/dist/src/cli.d.ts +1 -3
- package/dist/src/cli.js +61 -67
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +10 -0
- package/dist/src/config.js +64 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/env.js +30 -13
- package/dist/src/env.js.map +1 -1
- package/dist/src/eval.d.ts +1 -0
- package/dist/src/eval.js +7 -4
- package/dist/src/eval.js.map +1 -1
- package/dist/src/generate.js +3 -1
- package/dist/src/generate.js.map +1 -1
- package/dist/src/grade.js +7 -2
- package/dist/src/grade.js.map +1 -1
- package/dist/src/run.js +7 -2
- package/dist/src/run.js.map +1 -1
- package/dist/src/ui.d.ts +14 -0
- package/dist/src/ui.js +327 -0
- package/dist/src/ui.js.map +1 -0
- package/docs/skillcheck-cloud.md +111 -0
- package/examples/nvidia-proxy/README.md +19 -0
- package/examples/nvidia-proxy/server.mjs +96 -0
- package/package.json +4 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Skillcheck Cloud setup
|
|
2
|
+
|
|
3
|
+
Use this when you want users to install the CLI and run checks without configuring model-provider secrets locally.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
skillcheck CLI
|
|
9
|
+
-> Skillcheck Cloud API
|
|
10
|
+
-> model provider
|
|
11
|
+
|
|
12
|
+
Dashboard
|
|
13
|
+
-> user signs up
|
|
14
|
+
-> user creates a Skillcheck token
|
|
15
|
+
-> token is stored hashed in your database
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The CLI only needs:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
skillcheck setup
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The setup wizard asks for:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
https://api.yourdomain.com/v1
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
For token-gated private beta, users can additionally set:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
export SKILLCHECK_TOKEN=sk_live_...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If you want public free trials, the proxy can allow anonymous requests with strict rate limits and no token.
|
|
37
|
+
|
|
38
|
+
## API contract
|
|
39
|
+
|
|
40
|
+
The CLI expects an OpenAI-compatible endpoint:
|
|
41
|
+
|
|
42
|
+
```http
|
|
43
|
+
POST /v1/chat/completions
|
|
44
|
+
Authorization: Bearer <skillcheck-token>
|
|
45
|
+
Content-Type: application/json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Response should match OpenAI chat completions enough for the `openai` Node SDK:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"id": "chatcmpl_...",
|
|
53
|
+
"object": "chat.completion",
|
|
54
|
+
"created": 1780000000,
|
|
55
|
+
"model": "your-model",
|
|
56
|
+
"choices": [
|
|
57
|
+
{
|
|
58
|
+
"index": 0,
|
|
59
|
+
"message": {
|
|
60
|
+
"role": "assistant",
|
|
61
|
+
"content": "..."
|
|
62
|
+
},
|
|
63
|
+
"finish_reason": "stop"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"usage": {
|
|
67
|
+
"prompt_tokens": 1,
|
|
68
|
+
"completion_tokens": 1,
|
|
69
|
+
"total_tokens": 2
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Minimal proxy
|
|
75
|
+
|
|
76
|
+
The repo includes a tiny Node proxy in `examples/nvidia-proxy/`. It is useful for testing the `SKILLCHECK_API_URL` flow before building the dashboard.
|
|
77
|
+
|
|
78
|
+
Run it on a server:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
export NVIDIA_API_KEY=...
|
|
82
|
+
export SKILLCHECK_PROXY_TOKEN=dev-token
|
|
83
|
+
node examples/nvidia-proxy/server.mjs
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Point the CLI at it:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
export SKILLCHECK_API_URL=https://your-proxy.example.com/v1
|
|
90
|
+
export SKILLCHECK_TOKEN=dev-token
|
|
91
|
+
skillcheck check path/to/SKILL.md
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Dashboard requirements
|
|
95
|
+
|
|
96
|
+
- `users`: id, email, password/session provider, created_at.
|
|
97
|
+
- `tokens`: id, user_id, token_hash, prefix, created_at, last_used_at, revoked_at.
|
|
98
|
+
- `usage_events`: user_id, token_id, request_id, model, prompt_tokens, completion_tokens, created_at.
|
|
99
|
+
- Rate limit by token and IP.
|
|
100
|
+
- Store model-provider secrets only on the server.
|
|
101
|
+
- Never expose upstream provider secrets to the browser or CLI.
|
|
102
|
+
|
|
103
|
+
## First production path
|
|
104
|
+
|
|
105
|
+
1. Deploy the proxy API at `https://api.yourdomain.com/v1`.
|
|
106
|
+
2. Add dashboard auth with GitHub or email login.
|
|
107
|
+
3. Add “Create token” in the dashboard and show the token once.
|
|
108
|
+
4. Hash tokens before storing them.
|
|
109
|
+
5. Verify `Authorization: Bearer <token>` in the proxy.
|
|
110
|
+
6. Add rate limits and usage logging.
|
|
111
|
+
7. Ship the CLI with docs telling users to set `SKILLCHECK_API_URL` and `SKILLCHECK_TOKEN`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# skillcheck NVIDIA proxy
|
|
2
|
+
|
|
3
|
+
This is the safe way to let CLI users run `skillcheck` without seeing your NVIDIA key.
|
|
4
|
+
|
|
5
|
+
Run the proxy on a server:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
export NVIDIA_API_KEY=...
|
|
9
|
+
node examples/nvidia-proxy/server.mjs
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Point the CLI at the proxy:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
export SKILLCHECK_API_URL=https://your-proxy.example.com/v1
|
|
16
|
+
skillcheck check path/to/SKILL.md
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Do not publish `NVIDIA_API_KEY` inside the npm package. If the proxy is public, put it behind rate limiting, quotas, or authentication before sharing it broadly.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
|
|
4
|
+
const port = Number(process.env.PORT || 8787);
|
|
5
|
+
const nvidiaApiKey = process.env.NVIDIA_API_KEY?.trim();
|
|
6
|
+
const nvidiaBaseUrl = process.env.NVIDIA_BASE_URL?.trim() || 'https://integrate.api.nvidia.com/v1';
|
|
7
|
+
const proxyToken = process.env.SKILLCHECK_PROXY_TOKEN?.trim();
|
|
8
|
+
const maxBodyBytes = Number(process.env.MAX_BODY_BYTES || 5_000_000);
|
|
9
|
+
|
|
10
|
+
if (!nvidiaApiKey) {
|
|
11
|
+
throw new Error('Missing NVIDIA_API_KEY. Set it on the server, never inside the npm CLI.');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function writeJson(res, status, body) {
|
|
15
|
+
res.writeHead(status, {
|
|
16
|
+
'access-control-allow-headers': 'authorization, content-type',
|
|
17
|
+
'access-control-allow-methods': 'POST, OPTIONS',
|
|
18
|
+
'access-control-allow-origin': '*',
|
|
19
|
+
'content-type': 'application/json'
|
|
20
|
+
});
|
|
21
|
+
res.end(`${JSON.stringify(body)}\n`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readBody(req) {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const chunks = [];
|
|
27
|
+
let size = 0;
|
|
28
|
+
req.on('data', (chunk) => {
|
|
29
|
+
size += chunk.length;
|
|
30
|
+
if (size > maxBodyBytes) {
|
|
31
|
+
reject(new Error('Request body is too large'));
|
|
32
|
+
req.destroy();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
chunks.push(chunk);
|
|
36
|
+
});
|
|
37
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
38
|
+
req.on('error', reject);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isAuthorized(req) {
|
|
43
|
+
if (!proxyToken) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return req.headers.authorization === `Bearer ${proxyToken}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const server = createServer(async (req, res) => {
|
|
50
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
51
|
+
|
|
52
|
+
if (req.method === 'OPTIONS') {
|
|
53
|
+
writeJson(res, 204, {});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (req.method === 'GET' && url.pathname === '/health') {
|
|
58
|
+
writeJson(res, 200, { ok: true });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (req.method !== 'POST' || url.pathname !== '/v1/chat/completions') {
|
|
63
|
+
writeJson(res, 404, { error: 'Not found' });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!isAuthorized(req)) {
|
|
68
|
+
writeJson(res, 401, { error: 'Unauthorized' });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const body = await readBody(req);
|
|
74
|
+
const upstream = await fetch(`${nvidiaBaseUrl}/chat/completions`, {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers: {
|
|
77
|
+
authorization: `Bearer ${nvidiaApiKey}`,
|
|
78
|
+
'content-type': 'application/json'
|
|
79
|
+
},
|
|
80
|
+
body
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
res.writeHead(upstream.status, {
|
|
84
|
+
'access-control-allow-origin': '*',
|
|
85
|
+
'content-type': upstream.headers.get('content-type') || 'application/json'
|
|
86
|
+
});
|
|
87
|
+
res.end(await upstream.text());
|
|
88
|
+
} catch (error) {
|
|
89
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
90
|
+
writeJson(res, 500, { error: message });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
server.listen(port, () => {
|
|
95
|
+
console.log(`skillcheck NVIDIA proxy listening on http://localhost:${port}`);
|
|
96
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sx4im/skillcheck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Measure whether agent skills improve task performance.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,11 +28,13 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist",
|
|
31
|
+
"docs",
|
|
32
|
+
"examples",
|
|
31
33
|
"README.md",
|
|
32
34
|
"METHODOLOGY.md"
|
|
33
35
|
],
|
|
34
36
|
"scripts": {
|
|
35
|
-
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
37
|
+
"build": "rm -rf dist && tsc -p tsconfig.json && chmod +x dist/bin/skillcheck.js",
|
|
36
38
|
"m0": "tsx packages/cli/bin/skillcheck.ts m0",
|
|
37
39
|
"site:build": "next build packages/site",
|
|
38
40
|
"test": "vitest run",
|