dfns-mcp 1.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/LICENSE +21 -0
- package/README.md +174 -0
- package/package.json +50 -0
- package/src/docs-fetcher.ts +264 -0
- package/src/index.ts +1021 -0
- package/src/indexer.ts +915 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Josh Maddington
|
|
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
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# DFNS MCP Server
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that provides AI agents with access to the [DFNS](https://dfns.co) documentation, API reference, and SDK code.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Full-Text Search**: Instantly search across all DFNS guides, API docs, and SDK source code
|
|
8
|
+
- **TypeScript Type Intelligence**: Search and retrieve SDK type definitions with import paths
|
|
9
|
+
- **Auto-Updating Docs**: Documentation is fetched from GitHub on first run and cached locally
|
|
10
|
+
- **Context Initialization**: Dedicated `init` tool to enforce documentation-first behavior
|
|
11
|
+
- **Smart Context**: Retrieve specific documents, code examples, and API endpoint definitions
|
|
12
|
+
- **SDK Intelligence**: Mapped knowledge of supported blockchains and their SDK packages
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
This MCP server requires [Bun](https://bun.sh) - a fast JavaScript runtime.
|
|
17
|
+
|
|
18
|
+
**Linux/macOS:**
|
|
19
|
+
```bash
|
|
20
|
+
curl -fsSL https://bun.sh/install | bash
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Windows (PowerShell):**
|
|
24
|
+
```powershell
|
|
25
|
+
powershell -c "irm bun.sh/install.ps1 | iex"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Claude Code (Recommended)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
claude mcp add -s user dfns-docs -- bunx dfns-mcp@latest
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The `-s user` flag installs to the user so it's available in all your projects.
|
|
37
|
+
|
|
38
|
+
### Cursor
|
|
39
|
+
|
|
40
|
+
Add to your Cursor MCP settings (`.cursor/mcp.json`):
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"dfns-docs": {
|
|
46
|
+
"command": "bunx",
|
|
47
|
+
"args": ["dfns-mcp@latest"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Codex
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
codex mcp add dfns-docs -- bunx dfns-mcp@latest
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Gemini CLI
|
|
60
|
+
|
|
61
|
+
Add to your Gemini CLI config (`~/.gemini/settings.json`):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"dfns-docs": {
|
|
67
|
+
"command": "bunx",
|
|
68
|
+
"args": ["dfns-mcp@latest"]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Global Installation
|
|
75
|
+
|
|
76
|
+
If you prefer to install globally instead of using `bunx`:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bun install -g dfns-mcp
|
|
80
|
+
|
|
81
|
+
# Then reference as just "dfns-mcp" in your MCP config
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Agent Instructions (Recommended)
|
|
85
|
+
|
|
86
|
+
Add this to your global `~/.claude/CLAUDE.md` (or `~/AGENTS.md` for other agents) to ensure your AI always uses up-to-date DFNS documentation:
|
|
87
|
+
|
|
88
|
+
```markdown
|
|
89
|
+
## DFNS Development
|
|
90
|
+
|
|
91
|
+
When working with DFNS (wallet infrastructure, key management, blockchain integrations):
|
|
92
|
+
|
|
93
|
+
1. **Always** call `mcp__dfns-docs__init` at the start of any DFNS-related task
|
|
94
|
+
2. **Never** rely on training data for DFNS APIs - always use `search_docs` and `get_doc` to verify
|
|
95
|
+
3. Use `search_types` and `get_type` to get accurate TypeScript type definitions
|
|
96
|
+
4. DFNS APIs and SDKs change frequently - the MCP server has the latest documentation
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This prevents agents from hallucinating outdated API signatures or SDK patterns.
|
|
100
|
+
|
|
101
|
+
## How It Works
|
|
102
|
+
|
|
103
|
+
On first run, the server automatically downloads the latest DFNS documentation from GitHub and caches it locally in `~/.cache/dfns-mcp/`. The cache is refreshed every 24 hours automatically, or you can force an update using the `update_docs` tool.
|
|
104
|
+
|
|
105
|
+
## Available Tools
|
|
106
|
+
|
|
107
|
+
### Documentation Tools
|
|
108
|
+
|
|
109
|
+
| Tool | Description |
|
|
110
|
+
|------|-------------|
|
|
111
|
+
| **`init`** | **CALL THIS FIRST.** Initializes the session and mandates strict documentation adherence |
|
|
112
|
+
| `search_docs` | Search all documentation and SDK files |
|
|
113
|
+
| `get_doc` | Retrieve the full content of a specific document |
|
|
114
|
+
| `list_docs` | List available documents by category |
|
|
115
|
+
| `get_code_examples` | Extract code snippets for a specific topic |
|
|
116
|
+
| `browse_api_structure` | View hierarchical API endpoint structure |
|
|
117
|
+
| `get_api_endpoint` | Get details for a specific API endpoint (e.g., `POST /wallets`) |
|
|
118
|
+
| `get_blockchain_info` | Get SDK package info for a specific chain (e.g., `Solana`) |
|
|
119
|
+
| `list_blockchains` | List all supported blockchains with their SDK packages |
|
|
120
|
+
|
|
121
|
+
### TypeScript Type Tools
|
|
122
|
+
|
|
123
|
+
| Tool | Description |
|
|
124
|
+
|------|-------------|
|
|
125
|
+
| `search_types` | Search SDK types by name (e.g., "Wallet", "Signer", "Transaction") |
|
|
126
|
+
| `get_type` | Get full type definition, import path, and usage |
|
|
127
|
+
| `list_types` | List all types by category |
|
|
128
|
+
|
|
129
|
+
### Cache Management
|
|
130
|
+
|
|
131
|
+
| Tool | Description |
|
|
132
|
+
|------|-------------|
|
|
133
|
+
| `update_docs` | Force update the documentation cache from GitHub |
|
|
134
|
+
| `cache_info` | Get information about the cache (location, last update, etc.) |
|
|
135
|
+
|
|
136
|
+
## Resources
|
|
137
|
+
|
|
138
|
+
The server also exposes these quick-reference resources:
|
|
139
|
+
|
|
140
|
+
| Resource URI | Description |
|
|
141
|
+
|--------------|-------------|
|
|
142
|
+
| `dfns://quickref/authentication` | Authentication patterns and code samples |
|
|
143
|
+
| `dfns://quickref/sdk-setup` | Package installation and setup guide |
|
|
144
|
+
| `dfns://quickref/networks` | All supported blockchain networks |
|
|
145
|
+
|
|
146
|
+
## Best Practices for Agents
|
|
147
|
+
|
|
148
|
+
When using this server, agents should follow this workflow:
|
|
149
|
+
|
|
150
|
+
1. **Initialize**: Call `init` immediately to establish the "Documentation First" protocol
|
|
151
|
+
2. **Search**: Use `search_docs` to find relevant information before answering ANY question
|
|
152
|
+
3. **Read**: Use `get_doc` to read the actual source material
|
|
153
|
+
4. **Answer**: Formulate responses based *only* on the retrieved context
|
|
154
|
+
|
|
155
|
+
## Development
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Clone the repo
|
|
159
|
+
git clone https://github.com/jmaddington/dfns-mcp.git
|
|
160
|
+
cd dfns-mcp
|
|
161
|
+
|
|
162
|
+
# Install dependencies
|
|
163
|
+
bun install
|
|
164
|
+
|
|
165
|
+
# Run in development mode with auto-reload
|
|
166
|
+
bun run dev
|
|
167
|
+
|
|
168
|
+
# Test with MCP Inspector
|
|
169
|
+
bun run inspect
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dfns-mcp",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "MCP server for DFNS documentation and SDK reference - provides AI agents with access to DFNS API docs, TypeScript types, and code examples",
|
|
5
|
+
"module": "src/index.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"dfns-mcp": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src/**/*.ts",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"start": "bun run src/index.ts",
|
|
17
|
+
"dev": "bun --watch run src/index.ts",
|
|
18
|
+
"inspect": "bunx @modelcontextprotocol/inspector bun run src/index.ts"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"dfns",
|
|
23
|
+
"wallet",
|
|
24
|
+
"crypto",
|
|
25
|
+
"blockchain",
|
|
26
|
+
"ai",
|
|
27
|
+
"claude",
|
|
28
|
+
"documentation"
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/jhubbardsf/dfns-mcp.git"
|
|
33
|
+
},
|
|
34
|
+
"author": "Josh Hubbard",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"engines": {
|
|
37
|
+
"bun": ">=1.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/bun": "latest"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"typescript": "^5"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
47
|
+
"tar": "^7.4.3",
|
|
48
|
+
"zod": "^4.1.13"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { mkdir, stat, rm, readFile, writeFile, rename } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { createWriteStream } from "node:fs";
|
|
5
|
+
import { pipeline } from "node:stream/promises";
|
|
6
|
+
import { Readable } from "node:stream";
|
|
7
|
+
import { createGunzip } from "node:zlib";
|
|
8
|
+
import { extract } from "tar";
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Configuration
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
const CACHE_DIR = join(homedir(), ".cache", "dfns-mcp");
|
|
15
|
+
const METADATA_FILE = join(CACHE_DIR, "metadata.json");
|
|
16
|
+
|
|
17
|
+
const REPOS = {
|
|
18
|
+
"dfns-api-docs": {
|
|
19
|
+
owner: "dfns",
|
|
20
|
+
repo: "dfns-api-docs",
|
|
21
|
+
branch: "m", // DFNS uses 'm' as their default branch
|
|
22
|
+
},
|
|
23
|
+
"dfns-sdk-ts": {
|
|
24
|
+
owner: "dfns",
|
|
25
|
+
repo: "dfns-sdk-ts",
|
|
26
|
+
branch: "m", // DFNS uses 'm' as their default branch
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// How often to check for updates (24 hours)
|
|
31
|
+
const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
32
|
+
|
|
33
|
+
interface CacheMetadata {
|
|
34
|
+
lastUpdated: number;
|
|
35
|
+
repos: {
|
|
36
|
+
[key: string]: {
|
|
37
|
+
sha: string;
|
|
38
|
+
fetchedAt: number;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Helper Functions
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
async function exists(path: string): Promise<boolean> {
|
|
48
|
+
try {
|
|
49
|
+
await stat(path);
|
|
50
|
+
return true;
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function readMetadata(): Promise<CacheMetadata | null> {
|
|
57
|
+
try {
|
|
58
|
+
const content = await readFile(METADATA_FILE, "utf-8");
|
|
59
|
+
return JSON.parse(content);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function writeMetadata(metadata: CacheMetadata): Promise<void> {
|
|
66
|
+
await writeFile(METADATA_FILE, JSON.stringify(metadata, null, 2));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Fetch the latest commit SHA for a branch
|
|
71
|
+
*/
|
|
72
|
+
async function getLatestSha(owner: string, repo: string, branch: string): Promise<string | null> {
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(
|
|
75
|
+
`https://api.github.com/repos/${owner}/${repo}/commits/${branch}`,
|
|
76
|
+
{
|
|
77
|
+
headers: {
|
|
78
|
+
"Accept": "application/vnd.github.v3+json",
|
|
79
|
+
"User-Agent": "dfns-mcp",
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
console.error(`Failed to fetch SHA: ${response.status}`);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const data = await response.json() as { sha: string };
|
|
90
|
+
return data.sha;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error(`Error fetching SHA:`, err);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Download and extract a GitHub repository tarball
|
|
99
|
+
*/
|
|
100
|
+
async function downloadAndExtractRepo(
|
|
101
|
+
owner: string,
|
|
102
|
+
repo: string,
|
|
103
|
+
branch: string,
|
|
104
|
+
targetDir: string
|
|
105
|
+
): Promise<void> {
|
|
106
|
+
const url = `https://github.com/${owner}/${repo}/archive/refs/heads/${branch}.tar.gz`;
|
|
107
|
+
const tempDir = join(CACHE_DIR, `${repo}-temp-${Date.now()}`);
|
|
108
|
+
|
|
109
|
+
console.error(`Downloading ${owner}/${repo}...`);
|
|
110
|
+
|
|
111
|
+
const response = await fetch(url);
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
throw new Error(`Failed to download ${url}: ${response.status}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Create temp directory
|
|
117
|
+
await mkdir(tempDir, { recursive: true });
|
|
118
|
+
|
|
119
|
+
// Extract the tarball
|
|
120
|
+
const body = response.body;
|
|
121
|
+
if (!body) {
|
|
122
|
+
throw new Error("No response body");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Convert web stream to Node stream and extract
|
|
126
|
+
const nodeStream = Readable.fromWeb(body as any);
|
|
127
|
+
|
|
128
|
+
await pipeline(
|
|
129
|
+
nodeStream,
|
|
130
|
+
createGunzip(),
|
|
131
|
+
extract({
|
|
132
|
+
cwd: tempDir,
|
|
133
|
+
strip: 1, // Remove the top-level directory (e.g., dfns-api-docs-main/)
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Remove old target if exists
|
|
138
|
+
if (await exists(targetDir)) {
|
|
139
|
+
await rm(targetDir, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Rename temp to target
|
|
143
|
+
await rename(tempDir, targetDir);
|
|
144
|
+
|
|
145
|
+
console.error(`Extracted to ${targetDir}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ============================================================================
|
|
149
|
+
// Public API
|
|
150
|
+
// ============================================================================
|
|
151
|
+
|
|
152
|
+
export interface DocsPaths {
|
|
153
|
+
docsDir: string;
|
|
154
|
+
sdkDir: string;
|
|
155
|
+
fromCache: boolean;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Ensure docs are available, downloading if necessary.
|
|
160
|
+
* Returns paths to the docs and SDK directories.
|
|
161
|
+
*/
|
|
162
|
+
export async function ensureDocs(forceUpdate: boolean = false): Promise<DocsPaths> {
|
|
163
|
+
// Create cache directory
|
|
164
|
+
await mkdir(CACHE_DIR, { recursive: true });
|
|
165
|
+
|
|
166
|
+
const docsDir = join(CACHE_DIR, "dfns-api-docs");
|
|
167
|
+
const sdkDir = join(CACHE_DIR, "dfns-sdk-ts");
|
|
168
|
+
|
|
169
|
+
const metadata = await readMetadata();
|
|
170
|
+
const now = Date.now();
|
|
171
|
+
|
|
172
|
+
// Check if we need to update
|
|
173
|
+
const docsExist = await exists(docsDir) && await exists(sdkDir);
|
|
174
|
+
const needsUpdate = forceUpdate ||
|
|
175
|
+
!docsExist ||
|
|
176
|
+
!metadata ||
|
|
177
|
+
(now - metadata.lastUpdated > UPDATE_CHECK_INTERVAL_MS);
|
|
178
|
+
|
|
179
|
+
if (!needsUpdate && docsExist) {
|
|
180
|
+
console.error("Using cached documentation");
|
|
181
|
+
return { docsDir, sdkDir, fromCache: true };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Download/update repos
|
|
185
|
+
const newMetadata: CacheMetadata = {
|
|
186
|
+
lastUpdated: now,
|
|
187
|
+
repos: {},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
for (const [name, config] of Object.entries(REPOS)) {
|
|
191
|
+
const targetDir = name === "dfns-api-docs" ? docsDir : sdkDir;
|
|
192
|
+
const currentSha = metadata?.repos[name]?.sha;
|
|
193
|
+
|
|
194
|
+
// Check if there's a new version
|
|
195
|
+
const latestSha = await getLatestSha(config.owner, config.repo, config.branch);
|
|
196
|
+
|
|
197
|
+
if (!forceUpdate && latestSha && latestSha === currentSha && await exists(targetDir)) {
|
|
198
|
+
console.error(`${name} is up to date (${latestSha.slice(0, 7)})`);
|
|
199
|
+
newMetadata.repos[name] = metadata!.repos[name];
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Download the repo
|
|
204
|
+
await downloadAndExtractRepo(
|
|
205
|
+
config.owner,
|
|
206
|
+
config.repo,
|
|
207
|
+
config.branch,
|
|
208
|
+
targetDir
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
newMetadata.repos[name] = {
|
|
212
|
+
sha: latestSha || "unknown",
|
|
213
|
+
fetchedAt: now,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Save metadata
|
|
218
|
+
await writeMetadata(newMetadata);
|
|
219
|
+
|
|
220
|
+
return { docsDir, sdkDir, fromCache: false };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Force update all docs
|
|
225
|
+
*/
|
|
226
|
+
export async function updateDocs(): Promise<{ success: boolean; message: string }> {
|
|
227
|
+
try {
|
|
228
|
+
const result = await ensureDocs(true);
|
|
229
|
+
return {
|
|
230
|
+
success: true,
|
|
231
|
+
message: `Documentation updated successfully. Docs at: ${result.docsDir}`,
|
|
232
|
+
};
|
|
233
|
+
} catch (err) {
|
|
234
|
+
return {
|
|
235
|
+
success: false,
|
|
236
|
+
message: `Failed to update documentation: ${err}`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get the cache directory path
|
|
243
|
+
*/
|
|
244
|
+
export function getCacheDir(): string {
|
|
245
|
+
return CACHE_DIR;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get cached metadata
|
|
250
|
+
*/
|
|
251
|
+
export async function getCacheInfo(): Promise<{
|
|
252
|
+
cacheDir: string;
|
|
253
|
+
metadata: CacheMetadata | null;
|
|
254
|
+
docsExist: boolean;
|
|
255
|
+
sdkExist: boolean;
|
|
256
|
+
}> {
|
|
257
|
+
const metadata = await readMetadata();
|
|
258
|
+
return {
|
|
259
|
+
cacheDir: CACHE_DIR,
|
|
260
|
+
metadata,
|
|
261
|
+
docsExist: await exists(join(CACHE_DIR, "dfns-api-docs")),
|
|
262
|
+
sdkExist: await exists(join(CACHE_DIR, "dfns-sdk-ts")),
|
|
263
|
+
};
|
|
264
|
+
}
|