dxai-cli 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 +172 -0
- package/bin/cli.js +272 -0
- package/package.json +64 -0
- package/src/auto-update.js +106 -0
- package/src/branding.js +80 -0
- package/src/cleanup.js +615 -0
- package/src/config-remover.js +325 -0
- package/src/config-writer.js +781 -0
- package/src/detect-project.js +316 -0
- package/src/detect.js +587 -0
- package/src/fs-atomic.js +35 -0
- package/src/handshake.js +123 -0
- package/src/index.js +966 -0
- package/src/inspect.js +283 -0
- package/src/manifest.js +179 -0
- package/src/mcp-cmd.js +282 -0
- package/src/net.js +72 -0
- package/src/profile.js +139 -0
- package/src/registry/automation-tools.js +6 -0
- package/src/registry/data/automation-tools.json +37 -0
- package/src/registry/data/mcp-servers.json +451 -0
- package/src/registry/data/skills.json +132 -0
- package/src/registry/loader.js +102 -0
- package/src/registry/mcp-registry.js +292 -0
- package/src/registry/mcp-servers.js +72 -0
- package/src/registry/skills.js +10 -0
- package/src/registry/stacks.js +769 -0
- package/src/registry/validate.js +209 -0
- package/src/rollback.js +182 -0
- package/src/runtime.js +40 -0
- package/src/select.js +72 -0
- package/src/update.js +126 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
{
|
|
2
|
+
"categories": [
|
|
3
|
+
{
|
|
4
|
+
"id": "essential",
|
|
5
|
+
"label": "🔧 Essential",
|
|
6
|
+
"description": "Core tools every developer should have"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"id": "code-git",
|
|
10
|
+
"label": "💻 Code & Git",
|
|
11
|
+
"description": "Source control and code intelligence"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "design",
|
|
15
|
+
"label": "🎨 Design",
|
|
16
|
+
"description": "Design-to-code workflows"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "productivity",
|
|
20
|
+
"label": "📋 Productivity",
|
|
21
|
+
"description": "Project management and communication"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "database",
|
|
25
|
+
"label": "🗄️ Database",
|
|
26
|
+
"description": "Database access and management"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "browser",
|
|
30
|
+
"label": "🌐 Browser & Testing",
|
|
31
|
+
"description": "Browser automation and testing"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "cloud",
|
|
35
|
+
"label": "☁️ Cloud & Deploy",
|
|
36
|
+
"description": "Deployment and infrastructure"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "advanced",
|
|
40
|
+
"label": "⚡ Advanced",
|
|
41
|
+
"description": "Agent orchestration and specialized tools"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"servers": [
|
|
45
|
+
{
|
|
46
|
+
"id": "context7",
|
|
47
|
+
"name": "Context7",
|
|
48
|
+
"description": "Live, version-specific library documentation",
|
|
49
|
+
"category": "essential",
|
|
50
|
+
"recommended": true,
|
|
51
|
+
"registry": {
|
|
52
|
+
"name": "io.github.upstash/context7",
|
|
53
|
+
"resolved": {
|
|
54
|
+
"version": "4.0.5",
|
|
55
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
56
|
+
"fields": [
|
|
57
|
+
"transport",
|
|
58
|
+
"requiresEnv",
|
|
59
|
+
"requiresInput",
|
|
60
|
+
"version",
|
|
61
|
+
"stale",
|
|
62
|
+
"staleReason"
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"transport": {
|
|
67
|
+
"type": "http",
|
|
68
|
+
"url": "https://mcp.context7.com/mcp"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "sequential-thinking",
|
|
73
|
+
"name": "Sequential Thinking",
|
|
74
|
+
"description": "Multi-step structured reasoning for complex problems",
|
|
75
|
+
"category": "essential",
|
|
76
|
+
"recommended": true,
|
|
77
|
+
"version": "2025.12.18",
|
|
78
|
+
"transport": {
|
|
79
|
+
"type": "stdio",
|
|
80
|
+
"command": "npx",
|
|
81
|
+
"args": [
|
|
82
|
+
"-y",
|
|
83
|
+
"@modelcontextprotocol/server-sequential-thinking"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "github",
|
|
89
|
+
"name": "GitHub",
|
|
90
|
+
"description": "PRs, issues, repos, code search (official remote MCP, OAuth)",
|
|
91
|
+
"category": "code-git",
|
|
92
|
+
"recommended": true,
|
|
93
|
+
"registry": {
|
|
94
|
+
"name": "io.github.github/github-mcp-server",
|
|
95
|
+
"prefer": {
|
|
96
|
+
"transport": "remote"
|
|
97
|
+
},
|
|
98
|
+
"resolved": {
|
|
99
|
+
"version": "1.12.0",
|
|
100
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
101
|
+
"fields": [
|
|
102
|
+
"transport",
|
|
103
|
+
"requiresEnv",
|
|
104
|
+
"requiresInput",
|
|
105
|
+
"version",
|
|
106
|
+
"stale",
|
|
107
|
+
"staleReason"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"transport": {
|
|
112
|
+
"type": "http",
|
|
113
|
+
"url": "https://api.githubcopilot.com/mcp/"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "gitlab",
|
|
118
|
+
"name": "GitLab",
|
|
119
|
+
"description": "Merge requests, issues, pipelines (official remote MCP)",
|
|
120
|
+
"category": "code-git",
|
|
121
|
+
"registry": {
|
|
122
|
+
"name": "com.gitlab/mcp",
|
|
123
|
+
"resolved": {
|
|
124
|
+
"version": "0.0.1",
|
|
125
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
126
|
+
"fields": [
|
|
127
|
+
"transport",
|
|
128
|
+
"requiresEnv",
|
|
129
|
+
"requiresInput",
|
|
130
|
+
"version",
|
|
131
|
+
"stale",
|
|
132
|
+
"staleReason"
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"transport": {
|
|
137
|
+
"type": "http",
|
|
138
|
+
"url": "https://gitlab.com/api/v4/mcp"
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"id": "claude-code-mcp",
|
|
143
|
+
"name": "Claude Code as MCP",
|
|
144
|
+
"description": "Use Claude Code as a sub-agent inside other editors",
|
|
145
|
+
"category": "code-git",
|
|
146
|
+
"transport": {
|
|
147
|
+
"type": "stdio",
|
|
148
|
+
"command": "npx",
|
|
149
|
+
"args": [
|
|
150
|
+
"-y",
|
|
151
|
+
"@anthropic-ai/claude-code-mcp"
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
"excludeAgents": [
|
|
155
|
+
"claude-code",
|
|
156
|
+
"codex"
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"id": "figma",
|
|
161
|
+
"name": "Figma",
|
|
162
|
+
"description": "Design-to-code from Figma components",
|
|
163
|
+
"category": "design",
|
|
164
|
+
"registry": {
|
|
165
|
+
"name": "com.figma.mcp/mcp",
|
|
166
|
+
"resolved": {
|
|
167
|
+
"version": "1.0.3",
|
|
168
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
169
|
+
"fields": [
|
|
170
|
+
"transport",
|
|
171
|
+
"requiresEnv",
|
|
172
|
+
"requiresInput",
|
|
173
|
+
"version",
|
|
174
|
+
"stale",
|
|
175
|
+
"staleReason"
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"transport": {
|
|
180
|
+
"type": "http",
|
|
181
|
+
"url": "https://mcp.figma.com/mcp"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "notion",
|
|
186
|
+
"name": "Notion",
|
|
187
|
+
"description": "Read/write Notion pages and databases",
|
|
188
|
+
"category": "productivity",
|
|
189
|
+
"registry": {
|
|
190
|
+
"name": "com.notion/mcp",
|
|
191
|
+
"resolved": {
|
|
192
|
+
"version": "1.0.1",
|
|
193
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
194
|
+
"fields": [
|
|
195
|
+
"transport",
|
|
196
|
+
"requiresEnv",
|
|
197
|
+
"requiresInput",
|
|
198
|
+
"version",
|
|
199
|
+
"stale",
|
|
200
|
+
"staleReason"
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"transport": {
|
|
205
|
+
"type": "http",
|
|
206
|
+
"url": "https://mcp.notion.com/mcp"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"id": "slack",
|
|
211
|
+
"name": "Slack",
|
|
212
|
+
"description": "Search messages, channels, send notifications",
|
|
213
|
+
"category": "productivity",
|
|
214
|
+
"stale": true,
|
|
215
|
+
"staleReason": "Upstream @modelcontextprotocol/server-slack is archived; no official remote MCP yet. Kept working for now.",
|
|
216
|
+
"requiresEnv": {
|
|
217
|
+
"SLACK_BOT_TOKEN": "Slack Bot OAuth Token"
|
|
218
|
+
},
|
|
219
|
+
"transport": {
|
|
220
|
+
"type": "stdio",
|
|
221
|
+
"command": "npx",
|
|
222
|
+
"args": [
|
|
223
|
+
"-y",
|
|
224
|
+
"@modelcontextprotocol/server-slack"
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"id": "linear",
|
|
230
|
+
"name": "Linear",
|
|
231
|
+
"description": "Issues, projects, cycles management (official remote MCP, OAuth)",
|
|
232
|
+
"category": "productivity",
|
|
233
|
+
"registry": {
|
|
234
|
+
"name": "app.linear/linear",
|
|
235
|
+
"resolved": {
|
|
236
|
+
"version": "1.0.1",
|
|
237
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
238
|
+
"fields": [
|
|
239
|
+
"transport",
|
|
240
|
+
"requiresEnv",
|
|
241
|
+
"requiresInput",
|
|
242
|
+
"version",
|
|
243
|
+
"stale",
|
|
244
|
+
"staleReason"
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"transport": {
|
|
249
|
+
"type": "http",
|
|
250
|
+
"url": "https://mcp.linear.app/mcp"
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"id": "supabase",
|
|
255
|
+
"name": "Supabase",
|
|
256
|
+
"description": "Supabase database, auth, storage (official remote MCP)",
|
|
257
|
+
"category": "database",
|
|
258
|
+
"registry": {
|
|
259
|
+
"name": "com.supabase/mcp",
|
|
260
|
+
"resolved": {
|
|
261
|
+
"version": "0.12.0",
|
|
262
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
263
|
+
"fields": [
|
|
264
|
+
"transport",
|
|
265
|
+
"requiresEnv",
|
|
266
|
+
"requiresInput",
|
|
267
|
+
"version",
|
|
268
|
+
"stale",
|
|
269
|
+
"staleReason"
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
"transport": {
|
|
274
|
+
"type": "http",
|
|
275
|
+
"url": "https://mcp.supabase.com/mcp"
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "neon",
|
|
280
|
+
"name": "Neon Postgres",
|
|
281
|
+
"description": "Serverless Postgres database",
|
|
282
|
+
"category": "database",
|
|
283
|
+
"requiresEnv": {
|
|
284
|
+
"NEON_API_KEY": "Neon API Key"
|
|
285
|
+
},
|
|
286
|
+
"transport": {
|
|
287
|
+
"type": "stdio",
|
|
288
|
+
"command": "npx",
|
|
289
|
+
"args": [
|
|
290
|
+
"-y",
|
|
291
|
+
"@neondatabase/mcp-server-neon"
|
|
292
|
+
]
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"id": "playwright",
|
|
297
|
+
"name": "Playwright",
|
|
298
|
+
"description": "Browser automation, E2E testing, screenshots",
|
|
299
|
+
"category": "browser",
|
|
300
|
+
"recommended": true,
|
|
301
|
+
"registry": {
|
|
302
|
+
"name": "io.github.microsoft/playwright-mcp",
|
|
303
|
+
"resolved": {
|
|
304
|
+
"version": "0.0.79",
|
|
305
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
306
|
+
"fields": [
|
|
307
|
+
"transport",
|
|
308
|
+
"requiresEnv",
|
|
309
|
+
"requiresInput",
|
|
310
|
+
"version",
|
|
311
|
+
"stale",
|
|
312
|
+
"staleReason"
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
"transport": {
|
|
317
|
+
"type": "stdio",
|
|
318
|
+
"command": "npx",
|
|
319
|
+
"args": [
|
|
320
|
+
"-y",
|
|
321
|
+
"@playwright/mcp"
|
|
322
|
+
]
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"id": "browserbase",
|
|
327
|
+
"name": "Browserbase",
|
|
328
|
+
"description": "Cloud browser sessions for testing",
|
|
329
|
+
"category": "browser",
|
|
330
|
+
"registry": {
|
|
331
|
+
"name": "io.github.browserbase/mcp-server-browserbase",
|
|
332
|
+
"resolved": {
|
|
333
|
+
"version": "2.1.1",
|
|
334
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
335
|
+
"fields": [
|
|
336
|
+
"transport",
|
|
337
|
+
"requiresEnv",
|
|
338
|
+
"requiresInput",
|
|
339
|
+
"version",
|
|
340
|
+
"stale",
|
|
341
|
+
"staleReason"
|
|
342
|
+
]
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
"requiresEnv": {
|
|
346
|
+
"BROWSERBASE_API_KEY": "Your Browserbase API key",
|
|
347
|
+
"BROWSERBASE_PROJECT_ID": "Your Browserbase Project ID",
|
|
348
|
+
"GEMINI_API_KEY": "Your Gemini API key (default model)"
|
|
349
|
+
},
|
|
350
|
+
"transport": {
|
|
351
|
+
"type": "stdio",
|
|
352
|
+
"command": "npx",
|
|
353
|
+
"args": [
|
|
354
|
+
"-y",
|
|
355
|
+
"@browserbasehq/mcp-server-browserbase"
|
|
356
|
+
]
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"id": "vercel",
|
|
361
|
+
"name": "Vercel",
|
|
362
|
+
"description": "Deploy, manage projects, domains (official remote MCP)",
|
|
363
|
+
"category": "cloud",
|
|
364
|
+
"registry": {
|
|
365
|
+
"name": "com.vercel/vercel-mcp",
|
|
366
|
+
"resolved": {
|
|
367
|
+
"version": "0.0.3",
|
|
368
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
369
|
+
"fields": [
|
|
370
|
+
"transport",
|
|
371
|
+
"requiresEnv",
|
|
372
|
+
"requiresInput",
|
|
373
|
+
"version",
|
|
374
|
+
"stale",
|
|
375
|
+
"staleReason"
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
"transport": {
|
|
380
|
+
"type": "http",
|
|
381
|
+
"url": "https://mcp.vercel.com"
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
"id": "cloudflare",
|
|
386
|
+
"name": "Cloudflare",
|
|
387
|
+
"description": "Workers bindings: KV, D1, R2, Durable Objects (official remote MCP)",
|
|
388
|
+
"category": "cloud",
|
|
389
|
+
"registry": {
|
|
390
|
+
"name": "com.cloudflare.mcp/mcp",
|
|
391
|
+
"prefer": {
|
|
392
|
+
"remote": "bindings.mcp.cloudflare.com"
|
|
393
|
+
},
|
|
394
|
+
"resolved": {
|
|
395
|
+
"version": "1.0.0",
|
|
396
|
+
"at": "2026-09-05T13:19:09.627Z",
|
|
397
|
+
"fields": [
|
|
398
|
+
"transport",
|
|
399
|
+
"requiresEnv",
|
|
400
|
+
"requiresInput",
|
|
401
|
+
"version",
|
|
402
|
+
"stale",
|
|
403
|
+
"staleReason"
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
"transport": {
|
|
408
|
+
"type": "http",
|
|
409
|
+
"url": "https://bindings.mcp.cloudflare.com/mcp"
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
"id": "filesystem",
|
|
414
|
+
"name": "Filesystem",
|
|
415
|
+
"description": "Secure file access outside project root",
|
|
416
|
+
"category": "advanced",
|
|
417
|
+
"version": "2026.1.14",
|
|
418
|
+
"requiresInput": {
|
|
419
|
+
"allowedPath": {
|
|
420
|
+
"prompt": "Path the filesystem MCP is allowed to access",
|
|
421
|
+
"default": "~",
|
|
422
|
+
"placeholder": "/path/to/allowed"
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
"transport": {
|
|
426
|
+
"type": "stdio",
|
|
427
|
+
"command": "npx",
|
|
428
|
+
"args": [
|
|
429
|
+
"-y",
|
|
430
|
+
"@modelcontextprotocol/server-filesystem",
|
|
431
|
+
"/path/to/allowed"
|
|
432
|
+
]
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"id": "memory",
|
|
437
|
+
"name": "Memory",
|
|
438
|
+
"description": "Persistent memory across agent sessions",
|
|
439
|
+
"category": "advanced",
|
|
440
|
+
"version": "2026.1.26",
|
|
441
|
+
"transport": {
|
|
442
|
+
"type": "stdio",
|
|
443
|
+
"command": "npx",
|
|
444
|
+
"args": [
|
|
445
|
+
"-y",
|
|
446
|
+
"@modelcontextprotocol/server-memory"
|
|
447
|
+
]
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"categories": [
|
|
3
|
+
{
|
|
4
|
+
"id": "anthropic",
|
|
5
|
+
"label": "🔵 Anthropic Official"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": "vercel",
|
|
9
|
+
"label": "▲ Vercel Labs"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "community",
|
|
13
|
+
"label": "🌍 Community"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"skills": [
|
|
17
|
+
{
|
|
18
|
+
"id": "frontend-design",
|
|
19
|
+
"name": "Frontend Design",
|
|
20
|
+
"description": "Production-grade UI with high design quality",
|
|
21
|
+
"category": "anthropic",
|
|
22
|
+
"recommended": true,
|
|
23
|
+
"repo": "anthropics/skills",
|
|
24
|
+
"path": "skills/frontend-design"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "skill-creator",
|
|
28
|
+
"name": "Skill Creator",
|
|
29
|
+
"description": "Create, test, and optimize custom skills",
|
|
30
|
+
"category": "anthropic",
|
|
31
|
+
"recommended": true,
|
|
32
|
+
"repo": "anthropics/skills",
|
|
33
|
+
"path": "skills/skill-creator"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "docx",
|
|
37
|
+
"name": "Document (docx)",
|
|
38
|
+
"description": "Professional Word document generation",
|
|
39
|
+
"category": "anthropic",
|
|
40
|
+
"repo": "anthropics/skills",
|
|
41
|
+
"path": "skills/docx"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "pdf",
|
|
45
|
+
"name": "PDF",
|
|
46
|
+
"description": "PDF creation, extraction, and manipulation",
|
|
47
|
+
"category": "anthropic",
|
|
48
|
+
"repo": "anthropics/skills",
|
|
49
|
+
"path": "skills/pdf"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "pptx",
|
|
53
|
+
"name": "Presentation (pptx)",
|
|
54
|
+
"description": "Slide deck and presentation creation",
|
|
55
|
+
"category": "anthropic",
|
|
56
|
+
"repo": "anthropics/skills",
|
|
57
|
+
"path": "skills/pptx"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "xlsx",
|
|
61
|
+
"name": "Spreadsheet (xlsx)",
|
|
62
|
+
"description": "Excel/spreadsheet generation",
|
|
63
|
+
"category": "anthropic",
|
|
64
|
+
"repo": "anthropics/skills",
|
|
65
|
+
"path": "skills/xlsx"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "algorithmic-art",
|
|
69
|
+
"name": "Algorithmic Art",
|
|
70
|
+
"description": "Generative art and creative coding",
|
|
71
|
+
"category": "anthropic",
|
|
72
|
+
"repo": "anthropics/skills",
|
|
73
|
+
"path": "skills/algorithmic-art"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "canvas-design",
|
|
77
|
+
"name": "Canvas Design",
|
|
78
|
+
"description": "HTML Canvas-based visual design",
|
|
79
|
+
"category": "anthropic",
|
|
80
|
+
"repo": "anthropics/skills",
|
|
81
|
+
"path": "skills/canvas-design"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "mcp-builder",
|
|
85
|
+
"name": "MCP Server Builder",
|
|
86
|
+
"description": "Build custom MCP servers",
|
|
87
|
+
"category": "anthropic",
|
|
88
|
+
"repo": "anthropics/skills",
|
|
89
|
+
"path": "skills/mcp-builder"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "webapp-testing",
|
|
93
|
+
"name": "Web App Testing",
|
|
94
|
+
"description": "Automated testing for web applications",
|
|
95
|
+
"category": "anthropic",
|
|
96
|
+
"repo": "anthropics/skills",
|
|
97
|
+
"path": "skills/webapp-testing"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "claude-api",
|
|
101
|
+
"name": "Claude API",
|
|
102
|
+
"description": "Build apps with the Claude API",
|
|
103
|
+
"category": "anthropic",
|
|
104
|
+
"repo": "anthropics/skills",
|
|
105
|
+
"path": "skills/claude-api"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "web-artifacts-builder",
|
|
109
|
+
"name": "Web Artifacts Builder",
|
|
110
|
+
"description": "Build interactive web artifacts",
|
|
111
|
+
"category": "anthropic",
|
|
112
|
+
"repo": "anthropics/skills",
|
|
113
|
+
"path": "skills/web-artifacts-builder"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"id": "find-skills",
|
|
117
|
+
"name": "Find Skills",
|
|
118
|
+
"description": "Discover and install agent skills",
|
|
119
|
+
"category": "vercel",
|
|
120
|
+
"repo": "vercel-labs/skills",
|
|
121
|
+
"path": "skills/find-skills"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": "better-auth",
|
|
125
|
+
"name": "Better Auth",
|
|
126
|
+
"description": "Authentication best practices",
|
|
127
|
+
"category": "community",
|
|
128
|
+
"repo": "better-auth/skills",
|
|
129
|
+
"path": "better-auth/best-practices"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Registry loader — overlays remote/cached registry on top of bundled JSON.
|
|
2
|
+
//
|
|
3
|
+
// Resolution order at module init (synchronous):
|
|
4
|
+
// 1. Cache at ~/.dxai/cache/<name>.json (written by `dxai update`)
|
|
5
|
+
// 2. Bundled snapshot at src/registry/data/<name>.json
|
|
6
|
+
//
|
|
7
|
+
// `dxai update` does the actual remote fetch and writes the cache. Reading is
|
|
8
|
+
// always synchronous so we don't impose top-level await on consumers.
|
|
9
|
+
|
|
10
|
+
import fs from 'fs-extra';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import os from 'os';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { isSafeVersionRef } from './validate.js';
|
|
15
|
+
import { writeJsonAtomic } from '../fs-atomic.js';
|
|
16
|
+
import { fetchJson } from '../net.js';
|
|
17
|
+
|
|
18
|
+
// Default timeout for a registry fetch, so `dxai update` can't hang forever on a
|
|
19
|
+
// stalled connection.
|
|
20
|
+
const DEFAULT_FETCH_TIMEOUT_MS = 15000;
|
|
21
|
+
|
|
22
|
+
const HOME = os.homedir();
|
|
23
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
24
|
+
const __dirname = path.dirname(__filename);
|
|
25
|
+
|
|
26
|
+
export const CACHE_DIR = path.join(HOME, '.dxai', 'cache');
|
|
27
|
+
const BUNDLED_DIR = path.join(__dirname, 'data');
|
|
28
|
+
|
|
29
|
+
// Default remote URL — points at the bundled JSON in the repo. Overridable
|
|
30
|
+
// via the DXAI_REGISTRY_URL env var; that's the supported escape hatch for
|
|
31
|
+
// teams who want to host a fork.
|
|
32
|
+
export const DEFAULT_REGISTRY_BASE =
|
|
33
|
+
process.env.DXAI_REGISTRY_URL ||
|
|
34
|
+
'https://raw.githubusercontent.com/nandha-kumar-hajari/dxai/main/src/registry/data';
|
|
35
|
+
|
|
36
|
+
// Resolve the registry base URL for a fetch. Precedence:
|
|
37
|
+
// explicit url > version ref (swaps the branch segment of the default) > default.
|
|
38
|
+
// When DXAI_REGISTRY_URL is set but carries no `/main/` segment, a version ref is a no-op.
|
|
39
|
+
export function registryBaseFor({ version, url } = {}) {
|
|
40
|
+
if (url) return url;
|
|
41
|
+
if (version) {
|
|
42
|
+
// `version` is substituted into the fetch URL path; a "../.." here could
|
|
43
|
+
// repoint the fetch at a different repo. Only allow a clean branch/tag ref.
|
|
44
|
+
if (!isSafeVersionRef(version)) {
|
|
45
|
+
throw new Error(`Invalid registry version ref: ${version}`);
|
|
46
|
+
}
|
|
47
|
+
return DEFAULT_REGISTRY_BASE.replace(/\/main\//, `/${version}/`);
|
|
48
|
+
}
|
|
49
|
+
return DEFAULT_REGISTRY_BASE;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function readJsonOr(filePath, fallback) {
|
|
53
|
+
if (!fs.existsSync(filePath)) return fallback;
|
|
54
|
+
try {
|
|
55
|
+
return fs.readJsonSync(filePath);
|
|
56
|
+
} catch {
|
|
57
|
+
return fallback;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Synchronously load a registry file: cache > bundled. Returns parsed JSON.
|
|
62
|
+
// DXAI_REGISTRY_SOURCE=bundled skips the cache — the test runner, doc
|
|
63
|
+
// generators and catalogue scripts set it so a developer's stale ~/.dxai cache
|
|
64
|
+
// can never stand in for the JSON that is actually in the repo.
|
|
65
|
+
export function loadRegistry(name) {
|
|
66
|
+
const cachePath = path.join(CACHE_DIR, `${name}.json`);
|
|
67
|
+
const bundledPath = path.join(BUNDLED_DIR, `${name}.json`);
|
|
68
|
+
|
|
69
|
+
const bundled = readJsonOr(bundledPath, null);
|
|
70
|
+
if (!bundled) {
|
|
71
|
+
throw new Error(`Bundled registry missing: ${bundledPath}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (process.env.DXAI_REGISTRY_SOURCE === 'bundled') return bundled;
|
|
75
|
+
const cached = readJsonOr(cachePath, null);
|
|
76
|
+
return cached ?? bundled;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Remote fetch — used by `dxai update`. Async, since we hit the network.
|
|
80
|
+
// timeoutMs (optional) aborts a slow fetch; used by the background auto-refresh
|
|
81
|
+
// so a stale network never blocks an interactive run for long.
|
|
82
|
+
export async function fetchRegistry(name, baseUrl = DEFAULT_REGISTRY_BASE, { timeoutMs = DEFAULT_FETCH_TIMEOUT_MS, retries } = {}) {
|
|
83
|
+
const url = `${baseUrl.replace(/\/$/, '')}/${name}.json`;
|
|
84
|
+
const data = await fetchJson(url, { timeoutMs, retries });
|
|
85
|
+
return { url, data };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function writeRegistryCache(name, data) {
|
|
89
|
+
const cachePath = path.join(CACHE_DIR, `${name}.json`);
|
|
90
|
+
writeJsonAtomic(cachePath, data, { spaces: 2 });
|
|
91
|
+
return cachePath;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Diff two registry payloads; returns added/removed entries by ID.
|
|
95
|
+
// Works on { servers: [...] } / { skills: [...] } / generic { items: [...] }.
|
|
96
|
+
export function diffRegistry(prev, next, key) {
|
|
97
|
+
const prevIds = new Set((prev?.[key] || []).map((x) => x.id));
|
|
98
|
+
const nextIds = new Set((next?.[key] || []).map((x) => x.id));
|
|
99
|
+
const added = [...nextIds].filter((id) => !prevIds.has(id));
|
|
100
|
+
const removed = [...prevIds].filter((id) => !nextIds.has(id));
|
|
101
|
+
return { added, removed };
|
|
102
|
+
}
|