@kirkelabs/agent-readiness-scan 0.1.0 → 0.2.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/CHANGELOG.md +50 -0
- package/CITATION.cff +30 -30
- package/README.md +144 -142
- package/bin/cli.js +175 -172
- package/package.json +69 -64
- package/src/checks/04-mcp-exposure.js +165 -104
- package/src/checks/05-agentic-commerce.js +152 -85
- package/src/generators.js +228 -174
- package/src/index.js +127 -126
package/bin/cli.js
CHANGED
|
@@ -1,172 +1,175 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* bin/cli.js — command-line entry point.
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* npx @kirkelabs/agent-readiness-scan https://example.com
|
|
7
|
-
* npx @kirkelabs/agent-readiness-scan https://example.com --out ./report
|
|
8
|
-
* npx @kirkelabs/agent-readiness-scan https://example.com --json
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { writeFile, mkdir } from 'node:fs/promises';
|
|
12
|
-
import { resolve, join, dirname } from 'node:path';
|
|
13
|
-
import { scan } from '../src/index.js';
|
|
14
|
-
import { renderScorecard } from '../src/scorecard.js';
|
|
15
|
-
|
|
16
|
-
const RESET = '\x1b[0m';
|
|
17
|
-
const DIM = '\x1b[2m';
|
|
18
|
-
const BOLD = '\x1b[1m';
|
|
19
|
-
const GREEN = '\x1b[32m';
|
|
20
|
-
const YELLOW = '\x1b[33m';
|
|
21
|
-
const RED = '\x1b[31m';
|
|
22
|
-
const CYAN = '\x1b[36m';
|
|
23
|
-
|
|
24
|
-
function parseArgs(argv) {
|
|
25
|
-
const args = { url: null, out: './agent-readiness-out', json: false };
|
|
26
|
-
for (let i = 2; i < argv.length; i++) {
|
|
27
|
-
const a = argv[i];
|
|
28
|
-
if (a === '--out') args.out = argv[++i];
|
|
29
|
-
else if (a === '--json') args.json = true;
|
|
30
|
-
else if (a === '--help' || a === '-h') args.help = true;
|
|
31
|
-
else if (!a.startsWith('-')) args.url = a;
|
|
32
|
-
}
|
|
33
|
-
return args;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function help() {
|
|
37
|
-
console.log(`
|
|
38
|
-
${BOLD}agent-readiness-scan${RESET} — is your brand ready for AI agents to act on it?
|
|
39
|
-
|
|
40
|
-
${BOLD}Usage${RESET}
|
|
41
|
-
npx @kirkelabs/agent-readiness-scan <url> [options]
|
|
42
|
-
|
|
43
|
-
${BOLD}Options${RESET}
|
|
44
|
-
--out <dir> Output directory (default: ./agent-readiness-out)
|
|
45
|
-
--json Print machine-readable JSON to stdout (good for CI)
|
|
46
|
-
-h, --help Show this help
|
|
47
|
-
|
|
48
|
-
${BOLD}Outputs written to <dir>${RESET}
|
|
49
|
-
score.json Machine-readable result (CI-gateable)
|
|
50
|
-
report.md Human-readable report
|
|
51
|
-
scorecard.html Shareable static scorecard
|
|
52
|
-
customs-declaration/ Drop-in policy files
|
|
53
|
-
robots.txt
|
|
54
|
-
.well-known/security.txt
|
|
55
|
-
.well-known/mcp/server-card.json
|
|
56
|
-
.well-known/acp/manifest.json
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
await
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
await
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
);
|
|
148
|
-
console.log(
|
|
149
|
-
`${DIM}
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
md
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* bin/cli.js — command-line entry point.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx @kirkelabs/agent-readiness-scan https://example.com
|
|
7
|
+
* npx @kirkelabs/agent-readiness-scan https://example.com --out ./report
|
|
8
|
+
* npx @kirkelabs/agent-readiness-scan https://example.com --json
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
12
|
+
import { resolve, join, dirname } from 'node:path';
|
|
13
|
+
import { scan } from '../src/index.js';
|
|
14
|
+
import { renderScorecard } from '../src/scorecard.js';
|
|
15
|
+
|
|
16
|
+
const RESET = '\x1b[0m';
|
|
17
|
+
const DIM = '\x1b[2m';
|
|
18
|
+
const BOLD = '\x1b[1m';
|
|
19
|
+
const GREEN = '\x1b[32m';
|
|
20
|
+
const YELLOW = '\x1b[33m';
|
|
21
|
+
const RED = '\x1b[31m';
|
|
22
|
+
const CYAN = '\x1b[36m';
|
|
23
|
+
|
|
24
|
+
function parseArgs(argv) {
|
|
25
|
+
const args = { url: null, out: './agent-readiness-out', json: false };
|
|
26
|
+
for (let i = 2; i < argv.length; i++) {
|
|
27
|
+
const a = argv[i];
|
|
28
|
+
if (a === '--out') args.out = argv[++i];
|
|
29
|
+
else if (a === '--json') args.json = true;
|
|
30
|
+
else if (a === '--help' || a === '-h') args.help = true;
|
|
31
|
+
else if (!a.startsWith('-')) args.url = a;
|
|
32
|
+
}
|
|
33
|
+
return args;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function help() {
|
|
37
|
+
console.log(`
|
|
38
|
+
${BOLD}agent-readiness-scan${RESET} — is your brand ready for AI agents to act on it?
|
|
39
|
+
|
|
40
|
+
${BOLD}Usage${RESET}
|
|
41
|
+
npx @kirkelabs/agent-readiness-scan <url> [options]
|
|
42
|
+
|
|
43
|
+
${BOLD}Options${RESET}
|
|
44
|
+
--out <dir> Output directory (default: ./agent-readiness-out)
|
|
45
|
+
--json Print machine-readable JSON to stdout (good for CI)
|
|
46
|
+
-h, --help Show this help
|
|
47
|
+
|
|
48
|
+
${BOLD}Outputs written to <dir>${RESET}
|
|
49
|
+
score.json Machine-readable result (CI-gateable)
|
|
50
|
+
report.md Human-readable report
|
|
51
|
+
scorecard.html Shareable static scorecard
|
|
52
|
+
customs-declaration/ Drop-in policy files
|
|
53
|
+
robots.txt
|
|
54
|
+
.well-known/security.txt
|
|
55
|
+
.well-known/mcp/server-card.json
|
|
56
|
+
.well-known/acp/manifest.json
|
|
57
|
+
.well-known/agent-access.json
|
|
58
|
+
|
|
59
|
+
MIT · Kirke Labs · www.kirkelabs.com
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function color(level) {
|
|
64
|
+
return level === 'pass'
|
|
65
|
+
? GREEN
|
|
66
|
+
: level === 'warn'
|
|
67
|
+
? YELLOW
|
|
68
|
+
: level === 'fail'
|
|
69
|
+
? RED
|
|
70
|
+
: DIM;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function bar(pct, width = 22) {
|
|
74
|
+
const fill = Math.round((pct / 100) * width);
|
|
75
|
+
return '█'.repeat(fill) + '░'.repeat(width - fill);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function writeArtefact(outDir, relPath, content) {
|
|
79
|
+
const fullPath = join(outDir, relPath);
|
|
80
|
+
await mkdir(dirname(fullPath), { recursive: true });
|
|
81
|
+
await writeFile(fullPath, content);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function main() {
|
|
85
|
+
const args = parseArgs(process.argv);
|
|
86
|
+
if (args.help || !args.url) {
|
|
87
|
+
help();
|
|
88
|
+
process.exit(args.url ? 0 : 1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let url = args.url;
|
|
92
|
+
if (!/^https?:\/\//i.test(url)) url = 'https://' + url;
|
|
93
|
+
|
|
94
|
+
if (!args.json) {
|
|
95
|
+
console.log(
|
|
96
|
+
`\n${CYAN}⟶ Scanning ${BOLD}${url}${RESET}${CYAN} for agent-readiness…${RESET}\n`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const result = await scan(url);
|
|
101
|
+
|
|
102
|
+
if (args.json) {
|
|
103
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!result.ok) {
|
|
108
|
+
console.error(`${RED}✗ Could not scan: ${result.error}${RESET}\n`);
|
|
109
|
+
process.exit(2);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const gColor =
|
|
113
|
+
result.grade === 'A' || result.grade === 'B'
|
|
114
|
+
? GREEN
|
|
115
|
+
: result.grade === 'C'
|
|
116
|
+
? YELLOW
|
|
117
|
+
: RED;
|
|
118
|
+
|
|
119
|
+
console.log(
|
|
120
|
+
`${BOLD} Agent-Readiness Score: ${gColor}${result.score}/100 (${result.grade})${RESET}\n`,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
for (const d of result.dimensions) {
|
|
124
|
+
const pct = Math.round((d.score / d.max) * 100);
|
|
125
|
+
const c = pct >= 70 ? GREEN : pct >= 40 ? YELLOW : RED;
|
|
126
|
+
console.log(
|
|
127
|
+
` ${c}${bar(pct)}${RESET} ${d.title} ${DIM}(${d.score}/${d.max}, weight ${d.weight})${RESET}`,
|
|
128
|
+
);
|
|
129
|
+
for (const f of d.findings) {
|
|
130
|
+
console.log(` ${color(f.level)}•${RESET} ${f.msg}`);
|
|
131
|
+
}
|
|
132
|
+
console.log('');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Write artefacts.
|
|
136
|
+
const outDir = resolve(args.out);
|
|
137
|
+
await mkdir(outDir, { recursive: true });
|
|
138
|
+
await writeFile(join(outDir, 'score.json'), JSON.stringify(result, null, 2));
|
|
139
|
+
await writeFile(join(outDir, 'report.md'), toMarkdown(result));
|
|
140
|
+
await writeFile(join(outDir, 'scorecard.html'), renderScorecard(result));
|
|
141
|
+
|
|
142
|
+
// Customs declaration files.
|
|
143
|
+
for (const [relPath, content] of Object.entries(result.generated)) {
|
|
144
|
+
await writeArtefact(join(outDir, 'customs-declaration'), relPath, content);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log(`${DIM} Artefacts written to ${outDir}/${RESET}`);
|
|
148
|
+
console.log(
|
|
149
|
+
`${DIM} score.json · report.md · scorecard.html · customs-declaration/${RESET}\n`,
|
|
150
|
+
);
|
|
151
|
+
console.log(
|
|
152
|
+
`${DIM} Heuristic indicators, not a guarantee of agent action. See docs/METHODOLOGY.md${RESET}\n`,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
process.exit(result.score >= 50 ? 0 : 3);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function toMarkdown(r) {
|
|
159
|
+
let md = `# Agent-Readiness Report\n\n`;
|
|
160
|
+
md += `**URL:** ${r.url} \n**Score:** ${r.score}/100 (${r.grade}) \n`;
|
|
161
|
+
md += `**Scanned:** ${r.scannedAt}\n\n`;
|
|
162
|
+
md += `> Heuristic indicators of how ready this brand is for AI agents to discover, declare access to, and act on. Not a guarantee of agent uptake.\n\n`;
|
|
163
|
+
for (const d of r.dimensions) {
|
|
164
|
+
md += `## ${d.title} — ${d.score}/${d.max}\n\n_${d.why}_\n\n`;
|
|
165
|
+
for (const f of d.findings) md += `- **${f.level.toUpperCase()}** — ${f.msg}\n`;
|
|
166
|
+
md += `\n`;
|
|
167
|
+
}
|
|
168
|
+
md += `---\n\nGenerated by [\`@kirkelabs/agent-readiness-scan\`](https://github.com/KirkeLabs/agent-readiness-scan) — MIT. Built by Soleman El Gelawi (CTO, Kirke Labs), with Steve Kirton (www.kirkelabs.com) as a gift to the Algorand ecosystem.\n`;
|
|
169
|
+
return md;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
main().catch((e) => {
|
|
173
|
+
console.error(`${RED}Unexpected error:${RESET}`, e);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
});
|
package/package.json
CHANGED
|
@@ -1,64 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@kirkelabs/agent-readiness-scan",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Audit a website's customs-house posture for AI agents. Scores 8 dimensions — crawler policy, bot auth, MCP/ACP exposure, agent-actionable Product/Offer, brand identity corroboration, regulatory transparency — and generates a drop-in customs declaration (robots.txt + .well-known/ manifests). A gift to the Algorand ecosystem from Kirke Labs.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"agent-readiness-scan": "bin/cli.js"
|
|
8
|
-
},
|
|
9
|
-
"exports": {
|
|
10
|
-
".": "./src/index.js"
|
|
11
|
-
},
|
|
12
|
-
"files": [
|
|
13
|
-
"bin/",
|
|
14
|
-
"src/",
|
|
15
|
-
"LICENSE",
|
|
16
|
-
"README.md",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@kirkelabs/agent-readiness-scan",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Audit a website's customs-house posture for AI agents. Scores 8 dimensions — crawler policy, bot auth, MCP/ACP exposure, agent-actionable Product/Offer, brand identity corroboration, regulatory transparency — and generates a drop-in customs declaration (robots.txt + .well-known/ manifests). A gift to the Algorand ecosystem from Kirke Labs.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agent-readiness-scan": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./src/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"src/",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"README.md",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"AUTHORS",
|
|
19
|
+
"CITATION.cff"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"scan": "node bin/cli.js",
|
|
26
|
+
"test": "node --test \"test/*.test.js\"",
|
|
27
|
+
"lint": "eslint . --ext .js",
|
|
28
|
+
"format": "prettier --write \"**/*.{js,json,md}\"",
|
|
29
|
+
"prepublishOnly": "npm run lint && npm test"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"ai-agents",
|
|
33
|
+
"mcp",
|
|
34
|
+
"acp",
|
|
35
|
+
"agentic-commerce",
|
|
36
|
+
"crawler-policy",
|
|
37
|
+
"web-bot-auth",
|
|
38
|
+
"content-signals",
|
|
39
|
+
"universal-cart",
|
|
40
|
+
"schema-org",
|
|
41
|
+
"structured-data",
|
|
42
|
+
"algorand",
|
|
43
|
+
"cli",
|
|
44
|
+
"nodejs"
|
|
45
|
+
],
|
|
46
|
+
"author": "Soleman El Gelawi <soleman@kirkelabs.com> (https://www.kirkelabs.com)",
|
|
47
|
+
"contributors": [
|
|
48
|
+
"Steve Kirton <steve@kirkelabs.com> (https://www.kirkelabs.com)"
|
|
49
|
+
],
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"homepage": "https://kirkelabs.github.io/agent-readiness-scan/",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/KirkeLabs/agent-readiness-scan.git"
|
|
55
|
+
},
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/KirkeLabs/agent-readiness-scan/issues"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=20"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"cheerio": "^1.0.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"eslint": "^9.0.0",
|
|
67
|
+
"prettier": "^3.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|