kompass-sdk 0.6.0 → 0.7.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/dist/sources/erc8004.d.ts +3 -2
- package/dist/sources/erc8004.d.ts.map +1 -1
- package/dist/sources/erc8004.js +68 -114
- package/dist/sources/erc8004.js.map +1 -1
- package/package.json +1 -1
- package/src/sources/erc8004.ts +60 -121
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ERC-8004
|
|
3
|
-
*
|
|
2
|
+
* ERC-8004 Source Adapter
|
|
3
|
+
* Searches 8004scan.io API for registered AI agents
|
|
4
|
+
* Real data — agent identity, reputation, supported protocols
|
|
4
5
|
*/
|
|
5
6
|
import type { SourceAdapter } from "./types.js";
|
|
6
7
|
export declare function createErc8004Adapter(network?: "base" | "base-sepolia"): SourceAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erc8004.d.ts","sourceRoot":"","sources":["../../src/sources/erc8004.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"erc8004.d.ts","sourceRoot":"","sources":["../../src/sources/erc8004.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,YAAY,CAAC;AAInF,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,MAAM,GAAG,cAAuB,GAAG,aAAa,CAkD7F"}
|
package/dist/sources/erc8004.js
CHANGED
|
@@ -1,90 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ERC-8004
|
|
3
|
-
*
|
|
2
|
+
* ERC-8004 Source Adapter
|
|
3
|
+
* Searches 8004scan.io API for registered AI agents
|
|
4
|
+
* Real data — agent identity, reputation, supported protocols
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// ERC-8004 Identity Registry addresses
|
|
8
|
-
const REGISTRY_ADDRESSES = {
|
|
9
|
-
"base": "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
10
|
-
"base-sepolia": "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
11
|
-
};
|
|
12
|
-
const TRANSFER_EVENT = parseAbiItem("event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)");
|
|
13
|
-
const TOKEN_URI_ABI = [
|
|
14
|
-
{
|
|
15
|
-
type: "function",
|
|
16
|
-
name: "tokenURI",
|
|
17
|
-
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
18
|
-
outputs: [{ name: "", type: "string" }],
|
|
19
|
-
stateMutability: "view",
|
|
20
|
-
},
|
|
21
|
-
];
|
|
22
|
-
export function createErc8004Adapter(network = "base-sepolia") {
|
|
23
|
-
const chain = network === "base" ? base : baseSepolia;
|
|
24
|
-
const registryAddress = REGISTRY_ADDRESSES[network];
|
|
25
|
-
const client = createPublicClient({
|
|
26
|
-
chain,
|
|
27
|
-
transport: http(),
|
|
28
|
-
});
|
|
6
|
+
const SCAN_API = "https://www.8004scan.io/api/v1";
|
|
7
|
+
export function createErc8004Adapter(network = "base") {
|
|
29
8
|
return {
|
|
30
9
|
name: "erc8004",
|
|
31
|
-
displayName: "ERC-8004 Identity Registry",
|
|
10
|
+
displayName: "ERC-8004 Identity Registry (8004scan)",
|
|
32
11
|
async search(query, options) {
|
|
33
12
|
const limit = options?.limit ?? 20;
|
|
13
|
+
const timeout = options?.timeout ?? 10000;
|
|
34
14
|
try {
|
|
35
|
-
//
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
15
|
+
// Search across all chains on 8004scan
|
|
16
|
+
const url = new URL(`${SCAN_API}/agents`);
|
|
17
|
+
if (query)
|
|
18
|
+
url.searchParams.set("search", query);
|
|
19
|
+
url.searchParams.set("limit", String(limit));
|
|
20
|
+
const res = await fetch(url.toString(), {
|
|
21
|
+
signal: AbortSignal.timeout(timeout),
|
|
42
22
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
});
|
|
59
|
-
// Resolve URI to JSON
|
|
60
|
-
let metadata = {};
|
|
61
|
-
if (uri.startsWith("http") || uri.startsWith("ipfs")) {
|
|
62
|
-
const fetchUrl = uri.startsWith("ipfs://")
|
|
63
|
-
? `https://ipfs.io/ipfs/${uri.slice(7)}`
|
|
64
|
-
: uri;
|
|
65
|
-
const res = await fetch(fetchUrl, { signal: AbortSignal.timeout(3000) });
|
|
66
|
-
if (res.ok)
|
|
67
|
-
metadata = await res.json();
|
|
68
|
-
}
|
|
69
|
-
else if (uri.startsWith("data:")) {
|
|
70
|
-
const json = uri.split(",")[1];
|
|
71
|
-
metadata = JSON.parse(atob(json));
|
|
72
|
-
}
|
|
73
|
-
const agent = mapErc8004Agent(tokenId, owner, metadata, network);
|
|
74
|
-
// Filter by query
|
|
75
|
-
if (query) {
|
|
76
|
-
const searchText = `${agent.name} ${agent.description} ${agent.categories.join(" ")}`.toLowerCase();
|
|
77
|
-
if (!searchText.includes(query.toLowerCase()))
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
agents.push(agent);
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
// Skip agents with unresolvable metadata
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return agents;
|
|
23
|
+
if (!res.ok)
|
|
24
|
+
return [];
|
|
25
|
+
const data = await res.json();
|
|
26
|
+
const agents = data.items ?? data.agents ?? data.data ?? [];
|
|
27
|
+
if (!Array.isArray(agents))
|
|
28
|
+
return [];
|
|
29
|
+
return agents
|
|
30
|
+
.filter((a) => {
|
|
31
|
+
if (!query)
|
|
32
|
+
return true;
|
|
33
|
+
const text = `${a.name ?? ""} ${a.description ?? ""}`.toLowerCase();
|
|
34
|
+
return query.toLowerCase().split(/\s+/).some((t) => text.includes(t));
|
|
35
|
+
})
|
|
36
|
+
.slice(0, limit)
|
|
37
|
+
.map(mapErc8004Agent);
|
|
88
38
|
}
|
|
89
39
|
catch {
|
|
90
40
|
return [];
|
|
@@ -92,8 +42,10 @@ export function createErc8004Adapter(network = "base-sepolia") {
|
|
|
92
42
|
},
|
|
93
43
|
async ping() {
|
|
94
44
|
try {
|
|
95
|
-
await
|
|
96
|
-
|
|
45
|
+
const res = await fetch(`${SCAN_API}/agents?limit=1`, {
|
|
46
|
+
signal: AbortSignal.timeout(5000),
|
|
47
|
+
});
|
|
48
|
+
return res.ok;
|
|
97
49
|
}
|
|
98
50
|
catch {
|
|
99
51
|
return false;
|
|
@@ -101,50 +53,52 @@ export function createErc8004Adapter(network = "base-sepolia") {
|
|
|
101
53
|
},
|
|
102
54
|
};
|
|
103
55
|
}
|
|
104
|
-
function mapErc8004Agent(
|
|
105
|
-
const
|
|
56
|
+
function mapErc8004Agent(agent) {
|
|
57
|
+
const protocols = agent.supported_protocols ?? [];
|
|
58
|
+
const protocol = protocols.includes("A2A") ? "a2a"
|
|
59
|
+
: protocols.includes("MCP") ? "mcp"
|
|
60
|
+
: protocols.includes("x402") || agent.x402_supported ? "x402"
|
|
61
|
+
: "onchain";
|
|
106
62
|
const endpoints = {};
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
endpoints.x402 = svc.endpoint;
|
|
114
|
-
if (svc.protocol === "http")
|
|
115
|
-
endpoints.http = svc.endpoint;
|
|
116
|
-
}
|
|
63
|
+
if (protocols.includes("MCP"))
|
|
64
|
+
endpoints.mcp = agent.mcp_endpoint;
|
|
65
|
+
if (protocols.includes("A2A"))
|
|
66
|
+
endpoints.a2a = agent.a2a_endpoint;
|
|
67
|
+
if (agent.x402_supported)
|
|
68
|
+
endpoints.x402 = agent.x402_endpoint;
|
|
117
69
|
return {
|
|
118
|
-
id: `erc8004:${
|
|
119
|
-
nativeId:
|
|
120
|
-
name:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
70
|
+
id: `erc8004:${agent.agent_id ?? agent.token_id}`,
|
|
71
|
+
nativeId: agent.token_id?.toString() ?? agent.agent_id ?? "",
|
|
72
|
+
name: agent.name ?? `Agent #${agent.token_id}`,
|
|
73
|
+
ensName: agent.owner_ens ?? undefined,
|
|
74
|
+
description: agent.description ?? "",
|
|
75
|
+
categories: extractCategories(agent.name ?? "", agent.description ?? ""),
|
|
76
|
+
capabilities: protocols.map((p) => `Supports ${p}`),
|
|
124
77
|
source: "erc8004",
|
|
125
|
-
protocol
|
|
78
|
+
protocol,
|
|
126
79
|
endpoints,
|
|
127
80
|
reputation: {
|
|
128
|
-
score: 0,
|
|
129
|
-
count: 0,
|
|
130
|
-
source: "
|
|
81
|
+
score: agent.total_score ?? 0,
|
|
82
|
+
count: agent.star_count ?? 0,
|
|
83
|
+
source: "8004scan",
|
|
131
84
|
},
|
|
132
|
-
verified:
|
|
133
|
-
|
|
134
|
-
raw: { tokenId: tokenId.toString(), owner, metadata, network },
|
|
85
|
+
verified: agent.is_verified ?? false,
|
|
86
|
+
raw: agent,
|
|
135
87
|
};
|
|
136
88
|
}
|
|
137
|
-
function
|
|
138
|
-
const
|
|
89
|
+
function extractCategories(name, description) {
|
|
90
|
+
const text = `${name} ${description}`.toLowerCase();
|
|
139
91
|
const cats = [];
|
|
140
|
-
if (
|
|
92
|
+
if (text.match(/defi|yield|swap|pool|trading/))
|
|
141
93
|
cats.push("defi");
|
|
142
|
-
if (
|
|
94
|
+
if (text.match(/data|analyt|research/))
|
|
143
95
|
cats.push("data");
|
|
144
|
-
if (
|
|
145
|
-
cats.push("
|
|
146
|
-
if (
|
|
147
|
-
cats.push("
|
|
96
|
+
if (text.match(/code|develop|build/))
|
|
97
|
+
cats.push("development");
|
|
98
|
+
if (text.match(/ai|model|inference/))
|
|
99
|
+
cats.push("ai");
|
|
100
|
+
if (text.match(/security|audit/))
|
|
101
|
+
cats.push("security");
|
|
148
102
|
return cats.length > 0 ? cats : ["general"];
|
|
149
103
|
}
|
|
150
104
|
//# sourceMappingURL=erc8004.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erc8004.js","sourceRoot":"","sources":["../../src/sources/erc8004.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"erc8004.js","sourceRoot":"","sources":["../../src/sources/erc8004.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kompass-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Get any job done. Universal agent capability discovery + coordination across ACP, MCP, x402, A2A, skills, L402, and ERC-8004.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/src/sources/erc8004.ts
CHANGED
|
@@ -1,107 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ERC-8004
|
|
3
|
-
*
|
|
2
|
+
* ERC-8004 Source Adapter
|
|
3
|
+
* Searches 8004scan.io API for registered AI agents
|
|
4
|
+
* Real data — agent identity, reputation, supported protocols
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
import { createPublicClient, http, type Address, parseAbiItem } from "viem";
|
|
7
|
-
import { base, baseSepolia } from "viem/chains";
|
|
8
7
|
import type { SourceAdapter, UnifiedAgent, SourceSearchOptions } from "./types.js";
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
const REGISTRY_ADDRESSES: Record<string, Address> = {
|
|
12
|
-
"base": "0x8004A818BFB912233c491871b3d84c89A494BD9e" as Address,
|
|
13
|
-
"base-sepolia": "0x8004A818BFB912233c491871b3d84c89A494BD9e" as Address,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const TRANSFER_EVENT = parseAbiItem(
|
|
17
|
-
"event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
const TOKEN_URI_ABI = [
|
|
21
|
-
{
|
|
22
|
-
type: "function",
|
|
23
|
-
name: "tokenURI",
|
|
24
|
-
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
25
|
-
outputs: [{ name: "", type: "string" }],
|
|
26
|
-
stateMutability: "view",
|
|
27
|
-
},
|
|
28
|
-
] as const;
|
|
29
|
-
|
|
30
|
-
export function createErc8004Adapter(network: "base" | "base-sepolia" = "base-sepolia"): SourceAdapter {
|
|
31
|
-
const chain = network === "base" ? base : baseSepolia;
|
|
32
|
-
const registryAddress = REGISTRY_ADDRESSES[network];
|
|
33
|
-
|
|
34
|
-
const client = createPublicClient({
|
|
35
|
-
chain,
|
|
36
|
-
transport: http(),
|
|
37
|
-
});
|
|
9
|
+
const SCAN_API = "https://www.8004scan.io/api/v1";
|
|
38
10
|
|
|
11
|
+
export function createErc8004Adapter(network: "base" | "base-sepolia" = "base"): SourceAdapter {
|
|
39
12
|
return {
|
|
40
13
|
name: "erc8004",
|
|
41
|
-
displayName: "ERC-8004 Identity Registry",
|
|
14
|
+
displayName: "ERC-8004 Identity Registry (8004scan)",
|
|
42
15
|
|
|
43
16
|
async search(query: string, options?: SourceSearchOptions): Promise<UnifiedAgent[]> {
|
|
44
17
|
const limit = options?.limit ?? 20;
|
|
18
|
+
const timeout = options?.timeout ?? 10000;
|
|
45
19
|
|
|
46
20
|
try {
|
|
47
|
-
//
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
args: { from: "0x0000000000000000000000000000000000000000" as Address },
|
|
52
|
-
fromBlock: "earliest",
|
|
53
|
-
toBlock: "latest",
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const agents: UnifiedAgent[] = [];
|
|
57
|
-
|
|
58
|
-
// Process most recent first
|
|
59
|
-
const recentLogs = logs.slice(-limit * 2).reverse();
|
|
21
|
+
// Search across all chains on 8004scan
|
|
22
|
+
const url = new URL(`${SCAN_API}/agents`);
|
|
23
|
+
if (query) url.searchParams.set("search", query);
|
|
24
|
+
url.searchParams.set("limit", String(limit));
|
|
60
25
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const tokenId = log.args.tokenId!;
|
|
65
|
-
const owner = log.args.to!;
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
// Fetch tokenURI for agent metadata
|
|
69
|
-
const uri = await client.readContract({
|
|
70
|
-
address: registryAddress,
|
|
71
|
-
abi: TOKEN_URI_ABI,
|
|
72
|
-
functionName: "tokenURI",
|
|
73
|
-
args: [tokenId],
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Resolve URI to JSON
|
|
77
|
-
let metadata: any = {};
|
|
78
|
-
if (uri.startsWith("http") || uri.startsWith("ipfs")) {
|
|
79
|
-
const fetchUrl = uri.startsWith("ipfs://")
|
|
80
|
-
? `https://ipfs.io/ipfs/${uri.slice(7)}`
|
|
81
|
-
: uri;
|
|
82
|
-
const res = await fetch(fetchUrl, { signal: AbortSignal.timeout(3000) });
|
|
83
|
-
if (res.ok) metadata = await res.json();
|
|
84
|
-
} else if (uri.startsWith("data:")) {
|
|
85
|
-
const json = uri.split(",")[1];
|
|
86
|
-
metadata = JSON.parse(atob(json));
|
|
87
|
-
}
|
|
26
|
+
const res = await fetch(url.toString(), {
|
|
27
|
+
signal: AbortSignal.timeout(timeout),
|
|
28
|
+
});
|
|
88
29
|
|
|
89
|
-
|
|
30
|
+
if (!res.ok) return [];
|
|
90
31
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const searchText = `${agent.name} ${agent.description} ${agent.categories.join(" ")}`.toLowerCase();
|
|
94
|
-
if (!searchText.includes(query.toLowerCase())) continue;
|
|
95
|
-
}
|
|
32
|
+
const data = await res.json();
|
|
33
|
+
const agents = data.items ?? data.agents ?? data.data ?? [];
|
|
96
34
|
|
|
97
|
-
|
|
98
|
-
} catch {
|
|
99
|
-
// Skip agents with unresolvable metadata
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
35
|
+
if (!Array.isArray(agents)) return [];
|
|
103
36
|
|
|
104
|
-
return agents
|
|
37
|
+
return agents
|
|
38
|
+
.filter((a: any) => {
|
|
39
|
+
if (!query) return true;
|
|
40
|
+
const text = `${a.name ?? ""} ${a.description ?? ""}`.toLowerCase();
|
|
41
|
+
return query.toLowerCase().split(/\s+/).some((t) => text.includes(t));
|
|
42
|
+
})
|
|
43
|
+
.slice(0, limit)
|
|
44
|
+
.map(mapErc8004Agent);
|
|
105
45
|
} catch {
|
|
106
46
|
return [];
|
|
107
47
|
}
|
|
@@ -109,8 +49,10 @@ export function createErc8004Adapter(network: "base" | "base-sepolia" = "base-se
|
|
|
109
49
|
|
|
110
50
|
async ping(): Promise<boolean> {
|
|
111
51
|
try {
|
|
112
|
-
await
|
|
113
|
-
|
|
52
|
+
const res = await fetch(`${SCAN_API}/agents?limit=1`, {
|
|
53
|
+
signal: AbortSignal.timeout(5000),
|
|
54
|
+
});
|
|
55
|
+
return res.ok;
|
|
114
56
|
} catch {
|
|
115
57
|
return false;
|
|
116
58
|
}
|
|
@@ -118,49 +60,46 @@ export function createErc8004Adapter(network: "base" | "base-sepolia" = "base-se
|
|
|
118
60
|
};
|
|
119
61
|
}
|
|
120
62
|
|
|
121
|
-
function mapErc8004Agent(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const services = metadata.services ?? [];
|
|
128
|
-
const endpoints: UnifiedAgent["endpoints"] = {};
|
|
63
|
+
function mapErc8004Agent(agent: any): UnifiedAgent {
|
|
64
|
+
const protocols = agent.supported_protocols ?? [];
|
|
65
|
+
const protocol = protocols.includes("A2A") ? "a2a" as const
|
|
66
|
+
: protocols.includes("MCP") ? "mcp" as const
|
|
67
|
+
: protocols.includes("x402") || agent.x402_supported ? "x402" as const
|
|
68
|
+
: "onchain" as const;
|
|
129
69
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (svc.protocol === "http") endpoints.http = svc.endpoint;
|
|
135
|
-
}
|
|
70
|
+
const endpoints: UnifiedAgent["endpoints"] = {};
|
|
71
|
+
if (protocols.includes("MCP")) endpoints.mcp = agent.mcp_endpoint;
|
|
72
|
+
if (protocols.includes("A2A")) endpoints.a2a = agent.a2a_endpoint;
|
|
73
|
+
if (agent.x402_supported) endpoints.x402 = agent.x402_endpoint;
|
|
136
74
|
|
|
137
75
|
return {
|
|
138
|
-
id: `erc8004:${
|
|
139
|
-
nativeId:
|
|
140
|
-
name:
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
76
|
+
id: `erc8004:${agent.agent_id ?? agent.token_id}`,
|
|
77
|
+
nativeId: agent.token_id?.toString() ?? agent.agent_id ?? "",
|
|
78
|
+
name: agent.name ?? `Agent #${agent.token_id}`,
|
|
79
|
+
ensName: agent.owner_ens ?? undefined,
|
|
80
|
+
description: agent.description ?? "",
|
|
81
|
+
categories: extractCategories(agent.name ?? "", agent.description ?? ""),
|
|
82
|
+
capabilities: protocols.map((p: string) => `Supports ${p}`),
|
|
144
83
|
source: "erc8004",
|
|
145
|
-
protocol
|
|
84
|
+
protocol,
|
|
146
85
|
endpoints,
|
|
147
86
|
reputation: {
|
|
148
|
-
score: 0,
|
|
149
|
-
count: 0,
|
|
150
|
-
source: "
|
|
87
|
+
score: agent.total_score ?? 0,
|
|
88
|
+
count: agent.star_count ?? 0,
|
|
89
|
+
source: "8004scan",
|
|
151
90
|
},
|
|
152
|
-
verified:
|
|
153
|
-
|
|
154
|
-
raw: { tokenId: tokenId.toString(), owner, metadata, network },
|
|
91
|
+
verified: agent.is_verified ?? false,
|
|
92
|
+
raw: agent,
|
|
155
93
|
};
|
|
156
94
|
}
|
|
157
95
|
|
|
158
|
-
function
|
|
159
|
-
const
|
|
96
|
+
function extractCategories(name: string, description: string): string[] {
|
|
97
|
+
const text = `${name} ${description}`.toLowerCase();
|
|
160
98
|
const cats: string[] = [];
|
|
161
|
-
if (
|
|
162
|
-
if (
|
|
163
|
-
if (
|
|
164
|
-
if (
|
|
99
|
+
if (text.match(/defi|yield|swap|pool|trading/)) cats.push("defi");
|
|
100
|
+
if (text.match(/data|analyt|research/)) cats.push("data");
|
|
101
|
+
if (text.match(/code|develop|build/)) cats.push("development");
|
|
102
|
+
if (text.match(/ai|model|inference/)) cats.push("ai");
|
|
103
|
+
if (text.match(/security|audit/)) cats.push("security");
|
|
165
104
|
return cats.length > 0 ? cats : ["general"];
|
|
166
105
|
}
|