@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 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"}
@@ -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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"}
@@ -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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"}
@@ -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"}
@@ -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,4 @@
1
+ export { SkillAuditorClient } from './client.js';
2
+ export { SkillRejectedError, AuditTimeoutError, PaymentError } from './errors.js';
3
+ export { createConsoleLogger } from './logger.js';
4
+ //# sourceMappingURL=index.js.map
@@ -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"}
@@ -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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"}
@@ -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
@@ -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
+ }