agentverify 1.0.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/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/chunk-JWWQ7MRK.mjs +75 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +284 -0
- package/dist/cli.mjs +230 -0
- package/dist/sdk.d.mts +61 -0
- package/dist/sdk.d.ts +61 -0
- package/dist/sdk.js +100 -0
- package/dist/sdk.mjs +8 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AI Blockchain Ventures LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# agentverify
|
|
2
|
+
|
|
3
|
+
**Execution trust analysis for AI agents — CLI and SDK**
|
|
4
|
+
|
|
5
|
+
Scan AI agent configurations for security issues, credential exposure, and governance gaps. Results save automatically to your Agent Verify dashboard.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g agentverify
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## CLI Usage
|
|
14
|
+
|
|
15
|
+
### Scan a directory
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
agentverify scan ./agents --key av_your_key
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Scan a single file
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
agentverify scan --file agent.json --key av_your_key
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Use environment variable
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
export AGENTVERIFY_API_KEY=av_your_key
|
|
31
|
+
agentverify scan ./agents
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### JSON output (for CI/CD)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
agentverify scan . --key av_your_key --json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## SDK Usage
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { scan, scanMany } from 'agentverify'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Scan a single file
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const result = await scan(
|
|
50
|
+
{ content: agentCode, fileName: 'agent.js' },
|
|
51
|
+
{ apiKey: process.env.AGENTVERIFY_API_KEY }
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
console.log(result.verdict) // 'VERIFIED' | 'NOT VERIFIED'
|
|
55
|
+
console.log(result.riskScore) // 0-100
|
|
56
|
+
console.log(result.findings) // Array of security findings
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Scan multiple files
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
const results = await scanMany(
|
|
63
|
+
[
|
|
64
|
+
{ content: agent1Code, fileName: 'agent1.js' },
|
|
65
|
+
{ content: agent2Code, fileName: 'agent2.js' },
|
|
66
|
+
],
|
|
67
|
+
{ apiKey: process.env.AGENTVERIFY_API_KEY }
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## CI/CD Integration
|
|
72
|
+
|
|
73
|
+
### GitHub Actions
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
- name: Scan agents
|
|
77
|
+
run: npx agentverify scan ./agents --key ${{ secrets.AGENTVERIFY_API_KEY }} --json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Get your API key
|
|
81
|
+
|
|
82
|
+
Sign up at https://agentverify.ai and go to Dashboard → API
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT — AI Blockchain Ventures LLC
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// src/sdk.ts
|
|
2
|
+
var DEFAULT_API_URL = "https://agentverify-api.agentverify.workers.dev/v1/scan";
|
|
3
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
4
|
+
async function scan(input, options) {
|
|
5
|
+
const { apiKey, apiUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options;
|
|
6
|
+
if (!apiKey) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"API key required. Generate one at https://agentverify.ai/dashboard"
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
if (!input.content || input.content.trim().length === 0) {
|
|
12
|
+
throw new Error("content is required and cannot be empty");
|
|
13
|
+
}
|
|
14
|
+
const controller = new AbortController();
|
|
15
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
16
|
+
try {
|
|
17
|
+
const response = await fetch(apiUrl, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: {
|
|
20
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
"User-Agent": "agentverify-sdk/1.0.0"
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
content: input.content,
|
|
26
|
+
fileName: input.fileName ?? "agent",
|
|
27
|
+
platform: input.platform
|
|
28
|
+
}),
|
|
29
|
+
signal: controller.signal
|
|
30
|
+
});
|
|
31
|
+
if (response.status === 401) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"Invalid API key. Generate one at https://agentverify.ai/dashboard"
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (response.status === 400) {
|
|
37
|
+
const err = await response.json().catch(() => ({}));
|
|
38
|
+
throw new Error(err.error ?? "Invalid request");
|
|
39
|
+
}
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new Error(`API error: ${response.status} ${response.statusText}`);
|
|
42
|
+
}
|
|
43
|
+
const data = await response.json();
|
|
44
|
+
return data;
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
47
|
+
throw new Error(`Request timed out after ${timeout}ms`);
|
|
48
|
+
}
|
|
49
|
+
throw err;
|
|
50
|
+
} finally {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function scanMany(inputs, options, concurrency = 3) {
|
|
55
|
+
const results = [];
|
|
56
|
+
for (let i = 0; i < inputs.length; i += concurrency) {
|
|
57
|
+
const batch = inputs.slice(i, i + concurrency);
|
|
58
|
+
const batchResults = await Promise.allSettled(
|
|
59
|
+
batch.map((input) => scan(input, options))
|
|
60
|
+
);
|
|
61
|
+
batchResults.forEach((res, j) => {
|
|
62
|
+
if (res.status === "fulfilled") {
|
|
63
|
+
results.push({ input: batch[j], result: res.value, error: null });
|
|
64
|
+
} else {
|
|
65
|
+
results.push({ input: batch[j], result: null, error: res.reason instanceof Error ? res.reason.message : String(res.reason) });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
scan,
|
|
74
|
+
scanMany
|
|
75
|
+
};
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/cli.ts
|
|
5
|
+
var import_fs = require("fs");
|
|
6
|
+
var import_path = require("path");
|
|
7
|
+
|
|
8
|
+
// src/sdk.ts
|
|
9
|
+
var DEFAULT_API_URL = "https://agentverify-api.agentverify.workers.dev/v1/scan";
|
|
10
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
11
|
+
async function scan(input, options) {
|
|
12
|
+
const { apiKey, apiUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options;
|
|
13
|
+
if (!apiKey) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
"API key required. Generate one at https://agentverify.ai/dashboard"
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
if (!input.content || input.content.trim().length === 0) {
|
|
19
|
+
throw new Error("content is required and cannot be empty");
|
|
20
|
+
}
|
|
21
|
+
const controller = new AbortController();
|
|
22
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(apiUrl, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: {
|
|
27
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
"User-Agent": "agentverify-sdk/1.0.0"
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
content: input.content,
|
|
33
|
+
fileName: input.fileName ?? "agent",
|
|
34
|
+
platform: input.platform
|
|
35
|
+
}),
|
|
36
|
+
signal: controller.signal
|
|
37
|
+
});
|
|
38
|
+
if (response.status === 401) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
"Invalid API key. Generate one at https://agentverify.ai/dashboard"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
if (response.status === 400) {
|
|
44
|
+
const err = await response.json().catch(() => ({}));
|
|
45
|
+
throw new Error(err.error ?? "Invalid request");
|
|
46
|
+
}
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
throw new Error(`API error: ${response.status} ${response.statusText}`);
|
|
49
|
+
}
|
|
50
|
+
const data = await response.json();
|
|
51
|
+
return data;
|
|
52
|
+
} catch (err) {
|
|
53
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
54
|
+
throw new Error(`Request timed out after ${timeout}ms`);
|
|
55
|
+
}
|
|
56
|
+
throw err;
|
|
57
|
+
} finally {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/cli.ts
|
|
63
|
+
var VERSION = "1.0.0";
|
|
64
|
+
var API_URL = "https://agentverify-api.agentverify.workers.dev/v1/scan";
|
|
65
|
+
var c = {
|
|
66
|
+
reset: "\x1B[0m",
|
|
67
|
+
bold: "\x1B[1m",
|
|
68
|
+
dim: "\x1B[2m",
|
|
69
|
+
red: "\x1B[31m",
|
|
70
|
+
green: "\x1B[32m",
|
|
71
|
+
yellow: "\x1B[33m",
|
|
72
|
+
cyan: "\x1B[36m",
|
|
73
|
+
white: "\x1B[37m",
|
|
74
|
+
gray: "\x1B[90m"
|
|
75
|
+
};
|
|
76
|
+
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".ts", ".py", ".json", ".yaml", ".yml", ".md", ".mjs", ".cjs"]);
|
|
77
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "vendor", "coverage", ".cache"]);
|
|
78
|
+
function collectFiles(dir) {
|
|
79
|
+
const files = [];
|
|
80
|
+
try {
|
|
81
|
+
const entries = (0, import_fs.readdirSync)(dir);
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
if (SKIP_DIRS.has(entry)) continue;
|
|
84
|
+
const fullPath = (0, import_path.join)(dir, entry);
|
|
85
|
+
const stat = (0, import_fs.statSync)(fullPath);
|
|
86
|
+
if (stat.isDirectory()) {
|
|
87
|
+
files.push(...collectFiles(fullPath));
|
|
88
|
+
} else if (SUPPORTED_EXTENSIONS.has((0, import_path.extname)(entry).toLowerCase())) {
|
|
89
|
+
files.push(fullPath);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
return files;
|
|
95
|
+
}
|
|
96
|
+
function parseArgs(argv) {
|
|
97
|
+
const args = argv.slice(2);
|
|
98
|
+
const result = {
|
|
99
|
+
command: args[0] ?? "",
|
|
100
|
+
dir: ".",
|
|
101
|
+
key: "",
|
|
102
|
+
file: "",
|
|
103
|
+
json: false,
|
|
104
|
+
help: false,
|
|
105
|
+
version: false
|
|
106
|
+
};
|
|
107
|
+
if (result.command === "--help" || result.command === "-h") {
|
|
108
|
+
result.command = "";
|
|
109
|
+
result.help = true;
|
|
110
|
+
}
|
|
111
|
+
if (result.command === "--version" || result.command === "-v") {
|
|
112
|
+
result.command = "";
|
|
113
|
+
result.version = true;
|
|
114
|
+
}
|
|
115
|
+
for (let i = 1; i < args.length; i++) {
|
|
116
|
+
const arg = args[i];
|
|
117
|
+
if (arg === "--key" || arg === "-k") result.key = args[++i] ?? "";
|
|
118
|
+
else if (arg === "--file" || arg === "-f") result.file = args[++i] ?? "";
|
|
119
|
+
else if (arg === "--json") result.json = true;
|
|
120
|
+
else if (arg === "--help" || arg === "-h") result.help = true;
|
|
121
|
+
else if (arg === "--version" || arg === "-v") result.version = true;
|
|
122
|
+
else if (!arg.startsWith("-")) result.dir = arg;
|
|
123
|
+
}
|
|
124
|
+
if (!result.key) result.key = process.env.AGENTVERIFY_API_KEY ?? "";
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
function printHelp() {
|
|
128
|
+
console.log(`
|
|
129
|
+
${c.bold}${c.cyan}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}
|
|
130
|
+
${c.gray}Execution trust analysis for AI agents${c.reset}
|
|
131
|
+
|
|
132
|
+
${c.bold}Usage:${c.reset}
|
|
133
|
+
agentverify scan [dir] --key <api-key>
|
|
134
|
+
agentverify scan --file <file> --key <api-key>
|
|
135
|
+
|
|
136
|
+
${c.bold}Commands:${c.reset}
|
|
137
|
+
scan Scan agent files in a directory or a single file
|
|
138
|
+
|
|
139
|
+
${c.bold}Options:${c.reset}
|
|
140
|
+
--key, -k API key (or set AGENTVERIFY_API_KEY env var)
|
|
141
|
+
--file, -f Scan a single file instead of a directory
|
|
142
|
+
--json Output results as JSON
|
|
143
|
+
--version, -v Print version
|
|
144
|
+
--help, -h Show this help message
|
|
145
|
+
|
|
146
|
+
${c.bold}Examples:${c.reset}
|
|
147
|
+
${c.gray}# Scan all agent files in current directory${c.reset}
|
|
148
|
+
agentverify scan . --key av_your_key
|
|
149
|
+
|
|
150
|
+
${c.gray}# Scan a specific file${c.reset}
|
|
151
|
+
agentverify scan --file agent.json --key av_your_key
|
|
152
|
+
|
|
153
|
+
${c.gray}# Use environment variable for key${c.reset}
|
|
154
|
+
AGENTVERIFY_API_KEY=av_your_key agentverify scan ./agents
|
|
155
|
+
|
|
156
|
+
${c.gray}# Output as JSON (useful for CI/CD)${c.reset}
|
|
157
|
+
agentverify scan . --key av_your_key --json
|
|
158
|
+
|
|
159
|
+
${c.bold}Get your API key:${c.reset}
|
|
160
|
+
https://agentverify.ai/dashboard
|
|
161
|
+
|
|
162
|
+
${c.bold}Docs:${c.reset}
|
|
163
|
+
https://github.com/AI-Blockchain-Ventures/agentverify
|
|
164
|
+
`);
|
|
165
|
+
}
|
|
166
|
+
function printVerdict(result, fileName) {
|
|
167
|
+
const verified = result.verdict === "VERIFIED";
|
|
168
|
+
const icon = verified ? `${c.green}\u2713${c.reset}` : `${c.red}\u2717${c.reset}`;
|
|
169
|
+
const verdict = verified ? `${c.green}VERIFIED${c.reset} ` : `${c.red}NOT VERIFIED${c.reset}`;
|
|
170
|
+
const score = verified ? `${c.green}${result.riskScore}/100${c.reset}` : result.riskScore >= 50 ? `${c.yellow}${result.riskScore}/100${c.reset}` : `${c.red}${result.riskScore}/100${c.reset}`;
|
|
171
|
+
const findings = result.findings.length > 0 ? `${c.gray}\u2014 ${result.findings.length} finding${result.findings.length === 1 ? "" : "s"}${c.reset}` : "";
|
|
172
|
+
const name = fileName.padEnd(30);
|
|
173
|
+
console.log(` ${icon} ${verdict} ${name} score: ${score} ${findings}`);
|
|
174
|
+
if (result.saved && result.reportId) {
|
|
175
|
+
console.log(` ${c.gray}\u2192 Report: https://agentverify.ai/report/${result.reportId}${c.reset}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async function runScan(args) {
|
|
179
|
+
if (!args.key) {
|
|
180
|
+
console.error(`
|
|
181
|
+
${c.red}Error:${c.reset} API key required
|
|
182
|
+
`);
|
|
183
|
+
console.error(` Set with --key av_your_key or AGENTVERIFY_API_KEY env var`);
|
|
184
|
+
console.error(` Get your key at https://agentverify.ai/dashboard
|
|
185
|
+
`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
let files = [];
|
|
189
|
+
if (args.file) {
|
|
190
|
+
files = [args.file];
|
|
191
|
+
} else {
|
|
192
|
+
const dir = args.dir;
|
|
193
|
+
console.log(`
|
|
194
|
+
${c.bold}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}`);
|
|
195
|
+
console.log(`${c.gray}Scanning ${dir}...${c.reset}
|
|
196
|
+
`);
|
|
197
|
+
files = collectFiles(dir);
|
|
198
|
+
if (files.length === 0) {
|
|
199
|
+
console.log(`${c.yellow}No agent files found in ${dir}${c.reset}`);
|
|
200
|
+
console.log(`${c.gray}Supported: .js .ts .py .json .yaml .yml .md${c.reset}
|
|
201
|
+
`);
|
|
202
|
+
process.exit(0);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const jsonResults = [];
|
|
206
|
+
let verified = 0;
|
|
207
|
+
let notVerified = 0;
|
|
208
|
+
let errors = 0;
|
|
209
|
+
const CONCURRENCY = 3;
|
|
210
|
+
for (let i = 0; i < files.length; i += CONCURRENCY) {
|
|
211
|
+
const batch = files.slice(i, i + CONCURRENCY);
|
|
212
|
+
const batchResults = await Promise.allSettled(
|
|
213
|
+
batch.map(async (filePath) => {
|
|
214
|
+
const content = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
215
|
+
const relPath = (0, import_path.relative)(args.dir === "." ? process.cwd() : args.dir, filePath);
|
|
216
|
+
const result = await scan(
|
|
217
|
+
{ content, fileName: relPath },
|
|
218
|
+
{ apiKey: args.key, apiUrl: API_URL }
|
|
219
|
+
);
|
|
220
|
+
return { filePath, relPath, result };
|
|
221
|
+
})
|
|
222
|
+
);
|
|
223
|
+
for (let j = 0; j < batchResults.length; j++) {
|
|
224
|
+
const outcome = batchResults[j];
|
|
225
|
+
if (outcome.status === "fulfilled") {
|
|
226
|
+
const { relPath, result } = outcome.value;
|
|
227
|
+
if (!args.json) printVerdict(result, relPath);
|
|
228
|
+
jsonResults.push({ file: relPath, result, error: null });
|
|
229
|
+
if (result.verdict === "VERIFIED") verified++;
|
|
230
|
+
else notVerified++;
|
|
231
|
+
} else {
|
|
232
|
+
const filePath = batch[j];
|
|
233
|
+
const relPath = (0, import_path.relative)(args.dir, filePath);
|
|
234
|
+
const errMsg = outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason);
|
|
235
|
+
if (!args.json) {
|
|
236
|
+
console.log(` ${c.yellow}\u26A0${c.reset} ${c.yellow}WARNING${c.reset} ${relPath.padEnd(30)} ${c.gray}${errMsg}${c.reset}`);
|
|
237
|
+
}
|
|
238
|
+
jsonResults.push({ file: relPath, result: null, error: errMsg });
|
|
239
|
+
errors++;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (args.json) {
|
|
244
|
+
console.log(JSON.stringify({ results: jsonResults, summary: { total: files.length, verified, notVerified, errors } }, null, 2));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
console.log(`
|
|
248
|
+
${c.gray}${"\u2500".repeat(60)}${c.reset}`);
|
|
249
|
+
console.log(`${c.bold}Agent Verify Scan Complete${c.reset}`);
|
|
250
|
+
console.log(`${c.gray}Files scanned:${c.reset} ${files.length}`);
|
|
251
|
+
console.log(`${c.green}Verified:${c.reset} ${verified}`);
|
|
252
|
+
if (notVerified > 0) console.log(`${c.red}Not Verified:${c.reset} ${notVerified}`);
|
|
253
|
+
if (errors > 0) console.log(`${c.yellow}Errors:${c.reset} ${errors}`);
|
|
254
|
+
console.log(`${c.gray}${"\u2500".repeat(60)}${c.reset}`);
|
|
255
|
+
console.log(`
|
|
256
|
+
${c.gray}View reports: https://agentverify.ai/dashboard${c.reset}
|
|
257
|
+
`);
|
|
258
|
+
if (notVerified > 0) process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
async function main() {
|
|
261
|
+
const args = parseArgs(process.argv);
|
|
262
|
+
if (args.version) {
|
|
263
|
+
console.log(`agentverify v${VERSION}`);
|
|
264
|
+
process.exit(0);
|
|
265
|
+
}
|
|
266
|
+
if (args.help || !args.command) {
|
|
267
|
+
printHelp();
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
270
|
+
if (args.command === "scan") {
|
|
271
|
+
await runScan(args);
|
|
272
|
+
} else {
|
|
273
|
+
console.error(`
|
|
274
|
+
${c.red}Unknown command: ${args.command}${c.reset}`);
|
|
275
|
+
console.error(`Run ${c.cyan}agentverify --help${c.reset} for usage
|
|
276
|
+
`);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
main().catch((err) => {
|
|
281
|
+
console.error(`
|
|
282
|
+
${c.red}Fatal error:${c.reset}`, err instanceof Error ? err.message : err);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
});
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
scan
|
|
4
|
+
} from "./chunk-JWWQ7MRK.mjs";
|
|
5
|
+
|
|
6
|
+
// src/cli.ts
|
|
7
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
8
|
+
import { join, relative, extname } from "path";
|
|
9
|
+
var VERSION = "1.0.0";
|
|
10
|
+
var API_URL = "https://agentverify-api.agentverify.workers.dev/v1/scan";
|
|
11
|
+
var c = {
|
|
12
|
+
reset: "\x1B[0m",
|
|
13
|
+
bold: "\x1B[1m",
|
|
14
|
+
dim: "\x1B[2m",
|
|
15
|
+
red: "\x1B[31m",
|
|
16
|
+
green: "\x1B[32m",
|
|
17
|
+
yellow: "\x1B[33m",
|
|
18
|
+
cyan: "\x1B[36m",
|
|
19
|
+
white: "\x1B[37m",
|
|
20
|
+
gray: "\x1B[90m"
|
|
21
|
+
};
|
|
22
|
+
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".ts", ".py", ".json", ".yaml", ".yml", ".md", ".mjs", ".cjs"]);
|
|
23
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "vendor", "coverage", ".cache"]);
|
|
24
|
+
function collectFiles(dir) {
|
|
25
|
+
const files = [];
|
|
26
|
+
try {
|
|
27
|
+
const entries = readdirSync(dir);
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
if (SKIP_DIRS.has(entry)) continue;
|
|
30
|
+
const fullPath = join(dir, entry);
|
|
31
|
+
const stat = statSync(fullPath);
|
|
32
|
+
if (stat.isDirectory()) {
|
|
33
|
+
files.push(...collectFiles(fullPath));
|
|
34
|
+
} else if (SUPPORTED_EXTENSIONS.has(extname(entry).toLowerCase())) {
|
|
35
|
+
files.push(fullPath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
return files;
|
|
41
|
+
}
|
|
42
|
+
function parseArgs(argv) {
|
|
43
|
+
const args = argv.slice(2);
|
|
44
|
+
const result = {
|
|
45
|
+
command: args[0] ?? "",
|
|
46
|
+
dir: ".",
|
|
47
|
+
key: "",
|
|
48
|
+
file: "",
|
|
49
|
+
json: false,
|
|
50
|
+
help: false,
|
|
51
|
+
version: false
|
|
52
|
+
};
|
|
53
|
+
if (result.command === "--help" || result.command === "-h") {
|
|
54
|
+
result.command = "";
|
|
55
|
+
result.help = true;
|
|
56
|
+
}
|
|
57
|
+
if (result.command === "--version" || result.command === "-v") {
|
|
58
|
+
result.command = "";
|
|
59
|
+
result.version = true;
|
|
60
|
+
}
|
|
61
|
+
for (let i = 1; i < args.length; i++) {
|
|
62
|
+
const arg = args[i];
|
|
63
|
+
if (arg === "--key" || arg === "-k") result.key = args[++i] ?? "";
|
|
64
|
+
else if (arg === "--file" || arg === "-f") result.file = args[++i] ?? "";
|
|
65
|
+
else if (arg === "--json") result.json = true;
|
|
66
|
+
else if (arg === "--help" || arg === "-h") result.help = true;
|
|
67
|
+
else if (arg === "--version" || arg === "-v") result.version = true;
|
|
68
|
+
else if (!arg.startsWith("-")) result.dir = arg;
|
|
69
|
+
}
|
|
70
|
+
if (!result.key) result.key = process.env.AGENTVERIFY_API_KEY ?? "";
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
function printHelp() {
|
|
74
|
+
console.log(`
|
|
75
|
+
${c.bold}${c.cyan}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}
|
|
76
|
+
${c.gray}Execution trust analysis for AI agents${c.reset}
|
|
77
|
+
|
|
78
|
+
${c.bold}Usage:${c.reset}
|
|
79
|
+
agentverify scan [dir] --key <api-key>
|
|
80
|
+
agentverify scan --file <file> --key <api-key>
|
|
81
|
+
|
|
82
|
+
${c.bold}Commands:${c.reset}
|
|
83
|
+
scan Scan agent files in a directory or a single file
|
|
84
|
+
|
|
85
|
+
${c.bold}Options:${c.reset}
|
|
86
|
+
--key, -k API key (or set AGENTVERIFY_API_KEY env var)
|
|
87
|
+
--file, -f Scan a single file instead of a directory
|
|
88
|
+
--json Output results as JSON
|
|
89
|
+
--version, -v Print version
|
|
90
|
+
--help, -h Show this help message
|
|
91
|
+
|
|
92
|
+
${c.bold}Examples:${c.reset}
|
|
93
|
+
${c.gray}# Scan all agent files in current directory${c.reset}
|
|
94
|
+
agentverify scan . --key av_your_key
|
|
95
|
+
|
|
96
|
+
${c.gray}# Scan a specific file${c.reset}
|
|
97
|
+
agentverify scan --file agent.json --key av_your_key
|
|
98
|
+
|
|
99
|
+
${c.gray}# Use environment variable for key${c.reset}
|
|
100
|
+
AGENTVERIFY_API_KEY=av_your_key agentverify scan ./agents
|
|
101
|
+
|
|
102
|
+
${c.gray}# Output as JSON (useful for CI/CD)${c.reset}
|
|
103
|
+
agentverify scan . --key av_your_key --json
|
|
104
|
+
|
|
105
|
+
${c.bold}Get your API key:${c.reset}
|
|
106
|
+
https://agentverify.ai/dashboard
|
|
107
|
+
|
|
108
|
+
${c.bold}Docs:${c.reset}
|
|
109
|
+
https://github.com/AI-Blockchain-Ventures/agentverify
|
|
110
|
+
`);
|
|
111
|
+
}
|
|
112
|
+
function printVerdict(result, fileName) {
|
|
113
|
+
const verified = result.verdict === "VERIFIED";
|
|
114
|
+
const icon = verified ? `${c.green}\u2713${c.reset}` : `${c.red}\u2717${c.reset}`;
|
|
115
|
+
const verdict = verified ? `${c.green}VERIFIED${c.reset} ` : `${c.red}NOT VERIFIED${c.reset}`;
|
|
116
|
+
const score = verified ? `${c.green}${result.riskScore}/100${c.reset}` : result.riskScore >= 50 ? `${c.yellow}${result.riskScore}/100${c.reset}` : `${c.red}${result.riskScore}/100${c.reset}`;
|
|
117
|
+
const findings = result.findings.length > 0 ? `${c.gray}\u2014 ${result.findings.length} finding${result.findings.length === 1 ? "" : "s"}${c.reset}` : "";
|
|
118
|
+
const name = fileName.padEnd(30);
|
|
119
|
+
console.log(` ${icon} ${verdict} ${name} score: ${score} ${findings}`);
|
|
120
|
+
if (result.saved && result.reportId) {
|
|
121
|
+
console.log(` ${c.gray}\u2192 Report: https://agentverify.ai/report/${result.reportId}${c.reset}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function runScan(args) {
|
|
125
|
+
if (!args.key) {
|
|
126
|
+
console.error(`
|
|
127
|
+
${c.red}Error:${c.reset} API key required
|
|
128
|
+
`);
|
|
129
|
+
console.error(` Set with --key av_your_key or AGENTVERIFY_API_KEY env var`);
|
|
130
|
+
console.error(` Get your key at https://agentverify.ai/dashboard
|
|
131
|
+
`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
let files = [];
|
|
135
|
+
if (args.file) {
|
|
136
|
+
files = [args.file];
|
|
137
|
+
} else {
|
|
138
|
+
const dir = args.dir;
|
|
139
|
+
console.log(`
|
|
140
|
+
${c.bold}Agent Verify${c.reset} ${c.gray}v${VERSION}${c.reset}`);
|
|
141
|
+
console.log(`${c.gray}Scanning ${dir}...${c.reset}
|
|
142
|
+
`);
|
|
143
|
+
files = collectFiles(dir);
|
|
144
|
+
if (files.length === 0) {
|
|
145
|
+
console.log(`${c.yellow}No agent files found in ${dir}${c.reset}`);
|
|
146
|
+
console.log(`${c.gray}Supported: .js .ts .py .json .yaml .yml .md${c.reset}
|
|
147
|
+
`);
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const jsonResults = [];
|
|
152
|
+
let verified = 0;
|
|
153
|
+
let notVerified = 0;
|
|
154
|
+
let errors = 0;
|
|
155
|
+
const CONCURRENCY = 3;
|
|
156
|
+
for (let i = 0; i < files.length; i += CONCURRENCY) {
|
|
157
|
+
const batch = files.slice(i, i + CONCURRENCY);
|
|
158
|
+
const batchResults = await Promise.allSettled(
|
|
159
|
+
batch.map(async (filePath) => {
|
|
160
|
+
const content = readFileSync(filePath, "utf-8");
|
|
161
|
+
const relPath = relative(args.dir === "." ? process.cwd() : args.dir, filePath);
|
|
162
|
+
const result = await scan(
|
|
163
|
+
{ content, fileName: relPath },
|
|
164
|
+
{ apiKey: args.key, apiUrl: API_URL }
|
|
165
|
+
);
|
|
166
|
+
return { filePath, relPath, result };
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
for (let j = 0; j < batchResults.length; j++) {
|
|
170
|
+
const outcome = batchResults[j];
|
|
171
|
+
if (outcome.status === "fulfilled") {
|
|
172
|
+
const { relPath, result } = outcome.value;
|
|
173
|
+
if (!args.json) printVerdict(result, relPath);
|
|
174
|
+
jsonResults.push({ file: relPath, result, error: null });
|
|
175
|
+
if (result.verdict === "VERIFIED") verified++;
|
|
176
|
+
else notVerified++;
|
|
177
|
+
} else {
|
|
178
|
+
const filePath = batch[j];
|
|
179
|
+
const relPath = relative(args.dir, filePath);
|
|
180
|
+
const errMsg = outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason);
|
|
181
|
+
if (!args.json) {
|
|
182
|
+
console.log(` ${c.yellow}\u26A0${c.reset} ${c.yellow}WARNING${c.reset} ${relPath.padEnd(30)} ${c.gray}${errMsg}${c.reset}`);
|
|
183
|
+
}
|
|
184
|
+
jsonResults.push({ file: relPath, result: null, error: errMsg });
|
|
185
|
+
errors++;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (args.json) {
|
|
190
|
+
console.log(JSON.stringify({ results: jsonResults, summary: { total: files.length, verified, notVerified, errors } }, null, 2));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
console.log(`
|
|
194
|
+
${c.gray}${"\u2500".repeat(60)}${c.reset}`);
|
|
195
|
+
console.log(`${c.bold}Agent Verify Scan Complete${c.reset}`);
|
|
196
|
+
console.log(`${c.gray}Files scanned:${c.reset} ${files.length}`);
|
|
197
|
+
console.log(`${c.green}Verified:${c.reset} ${verified}`);
|
|
198
|
+
if (notVerified > 0) console.log(`${c.red}Not Verified:${c.reset} ${notVerified}`);
|
|
199
|
+
if (errors > 0) console.log(`${c.yellow}Errors:${c.reset} ${errors}`);
|
|
200
|
+
console.log(`${c.gray}${"\u2500".repeat(60)}${c.reset}`);
|
|
201
|
+
console.log(`
|
|
202
|
+
${c.gray}View reports: https://agentverify.ai/dashboard${c.reset}
|
|
203
|
+
`);
|
|
204
|
+
if (notVerified > 0) process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
async function main() {
|
|
207
|
+
const args = parseArgs(process.argv);
|
|
208
|
+
if (args.version) {
|
|
209
|
+
console.log(`agentverify v${VERSION}`);
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
if (args.help || !args.command) {
|
|
213
|
+
printHelp();
|
|
214
|
+
process.exit(0);
|
|
215
|
+
}
|
|
216
|
+
if (args.command === "scan") {
|
|
217
|
+
await runScan(args);
|
|
218
|
+
} else {
|
|
219
|
+
console.error(`
|
|
220
|
+
${c.red}Unknown command: ${args.command}${c.reset}`);
|
|
221
|
+
console.error(`Run ${c.cyan}agentverify --help${c.reset} for usage
|
|
222
|
+
`);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
main().catch((err) => {
|
|
227
|
+
console.error(`
|
|
228
|
+
${c.red}Fatal error:${c.reset}`, err instanceof Error ? err.message : err);
|
|
229
|
+
process.exit(1);
|
|
230
|
+
});
|
package/dist/sdk.d.mts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
interface ScanInput {
|
|
2
|
+
content: string;
|
|
3
|
+
fileName?: string;
|
|
4
|
+
platform?: string;
|
|
5
|
+
}
|
|
6
|
+
interface Finding {
|
|
7
|
+
title: string;
|
|
8
|
+
category: 'A' | 'B';
|
|
9
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
10
|
+
whatIsWrong: string;
|
|
11
|
+
whyItMatters: string;
|
|
12
|
+
recommendedFix: string;
|
|
13
|
+
evidence?: string;
|
|
14
|
+
}
|
|
15
|
+
interface ScanResult {
|
|
16
|
+
verdict: 'VERIFIED' | 'NOT VERIFIED';
|
|
17
|
+
riskScore: number;
|
|
18
|
+
riskLevel: 'Low Risk' | 'Moderate Risk' | 'High Risk';
|
|
19
|
+
findings: Finding[];
|
|
20
|
+
reportId: string;
|
|
21
|
+
scannedAt: string;
|
|
22
|
+
saved: boolean;
|
|
23
|
+
reportUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
interface ScanOptions {
|
|
26
|
+
apiKey: string;
|
|
27
|
+
apiUrl?: string;
|
|
28
|
+
timeout?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Scan an agent configuration for execution trust issues.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* import { scan } from 'agentverify'
|
|
36
|
+
*
|
|
37
|
+
* const result = await scan(
|
|
38
|
+
* { content: agentCode, fileName: 'agent.js' },
|
|
39
|
+
* { apiKey: process.env.AGENTVERIFY_API_KEY }
|
|
40
|
+
* )
|
|
41
|
+
*
|
|
42
|
+
* console.log(result.verdict) // 'VERIFIED' | 'NOT VERIFIED'
|
|
43
|
+
* console.log(result.riskScore) // 0-100
|
|
44
|
+
* console.log(result.findings) // Array of findings
|
|
45
|
+
*/
|
|
46
|
+
declare function scan(input: ScanInput, options: ScanOptions): Promise<ScanResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Scan multiple files concurrently.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* import { scanMany } from 'agentverify'
|
|
52
|
+
*
|
|
53
|
+
* const results = await scanMany(files, { apiKey: 'av_...' })
|
|
54
|
+
*/
|
|
55
|
+
declare function scanMany(inputs: ScanInput[], options: ScanOptions, concurrency?: number): Promise<Array<{
|
|
56
|
+
input: ScanInput;
|
|
57
|
+
result: ScanResult | null;
|
|
58
|
+
error: string | null;
|
|
59
|
+
}>>;
|
|
60
|
+
|
|
61
|
+
export { type Finding, type ScanInput, type ScanOptions, type ScanResult, scan, scanMany };
|
package/dist/sdk.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
interface ScanInput {
|
|
2
|
+
content: string;
|
|
3
|
+
fileName?: string;
|
|
4
|
+
platform?: string;
|
|
5
|
+
}
|
|
6
|
+
interface Finding {
|
|
7
|
+
title: string;
|
|
8
|
+
category: 'A' | 'B';
|
|
9
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
10
|
+
whatIsWrong: string;
|
|
11
|
+
whyItMatters: string;
|
|
12
|
+
recommendedFix: string;
|
|
13
|
+
evidence?: string;
|
|
14
|
+
}
|
|
15
|
+
interface ScanResult {
|
|
16
|
+
verdict: 'VERIFIED' | 'NOT VERIFIED';
|
|
17
|
+
riskScore: number;
|
|
18
|
+
riskLevel: 'Low Risk' | 'Moderate Risk' | 'High Risk';
|
|
19
|
+
findings: Finding[];
|
|
20
|
+
reportId: string;
|
|
21
|
+
scannedAt: string;
|
|
22
|
+
saved: boolean;
|
|
23
|
+
reportUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
interface ScanOptions {
|
|
26
|
+
apiKey: string;
|
|
27
|
+
apiUrl?: string;
|
|
28
|
+
timeout?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Scan an agent configuration for execution trust issues.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* import { scan } from 'agentverify'
|
|
36
|
+
*
|
|
37
|
+
* const result = await scan(
|
|
38
|
+
* { content: agentCode, fileName: 'agent.js' },
|
|
39
|
+
* { apiKey: process.env.AGENTVERIFY_API_KEY }
|
|
40
|
+
* )
|
|
41
|
+
*
|
|
42
|
+
* console.log(result.verdict) // 'VERIFIED' | 'NOT VERIFIED'
|
|
43
|
+
* console.log(result.riskScore) // 0-100
|
|
44
|
+
* console.log(result.findings) // Array of findings
|
|
45
|
+
*/
|
|
46
|
+
declare function scan(input: ScanInput, options: ScanOptions): Promise<ScanResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Scan multiple files concurrently.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* import { scanMany } from 'agentverify'
|
|
52
|
+
*
|
|
53
|
+
* const results = await scanMany(files, { apiKey: 'av_...' })
|
|
54
|
+
*/
|
|
55
|
+
declare function scanMany(inputs: ScanInput[], options: ScanOptions, concurrency?: number): Promise<Array<{
|
|
56
|
+
input: ScanInput;
|
|
57
|
+
result: ScanResult | null;
|
|
58
|
+
error: string | null;
|
|
59
|
+
}>>;
|
|
60
|
+
|
|
61
|
+
export { type Finding, type ScanInput, type ScanOptions, type ScanResult, scan, scanMany };
|
package/dist/sdk.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/sdk.ts
|
|
21
|
+
var sdk_exports = {};
|
|
22
|
+
__export(sdk_exports, {
|
|
23
|
+
scan: () => scan,
|
|
24
|
+
scanMany: () => scanMany
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(sdk_exports);
|
|
27
|
+
var DEFAULT_API_URL = "https://agentverify-api.agentverify.workers.dev/v1/scan";
|
|
28
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
29
|
+
async function scan(input, options) {
|
|
30
|
+
const { apiKey, apiUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options;
|
|
31
|
+
if (!apiKey) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"API key required. Generate one at https://agentverify.ai/dashboard"
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (!input.content || input.content.trim().length === 0) {
|
|
37
|
+
throw new Error("content is required and cannot be empty");
|
|
38
|
+
}
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(apiUrl, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
"User-Agent": "agentverify-sdk/1.0.0"
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
content: input.content,
|
|
51
|
+
fileName: input.fileName ?? "agent",
|
|
52
|
+
platform: input.platform
|
|
53
|
+
}),
|
|
54
|
+
signal: controller.signal
|
|
55
|
+
});
|
|
56
|
+
if (response.status === 401) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"Invalid API key. Generate one at https://agentverify.ai/dashboard"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (response.status === 400) {
|
|
62
|
+
const err = await response.json().catch(() => ({}));
|
|
63
|
+
throw new Error(err.error ?? "Invalid request");
|
|
64
|
+
}
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
throw new Error(`API error: ${response.status} ${response.statusText}`);
|
|
67
|
+
}
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
return data;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
72
|
+
throw new Error(`Request timed out after ${timeout}ms`);
|
|
73
|
+
}
|
|
74
|
+
throw err;
|
|
75
|
+
} finally {
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function scanMany(inputs, options, concurrency = 3) {
|
|
80
|
+
const results = [];
|
|
81
|
+
for (let i = 0; i < inputs.length; i += concurrency) {
|
|
82
|
+
const batch = inputs.slice(i, i + concurrency);
|
|
83
|
+
const batchResults = await Promise.allSettled(
|
|
84
|
+
batch.map((input) => scan(input, options))
|
|
85
|
+
);
|
|
86
|
+
batchResults.forEach((res, j) => {
|
|
87
|
+
if (res.status === "fulfilled") {
|
|
88
|
+
results.push({ input: batch[j], result: res.value, error: null });
|
|
89
|
+
} else {
|
|
90
|
+
results.push({ input: batch[j], result: null, error: res.reason instanceof Error ? res.reason.message : String(res.reason) });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
97
|
+
0 && (module.exports = {
|
|
98
|
+
scan,
|
|
99
|
+
scanMany
|
|
100
|
+
});
|
package/dist/sdk.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentverify",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI and SDK for Agent Verify — execution trust analysis for AI agents",
|
|
5
|
+
"bin": {
|
|
6
|
+
"agentverify": "./dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/sdk.js",
|
|
9
|
+
"module": "./dist/sdk.mjs",
|
|
10
|
+
"types": "./dist/sdk.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/sdk.d.ts",
|
|
14
|
+
"import": "./dist/sdk.mjs",
|
|
15
|
+
"require": "./dist/sdk.js"
|
|
16
|
+
},
|
|
17
|
+
"./cli": "./dist/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/cli.ts src/sdk.ts --format cjs,esm --dts --clean",
|
|
22
|
+
"dev": "tsup src/cli.ts src/sdk.ts --format cjs,esm --dts --watch",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"engines": { "node": ">=18.0.0" },
|
|
26
|
+
"keywords": [
|
|
27
|
+
"ai", "agents", "security", "verification", "a2spa",
|
|
28
|
+
"agent-security", "llm", "ai-safety", "cli"
|
|
29
|
+
],
|
|
30
|
+
"author": "AI Blockchain Ventures LLC",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/AI-Blockchain-Ventures/agentverify"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://agentverify.ai",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"typescript": "^5.0.0",
|
|
40
|
+
"@types/node": "^20.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|