@skillauditor/client 0.1.0
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 +140 -0
- package/dist/agentkit.d.ts +8 -0
- package/dist/agentkit.d.ts.map +1 -0
- package/dist/agentkit.js +77 -0
- package/dist/agentkit.js.map +1 -0
- package/dist/client.d.ts +100 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +153 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +29 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +15 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +146 -0
- package/dist/logger.js.map +1 -0
- package/dist/poller.d.ts +42 -0
- package/dist/poller.d.ts.map +1 -0
- package/dist/poller.js +56 -0
- package/dist/poller.js.map +1 -0
- package/dist/x402.d.ts +28 -0
- package/dist/x402.d.ts.map +1 -0
- package/dist/x402.js +65 -0
- package/dist/x402.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# @skillauditor/client
|
|
2
|
+
|
|
3
|
+
Agent SDK for [SkillAuditor](https://skillauditor.xyz) — verify that an AI skill (SKILL.md) is safe before loading it into your agent.
|
|
4
|
+
|
|
5
|
+
One call. Handles World AgentKit auth, x402 payments, polling, and live terminal logging automatically.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @skillauditor/client
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Quick start (dev mode — no keys needed)
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { SkillAuditorClient } from '@skillauditor/client'
|
|
19
|
+
|
|
20
|
+
const client = new SkillAuditorClient()
|
|
21
|
+
const result = await client.verifySkill(skillContent)
|
|
22
|
+
// throws SkillRejectedError if verdict != safe or score < 70
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Production
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { SkillAuditorClient } from '@skillauditor/client'
|
|
29
|
+
|
|
30
|
+
const client = new SkillAuditorClient({
|
|
31
|
+
privateKey: process.env.AGENT_PRIVATE_KEY, // EVM key for World AgentKit SIWE
|
|
32
|
+
tier: 'pro', // onchain stamp + ENS subname
|
|
33
|
+
paymentHandler: async (req) => { // called on HTTP 402 — return X-Payment header
|
|
34
|
+
return await wallet.payX402(req)
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const result = await client.verifySkill(skillContent)
|
|
39
|
+
console.log(result.verdict) // "safe" | "unsafe" | "review_required"
|
|
40
|
+
console.log(result.score) // 0-100
|
|
41
|
+
console.log(result.ensSubname) // "a1b2c3d4.skills.skillauditor.eth"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Guard pattern
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
if (await client.isSafe(skillContent)) {
|
|
48
|
+
loadSkill(skillContent)
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Check without submitting
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const cached = await client.checkVerified(skillContent)
|
|
56
|
+
if (cached.verified) {
|
|
57
|
+
// already audited — use cached result, no new audit kicked off
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Options
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
new SkillAuditorClient({
|
|
65
|
+
apiUrl?: string // default: http://localhost:3001
|
|
66
|
+
privateKey?: string // "dev" skips signing (local only)
|
|
67
|
+
tier?: 'free' | 'pro' // default: "free"
|
|
68
|
+
paymentHandler?: (req) => Promise<string> // required for tier: "pro" in prod
|
|
69
|
+
logs?: true | 'verbose' | false // default: true
|
|
70
|
+
onProgress?: (event) => void // custom progress handler
|
|
71
|
+
pollIntervalMs?: number // default: 3000
|
|
72
|
+
timeoutMs?: number // default: 300000 (5 min)
|
|
73
|
+
rejectOnUnsafe?: boolean // default: true
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Terminal logging
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
▶ Auditing: My GitHub Skill [audit-abc123] tier=free
|
|
81
|
+
✔ Stage 1 — Structural extraction complete
|
|
82
|
+
✔ Stage 2 — Content analysis complete
|
|
83
|
+
✔ Stage 3 — Sandbox simulation complete
|
|
84
|
+
✔ Stage 4 — Verdict synthesis complete
|
|
85
|
+
✔ SAFE score=92/100
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- `logs: true` (default) — stage transitions only
|
|
89
|
+
- `logs: 'verbose'` — every sandbox tool call included
|
|
90
|
+
- `logs: false` — silent
|
|
91
|
+
|
|
92
|
+
## Result shape
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
interface VerifyResult {
|
|
96
|
+
verified: boolean
|
|
97
|
+
verdict: 'safe' | 'unsafe' | 'review_required'
|
|
98
|
+
score: number // 0-100
|
|
99
|
+
auditId: string
|
|
100
|
+
skillHash: string // 0x-prefixed SHA-256
|
|
101
|
+
auditedAt: string // ISO timestamp
|
|
102
|
+
ensSubname?: string // set for Pro tier audits
|
|
103
|
+
onchainStamp?: {
|
|
104
|
+
txHash: string
|
|
105
|
+
chainId: number
|
|
106
|
+
contractAddress: string
|
|
107
|
+
ensName: string | null
|
|
108
|
+
stampedAt: string
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Errors
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { SkillRejectedError, AuditTimeoutError, PaymentError } from '@skillauditor/client'
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
await client.verifySkill(content)
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (err instanceof SkillRejectedError) {
|
|
122
|
+
console.log(err.verdict, err.score) // "unsafe", 23
|
|
123
|
+
}
|
|
124
|
+
if (err instanceof AuditTimeoutError) {
|
|
125
|
+
// audit took > timeoutMs
|
|
126
|
+
}
|
|
127
|
+
if (err instanceof PaymentError) {
|
|
128
|
+
// x402 payment failed
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## How it works
|
|
134
|
+
|
|
135
|
+
1. `POST /v1/verify` — fast path, returns immediately if already audited
|
|
136
|
+
2. `POST /v1/agent/submit` — kicks off 4-stage pipeline (structural → content → sandbox → verdict)
|
|
137
|
+
3. Polls `GET /v1/audits/:id/logs` with live progress events until complete
|
|
138
|
+
4. Returns `VerifyResult` — or throws `SkillRejectedError` if unsafe
|
|
139
|
+
|
|
140
|
+
The wallet at `privateKey` must be registered in [World AgentBook](https://docs.world.org/agentkit) for production use. In dev mode (`privateKey: 'dev'`), the server bypass is used — no registration needed.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the `agentkit` header value for a request to a given URL.
|
|
3
|
+
*
|
|
4
|
+
* @param privateKey Hex private key ("0x...") or "dev" for local bypass
|
|
5
|
+
* @param resourceUrl The full URL of the endpoint being called
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildAgentkitHeader(privateKey: string, resourceUrl: string): Promise<string>;
|
|
8
|
+
//# sourceMappingURL=agentkit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentkit.d.ts","sourceRoot":"","sources":["../src/agentkit.ts"],"names":[],"mappings":"AAwCA;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CA4CjB"}
|
package/dist/agentkit.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Builds the `agentkit` request header required by /v1/agent/submit.
|
|
2
|
+
//
|
|
3
|
+
// In dev mode (privateKey === 'dev' or WORLD_CHAIN_RPC_URL is absent on the server):
|
|
4
|
+
// header value → "dev:<walletAddress>"
|
|
5
|
+
// The server accepts this without signature verification.
|
|
6
|
+
//
|
|
7
|
+
// In prod mode (a real hex private key is supplied):
|
|
8
|
+
// 1. Derive the EVM address from the private key
|
|
9
|
+
// 2. Build a SIWE message using @worldcoin/agentkit's formatSIWEMessage
|
|
10
|
+
// 3. Sign the message with viem's signMessage (EIP-191)
|
|
11
|
+
// 4. JSON-encode the AgentkitPayload and base64-encode for the header
|
|
12
|
+
//
|
|
13
|
+
// The wallet must be registered in World AgentBook before prod calls will succeed:
|
|
14
|
+
// npx @worldcoin/agentkit-cli register <wallet-address>
|
|
15
|
+
import { formatSIWEMessage } from '@worldcoin/agentkit';
|
|
16
|
+
import { privateKeyToAccount, } from 'viem/accounts';
|
|
17
|
+
import { createHash, randomBytes } from 'crypto';
|
|
18
|
+
// CAIP-2 chain ID for World Chain mainnet (chainId 480)
|
|
19
|
+
const WORLD_CHAIN_ID = 'eip155:480';
|
|
20
|
+
function nonce() {
|
|
21
|
+
return randomBytes(16).toString('hex');
|
|
22
|
+
}
|
|
23
|
+
function isDevKey(privateKey) {
|
|
24
|
+
return privateKey === 'dev' || privateKey.startsWith('dev:');
|
|
25
|
+
}
|
|
26
|
+
function deriveDevAddress(privateKey) {
|
|
27
|
+
// Deterministic fake address from the dev key string so the server
|
|
28
|
+
// gets a stable identity across requests in the same session.
|
|
29
|
+
const hash = createHash('sha256').update(privateKey).digest('hex');
|
|
30
|
+
return `0x${hash.slice(0, 40)}`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build the `agentkit` header value for a request to a given URL.
|
|
34
|
+
*
|
|
35
|
+
* @param privateKey Hex private key ("0x...") or "dev" for local bypass
|
|
36
|
+
* @param resourceUrl The full URL of the endpoint being called
|
|
37
|
+
*/
|
|
38
|
+
export async function buildAgentkitHeader(privateKey, resourceUrl) {
|
|
39
|
+
if (isDevKey(privateKey)) {
|
|
40
|
+
const address = deriveDevAddress(privateKey);
|
|
41
|
+
return `dev:${address}`;
|
|
42
|
+
}
|
|
43
|
+
const key = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`;
|
|
44
|
+
const account = privateKeyToAccount(key);
|
|
45
|
+
const url = new URL(resourceUrl);
|
|
46
|
+
const domain = url.host;
|
|
47
|
+
const now = new Date();
|
|
48
|
+
const exp = new Date(now.getTime() + 5 * 60 * 1_000); // 5 minute window
|
|
49
|
+
// CompleteAgentkitInfo fields expected by formatSIWEMessage
|
|
50
|
+
const info = {
|
|
51
|
+
domain,
|
|
52
|
+
uri: resourceUrl,
|
|
53
|
+
version: '1',
|
|
54
|
+
nonce: nonce(),
|
|
55
|
+
issuedAt: now.toISOString(),
|
|
56
|
+
expirationTime: exp.toISOString(),
|
|
57
|
+
chainId: WORLD_CHAIN_ID,
|
|
58
|
+
type: 'eip191',
|
|
59
|
+
};
|
|
60
|
+
const message = formatSIWEMessage(info, account.address);
|
|
61
|
+
const signature = await account.signMessage({ message });
|
|
62
|
+
// AgentkitPayload shape that parseAgentkitHeader expects
|
|
63
|
+
const payload = {
|
|
64
|
+
domain: info.domain,
|
|
65
|
+
address: account.address,
|
|
66
|
+
uri: info.uri,
|
|
67
|
+
version: info.version,
|
|
68
|
+
chainId: info.chainId,
|
|
69
|
+
type: info.type,
|
|
70
|
+
nonce: info.nonce,
|
|
71
|
+
issuedAt: info.issuedAt,
|
|
72
|
+
expirationTime: info.expirationTime,
|
|
73
|
+
signature,
|
|
74
|
+
};
|
|
75
|
+
return Buffer.from(JSON.stringify(payload)).toString('base64');
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=agentkit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentkit.js","sourceRoot":"","sources":["../src/agentkit.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { type PaymentHandler } from './x402.js';
|
|
2
|
+
import { type VerifyResult, type ProgressEvent } from './poller.js';
|
|
3
|
+
import { type LogsOption } from './logger.js';
|
|
4
|
+
export type { LogsOption };
|
|
5
|
+
export interface SkillAuditorClientOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Base URL of the SkillAuditor API.
|
|
8
|
+
* Defaults to http://localhost:3001 for local development.
|
|
9
|
+
*/
|
|
10
|
+
apiUrl?: string;
|
|
11
|
+
/**
|
|
12
|
+
* EVM private key for World AgentKit SIWE signing ("0x...").
|
|
13
|
+
* Pass "dev" (or omit) to use the dev bypass — no signing, no AgentBook required.
|
|
14
|
+
*/
|
|
15
|
+
privateKey?: string;
|
|
16
|
+
/**
|
|
17
|
+
* "free" (default) — LLM audit only, no onchain stamp, no payment required.
|
|
18
|
+
* "pro" — full audit + onchain stamp + ENS subname, requires $9 USDC payment.
|
|
19
|
+
*/
|
|
20
|
+
tier?: 'free' | 'pro';
|
|
21
|
+
/**
|
|
22
|
+
* Required when tier = "pro". Receives the x402 payment requirements and
|
|
23
|
+
* must return an X-Payment receipt string. See src/x402.ts for details.
|
|
24
|
+
*/
|
|
25
|
+
paymentHandler?: PaymentHandler;
|
|
26
|
+
/**
|
|
27
|
+
* Controls terminal log output.
|
|
28
|
+
*
|
|
29
|
+
* true (default) — normal: stage transitions + warnings, no per-tool-call noise
|
|
30
|
+
* 'verbose' — everything, including every sandbox tool call
|
|
31
|
+
* false — silent: no terminal output at all
|
|
32
|
+
*
|
|
33
|
+
* You can also supply a custom onProgress callback instead for full control.
|
|
34
|
+
* If both logs and onProgress are provided, onProgress takes precedence.
|
|
35
|
+
*/
|
|
36
|
+
logs?: LogsOption;
|
|
37
|
+
/**
|
|
38
|
+
* Custom progress handler. Overrides the built-in console logger.
|
|
39
|
+
* Called for each pipeline log entry while the audit is running.
|
|
40
|
+
*/
|
|
41
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
42
|
+
/**
|
|
43
|
+
* How often to check audit status. Default: 3000ms.
|
|
44
|
+
*/
|
|
45
|
+
pollIntervalMs?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Abort and throw AuditTimeoutError after this many ms. Default: 5 minutes.
|
|
48
|
+
*/
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
/**
|
|
51
|
+
* When true (default), throw SkillRejectedError if verdict != "safe" or score < 70.
|
|
52
|
+
* Set to false to receive the result regardless of verdict.
|
|
53
|
+
*/
|
|
54
|
+
rejectOnUnsafe?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface VerifyOptions {
|
|
57
|
+
/** Override the instance-level tier for this call only. */
|
|
58
|
+
tier?: 'free' | 'pro';
|
|
59
|
+
/** Override the instance-level logs setting for this call only. */
|
|
60
|
+
logs?: LogsOption;
|
|
61
|
+
/** Override the instance-level onProgress for this call only. */
|
|
62
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
63
|
+
}
|
|
64
|
+
export declare class SkillAuditorClient {
|
|
65
|
+
private readonly apiUrl;
|
|
66
|
+
private readonly privateKey;
|
|
67
|
+
private readonly tier;
|
|
68
|
+
private readonly paymentHandler;
|
|
69
|
+
private readonly logs;
|
|
70
|
+
private readonly onProgress;
|
|
71
|
+
private readonly pollIntervalMs;
|
|
72
|
+
private readonly timeoutMs;
|
|
73
|
+
private readonly rejectOnUnsafe;
|
|
74
|
+
constructor(opts?: SkillAuditorClientOptions);
|
|
75
|
+
/**
|
|
76
|
+
* Verify a skill is safe before using it.
|
|
77
|
+
*
|
|
78
|
+
* Flow:
|
|
79
|
+
* 1. POST /v1/verify — if already stamped and safe, return immediately (fast path)
|
|
80
|
+
* 2. POST /v1/agent/submit — kick off the audit pipeline
|
|
81
|
+
* - Auto-builds World AgentKit SIWE header from privateKey
|
|
82
|
+
* - Auto-handles x402: if 402 received, pays via paymentHandler and retries
|
|
83
|
+
* 3. Poll /v1/audits/:auditId until complete (with live log streaming to stdout)
|
|
84
|
+
* 4. Return VerifyResult — or throw SkillRejectedError if verdict is not safe
|
|
85
|
+
*/
|
|
86
|
+
verifySkill(skillContent: string, opts?: VerifyOptions): Promise<VerifyResult>;
|
|
87
|
+
/**
|
|
88
|
+
* Check if a skill has already been audited and verified, without submitting.
|
|
89
|
+
* Returns verified: false (with null verdict/score) if no audit exists yet.
|
|
90
|
+
*/
|
|
91
|
+
checkVerified(skillContent: string): Promise<VerifyResult>;
|
|
92
|
+
/**
|
|
93
|
+
* Like verifySkill, but returns false instead of throwing when the skill
|
|
94
|
+
* is unsafe. Useful for conditional loading logic.
|
|
95
|
+
*
|
|
96
|
+
* if (await client.isSafe(skillContent)) { loadSkill() }
|
|
97
|
+
*/
|
|
98
|
+
isSafe(skillContent: string, opts?: VerifyOptions): Promise<boolean>;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAA2B,WAAW,CAAA;AACnF,OAAO,EAAqB,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAEtF,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAA;AAEpB,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,cAAc,CAAA;IAE/B;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,UAAU,CAAA;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAE3C;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACrB,mEAAmE;IACnE,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,iEAAiE;IACjE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CAC5C;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA4B;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8C;IACzE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,IAAI,GAAE,yBAA8B;IAYhD;;;;;;;;;;OAUG;IACG,WAAW,CACf,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,YAAY,CAAC;IAkExB;;;OAGG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BhE;;;;;OAKG;IACG,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;CAS/E"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// SkillAuditorClient — single-call agent SDK for SkillAuditor.
|
|
2
|
+
//
|
|
3
|
+
// Hides all protocol complexity so any agent (Claude Code, custom LLM agent,
|
|
4
|
+
// CI pipeline) can verify a skill with one method call and zero knowledge of
|
|
5
|
+
// World AgentKit, x402, or polling.
|
|
6
|
+
//
|
|
7
|
+
// Usage (dev mode — no real keys needed):
|
|
8
|
+
// const client = new SkillAuditorClient({ privateKey: 'dev' })
|
|
9
|
+
// const result = await client.verifySkill(skillContent)
|
|
10
|
+
//
|
|
11
|
+
// Usage (prod mode):
|
|
12
|
+
// const client = new SkillAuditorClient({
|
|
13
|
+
// privateKey: process.env.AGENT_PRIVATE_KEY!,
|
|
14
|
+
// tier: 'pro',
|
|
15
|
+
// paymentHandler: (req) => getPaymentHeader(req, wallet),
|
|
16
|
+
// })
|
|
17
|
+
// const result = await client.verifySkill(skillContent)
|
|
18
|
+
//
|
|
19
|
+
// The wallet at privateKey must be registered in World AgentBook for prod:
|
|
20
|
+
// npx @worldcoin/agentkit-cli register <wallet-address>
|
|
21
|
+
import { buildAgentkitHeader } from './agentkit.js';
|
|
22
|
+
import { fetchWithX402 } from './x402.js';
|
|
23
|
+
import { pollUntilComplete } from './poller.js';
|
|
24
|
+
import { SkillRejectedError } from './errors.js';
|
|
25
|
+
import { createConsoleLogger, printAuditHeader, printAuditResult, printAuditRejected, } from './logger.js';
|
|
26
|
+
export class SkillAuditorClient {
|
|
27
|
+
apiUrl;
|
|
28
|
+
privateKey;
|
|
29
|
+
tier;
|
|
30
|
+
paymentHandler;
|
|
31
|
+
logs;
|
|
32
|
+
onProgress;
|
|
33
|
+
pollIntervalMs;
|
|
34
|
+
timeoutMs;
|
|
35
|
+
rejectOnUnsafe;
|
|
36
|
+
constructor(opts = {}) {
|
|
37
|
+
this.apiUrl = (opts.apiUrl ?? 'http://localhost:3001').replace(/\/$/, '');
|
|
38
|
+
this.privateKey = opts.privateKey ?? 'dev';
|
|
39
|
+
this.tier = opts.tier ?? 'free';
|
|
40
|
+
this.paymentHandler = opts.paymentHandler;
|
|
41
|
+
this.logs = opts.logs ?? true; // on by default
|
|
42
|
+
this.onProgress = opts.onProgress;
|
|
43
|
+
this.pollIntervalMs = opts.pollIntervalMs ?? 3_000;
|
|
44
|
+
this.timeoutMs = opts.timeoutMs ?? 5 * 60 * 1_000;
|
|
45
|
+
this.rejectOnUnsafe = opts.rejectOnUnsafe ?? true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Verify a skill is safe before using it.
|
|
49
|
+
*
|
|
50
|
+
* Flow:
|
|
51
|
+
* 1. POST /v1/verify — if already stamped and safe, return immediately (fast path)
|
|
52
|
+
* 2. POST /v1/agent/submit — kick off the audit pipeline
|
|
53
|
+
* - Auto-builds World AgentKit SIWE header from privateKey
|
|
54
|
+
* - Auto-handles x402: if 402 received, pays via paymentHandler and retries
|
|
55
|
+
* 3. Poll /v1/audits/:auditId until complete (with live log streaming to stdout)
|
|
56
|
+
* 4. Return VerifyResult — or throw SkillRejectedError if verdict is not safe
|
|
57
|
+
*/
|
|
58
|
+
async verifySkill(skillContent, opts = {}) {
|
|
59
|
+
const tier = opts.tier ?? this.tier;
|
|
60
|
+
const logsLevel = opts.logs ?? this.logs;
|
|
61
|
+
// Explicit onProgress overrides the built-in logger
|
|
62
|
+
const onProgress = opts.onProgress ?? this.onProgress ?? createConsoleLogger(logsLevel);
|
|
63
|
+
const silent = logsLevel === false && !opts.onProgress && !this.onProgress;
|
|
64
|
+
// ── Fast path: already verified ────────────────────────────────────────────
|
|
65
|
+
const cached = await this.checkVerified(skillContent);
|
|
66
|
+
if (cached.verified) {
|
|
67
|
+
if (!silent)
|
|
68
|
+
printAuditResult(cached);
|
|
69
|
+
return cached;
|
|
70
|
+
}
|
|
71
|
+
// ── Submit for audit ────────────────────────────────────────────────────────
|
|
72
|
+
const submitUrl = `${this.apiUrl}/v1/agent/submit`;
|
|
73
|
+
const agentkit = await buildAgentkitHeader(this.privateKey, submitUrl);
|
|
74
|
+
const body = JSON.stringify({ skillContent, tier });
|
|
75
|
+
const submitRes = await fetchWithX402(submitUrl, {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'application/json',
|
|
79
|
+
'agentkit': agentkit,
|
|
80
|
+
},
|
|
81
|
+
body,
|
|
82
|
+
}, tier === 'pro' ? this.paymentHandler : undefined);
|
|
83
|
+
if (!submitRes.ok && submitRes.status !== 202) {
|
|
84
|
+
const err = await submitRes.json().catch(() => ({ error: submitRes.statusText }));
|
|
85
|
+
throw new Error(`Skill submission failed (${submitRes.status}): ${err.error}`);
|
|
86
|
+
}
|
|
87
|
+
const { auditId, skillHash } = await submitRes.json();
|
|
88
|
+
// ── Print header now that we have auditId + skillHash ──────────────────────
|
|
89
|
+
// Extract skill name from frontmatter if possible (simple regex — no dep needed)
|
|
90
|
+
const nameMatch = skillContent.match(/^name\s*:\s*(.+)$/m);
|
|
91
|
+
const skillName = nameMatch?.[1]?.trim() ?? skillHash.slice(0, 10) + '…';
|
|
92
|
+
if (!silent)
|
|
93
|
+
printAuditHeader(skillName, auditId, tier);
|
|
94
|
+
// ── Poll until done ─────────────────────────────────────────────────────────
|
|
95
|
+
let result;
|
|
96
|
+
try {
|
|
97
|
+
result = await pollUntilComplete(this.apiUrl, auditId, {
|
|
98
|
+
intervalMs: this.pollIntervalMs,
|
|
99
|
+
timeoutMs: this.timeoutMs,
|
|
100
|
+
onProgress,
|
|
101
|
+
rejectOnUnsafe: this.rejectOnUnsafe,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
if (err instanceof SkillRejectedError && !silent) {
|
|
106
|
+
printAuditRejected(err.verdict, err.score);
|
|
107
|
+
}
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
if (!silent)
|
|
111
|
+
printAuditResult(result);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if a skill has already been audited and verified, without submitting.
|
|
116
|
+
* Returns verified: false (with null verdict/score) if no audit exists yet.
|
|
117
|
+
*/
|
|
118
|
+
async checkVerified(skillContent) {
|
|
119
|
+
const res = await fetch(`${this.apiUrl}/v1/verify`, {
|
|
120
|
+
method: 'POST',
|
|
121
|
+
headers: { 'Content-Type': 'application/json' },
|
|
122
|
+
body: JSON.stringify({ skillContent }),
|
|
123
|
+
});
|
|
124
|
+
const data = await res.json();
|
|
125
|
+
return {
|
|
126
|
+
verified: data.verified,
|
|
127
|
+
verdict: (data.verdict ?? 'unsafe'),
|
|
128
|
+
score: data.score ?? 0,
|
|
129
|
+
auditId: data.auditId ?? '',
|
|
130
|
+
skillHash: data.skillHash,
|
|
131
|
+
auditedAt: data.auditedAt ?? '',
|
|
132
|
+
ensSubname: data.ensSubname ?? undefined,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Like verifySkill, but returns false instead of throwing when the skill
|
|
137
|
+
* is unsafe. Useful for conditional loading logic.
|
|
138
|
+
*
|
|
139
|
+
* if (await client.isSafe(skillContent)) { loadSkill() }
|
|
140
|
+
*/
|
|
141
|
+
async isSafe(skillContent, opts = {}) {
|
|
142
|
+
try {
|
|
143
|
+
const result = await this.verifySkill(skillContent, opts);
|
|
144
|
+
return result.verified;
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (err instanceof SkillRejectedError)
|
|
148
|
+
return false;
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class SkillRejectedError extends Error {
|
|
2
|
+
readonly verdict: string;
|
|
3
|
+
readonly score: number;
|
|
4
|
+
readonly auditId: string;
|
|
5
|
+
constructor(verdict: string, score: number, auditId: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class AuditTimeoutError extends Error {
|
|
8
|
+
readonly auditId: string;
|
|
9
|
+
constructor(auditId: string, timeoutMs: number);
|
|
10
|
+
}
|
|
11
|
+
export declare class PaymentError extends Error {
|
|
12
|
+
readonly statusCode: number;
|
|
13
|
+
constructor(message: string, statusCode: number);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAO5D;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;gBAEZ,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAK/C;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;gBAEf,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAKhD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class SkillRejectedError extends Error {
|
|
2
|
+
verdict;
|
|
3
|
+
score;
|
|
4
|
+
auditId;
|
|
5
|
+
constructor(verdict, score, auditId) {
|
|
6
|
+
super(`Skill rejected: verdict=${verdict} score=${score}/100`);
|
|
7
|
+
this.name = 'SkillRejectedError';
|
|
8
|
+
this.verdict = verdict;
|
|
9
|
+
this.score = score;
|
|
10
|
+
this.auditId = auditId;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class AuditTimeoutError extends Error {
|
|
14
|
+
auditId;
|
|
15
|
+
constructor(auditId, timeoutMs) {
|
|
16
|
+
super(`Audit ${auditId} did not complete within ${timeoutMs / 1000}s`);
|
|
17
|
+
this.name = 'AuditTimeoutError';
|
|
18
|
+
this.auditId = auditId;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class PaymentError extends Error {
|
|
22
|
+
statusCode;
|
|
23
|
+
constructor(message, statusCode) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = 'PaymentError';
|
|
26
|
+
this.statusCode = statusCode;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,OAAO,CAAQ;IACf,KAAK,CAAQ;IACb,OAAO,CAAQ;IAExB,YAAY,OAAe,EAAE,KAAa,EAAE,OAAe;QACzD,KAAK,CAAC,2BAA2B,OAAO,UAAU,KAAK,MAAM,CAAC,CAAA;QAC9D,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;QAChC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,OAAO,CAAQ;IAExB,YAAY,OAAe,EAAE,SAAiB;QAC5C,KAAK,CAAC,SAAS,OAAO,4BAA4B,SAAS,GAAG,IAAI,GAAG,CAAC,CAAA;QACtE,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,UAAU,CAAQ;IAE3B,YAAY,OAAe,EAAE,UAAkB;QAC7C,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,cAAc,CAAA;QAC1B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SkillAuditorClient } from './client.js';
|
|
2
|
+
export type { SkillAuditorClientOptions, VerifyOptions, LogsOption } from './client.js';
|
|
3
|
+
export type { VerifyResult, ProgressEvent, AuditFinding, OnchainStamp } from './poller.js';
|
|
4
|
+
export type { PaymentHandler, X402PaymentRequirements } from './x402.js';
|
|
5
|
+
export { SkillRejectedError, AuditTimeoutError, PaymentError } from './errors.js';
|
|
6
|
+
export { createConsoleLogger } from './logger.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAyC,aAAa,CAAA;AACnF,YAAY,EAAE,yBAAyB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACvF,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1F,YAAY,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAe,WAAW,CAAA;AACjF,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAQ,aAAa,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAyC,aAAa,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAyC,aAAa,CAAA;AAInF,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAQ,aAAa,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAyC,aAAa,CAAA"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ProgressEvent, VerifyResult } from './poller.js';
|
|
2
|
+
export declare function printAuditHeader(skillName: string, auditId: string, tier: 'free' | 'pro'): void;
|
|
3
|
+
export declare function printAuditResult(result: VerifyResult): void;
|
|
4
|
+
export declare function printAuditRejected(verdict: string, score: number): void;
|
|
5
|
+
export type LogsOption = boolean | 'verbose';
|
|
6
|
+
/**
|
|
7
|
+
* Returns an onProgress callback that prints formatted pipeline logs to stdout.
|
|
8
|
+
*
|
|
9
|
+
* @param level
|
|
10
|
+
* true — normal: stage transitions + warnings (default)
|
|
11
|
+
* 'verbose' — everything, including every sandbox tool call
|
|
12
|
+
* false — silent: returns undefined (no callback)
|
|
13
|
+
*/
|
|
14
|
+
export declare function createConsoleLogger(level: LogsOption): ((event: ProgressEvent) => void) | undefined;
|
|
15
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AA6E9D,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAS/F;AAID,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAqB3D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAUvE;AA0BD,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,SAAS,CAAA;AAE5C;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,UAAU,GAChB,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,SAAS,CAS9C"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Terminal logger for the SkillAuditor audit pipeline.
|
|
2
|
+
//
|
|
3
|
+
// Mirrors the same stage labels, colors, and information hierarchy shown in the
|
|
4
|
+
// web UI's Pipeline Logs panel so agents and terminal users see the same picture.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// new SkillAuditorClient({ logs: true }) // normal (default) — stage transitions + warnings
|
|
8
|
+
// new SkillAuditorClient({ logs: 'verbose' }) // verbose — every sandbox tool call too
|
|
9
|
+
// new SkillAuditorClient({ logs: false }) // silent — no output
|
|
10
|
+
//
|
|
11
|
+
// You can also use createConsoleLogger() directly as an onProgress callback:
|
|
12
|
+
// new SkillAuditorClient({ onProgress: createConsoleLogger('verbose') })
|
|
13
|
+
// ── ANSI color codes ───────────────────────────────────────────────────────────
|
|
14
|
+
// Only applied when stdout is a real TTY (not piped into a file or CI that
|
|
15
|
+
// doesn't support ANSI). Falls back to plain text automatically.
|
|
16
|
+
const tty = typeof process !== 'undefined' && process.stdout?.isTTY === true;
|
|
17
|
+
const c = {
|
|
18
|
+
reset: tty ? '\x1b[0m' : '',
|
|
19
|
+
dim: tty ? '\x1b[2m' : '',
|
|
20
|
+
bold: tty ? '\x1b[1m' : '',
|
|
21
|
+
red: tty ? '\x1b[31m' : '',
|
|
22
|
+
green: tty ? '\x1b[32m' : '',
|
|
23
|
+
yellow: tty ? '\x1b[33m' : '',
|
|
24
|
+
blue: tty ? '\x1b[34m' : '',
|
|
25
|
+
cyan: tty ? '\x1b[36m' : '',
|
|
26
|
+
white: tty ? '\x1b[37m' : '',
|
|
27
|
+
gray: tty ? '\x1b[90m' : '',
|
|
28
|
+
// Bright variants
|
|
29
|
+
bRed: tty ? '\x1b[91m' : '',
|
|
30
|
+
bGreen: tty ? '\x1b[92m' : '',
|
|
31
|
+
bYellow: tty ? '\x1b[93m' : '',
|
|
32
|
+
bBlue: tty ? '\x1b[94m' : '',
|
|
33
|
+
bCyan: tty ? '\x1b[96m' : '',
|
|
34
|
+
};
|
|
35
|
+
// Stage → ANSI color, mirroring the UI:
|
|
36
|
+
// structural = sky → cyan
|
|
37
|
+
// content = violet → blue
|
|
38
|
+
// sandbox = orange → yellow
|
|
39
|
+
// verdict = emerald → green
|
|
40
|
+
// onchain = blue → bright blue
|
|
41
|
+
// pipeline = zinc → gray
|
|
42
|
+
const STAGE_COLOR = {
|
|
43
|
+
structural: c.cyan,
|
|
44
|
+
content: c.blue,
|
|
45
|
+
sandbox: c.yellow,
|
|
46
|
+
verdict: c.bGreen,
|
|
47
|
+
onchain: c.bBlue,
|
|
48
|
+
pipeline: c.gray,
|
|
49
|
+
};
|
|
50
|
+
// Pad stage label to a fixed width so message columns align
|
|
51
|
+
const STAGE_WIDTH = 10; // "structural" is the longest
|
|
52
|
+
function stageLabel(stage) {
|
|
53
|
+
const padded = stage.padEnd(STAGE_WIDTH);
|
|
54
|
+
const color = STAGE_COLOR[stage] ?? c.gray;
|
|
55
|
+
return `${color}${padded}${c.reset}`;
|
|
56
|
+
}
|
|
57
|
+
// ── Timestamp ─────────────────────────────────────────────────────────────────
|
|
58
|
+
function fmtTime(ts) {
|
|
59
|
+
return `${c.gray}${new Date(ts).toISOString().slice(11, 23)}${c.reset}`;
|
|
60
|
+
}
|
|
61
|
+
// ── Filtering ─────────────────────────────────────────────────────────────────
|
|
62
|
+
// In normal mode, skip the noisy per-tool-call sandbox lines.
|
|
63
|
+
// They look like "[run 1/3 · task] → toolName: target" or " ← result snippet".
|
|
64
|
+
// Warnings (scope violations, exfil attempts) are always shown.
|
|
65
|
+
function isToolCallLine(msg) {
|
|
66
|
+
return msg.startsWith('[run ') || msg.startsWith(' ←');
|
|
67
|
+
}
|
|
68
|
+
function shouldShow(event, verbose) {
|
|
69
|
+
if (verbose)
|
|
70
|
+
return true;
|
|
71
|
+
if (event.stage === 'sandbox' && event.level === 'info' && isToolCallLine(event.message)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
// ── Header ────────────────────────────────────────────────────────────────────
|
|
77
|
+
export function printAuditHeader(skillName, auditId, tier) {
|
|
78
|
+
const tierLabel = tier === 'pro'
|
|
79
|
+
? `${c.bCyan}pro${c.reset}`
|
|
80
|
+
: `${c.gray}free${c.reset}`;
|
|
81
|
+
process.stdout.write(`\n${c.bold}▶ SkillAuditor${c.reset} auditing ${c.white}"${skillName}"${c.reset} (${tierLabel})\n` +
|
|
82
|
+
`${c.gray} audit ${auditId}${c.reset}\n\n`);
|
|
83
|
+
}
|
|
84
|
+
// ── Result footer ─────────────────────────────────────────────────────────────
|
|
85
|
+
export function printAuditResult(result) {
|
|
86
|
+
const { verdict, score, onchain, ensSubname } = result;
|
|
87
|
+
const icon = verdict === 'safe' ? `${c.bGreen}✔${c.reset}`
|
|
88
|
+
: verdict === 'review_required' ? `${c.bYellow}▲${c.reset}`
|
|
89
|
+
: `${c.bRed}✖${c.reset}`;
|
|
90
|
+
const verdictText = verdict === 'safe' ? `${c.bGreen}SAFE${c.reset}`
|
|
91
|
+
: verdict === 'review_required' ? `${c.bYellow}REVIEW REQUIRED${c.reset}`
|
|
92
|
+
: `${c.bRed}UNSAFE${c.reset}`;
|
|
93
|
+
const scoreColor = score >= 80 ? c.bGreen : score >= 60 ? c.bYellow : c.bRed;
|
|
94
|
+
let out = `\n${icon} ${verdictText} ${scoreColor}${score}/100${c.reset}\n`;
|
|
95
|
+
const ens = ensSubname ?? onchain?.ensName;
|
|
96
|
+
if (ens)
|
|
97
|
+
out += ` ${c.bBlue}ENS${c.reset} ${ens}\n`;
|
|
98
|
+
if (onchain?.txHash)
|
|
99
|
+
out += ` ${c.gray}tx ${onchain.txHash}${c.reset}\n`;
|
|
100
|
+
out += '\n';
|
|
101
|
+
process.stdout.write(out);
|
|
102
|
+
}
|
|
103
|
+
export function printAuditRejected(verdict, score) {
|
|
104
|
+
const icon = verdict === 'review_required' ? `${c.bYellow}▲${c.reset}` : `${c.bRed}✖${c.reset}`;
|
|
105
|
+
const verdictText = verdict === 'review_required'
|
|
106
|
+
? `${c.bYellow}REVIEW REQUIRED${c.reset}`
|
|
107
|
+
: `${c.bRed}UNSAFE${c.reset}`;
|
|
108
|
+
const scoreColor = score >= 60 ? c.bYellow : c.bRed;
|
|
109
|
+
process.stdout.write(`\n${icon} ${verdictText} ${scoreColor}${score}/100${c.reset}\n\n`);
|
|
110
|
+
}
|
|
111
|
+
// ── Per-event renderer ────────────────────────────────────────────────────────
|
|
112
|
+
function renderEvent(event) {
|
|
113
|
+
const { stage, level, message, ts } = event;
|
|
114
|
+
const time = fmtTime(ts);
|
|
115
|
+
const label = stageLabel(stage);
|
|
116
|
+
let prefix = '';
|
|
117
|
+
let msgColor = '';
|
|
118
|
+
if (level === 'warn') {
|
|
119
|
+
prefix = `${c.bYellow}⚠ ${c.reset}`;
|
|
120
|
+
msgColor = c.bYellow;
|
|
121
|
+
}
|
|
122
|
+
else if (level === 'error') {
|
|
123
|
+
prefix = `${c.bRed}✖ ${c.reset}`;
|
|
124
|
+
msgColor = c.bRed;
|
|
125
|
+
}
|
|
126
|
+
process.stdout.write(` ${time} ${label} ${prefix}${msgColor}${message}${c.reset}\n`);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Returns an onProgress callback that prints formatted pipeline logs to stdout.
|
|
130
|
+
*
|
|
131
|
+
* @param level
|
|
132
|
+
* true — normal: stage transitions + warnings (default)
|
|
133
|
+
* 'verbose' — everything, including every sandbox tool call
|
|
134
|
+
* false — silent: returns undefined (no callback)
|
|
135
|
+
*/
|
|
136
|
+
export function createConsoleLogger(level) {
|
|
137
|
+
if (level === false)
|
|
138
|
+
return undefined;
|
|
139
|
+
const verbose = level === 'verbose';
|
|
140
|
+
return (event) => {
|
|
141
|
+
if (!shouldShow(event, verbose))
|
|
142
|
+
return;
|
|
143
|
+
renderEvent(event);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/poller.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface AuditFinding {
|
|
2
|
+
severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
3
|
+
category: string;
|
|
4
|
+
description: string;
|
|
5
|
+
evidence?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface OnchainStamp {
|
|
8
|
+
txHash: string;
|
|
9
|
+
chainId: number;
|
|
10
|
+
contractAddress: string;
|
|
11
|
+
ensName?: string;
|
|
12
|
+
stampedAt: string;
|
|
13
|
+
}
|
|
14
|
+
export interface VerifyResult {
|
|
15
|
+
verified: boolean;
|
|
16
|
+
verdict: 'safe' | 'review_required' | 'unsafe';
|
|
17
|
+
score: number;
|
|
18
|
+
auditId: string;
|
|
19
|
+
skillHash: string;
|
|
20
|
+
auditedAt: string;
|
|
21
|
+
onchain?: OnchainStamp;
|
|
22
|
+
findings?: AuditFinding[];
|
|
23
|
+
ensSubname?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ProgressEvent {
|
|
26
|
+
stage: 'structural' | 'content' | 'sandbox' | 'verdict' | 'onchain' | 'pipeline';
|
|
27
|
+
level: 'info' | 'warn' | 'error';
|
|
28
|
+
message: string;
|
|
29
|
+
ts: number;
|
|
30
|
+
}
|
|
31
|
+
export interface PollOptions {
|
|
32
|
+
/** How often to check audit status. Default: 3000ms */
|
|
33
|
+
intervalMs?: number;
|
|
34
|
+
/** Give up after this many ms. Default: 5 minutes */
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
/** Called with live pipeline log entries as they arrive */
|
|
37
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
38
|
+
/** Throw SkillRejectedError when verdict != 'safe' or score < 70. Default: true */
|
|
39
|
+
rejectOnUnsafe?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare function pollUntilComplete(apiUrl: string, auditId: string, opts?: PollOptions): Promise<VerifyResult>;
|
|
42
|
+
//# sourceMappingURL=poller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poller.d.ts","sourceRoot":"","sources":["../src/poller.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;IACzD,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,QAAQ,CAAA;IAC9C,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAA;IAChF,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;CACX;AAED,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC3C,mFAAmF;IACnF,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,YAAY,CAAC,CA+DvB"}
|
package/dist/poller.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { AuditTimeoutError, SkillRejectedError } from './errors.js';
|
|
2
|
+
export async function pollUntilComplete(apiUrl, auditId, opts = {}) {
|
|
3
|
+
const { intervalMs = 3_000, timeoutMs = 5 * 60 * 1_000, onProgress, rejectOnUnsafe = true, } = opts;
|
|
4
|
+
const deadline = Date.now() + timeoutMs;
|
|
5
|
+
let lastLogTs = 0;
|
|
6
|
+
while (Date.now() < deadline) {
|
|
7
|
+
// Poll audit status
|
|
8
|
+
const res = await fetch(`${apiUrl}/v1/audits/${auditId}`);
|
|
9
|
+
const data = await res.json();
|
|
10
|
+
if (data.status === 'completed') {
|
|
11
|
+
const result = data.result;
|
|
12
|
+
const onchain = data.onchain;
|
|
13
|
+
const verdict = (result?.verdict ?? 'unsafe');
|
|
14
|
+
const score = result?.score ?? 0;
|
|
15
|
+
const verified = verdict === 'safe' && score >= 70;
|
|
16
|
+
if (rejectOnUnsafe && !verified) {
|
|
17
|
+
throw new SkillRejectedError(verdict, score, auditId);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
verified,
|
|
21
|
+
verdict,
|
|
22
|
+
score,
|
|
23
|
+
auditId,
|
|
24
|
+
skillHash: data.skillHash,
|
|
25
|
+
auditedAt: data.completedAt,
|
|
26
|
+
onchain: onchain?.txHash ? onchain : undefined,
|
|
27
|
+
findings: data.findings,
|
|
28
|
+
ensSubname: onchain?.ensName,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (data.status === 'failed') {
|
|
32
|
+
throw new Error(`Audit ${auditId} pipeline failed. Try resubmitting.`);
|
|
33
|
+
}
|
|
34
|
+
// Stream new log entries to onProgress if provided
|
|
35
|
+
if (onProgress && (data.status === 'running' || data.status === 'pending')) {
|
|
36
|
+
try {
|
|
37
|
+
const logRes = await fetch(`${apiUrl}/v1/audits/${auditId}/logs?since=${lastLogTs}`);
|
|
38
|
+
const logData = await logRes.json();
|
|
39
|
+
for (const entry of logData.logs ?? []) {
|
|
40
|
+
onProgress(entry);
|
|
41
|
+
if (entry.ts > lastLogTs)
|
|
42
|
+
lastLogTs = entry.ts;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// non-fatal — progress streaming is best-effort
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
await sleep(intervalMs);
|
|
50
|
+
}
|
|
51
|
+
throw new AuditTimeoutError(auditId, timeoutMs);
|
|
52
|
+
}
|
|
53
|
+
function sleep(ms) {
|
|
54
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=poller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poller.js","sourceRoot":"","sources":["../src/poller.ts"],"names":[],"mappings":"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"}
|
package/dist/x402.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface X402PaymentRequirements {
|
|
2
|
+
x402Version: number;
|
|
3
|
+
accepts: Array<{
|
|
4
|
+
scheme: string;
|
|
5
|
+
network: string;
|
|
6
|
+
maxAmountRequired: string;
|
|
7
|
+
resource: string;
|
|
8
|
+
description: string;
|
|
9
|
+
payTo: string;
|
|
10
|
+
maxTimeoutSeconds: number;
|
|
11
|
+
asset: string;
|
|
12
|
+
}>;
|
|
13
|
+
error: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Called when a 402 is received. Must return the X-Payment header value
|
|
17
|
+
* (a payment receipt string) for the retry request.
|
|
18
|
+
*/
|
|
19
|
+
export type PaymentHandler = (requirements: X402PaymentRequirements) => Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Perform a fetch that transparently handles x402 payment for Pro audits.
|
|
22
|
+
*
|
|
23
|
+
* On first call, sends the request normally.
|
|
24
|
+
* If a 402 is received and `paymentHandler` is provided, pays and retries once.
|
|
25
|
+
* If no `paymentHandler` is provided, throws PaymentError immediately.
|
|
26
|
+
*/
|
|
27
|
+
export declare function fetchWithX402(url: string, init: RequestInit, paymentHandler?: PaymentHandler): Promise<Response>;
|
|
28
|
+
//# sourceMappingURL=x402.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.d.ts","sourceRoot":"","sources":["../src/x402.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,KAAK,CAAC;QACb,MAAM,EAAa,MAAM,CAAA;QACzB,OAAO,EAAY,MAAM,CAAA;QACzB,iBAAiB,EAAE,MAAM,CAAA;QACzB,QAAQ,EAAW,MAAM,CAAA;QACzB,WAAW,EAAQ,MAAM,CAAA;QACzB,KAAK,EAAc,MAAM,CAAA;QACzB,iBAAiB,EAAE,MAAM,CAAA;QACzB,KAAK,EAAc,MAAM,CAAA;KAC1B,CAAC,CAAA;IACF,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,YAAY,EAAE,uBAAuB,KAClC,OAAO,CAAC,MAAM,CAAC,CAAA;AAEpB;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,QAAQ,CAAC,CA6CnB"}
|
package/dist/x402.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// x402 payment handling for Pro tier audits.
|
|
2
|
+
//
|
|
3
|
+
// When the server returns HTTP 402, it means the request requires a $9 USDC
|
|
4
|
+
// payment on Base before the audit pipeline will run. This module:
|
|
5
|
+
// 1. Detects the 402 and extracts the payment requirements from the body
|
|
6
|
+
// 2. Invokes a user-supplied `paymentHandler` with those requirements
|
|
7
|
+
// 3. Retries the original request with the `X-Payment` header set to the receipt
|
|
8
|
+
//
|
|
9
|
+
// For free tier audits, this module is never invoked — the server only returns 402
|
|
10
|
+
// when the request body contains `tier: "pro"`.
|
|
11
|
+
//
|
|
12
|
+
// Implementing `paymentHandler`:
|
|
13
|
+
// The handler receives the payment requirements and must return a payment receipt
|
|
14
|
+
// string suitable for the X-Payment header. Typical implementations use:
|
|
15
|
+
// - `x402-fetch` from the x402 npm package (auto-pays from an EVM wallet)
|
|
16
|
+
// - A Privy embedded wallet signing a USDC TransferWithAuthorization (EIP-3009)
|
|
17
|
+
// - A Ledger device signing the same EIP-3009 payload for hardware approval
|
|
18
|
+
//
|
|
19
|
+
// Example (x402-fetch):
|
|
20
|
+
// import { getPaymentHeader } from 'x402-fetch'
|
|
21
|
+
// const handler: PaymentHandler = async (req) => getPaymentHeader(req, wallet)
|
|
22
|
+
import { PaymentError } from './errors.js';
|
|
23
|
+
/**
|
|
24
|
+
* Perform a fetch that transparently handles x402 payment for Pro audits.
|
|
25
|
+
*
|
|
26
|
+
* On first call, sends the request normally.
|
|
27
|
+
* If a 402 is received and `paymentHandler` is provided, pays and retries once.
|
|
28
|
+
* If no `paymentHandler` is provided, throws PaymentError immediately.
|
|
29
|
+
*/
|
|
30
|
+
export async function fetchWithX402(url, init, paymentHandler) {
|
|
31
|
+
const res = await fetch(url, init);
|
|
32
|
+
if (res.status !== 402)
|
|
33
|
+
return res;
|
|
34
|
+
// Parse payment requirements
|
|
35
|
+
let requirements;
|
|
36
|
+
try {
|
|
37
|
+
requirements = await res.json();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new PaymentError('Received 402 but could not parse payment requirements', 402);
|
|
41
|
+
}
|
|
42
|
+
if (!paymentHandler) {
|
|
43
|
+
const amount = requirements.accepts[0]?.maxAmountRequired;
|
|
44
|
+
const usdcAmt = amount ? `$${(Number(amount) / 1_000_000).toFixed(2)} USDC` : 'USDC';
|
|
45
|
+
throw new PaymentError(`Pro audit requires a ${usdcAmt} payment on Base. ` +
|
|
46
|
+
`Provide a paymentHandler in SkillAuditorClient options to enable automatic payment.`, 402);
|
|
47
|
+
}
|
|
48
|
+
// Obtain payment receipt from the handler
|
|
49
|
+
let receipt;
|
|
50
|
+
try {
|
|
51
|
+
receipt = await paymentHandler(requirements);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw new PaymentError(`Payment handler failed: ${err.message}`, 402);
|
|
55
|
+
}
|
|
56
|
+
// Retry with payment header
|
|
57
|
+
const headers = new Headers(init.headers);
|
|
58
|
+
headers.set('X-Payment', receipt);
|
|
59
|
+
const retryRes = await fetch(url, { ...init, headers });
|
|
60
|
+
if (retryRes.status === 402) {
|
|
61
|
+
throw new PaymentError('Payment was rejected by the server', 402);
|
|
62
|
+
}
|
|
63
|
+
return retryRes;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=x402.js.map
|
package/dist/x402.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"x402.js","sourceRoot":"","sources":["../src/x402.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,4EAA4E;AAC5E,mEAAmE;AACnE,2EAA2E;AAC3E,wEAAwE;AACxE,mFAAmF;AACnF,EAAE;AACF,mFAAmF;AACnF,gDAAgD;AAChD,EAAE;AACF,iCAAiC;AACjC,oFAAoF;AACpF,2EAA2E;AAC3E,4EAA4E;AAC5E,kFAAkF;AAClF,8EAA8E;AAC9E,EAAE;AACF,wBAAwB;AACxB,kDAAkD;AAClD,iFAAiF;AAEjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAyB1C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,IAAiB,EACjB,cAA+B;IAE/B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAElC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,GAAG,CAAA;IAElC,6BAA6B;IAC7B,IAAI,YAAqC,CAAA;IACzC,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,GAAG,CAAC,IAAI,EAA6B,CAAA;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,YAAY,CAAC,uDAAuD,EAAE,GAAG,CAAC,CAAA;IACtF,CAAC;IAED,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAA;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAA;QACpF,MAAM,IAAI,YAAY,CACpB,wBAAwB,OAAO,oBAAoB;YACnD,qFAAqF,EACrF,GAAG,CACJ,CAAA;IACH,CAAC;IAED,0CAA0C;IAC1C,IAAI,OAAe,CAAA;IACnB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,YAAY,CACpB,2BAA4B,GAAa,CAAC,OAAO,EAAE,EACnD,GAAG,CACJ,CAAA;IACH,CAAC;IAED,4BAA4B;IAC5B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACzC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAEjC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAEvD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,YAAY,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAA;IACnE,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skillauditor/client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent SDK for SkillAuditor — submit, verify, and check skills onchain in one call",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/Arttribute/skillauditor.git",
|
|
10
|
+
"directory": "packages/skillauditor-client"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["skillauditor", "skill", "agent", "sdk", "ens", "onchain", "worldcoin"],
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"prepublishOnly": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@worldcoin/agentkit": "^0.1.6",
|
|
35
|
+
"viem": "^2.47.10"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.11.17",
|
|
39
|
+
"typescript": "^5.8.3"
|
|
40
|
+
}
|
|
41
|
+
}
|