ai-friendly-check 0.0.0-stage → 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 +79 -2
- package/bin/cli.js +121 -0
- package/index.js +165 -0
- package/package.json +32 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 落地派 (https://www.geofde.cn)
|
|
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
CHANGED
|
@@ -1,3 +1,80 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ai-friendly-check
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
检查一个网页对 **AI 搜索引擎**(DeepSeek、豆包、元宝、ChatGPT 等)的友好度。
|
|
4
|
+
|
|
5
|
+
8 项指标,40 分制,一行命令出报告。
|
|
6
|
+
|
|
7
|
+
> 由 [落地派](https://www.geofde.cn) 维护 · 企业搞 AI,就找落地派
|
|
8
|
+
|
|
9
|
+
## 快速开始
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx ai-friendly-check https://example.com
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
输出示例:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
AI 友好度检测 https://example.com
|
|
19
|
+
|
|
20
|
+
████████████████░░░░ 32/40 良好
|
|
21
|
+
|
|
22
|
+
✓ 页面标题 长度 24 字:企业官网建设与 AI 搜索优化
|
|
23
|
+
✓ 页面描述 长度 86 字
|
|
24
|
+
✓ H1 结构 检测到 1 个 H1
|
|
25
|
+
✓ 结构化数据 检测到 JSON-LD
|
|
26
|
+
✗ 问答结构 未检测到问答内容
|
|
27
|
+
✓ 语义化标签 检测到:main, nav, header
|
|
28
|
+
✓ 正文信息量 正文约 1200 字
|
|
29
|
+
✗ 可索引性 可索引,但缺少 canonical
|
|
30
|
+
|
|
31
|
+
先改这两项
|
|
32
|
+
1. 问答结构:把客户最常问的 5–10 个问题做成「问题 + 简明回答」,并加 FAQPage 标记。
|
|
33
|
+
2. 可索引性:移除 noindex,并声明 canonical 指向规范地址,避免同一内容多个 URL 分散权重。
|
|
34
|
+
|
|
35
|
+
完整 40 分自测(含改进清单):https://www.geofde.cn/tools
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 8 项指标
|
|
39
|
+
|
|
40
|
+
| # | 指标 | 检查内容 | 分值 |
|
|
41
|
+
| --- | --- | --- | --- |
|
|
42
|
+
| 1 | 页面标题 | `<title>` 长度 8–60 字 | 5 |
|
|
43
|
+
| 2 | 页面描述 | `meta description` 长度 40–160 字 | 5 |
|
|
44
|
+
| 3 | H1 结构 | 恰好一个 `<h1>` | 5 |
|
|
45
|
+
| 4 | 结构化数据 | 存在 JSON-LD | 5 |
|
|
46
|
+
| 5 | 问答结构 | FAQPage 标记或问答式标题 | 5 |
|
|
47
|
+
| 6 | 语义化标签 | main/article/nav/header 等 ≥ 2 种 | 5 |
|
|
48
|
+
| 7 | 正文信息量 | 有效正文 ≥ 500 字 | 5 |
|
|
49
|
+
| 8 | 可索引性 | 无 noindex 且声明 canonical | 5 |
|
|
50
|
+
|
|
51
|
+
## 作为库使用
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const { audit } = require('ai-friendly-check');
|
|
55
|
+
|
|
56
|
+
const result = audit('<html>...</html>', 'https://example.com');
|
|
57
|
+
console.log(result.score); // 0–40
|
|
58
|
+
console.log(result.grade); // 优秀 / 良好 / 及格 / 待改进
|
|
59
|
+
console.log(result.checks); // 每项检测详情
|
|
60
|
+
console.log(result.suggestions);// 优先改进建议(最多 2 条)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
也支持 CLI 输出 JSON,便于接入 CI 或批量检测:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx ai-friendly-check https://example.com --json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 为什么做这个
|
|
70
|
+
|
|
71
|
+
客户已经开始在 AI 里找供应商了。如果 AI 回答「XX 找哪家好」时从没提到你,生意就在悄悄流走。
|
|
72
|
+
|
|
73
|
+
让 AI 愿意推荐你,第一步是让它**读得懂你的网站**:有结构、有出处、有明确的问答。`ai-friendly-check` 把这套检查做成了一行命令。
|
|
74
|
+
|
|
75
|
+
想系统做这件事(内容建设、实体标注、按月效果对比),可以看看落地派的做法:
|
|
76
|
+
**[https://www.geofde.cn](https://www.geofde.cn)** · 免费自测:[https://www.geofde.cn/tools](https://www.geofde.cn/tools)
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
[MIT](LICENSE) © 2026 落地派
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { audit } = require('../index');
|
|
5
|
+
|
|
6
|
+
const C = {
|
|
7
|
+
reset: '\x1b[0m',
|
|
8
|
+
bold: '\x1b[1m',
|
|
9
|
+
dim: '\x1b[2m',
|
|
10
|
+
green: '\x1b[32m',
|
|
11
|
+
red: '\x1b[31m',
|
|
12
|
+
yellow: '\x1b[33m',
|
|
13
|
+
cyan: '\x1b[36m',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function help() {
|
|
17
|
+
console.log(`
|
|
18
|
+
${C.bold}ai-friendly-check${C.reset} — 检查网页对 AI 搜索引擎的友好度
|
|
19
|
+
|
|
20
|
+
${C.bold}用法${C.reset}
|
|
21
|
+
npx ai-friendly-check <url> 检查一个网页
|
|
22
|
+
npx ai-friendly-check <url> --json 输出 JSON(便于接入自动化)
|
|
23
|
+
npx ai-friendly-check <url> --no-color 关闭颜色
|
|
24
|
+
|
|
25
|
+
${C.bold}示例${C.reset}
|
|
26
|
+
npx ai-friendly-check https://www.geofde.cn
|
|
27
|
+
|
|
28
|
+
${C.dim}8 项指标,40 分制 · 官网 https://www.geofde.cn/tools${C.reset}
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function main() {
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
if (!args.length || args.includes('-h') || args.includes('--help')) {
|
|
35
|
+
help();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const json = args.includes('--json');
|
|
40
|
+
const noColor = args.includes('--no-color') || !process.stdout.isTTY;
|
|
41
|
+
const color = (code, text) => (noColor ? text : `${code}${text}${C.reset}`);
|
|
42
|
+
|
|
43
|
+
const url = args.find((a) => !a.startsWith('-'));
|
|
44
|
+
if (!url) {
|
|
45
|
+
console.error('缺少网址参数。运行 npx ai-friendly-check --help 查看用法。');
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let parsed;
|
|
51
|
+
try {
|
|
52
|
+
parsed = new URL(url);
|
|
53
|
+
if (!/^https?:$/.test(parsed.protocol)) throw new Error('only http/https');
|
|
54
|
+
} catch {
|
|
55
|
+
console.error(`网址格式不对:${url}(需要以 http:// 或 https:// 开头)`);
|
|
56
|
+
process.exitCode = 1;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const controller = new AbortController();
|
|
61
|
+
const timer = setTimeout(() => controller.abort(), 20000);
|
|
62
|
+
|
|
63
|
+
let res;
|
|
64
|
+
try {
|
|
65
|
+
res = await fetch(parsed.toString(), {
|
|
66
|
+
redirect: 'follow',
|
|
67
|
+
signal: controller.signal,
|
|
68
|
+
headers: {
|
|
69
|
+
'user-agent': 'ai-friendly-check/1.0 (+https://www.geofde.cn)',
|
|
70
|
+
accept: 'text/html,application/xhtml+xml',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
} catch (err) {
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
console.error(`抓取失败:${err.name === 'AbortError' ? '请求超时(20 秒)' : err.message}`);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
|
|
81
|
+
if (!res.ok) {
|
|
82
|
+
console.error(`抓取失败:HTTP ${res.status} ${res.statusText}`);
|
|
83
|
+
process.exitCode = 1;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const html = await res.text();
|
|
88
|
+
const result = audit(html, res.url || parsed.toString());
|
|
89
|
+
|
|
90
|
+
if (json) {
|
|
91
|
+
console.log(JSON.stringify(result, null, 2));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const barLen = 20;
|
|
96
|
+
const filled = Math.round((result.score / result.maxScore) * barLen);
|
|
97
|
+
const bar = '█'.repeat(filled) + '░'.repeat(barLen - filled);
|
|
98
|
+
const scoreColor = result.score >= 28 ? C.green : result.score >= 20 ? C.yellow : C.red;
|
|
99
|
+
|
|
100
|
+
console.log('');
|
|
101
|
+
console.log(`${C.bold}AI 友好度检测${C.reset} ${C.dim}${result.url}${C.reset}`);
|
|
102
|
+
console.log('');
|
|
103
|
+
console.log(` ${color(scoreColor, bar)} ${color(scoreColor, `${result.score}/${result.maxScore}`)} ${result.grade}`);
|
|
104
|
+
console.log('');
|
|
105
|
+
for (const c of result.checks) {
|
|
106
|
+
const mark = c.passed ? color(C.green, '✓') : color(C.red, '✗');
|
|
107
|
+
console.log(` ${mark} ${c.name.padEnd(8, ' ')} ${C.dim}${c.detail}${C.reset}`);
|
|
108
|
+
}
|
|
109
|
+
if (result.suggestions.length) {
|
|
110
|
+
console.log('');
|
|
111
|
+
console.log(` ${C.bold}先改这两项${C.reset}`);
|
|
112
|
+
result.suggestions.forEach((s, i) => {
|
|
113
|
+
console.log(` ${i + 1}. ${s.name}:${s.advice}`);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
console.log('');
|
|
117
|
+
console.log(`${C.dim} 完整 40 分自测(含改进清单):https://www.geofde.cn/tools${C.reset}`);
|
|
118
|
+
console.log('');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
main();
|
package/index.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ai-friendly-check — 检查网页对 AI 搜索引擎(GEO)的友好度
|
|
5
|
+
* 8 项指标,40 分制。
|
|
6
|
+
*
|
|
7
|
+
* 官网:https://www.geofde.cn/tools
|
|
8
|
+
* 许可:MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const MAX_SCORE = 40;
|
|
12
|
+
|
|
13
|
+
function parseAttrs(tag) {
|
|
14
|
+
const attrs = {};
|
|
15
|
+
const re = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)\s*=\s*("([^"]*)"|'([^']*)'|([^\s"'>]+))/g;
|
|
16
|
+
let m;
|
|
17
|
+
while ((m = re.exec(tag))) {
|
|
18
|
+
attrs[m[1].toLowerCase()] = m[3] !== undefined ? m[3] : m[4] !== undefined ? m[4] : m[5];
|
|
19
|
+
}
|
|
20
|
+
return attrs;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function findMeta(html, name) {
|
|
24
|
+
const re = /<meta\b[^>]*>/gi;
|
|
25
|
+
let m;
|
|
26
|
+
while ((m = re.exec(html))) {
|
|
27
|
+
const a = parseAttrs(m[0]);
|
|
28
|
+
const key = (a.name || a.property || '').toLowerCase();
|
|
29
|
+
if (key === name.toLowerCase()) return (a.content || '').trim();
|
|
30
|
+
}
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function extractText(html) {
|
|
35
|
+
return html
|
|
36
|
+
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
|
37
|
+
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
|
38
|
+
.replace(/<noscript[\s\S]*?<\/noscript>/gi, ' ')
|
|
39
|
+
.replace(/<!--[\s\S]*?-->/g, ' ')
|
|
40
|
+
.replace(/<[^>]+>/g, ' ')
|
|
41
|
+
.replace(/ /g, ' ')
|
|
42
|
+
.replace(/&/g, '&')
|
|
43
|
+
.replace(/</g, '<')
|
|
44
|
+
.replace(/>/g, '>')
|
|
45
|
+
.replace(/"/g, '"')
|
|
46
|
+
.replace(/'/g, "'")
|
|
47
|
+
.replace(/\s+/g, ' ')
|
|
48
|
+
.trim();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function textSize(text) {
|
|
52
|
+
const cjk = (text.match(/[\u4e00-\u9fff]/g) || []).length;
|
|
53
|
+
const words = (text.replace(/[\u4e00-\u9fff]/g, ' ').match(/[a-zA-Z0-9]+/g) || []).length;
|
|
54
|
+
return cjk + words;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 审计一段 HTML。
|
|
59
|
+
* @param {string} html 页面 HTML
|
|
60
|
+
* @param {string} [url] 页面地址(可选,仅用于回显)
|
|
61
|
+
* @returns {object} 审计结果
|
|
62
|
+
*/
|
|
63
|
+
function audit(html, url = '') {
|
|
64
|
+
if (typeof html !== 'string') throw new TypeError('html must be a string');
|
|
65
|
+
const source = html;
|
|
66
|
+
|
|
67
|
+
const titleMatch = source.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
|
|
68
|
+
const title = titleMatch ? titleMatch[1].replace(/\s+/g, ' ').trim() : '';
|
|
69
|
+
const description = findMeta(source, 'description');
|
|
70
|
+
const h1Count = (source.match(/<h1\b[^>]*>/gi) || []).length;
|
|
71
|
+
const hasJsonLd = /<script[^>]+type\s*=\s*["']application\/ld\+json["'][^>]*>/i.test(source);
|
|
72
|
+
const hasFaqSchema = /FAQPage|"@type"\s*:\s*"Question"/i.test(source);
|
|
73
|
+
const hasFaqHeadings = /<h[23][^>]*>[^<]{0,80}[??]\s*<\/h[23]>/i.test(source);
|
|
74
|
+
const semanticTags = ['main', 'article', 'nav', 'header', 'footer'].filter((t) =>
|
|
75
|
+
new RegExp(`<${t}\\b`, 'i').test(source)
|
|
76
|
+
);
|
|
77
|
+
const text = extractText(source);
|
|
78
|
+
const size = textSize(text);
|
|
79
|
+
const robots = findMeta(source, 'robots');
|
|
80
|
+
const noindex = /noindex/i.test(robots);
|
|
81
|
+
const hasCanonical = /<link\b[^>]*rel\s*=\s*["']canonical["']/i.test(source);
|
|
82
|
+
|
|
83
|
+
const checks = [
|
|
84
|
+
{
|
|
85
|
+
id: 'title',
|
|
86
|
+
name: '页面标题',
|
|
87
|
+
points: 5,
|
|
88
|
+
passed: title.length >= 8 && title.length <= 60,
|
|
89
|
+
detail: title ? `长度 ${title.length} 字:${title.slice(0, 40)}${title.length > 40 ? '…' : ''}` : '未找到 <title>',
|
|
90
|
+
advice: '标题控制在 8–60 字,写清「做什么 + 给谁 + 在哪」,避免纯关键词堆砌。',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'description',
|
|
94
|
+
name: '页面描述',
|
|
95
|
+
points: 5,
|
|
96
|
+
passed: description.length >= 40 && description.length <= 160,
|
|
97
|
+
detail: description ? `长度 ${description.length} 字` : '未找到 meta description',
|
|
98
|
+
advice: '补一段 40–160 字的 meta description,用完整句子说清「你是谁、解决什么问题」。',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'h1',
|
|
102
|
+
name: 'H1 结构',
|
|
103
|
+
points: 5,
|
|
104
|
+
passed: h1Count === 1,
|
|
105
|
+
detail: `检测到 ${h1Count} 个 H1`,
|
|
106
|
+
advice: '每页只保留一个 H1,用一句话概括页面主题,其余层级用 H2/H3。',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'jsonld',
|
|
110
|
+
name: '结构化数据',
|
|
111
|
+
points: 5,
|
|
112
|
+
passed: hasJsonLd,
|
|
113
|
+
detail: hasJsonLd ? '检测到 JSON-LD' : '未检测到 JSON-LD',
|
|
114
|
+
advice: '用 JSON-LD 标注 Organization、Product、FAQPage 等实体,AI 更容易准确引用你。',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 'faq',
|
|
118
|
+
name: '问答结构',
|
|
119
|
+
points: 5,
|
|
120
|
+
passed: hasFaqSchema || hasFaqHeadings,
|
|
121
|
+
detail: hasFaqSchema ? '检测到 FAQ 结构化标记' : hasFaqHeadings ? '检测到问答式标题' : '未检测到问答内容',
|
|
122
|
+
advice: '把客户最常问的 5–10 个问题做成「问题 + 简明回答」,并加 FAQPage 标记。',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'semantic',
|
|
126
|
+
name: '语义化标签',
|
|
127
|
+
points: 5,
|
|
128
|
+
passed: semanticTags.length >= 2,
|
|
129
|
+
detail: semanticTags.length ? `检测到:${semanticTags.join(', ')}` : '未检测到语义化标签',
|
|
130
|
+
advice: '用 main / article / nav / header 等标签划分页面结构,帮助 AI 判断内容主次。',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'content',
|
|
134
|
+
name: '正文信息量',
|
|
135
|
+
points: 5,
|
|
136
|
+
passed: size >= 500,
|
|
137
|
+
detail: `正文约 ${size} 字`,
|
|
138
|
+
advice: '正文至少 500 字有效内容,围绕真实业务问题展开,而不是口号式短句。',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: 'indexable',
|
|
142
|
+
name: '可索引性',
|
|
143
|
+
points: 5,
|
|
144
|
+
passed: !noindex && hasCanonical,
|
|
145
|
+
detail: noindex ? '检测到 noindex' : hasCanonical ? '可索引,已声明 canonical' : '可索引,但缺少 canonical',
|
|
146
|
+
advice: '移除 noindex,并声明 canonical 指向规范地址,避免同一内容多个 URL 分散权重。',
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
const score = checks.reduce((sum, c) => sum + (c.passed ? c.points : 0), 0);
|
|
151
|
+
const failed = checks.filter((c) => !c.passed);
|
|
152
|
+
const grade =
|
|
153
|
+
score >= 36 ? '优秀' : score >= 28 ? '良好' : score >= 20 ? '及格' : '待改进';
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
url,
|
|
157
|
+
score,
|
|
158
|
+
maxScore: MAX_SCORE,
|
|
159
|
+
grade,
|
|
160
|
+
checks,
|
|
161
|
+
suggestions: failed.slice(0, 2).map((c) => ({ id: c.id, name: c.name, advice: c.advice })),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = { audit, MAX_SCORE };
|
package/package.json
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-friendly-check",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "检查网页对 AI 搜索引擎的友好度:8 项指标、40 分制评分,一行命令出报告。",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ai-friendly-check": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"bin/",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=18"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"geo",
|
|
20
|
+
"generative-engine-optimization",
|
|
21
|
+
"ai-search",
|
|
22
|
+
"seo",
|
|
23
|
+
"audit",
|
|
24
|
+
"llm",
|
|
25
|
+
"ai-friendly",
|
|
26
|
+
"structured-data"
|
|
27
|
+
],
|
|
28
|
+
"homepage": "https://www.geofde.cn/tools",
|
|
29
|
+
"author": "落地派 <hello@geofde.cn> (https://www.geofde.cn)",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "node --test test/audit.test.js"
|
|
33
|
+
}
|
|
34
|
+
}
|