kompass-sdk 0.4.0 → 0.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"acp.js","sourceRoot":"","sources":["../../../src/wallet/handlers/acp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acp.js","sourceRoot":"","sources":["../../../src/wallet/handlers/acp.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.4.0",
3
+ "version": "0.6.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/cli.ts CHANGED
@@ -248,14 +248,24 @@ program
248
248
  .option("--json", "output as JSON")
249
249
  .option("--log <path>", "write structured agent_log.json to path")
250
250
  .option("--manifest <path>", "write agent.json manifest to path")
251
+ .option("-w, --wallet <path>", "path to Kompass wallet keystore")
251
252
  .action(
252
253
  async (
253
254
  task: string,
254
- opts: { budget: string; cost: string; protocol?: string; dryRun?: boolean; json?: boolean; log?: string; manifest?: string }
255
+ opts: { budget: string; cost: string; protocol?: string; dryRun?: boolean; json?: boolean; log?: string; manifest?: string; wallet?: string }
255
256
  ) => {
256
257
  const { KompassUnified } = await import("./unified.js");
257
258
  const { writeFileSync } = await import("fs");
258
- const kompass = await KompassUnified.create();
259
+
260
+ // Load wallet if specified
261
+ let walletInstance: any = undefined;
262
+ if (opts.wallet) {
263
+ const { KompassWallet } = await import("./wallet/index.js");
264
+ walletInstance = KompassWallet.load(opts.wallet);
265
+ if (!opts.json) console.log(`Using wallet: ${walletInstance.getAddress()} (${walletInstance.getNetwork()})`);
266
+ }
267
+
268
+ const kompass = await KompassUnified.create({ wallet: walletInstance });
259
269
 
260
270
  if (!opts.json) {
261
271
  console.log(`\n⚡ Kompass: Getting it done — "${task}"\n`);
package/src/router.ts CHANGED
@@ -16,6 +16,8 @@ import { Aggregator } from "./aggregator.js";
16
16
  import { rankAgents, parseIntent, type MatchResult } from "./matching.js";
17
17
  import { ProtocolBridge, type BridgeHireResult } from "./bridge.js";
18
18
  import { ReputationWriter, type ReputationWriterConfig } from "./reputation-writer.js";
19
+ import { routePayment, type PaymentResult } from "./wallet/payment-router.js";
20
+ import type { KompassWallet } from "./wallet/index.js";
19
21
 
20
22
  export type CostPreference = "cheapest" | "balanced" | "best-quality";
21
23
 
@@ -71,10 +73,12 @@ export class CapabilityRouter {
71
73
  private aggregator: Aggregator;
72
74
  private bridge: ProtocolBridge;
73
75
  private reputationWriter?: ReputationWriter;
76
+ private wallet?: KompassWallet;
74
77
 
75
- constructor(aggregator: Aggregator, bridge: ProtocolBridge, reputationConfig?: ReputationWriterConfig) {
78
+ constructor(aggregator: Aggregator, bridge: ProtocolBridge, reputationConfig?: ReputationWriterConfig, wallet?: KompassWallet) {
76
79
  this.aggregator = aggregator;
77
80
  this.bridge = bridge;
81
+ this.wallet = wallet;
78
82
  if (reputationConfig) {
79
83
  this.reputationWriter = new ReputationWriter(reputationConfig);
80
84
  }
@@ -142,18 +146,49 @@ export class CapabilityRouter {
142
146
  };
143
147
  }
144
148
 
145
- // 7. Execute (unless dry run)
149
+ // 7. Execute (unless dry run) — with retry on failure
146
150
  let execution: BridgeHireResult | null = null;
151
+ let actualSelected = selected;
147
152
 
148
153
  if (!dryRun) {
149
- execution = await this.bridge.hire(selected.agent, {
150
- task,
151
- timeout: options.timeout,
152
- payload: options.payload,
153
- });
154
+ // Try up to 5 candidates if one fails/rejects
155
+ for (let attempt = 0; attempt < Math.min(5, reranked.length); attempt++) {
156
+ const candidate = reranked[attempt];
157
+ actualSelected = candidate;
158
+
159
+ if (this.wallet) {
160
+ const paymentResult = await routePayment(this.wallet, candidate.agent, task);
161
+ execution = {
162
+ success: paymentResult.success,
163
+ protocol: paymentResult.protocol as any,
164
+ agent: candidate.agent,
165
+ jobId: paymentResult.jobId,
166
+ deliverable: paymentResult.deliverable,
167
+ txHash: paymentResult.txHash,
168
+ error: paymentResult.error,
169
+ durationMs: 0,
170
+ };
171
+ } else {
172
+ execution = await this.bridge.hire(candidate.agent, {
173
+ task,
174
+ timeout: options.timeout,
175
+ payload: options.payload,
176
+ });
177
+ }
178
+
179
+ if (execution?.success) break;
180
+
181
+ // Log failure and try next candidate
182
+ const phase = (execution?.deliverable as any)?.phase;
183
+ if (phase === "REJECTED" || !execution?.success) {
184
+ console.log(`[Kompass] ${candidate.agent.name} failed/rejected. Trying next candidate...`);
185
+ continue;
186
+ }
187
+ break;
188
+ }
154
189
 
155
190
  // 8. Write ERC-8004 reputation feedback on-chain
156
- if (this.reputationWriter && selected.agent.reputation?.source === "erc8004") {
191
+ if (this.reputationWriter && actualSelected.agent.reputation?.source === "erc8004") {
157
192
  const agentId = BigInt(selected.agent.nativeId || "0");
158
193
  if (agentId > 0n) {
159
194
  const category = selected.agent.categories[0] ?? "general";
@@ -167,13 +202,13 @@ export class CapabilityRouter {
167
202
  }
168
203
  }
169
204
 
170
- const reasoning = this.explainChoice(selected, reranked, options);
205
+ const reasoning = this.explainChoice(actualSelected, reranked, options);
171
206
 
172
207
  return {
173
208
  success: dryRun ? true : (execution?.success ?? false),
174
209
  task,
175
210
  options: capabilityOptions.slice(0, 10), // Top 10 options
176
- selected,
211
+ selected: actualSelected,
177
212
  execution,
178
213
  discovery: {
179
214
  sourcesQueried: searchResult.sources.length,
@@ -214,15 +249,6 @@ export class CapabilityRouter {
214
249
  private applyPreferences(options: CapabilityOption[], doOptions: DoOptions): CapabilityOption[] {
215
250
  let sorted = [...options];
216
251
 
217
- // Protocol preference
218
- if (doOptions.preferProtocol) {
219
- sorted.sort((a, b) => {
220
- const aMatch = a.protocol === doOptions.preferProtocol ? 1 : 0;
221
- const bMatch = b.protocol === doOptions.preferProtocol ? 1 : 0;
222
- return bMatch - aMatch;
223
- });
224
- }
225
-
226
252
  // Source preference
227
253
  if (doOptions.preferSource) {
228
254
  sorted.sort((a, b) => {
@@ -265,6 +291,13 @@ export class CapabilityRouter {
265
291
  break;
266
292
  }
267
293
 
294
+ // Protocol preference — ALWAYS applied last to take highest priority
295
+ if (doOptions.preferProtocol) {
296
+ const preferred = sorted.filter((o) => o.protocol === doOptions.preferProtocol || o.source === doOptions.preferProtocol);
297
+ const rest = sorted.filter((o) => o.protocol !== doOptions.preferProtocol && o.source !== doOptions.preferProtocol);
298
+ sorted = [...preferred, ...rest];
299
+ }
300
+
268
301
  return sorted;
269
302
  }
270
303
 
@@ -1,51 +1,71 @@
1
1
  /**
2
- * L402 Directory Source Adapter
3
- * Indexes Lightning 402 endpoints from known directories
2
+ * L402 Lightning Directory Source Adapter
3
+ * Searches 402index.io filtered to L402 (Lightning) protocol
4
+ * Real data — not hardcoded seed list
4
5
  */
5
6
 
6
7
  import type { SourceAdapter, UnifiedAgent, SourceSearchOptions } from "./types.js";
7
8
 
8
- // Known L402 services (from satring, l402.directory, and community)
9
- const KNOWN_L402_SERVICES = [
10
- { name: "Satring", url: "https://satring.com", description: "Curated L402 + x402 API directory. 36 endpoints across 4 providers", categories: ["directory", "tools"] },
11
- { name: "Lightning Faucet L402", url: "https://lightningfaucet.com", description: "L402 API registry and testing tools", categories: ["tools", "testing"] },
12
- { name: "Nostr NIP-68 Bridge", url: "https://l402.nostr.com", description: "L402 payments over Nostr relay network", categories: ["social", "payments"] },
13
- { name: "Stacker News", url: "https://stacker.news", description: "Lightning-powered news with L402 API access", categories: ["content", "data"] },
14
- { name: "Nodana", url: "https://nodana.io", description: "L402 agentic access for Bitcoin app deployment", categories: ["development", "compute"] },
15
- ];
9
+ const INDEX_API = "https://402index.io/api/v1/services";
16
10
 
17
11
  export const l402DirectoryAdapter: SourceAdapter = {
18
12
  name: "l402-directory",
19
- displayName: "L402 Lightning Directory",
13
+ displayName: "L402 Lightning Directory (402index)",
20
14
 
21
15
  async search(query: string, options?: SourceSearchOptions): Promise<UnifiedAgent[]> {
22
- const lower = query.toLowerCase();
23
- const filtered = query
24
- ? KNOWN_L402_SERVICES.filter(
25
- (s) =>
26
- s.name.toLowerCase().includes(lower) ||
27
- s.description.toLowerCase().includes(lower) ||
28
- s.categories.some((c) => c.includes(lower))
29
- )
30
- : KNOWN_L402_SERVICES;
31
-
32
- return filtered.slice(0, options?.limit ?? 50).map((service) => ({
33
- id: `l402-directory:${service.name.toLowerCase().replace(/\s+/g, "-")}`,
34
- nativeId: service.name,
35
- name: service.name,
36
- description: service.description,
37
- categories: service.categories,
38
- capabilities: [service.description],
39
- source: "l402-directory" as const,
40
- protocol: "l402" as const,
41
- endpoints: { l402: service.url, http: service.url },
42
- pricing: { model: "per-call" as const, currency: "BTC/sats" },
43
- verified: true,
44
- raw: service,
45
- }));
16
+ const limit = options?.limit ?? 20;
17
+ const timeout = options?.timeout ?? 10000;
18
+
19
+ try {
20
+ const url = new URL(INDEX_API);
21
+ if (query) url.searchParams.set("q", query);
22
+ url.searchParams.set("protocol", "L402");
23
+ url.searchParams.set("limit", String(limit));
24
+ url.searchParams.set("health", "healthy");
25
+ url.searchParams.set("sort", "reliability");
26
+
27
+ const res = await fetch(url.toString(), { signal: AbortSignal.timeout(timeout) });
28
+ if (!res.ok) return [];
29
+
30
+ const data = await res.json();
31
+ const services = data.services ?? data.data ?? [];
32
+ if (!Array.isArray(services)) return [];
33
+
34
+ return services.slice(0, limit).map((s: any) => ({
35
+ id: `l402-directory:${s.id ?? s.url}`,
36
+ nativeId: s.id ?? s.name,
37
+ name: (s.name ?? "L402 Service").replace(/^\s+/g, "").split("\n")[0].trim().slice(0, 100),
38
+ description: (s.description ?? "").replace(/^\s+|\s+$/g, "").replace(/\s+/g, " ").slice(0, 300),
39
+ categories: s.category ? s.category.split("/").map((c: string) => c.trim()) : ["general"],
40
+ capabilities: [s.description ?? s.name ?? ""],
41
+ source: "l402-directory" as const,
42
+ protocol: "l402" as const,
43
+ endpoints: { l402: s.url, http: s.url },
44
+ pricing: {
45
+ model: "per-call" as const,
46
+ amount: s.price_sats ? `${s.price_sats} sats` : s.price_usd ? String(s.price_usd) : undefined,
47
+ currency: "sats",
48
+ },
49
+ reputation: s.reliability_score ? {
50
+ score: s.reliability_score,
51
+ count: s.uptime_30d ? Math.round(s.uptime_30d * 100) : 0,
52
+ source: "402index",
53
+ } : undefined,
54
+ verified: s.health_status === "healthy",
55
+ lastSeen: s.last_checked ? new Date(s.last_checked).getTime() : undefined,
56
+ raw: s,
57
+ }));
58
+ } catch {
59
+ return [];
60
+ }
46
61
  },
47
62
 
48
63
  async ping(): Promise<boolean> {
49
- return true; // Seed list always available
64
+ try {
65
+ const res = await fetch(`${INDEX_API}?protocol=L402&limit=1`, { signal: AbortSignal.timeout(5000) });
66
+ return res.ok;
67
+ } catch {
68
+ return false;
69
+ }
50
70
  },
51
71
  };
@@ -1,13 +1,16 @@
1
1
  /**
2
2
  * Skills Source Adapter
3
- * Searches skills.sh (Vercel) and ClawHub registries for agent skills
4
- * 13,700+ capabilities indexed across both registries
3
+ * Searches REAL APIs:
4
+ * - skills.sh (Vercel) /api/search?q=
5
+ * - ClawHub (OpenClaw) — /api/search?q= (vector search)
6
+ *
7
+ * No hardcoded seed lists. All real data.
5
8
  */
6
9
 
7
10
  import type { SourceAdapter, UnifiedAgent, SourceSearchOptions } from "./types.js";
8
11
 
9
- const SKILLS_SH_API = "https://skills.sh";
10
- const CLAWHUB_API = "https://clawhub.ai";
12
+ const SKILLS_SH_API = "https://skills.sh/api/search";
13
+ const CLAWHUB_API = "https://clawhub.ai/api/search";
11
14
 
12
15
  export const skillsAdapter: SourceAdapter = {
13
16
  name: "skills-registry",
@@ -19,143 +22,111 @@ export const skillsAdapter: SourceAdapter = {
19
22
  const results: UnifiedAgent[] = [];
20
23
 
21
24
  // Search skills.sh
22
- try {
23
- const skillsShResults = await searchSkillsSh(query, Math.ceil(limit / 2), timeout);
24
- results.push(...skillsShResults);
25
- } catch {
26
- // skills.sh might not have a public search API — fall back to known skills
27
- }
28
-
29
- // Search ClawHub
30
- try {
31
- const clawHubResults = await searchClawHub(query, Math.ceil(limit / 2), timeout);
32
- results.push(...clawHubResults);
33
- } catch {
34
- // ClawHub might be rate-limited
35
- }
25
+ const [skillsShResults, clawHubResults] = await Promise.allSettled([
26
+ searchSkillsSh(query, Math.ceil(limit / 2), timeout),
27
+ searchClawHub(query, Math.ceil(limit / 2), timeout),
28
+ ]);
36
29
 
37
- // If both APIs fail, return from seed list
38
- if (results.length === 0) {
39
- return searchSeedList(query, limit);
40
- }
30
+ if (skillsShResults.status === "fulfilled") results.push(...skillsShResults.value);
31
+ if (clawHubResults.status === "fulfilled") results.push(...clawHubResults.value);
41
32
 
42
33
  return results.slice(0, limit);
43
34
  },
44
35
 
45
36
  async ping(): Promise<boolean> {
46
37
  try {
47
- const res = await fetch(SKILLS_SH_API, { signal: AbortSignal.timeout(3000) });
38
+ const res = await fetch(`${SKILLS_SH_API}?q=test`, { signal: AbortSignal.timeout(3000) });
48
39
  return res.ok;
49
40
  } catch {
50
- return true; // Seed list always available
41
+ return false;
51
42
  }
52
43
  },
53
44
  };
54
45
 
55
46
  async function searchSkillsSh(query: string, limit: number, timeout: number): Promise<UnifiedAgent[]> {
56
- // skills.sh has a search page — try to query it
57
- const res = await fetch(`${SKILLS_SH_API}/api/search?q=${encodeURIComponent(query)}&limit=${limit}`, {
58
- signal: AbortSignal.timeout(timeout),
59
- });
60
-
61
- if (!res.ok) {
62
- // Try the leaderboard endpoint
63
- const lbRes = await fetch(`${SKILLS_SH_API}/api/leaderboard?limit=${limit}`, {
47
+ try {
48
+ const res = await fetch(`${SKILLS_SH_API}?q=${encodeURIComponent(query)}`, {
64
49
  signal: AbortSignal.timeout(timeout),
65
50
  });
66
- if (!lbRes.ok) return [];
67
- const data = await lbRes.json();
68
- const skills = Array.isArray(data) ? data : data.skills ?? data.data ?? [];
69
- return skills
70
- .filter((s: any) => matchesQuery(s, query))
71
- .map((s: any) => mapSkill(s, "skills-sh"));
72
- }
73
51
 
74
- const data = await res.json();
75
- const skills = Array.isArray(data) ? data : data.skills ?? data.results ?? [];
76
- return skills.map((s: any) => mapSkill(s, "skills-sh"));
52
+ if (!res.ok) return [];
53
+
54
+ const data = await res.json();
55
+ const skills = data.skills ?? [];
56
+
57
+ return skills.slice(0, limit).map((s: any) => ({
58
+ id: `skills-registry:skills-sh:${s.id ?? s.skillId}`,
59
+ nativeId: s.id ?? s.skillId,
60
+ name: s.name ?? s.skillId ?? "Unknown Skill",
61
+ description: s.description ?? "",
62
+ categories: extractSkillCategories(s.name ?? "", s.description ?? ""),
63
+ capabilities: [s.name, s.description].filter(Boolean),
64
+ source: "skills-registry" as const,
65
+ protocol: "skill" as const,
66
+ endpoints: {
67
+ http: `https://skills.sh/${s.source ?? s.id}`,
68
+ },
69
+ pricing: { model: "free" as const },
70
+ verified: (s.installs ?? 0) > 100,
71
+ reputation: s.installs ? {
72
+ score: Math.min(s.installs / 100, 100),
73
+ count: s.installs,
74
+ source: "skills-sh-installs",
75
+ } : undefined,
76
+ raw: { ...s, registry: "skills-sh" },
77
+ }));
78
+ } catch {
79
+ return [];
80
+ }
77
81
  }
78
82
 
79
83
  async function searchClawHub(query: string, limit: number, timeout: number): Promise<UnifiedAgent[]> {
80
- const res = await fetch(`${CLAWHUB_API}/api/skills/search?q=${encodeURIComponent(query)}&limit=${limit}`, {
81
- signal: AbortSignal.timeout(timeout),
82
- });
83
-
84
- if (!res.ok) return [];
85
-
86
- const data = await res.json();
87
- const skills = Array.isArray(data) ? data : data.skills ?? data.results ?? [];
88
- return skills.map((s: any) => mapSkill(s, "clawhub"));
89
- }
90
-
91
- function mapSkill(skill: any, registry: string): UnifiedAgent {
92
- const name = skill.name ?? skill.slug ?? skill.title ?? "Unknown Skill";
93
- const description = skill.description ?? "";
94
- const repo = skill.repo ?? skill.repository ?? skill.url ?? "";
95
- const installs = skill.installs ?? skill.downloads ?? 0;
96
-
97
- return {
98
- id: `skills-registry:${registry}:${name.toLowerCase().replace(/\s+/g, "-")}`,
99
- nativeId: skill.id ?? name,
100
- name,
101
- description,
102
- categories: extractSkillCategories(name, description),
103
- capabilities: [description, ...(skill.tags ?? [])],
104
- source: "skills-registry" as any,
105
- protocol: "skill" as any,
106
- endpoints: {
107
- http: repo || `https://skills.sh/${name}`,
108
- },
109
- pricing: { model: "free" as const },
110
- verified: installs > 100,
111
- lastSeen: Date.now(),
112
- raw: { ...skill, registry },
113
- };
114
- }
115
-
116
- // Seed list of well-known skills for when APIs are unavailable
117
- const KNOWN_SKILLS = [
118
- { name: "remotion-best-practices", description: "Video creation in React with Remotion", categories: ["media", "development"], registry: "skills-sh", installs: 145000 },
119
- { name: "web-design-guidelines", description: "UI/UX design best practices for web development", categories: ["design", "development"], registry: "skills-sh", installs: 89000 },
120
- { name: "react-best-practices", description: "React and Next.js performance optimization from Vercel", categories: ["development"], registry: "skills-sh", installs: 120000 },
121
- { name: "solana-dev", description: "End-to-end Solana development playbook", categories: ["development", "defi"], registry: "skills-sh", installs: 50000 },
122
- { name: "cairo-contracts", description: "Write Cairo smart contracts on Starknet", categories: ["development", "defi"], registry: "skills-sh", installs: 30000 },
123
- { name: "x402-skill", description: "x402 HTTP payment protocol for monetizing APIs", categories: ["payments", "development"], registry: "skills-sh", installs: 25000 },
124
- { name: "agent-browser", description: "Automate browser interactions, screenshots, form filling", categories: ["tools", "automation"], registry: "skills-sh", installs: 70000 },
125
- { name: "implement-design", description: "Translate Figma designs into production-ready code", categories: ["design", "development"], registry: "skills-sh", installs: 60000 },
126
- { name: "find-skills", description: "Discover and install new agent skills", categories: ["tools", "discovery"], registry: "skills-sh", installs: 200000 },
127
- { name: "tailwind-v4-shadcn", description: "Set up Tailwind v4 with shadcn/ui", categories: ["development", "design"], registry: "skills-sh", installs: 45000 },
128
- { name: "ethskills", description: "Learn Ethereum, Solidity, smart contracts, web3 development", categories: ["development", "defi"], registry: "skills-sh", installs: 8000 },
129
- { name: "soul-markets", description: "Agent skill marketplace — monetize agent capabilities", categories: ["marketplace", "commerce"], registry: "clawhub", installs: 5000 },
130
- { name: "a2a-market", description: "Buy and sell agent skills using USDC on Base via A2A", categories: ["marketplace", "commerce"], registry: "clawhub", installs: 3000 },
131
- { name: "skillzmarket", description: "Discover and install skills from community marketplace", categories: ["marketplace", "discovery"], registry: "clawhub", installs: 4000 },
132
- { name: "x402-agent-marketplace", description: "x402 agent marketplace for paid AI capabilities", categories: ["marketplace", "payments"], registry: "clawhub", installs: 2000 },
133
- ];
134
-
135
- function searchSeedList(query: string, limit: number): UnifiedAgent[] {
136
- const lower = query.toLowerCase();
137
- return KNOWN_SKILLS
138
- .filter((s) => matchesQuery(s, query))
139
- .slice(0, limit)
140
- .map((s) => mapSkill({ ...s, installs: s.installs }, s.registry));
141
- }
84
+ try {
85
+ const res = await fetch(`${CLAWHUB_API}?q=${encodeURIComponent(query)}`, {
86
+ signal: AbortSignal.timeout(timeout),
87
+ });
142
88
 
143
- function matchesQuery(skill: any, query: string): boolean {
144
- if (!query) return true;
145
- const lower = query.toLowerCase();
146
- const text = `${skill.name ?? ""} ${skill.description ?? ""} ${(skill.tags ?? []).join(" ")} ${(skill.categories ?? []).join(" ")}`.toLowerCase();
147
- return lower.split(/\s+/).some((term) => text.includes(term));
89
+ if (!res.ok) return [];
90
+
91
+ const data = await res.json();
92
+ const skills = data.results ?? [];
93
+
94
+ return skills.slice(0, limit).map((s: any) => ({
95
+ id: `skills-registry:clawhub:${s.slug}`,
96
+ nativeId: s.slug,
97
+ name: s.displayName ?? s.slug ?? "Unknown Skill",
98
+ description: s.summary ?? "",
99
+ categories: extractSkillCategories(s.displayName ?? "", s.summary ?? ""),
100
+ capabilities: [s.summary ?? s.displayName ?? ""],
101
+ source: "skills-registry" as const,
102
+ protocol: "skill" as const,
103
+ endpoints: {
104
+ http: `https://clawhub.ai/${s.slug}`,
105
+ },
106
+ pricing: { model: "free" as const },
107
+ verified: true,
108
+ reputation: s.score ? {
109
+ score: Math.round(s.score * 25),
110
+ count: 0,
111
+ source: "clawhub-relevance",
112
+ } : undefined,
113
+ raw: { ...s, registry: "clawhub" },
114
+ }));
115
+ } catch {
116
+ return [];
117
+ }
148
118
  }
149
119
 
150
120
  function extractSkillCategories(name: string, description: string): string[] {
151
121
  const text = `${name} ${description}`.toLowerCase();
152
122
  const cats: string[] = [];
153
123
  if (text.match(/react|next|vue|svelte|frontend|css|tailwind|design/)) cats.push("development");
154
- if (text.match(/defi|yield|swap|solidity|ethereum|solana|contract/)) cats.push("defi");
124
+ if (text.match(/defi|yield|swap|solidity|ethereum|solana|contract|crypto/)) cats.push("defi");
155
125
  if (text.match(/image|video|audio|media|remotion|figma/)) cats.push("media");
156
- if (text.match(/data|analytics|research|search/)) cats.push("data");
126
+ if (text.match(/data|analytics|research|search|scrape/)) cats.push("data");
157
127
  if (text.match(/browser|automat|tool|file/)) cats.push("tools");
158
128
  if (text.match(/market|commerce|pay|x402|monetiz/)) cats.push("commerce");
159
129
  if (text.match(/security|audit|test/)) cats.push("security");
130
+ if (text.match(/ai|llm|model|agent/)) cats.push("ai");
160
131
  return cats.length > 0 ? cats : ["general"];
161
132
  }