midnight-mcp 0.1.41 → 0.2.2
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/README.md +32 -1
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +60 -0
- package/dist/chunk-HOWO4K5A.js +2197 -0
- package/dist/chunk-S7G4OHA4.js +8306 -0
- package/dist/db-YDGUWI5K.js +7 -0
- package/dist/index.d.ts +205 -3
- package/dist/index.js +28 -16
- package/package.json +16 -6
- package/dist/config/compact-version.d.ts +0 -183
- package/dist/config/compact-version.js +0 -423
- package/dist/db/index.d.ts +0 -3
- package/dist/db/index.js +0 -2
- package/dist/db/vectorStore.d.ts +0 -69
- package/dist/db/vectorStore.js +0 -196
- package/dist/pipeline/embeddings.d.ts +0 -25
- package/dist/pipeline/embeddings.js +0 -103
- package/dist/pipeline/github.d.ts +0 -84
- package/dist/pipeline/github.js +0 -399
- package/dist/pipeline/index.d.ts +0 -11
- package/dist/pipeline/index.js +0 -6
- package/dist/pipeline/indexer.d.ts +0 -41
- package/dist/pipeline/indexer.js +0 -254
- package/dist/pipeline/parser.d.ts +0 -46
- package/dist/pipeline/parser.js +0 -436
- package/dist/pipeline/releases.d.ts +0 -112
- package/dist/pipeline/releases.js +0 -298
- package/dist/pipeline/repository.d.ts +0 -372
- package/dist/pipeline/repository.js +0 -520
- package/dist/prompts/index.d.ts +0 -3
- package/dist/prompts/index.js +0 -2
- package/dist/prompts/templates.d.ts +0 -26
- package/dist/prompts/templates.js +0 -443
- package/dist/resources/code.d.ts +0 -15
- package/dist/resources/code.js +0 -122
- package/dist/resources/content/code-content.d.ts +0 -6
- package/dist/resources/content/code-content.js +0 -802
- package/dist/resources/content/docs-content.d.ts +0 -14
- package/dist/resources/content/docs-content.js +0 -1202
- package/dist/resources/content/index.d.ts +0 -6
- package/dist/resources/content/index.js +0 -6
- package/dist/resources/docs.d.ts +0 -15
- package/dist/resources/docs.js +0 -98
- package/dist/resources/index.d.ts +0 -6
- package/dist/resources/index.js +0 -13
- package/dist/resources/schemas.d.ts +0 -16
- package/dist/resources/schemas.js +0 -407
- package/dist/scripts/index-repos.d.ts +0 -12
- package/dist/scripts/index-repos.js +0 -53
- package/dist/server.d.ts +0 -43
- package/dist/server.js +0 -696
- package/dist/services/index.d.ts +0 -6
- package/dist/services/index.js +0 -6
- package/dist/services/sampling.d.ts +0 -62
- package/dist/services/sampling.js +0 -277
- package/dist/tools/analyze.d.ts +0 -106
- package/dist/tools/analyze.js +0 -431
- package/dist/tools/generation.d.ts +0 -9
- package/dist/tools/generation.js +0 -285
- package/dist/tools/health.d.ts +0 -120
- package/dist/tools/health.js +0 -365
- package/dist/tools/index.d.ts +0 -14
- package/dist/tools/index.js +0 -22
- package/dist/tools/meta.d.ts +0 -61
- package/dist/tools/meta.js +0 -282
- package/dist/tools/repository/constants.d.ts +0 -19
- package/dist/tools/repository/constants.js +0 -324
- package/dist/tools/repository/handlers.d.ts +0 -373
- package/dist/tools/repository/handlers.js +0 -724
- package/dist/tools/repository/index.d.ts +0 -9
- package/dist/tools/repository/index.js +0 -13
- package/dist/tools/repository/schemas.d.ts +0 -153
- package/dist/tools/repository/schemas.js +0 -106
- package/dist/tools/repository/tools.d.ts +0 -7
- package/dist/tools/repository/tools.js +0 -484
- package/dist/tools/repository/validation.d.ts +0 -106
- package/dist/tools/repository/validation.js +0 -820
- package/dist/tools/repository.d.ts +0 -6
- package/dist/tools/repository.js +0 -7
- package/dist/tools/search.d.ts +0 -76
- package/dist/tools/search.js +0 -423
- package/dist/types/index.d.ts +0 -2
- package/dist/types/index.js +0 -2
- package/dist/types/mcp.d.ts +0 -187
- package/dist/types/mcp.js +0 -6
- package/dist/utils/cache.d.ts +0 -77
- package/dist/utils/cache.js +0 -172
- package/dist/utils/config.d.ts +0 -70
- package/dist/utils/config.js +0 -294
- package/dist/utils/errors.d.ts +0 -111
- package/dist/utils/errors.js +0 -165
- package/dist/utils/health.d.ts +0 -29
- package/dist/utils/health.js +0 -132
- package/dist/utils/hosted-api.d.ts +0 -67
- package/dist/utils/hosted-api.js +0 -119
- package/dist/utils/index.d.ts +0 -16
- package/dist/utils/index.js +0 -15
- package/dist/utils/logger.d.ts +0 -48
- package/dist/utils/logger.js +0 -124
- package/dist/utils/rate-limit.d.ts +0 -61
- package/dist/utils/rate-limit.js +0 -148
- package/dist/utils/validation.d.ts +0 -52
- package/dist/utils/validation.js +0 -255
|
@@ -1,724 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Repository handler functions
|
|
3
|
-
* Business logic for repository-related MCP tools
|
|
4
|
-
*/
|
|
5
|
-
import { githubClient } from "../../pipeline/index.js";
|
|
6
|
-
import { releaseTracker } from "../../pipeline/releases.js";
|
|
7
|
-
import { logger, DEFAULT_REPOSITORIES, SelfCorrectionHints, } from "../../utils/index.js";
|
|
8
|
-
import { sendProgressNotification } from "../../server.js";
|
|
9
|
-
import { REPO_ALIASES, EXAMPLES } from "./constants.js";
|
|
10
|
-
import { EMBEDDED_DOCS } from "../../resources/content/docs-content.js";
|
|
11
|
-
import { COMPACT_VERSION, RECOMMENDED_PRAGMA, REFERENCE_CONTRACTS, BUILTIN_FUNCTIONS, TYPE_COMPATIBILITY, LEDGER_TYPE_LIMITS, COMMON_ERRORS, } from "../../config/compact-version.js";
|
|
12
|
-
// Re-export validation handlers from validation.ts
|
|
13
|
-
export { extractContractStructure } from "./validation.js";
|
|
14
|
-
/**
|
|
15
|
-
* Resolve repository name alias to owner/repo
|
|
16
|
-
*/
|
|
17
|
-
export function resolveRepo(repoName) {
|
|
18
|
-
// Default to compact if not provided
|
|
19
|
-
const name = repoName || "compact";
|
|
20
|
-
const normalized = name.toLowerCase().replace(/^midnightntwrk\//, "");
|
|
21
|
-
const alias = REPO_ALIASES[normalized];
|
|
22
|
-
if (alias)
|
|
23
|
-
return alias;
|
|
24
|
-
// Try to find in configured repos
|
|
25
|
-
for (const config of DEFAULT_REPOSITORIES) {
|
|
26
|
-
if (config.repo.toLowerCase() === normalized) {
|
|
27
|
-
return { owner: config.owner, repo: config.repo };
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// Assume it's a full org/repo name
|
|
31
|
-
if (name.includes("/")) {
|
|
32
|
-
const [owner, repo] = name.split("/");
|
|
33
|
-
return { owner, repo };
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Retrieve a specific file from Midnight repositories
|
|
39
|
-
*/
|
|
40
|
-
export async function getFile(input) {
|
|
41
|
-
logger.debug("Getting file", { repo: input.repo, path: input.path });
|
|
42
|
-
const repoInfo = resolveRepo(input.repo);
|
|
43
|
-
if (!repoInfo) {
|
|
44
|
-
return SelfCorrectionHints.UNKNOWN_REPO(input.repo, Object.keys(REPO_ALIASES));
|
|
45
|
-
}
|
|
46
|
-
const file = await githubClient.getFileContent(repoInfo.owner, repoInfo.repo, input.path, input.ref);
|
|
47
|
-
if (!file) {
|
|
48
|
-
return SelfCorrectionHints.FILE_NOT_FOUND(input.path, `${repoInfo.owner}/${repoInfo.repo}`);
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
51
|
-
content: file.content,
|
|
52
|
-
path: file.path,
|
|
53
|
-
repository: `${repoInfo.owner}/${repoInfo.repo}`,
|
|
54
|
-
sha: file.sha,
|
|
55
|
-
size: file.size,
|
|
56
|
-
url: `https://github.com/${repoInfo.owner}/${repoInfo.repo}/blob/${input.ref || "main"}/${file.path}`,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* List available example contracts and DApps
|
|
61
|
-
*/
|
|
62
|
-
export async function listExamples(input) {
|
|
63
|
-
logger.debug("Listing examples", { category: input.category });
|
|
64
|
-
let filteredExamples = EXAMPLES;
|
|
65
|
-
if (input.category && input.category !== "all") {
|
|
66
|
-
filteredExamples = EXAMPLES.filter((e) => e.category === input.category);
|
|
67
|
-
}
|
|
68
|
-
return {
|
|
69
|
-
examples: filteredExamples.map((e) => ({
|
|
70
|
-
name: e.name,
|
|
71
|
-
repository: e.repository,
|
|
72
|
-
description: e.description,
|
|
73
|
-
complexity: e.complexity,
|
|
74
|
-
mainFile: e.mainFile,
|
|
75
|
-
features: e.features,
|
|
76
|
-
githubUrl: `https://github.com/${e.repository}`,
|
|
77
|
-
})),
|
|
78
|
-
totalCount: filteredExamples.length,
|
|
79
|
-
categories: [...new Set(EXAMPLES.map((e) => e.category))],
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Retrieve recent changes across Midnight repositories
|
|
84
|
-
*/
|
|
85
|
-
export async function getLatestUpdates(input) {
|
|
86
|
-
logger.debug("Getting latest updates", input);
|
|
87
|
-
// Default to last 7 days
|
|
88
|
-
const since = input.since || new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
|
|
89
|
-
const repos = input.repos?.map(resolveRepo).filter(Boolean) ||
|
|
90
|
-
DEFAULT_REPOSITORIES.map((r) => ({ owner: r.owner, repo: r.repo }));
|
|
91
|
-
const updates = [];
|
|
92
|
-
for (const repo of repos) {
|
|
93
|
-
if (!repo)
|
|
94
|
-
continue;
|
|
95
|
-
const commits = await githubClient.getRecentCommits(repo.owner, repo.repo, since, 10);
|
|
96
|
-
if (commits.length > 0) {
|
|
97
|
-
updates.push({
|
|
98
|
-
repository: `${repo.owner}/${repo.repo}`,
|
|
99
|
-
commits,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
// Sort by most recent commit
|
|
104
|
-
updates.sort((a, b) => {
|
|
105
|
-
const aDate = a.commits[0]?.date || "";
|
|
106
|
-
const bDate = b.commits[0]?.date || "";
|
|
107
|
-
return bDate.localeCompare(aDate);
|
|
108
|
-
});
|
|
109
|
-
// Generate summary
|
|
110
|
-
const totalCommits = updates.reduce((sum, u) => sum + u.commits.length, 0);
|
|
111
|
-
const activeRepos = updates.filter((u) => u.commits.length > 0).length;
|
|
112
|
-
return {
|
|
113
|
-
summary: {
|
|
114
|
-
since,
|
|
115
|
-
totalCommits,
|
|
116
|
-
activeRepositories: activeRepos,
|
|
117
|
-
checkedRepositories: repos.length,
|
|
118
|
-
},
|
|
119
|
-
updates: updates.map((u) => ({
|
|
120
|
-
repository: u.repository,
|
|
121
|
-
commitCount: u.commits.length,
|
|
122
|
-
latestCommit: u.commits[0]
|
|
123
|
-
? {
|
|
124
|
-
message: u.commits[0].message.split("\n")[0], // First line only
|
|
125
|
-
date: u.commits[0].date,
|
|
126
|
-
author: u.commits[0].author,
|
|
127
|
-
url: u.commits[0].url,
|
|
128
|
-
}
|
|
129
|
-
: null,
|
|
130
|
-
recentCommits: u.commits.slice(0, 5).map((c) => ({
|
|
131
|
-
message: c.message.split("\n")[0],
|
|
132
|
-
date: c.date,
|
|
133
|
-
sha: c.sha.substring(0, 7),
|
|
134
|
-
})),
|
|
135
|
-
})),
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Get version and release info for a repository
|
|
140
|
-
*/
|
|
141
|
-
export async function getVersionInfo(input) {
|
|
142
|
-
// Ensure repo defaults to compact if undefined/empty
|
|
143
|
-
const repoName = input?.repo || "compact";
|
|
144
|
-
logger.debug("Getting version info", { repo: repoName });
|
|
145
|
-
const resolved = resolveRepo(repoName);
|
|
146
|
-
if (!resolved) {
|
|
147
|
-
throw new Error(`Unknown repository: ${input.repo}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
148
|
-
}
|
|
149
|
-
const versionInfo = await releaseTracker.getVersionInfo(resolved.owner, resolved.repo);
|
|
150
|
-
return {
|
|
151
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
152
|
-
latestVersion: versionInfo.latestRelease?.tag || "No releases found",
|
|
153
|
-
latestStableVersion: versionInfo.latestStableRelease?.tag || "No stable releases",
|
|
154
|
-
publishedAt: versionInfo.latestRelease?.publishedAt || null,
|
|
155
|
-
releaseNotes: versionInfo.latestRelease?.body || null,
|
|
156
|
-
recentReleases: versionInfo.recentReleases.slice(0, 5).map((r) => ({
|
|
157
|
-
version: r.tag,
|
|
158
|
-
date: r.publishedAt.split("T")[0],
|
|
159
|
-
isPrerelease: r.isPrerelease,
|
|
160
|
-
url: r.url,
|
|
161
|
-
})),
|
|
162
|
-
recentBreakingChanges: versionInfo.changelog
|
|
163
|
-
.slice(0, 3)
|
|
164
|
-
.flatMap((c) => c.changes.breaking)
|
|
165
|
-
.slice(0, 10),
|
|
166
|
-
versionContext: releaseTracker.getVersionContext(versionInfo),
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Check for breaking changes since a specific version
|
|
171
|
-
*/
|
|
172
|
-
export async function checkBreakingChanges(input) {
|
|
173
|
-
// Ensure repo defaults to compact if undefined/empty
|
|
174
|
-
const repoName = input?.repo || "compact";
|
|
175
|
-
logger.debug("Checking breaking changes", {
|
|
176
|
-
repo: repoName,
|
|
177
|
-
currentVersion: input.currentVersion,
|
|
178
|
-
});
|
|
179
|
-
const resolved = resolveRepo(repoName);
|
|
180
|
-
if (!resolved) {
|
|
181
|
-
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
182
|
-
}
|
|
183
|
-
const outdatedInfo = await releaseTracker.isOutdated(resolved.owner, resolved.repo, input.currentVersion);
|
|
184
|
-
const breakingChanges = await releaseTracker.getBreakingChangesSince(resolved.owner, resolved.repo, input.currentVersion);
|
|
185
|
-
return {
|
|
186
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
187
|
-
currentVersion: input.currentVersion,
|
|
188
|
-
latestVersion: outdatedInfo.latestVersion,
|
|
189
|
-
isOutdated: outdatedInfo.isOutdated,
|
|
190
|
-
versionsBehind: outdatedInfo.versionsBehind,
|
|
191
|
-
hasBreakingChanges: outdatedInfo.hasBreakingChanges,
|
|
192
|
-
breakingChanges: breakingChanges,
|
|
193
|
-
recommendation: outdatedInfo.hasBreakingChanges
|
|
194
|
-
? `⚠️ Breaking changes detected! Review the ${breakingChanges.length} breaking change(s) before upgrading.`
|
|
195
|
-
: outdatedInfo.isOutdated
|
|
196
|
-
? `✅ Safe to upgrade. No breaking changes detected since ${input.currentVersion}.`
|
|
197
|
-
: `✅ You're on the latest version.`,
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Get migration guide between versions
|
|
202
|
-
*/
|
|
203
|
-
export async function getMigrationGuide(input) {
|
|
204
|
-
// Ensure repo defaults to compact if undefined/empty
|
|
205
|
-
const repoName = input?.repo || "compact";
|
|
206
|
-
logger.debug("Getting migration guide", {
|
|
207
|
-
repo: repoName,
|
|
208
|
-
fromVersion: input.fromVersion,
|
|
209
|
-
toVersion: input.toVersion,
|
|
210
|
-
});
|
|
211
|
-
const resolved = resolveRepo(repoName);
|
|
212
|
-
if (!resolved) {
|
|
213
|
-
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
214
|
-
}
|
|
215
|
-
const guide = await releaseTracker.getMigrationGuide(resolved.owner, resolved.repo, input.fromVersion, input.toVersion);
|
|
216
|
-
return {
|
|
217
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
218
|
-
from: guide.from,
|
|
219
|
-
to: guide.to,
|
|
220
|
-
summary: {
|
|
221
|
-
breakingChangesCount: guide.breakingChanges.length,
|
|
222
|
-
deprecationsCount: guide.deprecations.length,
|
|
223
|
-
newFeaturesCount: guide.newFeatures.length,
|
|
224
|
-
},
|
|
225
|
-
breakingChanges: guide.breakingChanges,
|
|
226
|
-
deprecations: guide.deprecations,
|
|
227
|
-
newFeatures: guide.newFeatures,
|
|
228
|
-
migrationSteps: guide.migrationSteps,
|
|
229
|
-
migrationDifficulty: guide.breakingChanges.length === 0
|
|
230
|
-
? "Easy - No breaking changes"
|
|
231
|
-
: guide.breakingChanges.length <= 3
|
|
232
|
-
? "Moderate - Few breaking changes"
|
|
233
|
-
: "Complex - Multiple breaking changes, plan carefully",
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Get a file at a specific version - critical for version-accurate recommendations
|
|
238
|
-
*/
|
|
239
|
-
export async function getFileAtVersion(input) {
|
|
240
|
-
// Ensure repo defaults to compact if undefined/empty
|
|
241
|
-
const repoName = input?.repo || "compact";
|
|
242
|
-
logger.debug("Getting file at version", {
|
|
243
|
-
repo: repoName,
|
|
244
|
-
path: input.path,
|
|
245
|
-
version: input.version,
|
|
246
|
-
});
|
|
247
|
-
const resolved = resolveRepo(repoName);
|
|
248
|
-
if (!resolved) {
|
|
249
|
-
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
250
|
-
}
|
|
251
|
-
const result = await releaseTracker.getFileAtVersion(resolved.owner, resolved.repo, input.path, input.version);
|
|
252
|
-
if (!result) {
|
|
253
|
-
throw new Error(`File not found: ${input.path} at version ${input.version} in ${repoName}`);
|
|
254
|
-
}
|
|
255
|
-
return {
|
|
256
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
257
|
-
path: input.path,
|
|
258
|
-
version: result.version,
|
|
259
|
-
content: result.content,
|
|
260
|
-
note: `This is the exact content at version ${result.version}. Use this as the source of truth for syntax and API at this version.`,
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Compare syntax between two versions - shows what changed
|
|
265
|
-
*/
|
|
266
|
-
export async function compareSyntax(input) {
|
|
267
|
-
// Ensure repo defaults to compact if undefined/empty
|
|
268
|
-
const repoName = input?.repo || "compact";
|
|
269
|
-
logger.debug("Comparing syntax between versions", {
|
|
270
|
-
repo: repoName,
|
|
271
|
-
oldVersion: input.oldVersion,
|
|
272
|
-
newVersion: input.newVersion,
|
|
273
|
-
});
|
|
274
|
-
const resolved = resolveRepo(repoName);
|
|
275
|
-
if (!resolved) {
|
|
276
|
-
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
277
|
-
}
|
|
278
|
-
// If no newVersion specified, get latest
|
|
279
|
-
let newVersion = input.newVersion;
|
|
280
|
-
if (!newVersion) {
|
|
281
|
-
const versionInfo = await releaseTracker.getVersionInfo(resolved.owner, resolved.repo);
|
|
282
|
-
newVersion =
|
|
283
|
-
versionInfo.latestStableRelease?.tag ||
|
|
284
|
-
versionInfo.latestRelease?.tag ||
|
|
285
|
-
"main";
|
|
286
|
-
}
|
|
287
|
-
const comparison = await releaseTracker.compareSyntax(resolved.owner, resolved.repo, input.path, input.oldVersion, newVersion);
|
|
288
|
-
return {
|
|
289
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
290
|
-
path: input.path,
|
|
291
|
-
oldVersion: comparison.oldVersion,
|
|
292
|
-
newVersion: comparison.newVersion,
|
|
293
|
-
hasDifferences: comparison.hasDifferences,
|
|
294
|
-
oldContent: comparison.oldContent,
|
|
295
|
-
newContent: comparison.newContent,
|
|
296
|
-
recommendation: comparison.hasDifferences
|
|
297
|
-
? `⚠️ This file has changed between ${comparison.oldVersion} and ${comparison.newVersion}. Review the differences before using code patterns from the old version.`
|
|
298
|
-
: `✅ No changes in this file between versions.`,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Get the latest syntax reference for Compact language
|
|
303
|
-
* This is the source of truth for writing valid, compilable contracts
|
|
304
|
-
*/
|
|
305
|
-
export async function getLatestSyntax(input) {
|
|
306
|
-
// Ensure repo defaults to compact if undefined/empty
|
|
307
|
-
const repoName = input?.repo || "compact";
|
|
308
|
-
logger.debug("Getting latest syntax reference", { repo: repoName });
|
|
309
|
-
// For Compact language, always return our curated reference first
|
|
310
|
-
// This is more reliable than fetching from GitHub and includes pitfalls/patterns
|
|
311
|
-
if (repoName === "compact" || repoName === "midnight-compact") {
|
|
312
|
-
const compactReference = EMBEDDED_DOCS["midnight://docs/compact-reference"];
|
|
313
|
-
// Check if there's a newer release we might not have documented
|
|
314
|
-
// Version config is centralized in src/config/compact-version.ts
|
|
315
|
-
let versionWarning;
|
|
316
|
-
try {
|
|
317
|
-
const versionInfo = await releaseTracker.getVersionInfo("midnightntwrk", "compact");
|
|
318
|
-
const latestTag = versionInfo.latestStableRelease?.tag || versionInfo.latestRelease?.tag;
|
|
319
|
-
if (latestTag) {
|
|
320
|
-
// Extract version number from tag (e.g., "v0.18.0" -> "0.18")
|
|
321
|
-
const latestVersion = latestTag
|
|
322
|
-
.replace(/^v/, "")
|
|
323
|
-
.split(".")
|
|
324
|
-
.slice(0, 2)
|
|
325
|
-
.join(".");
|
|
326
|
-
if (latestVersion !== COMPACT_VERSION.max &&
|
|
327
|
-
parseFloat(latestVersion) > parseFloat(COMPACT_VERSION.max)) {
|
|
328
|
-
versionWarning = `⚠️ Compact ${latestTag} is available. This reference is based on ${COMPACT_VERSION.max}. Some syntax may have changed - check release notes for breaking changes. See docs/SYNTAX_MAINTENANCE.md for update instructions.`;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
catch {
|
|
333
|
-
// Ignore version check errors, still return cached docs
|
|
334
|
-
}
|
|
335
|
-
if (compactReference) {
|
|
336
|
-
return {
|
|
337
|
-
repository: "midnightntwrk/compact",
|
|
338
|
-
version: `${COMPACT_VERSION.min}-${COMPACT_VERSION.max} (current)`,
|
|
339
|
-
versionConfig: {
|
|
340
|
-
min: COMPACT_VERSION.min,
|
|
341
|
-
max: COMPACT_VERSION.max,
|
|
342
|
-
lastUpdated: COMPACT_VERSION.lastUpdated,
|
|
343
|
-
maintenanceGuide: "See docs/SYNTAX_MAINTENANCE.md for update instructions",
|
|
344
|
-
},
|
|
345
|
-
...(versionWarning && { versionWarning }),
|
|
346
|
-
// Quick start template - ALWAYS compiles
|
|
347
|
-
quickStartTemplate: `${RECOMMENDED_PRAGMA}
|
|
348
|
-
|
|
349
|
-
import CompactStandardLibrary;
|
|
350
|
-
|
|
351
|
-
export ledger counter: Counter;
|
|
352
|
-
export ledger owner: Bytes<32>;
|
|
353
|
-
|
|
354
|
-
witness local_secret_key(): Bytes<32>;
|
|
355
|
-
|
|
356
|
-
export circuit increment(): [] {
|
|
357
|
-
counter.increment(1);
|
|
358
|
-
}`,
|
|
359
|
-
// Built-in functions vs patterns (CRITICAL knowledge)
|
|
360
|
-
builtinFunctions: BUILTIN_FUNCTIONS,
|
|
361
|
-
// Type compatibility rules
|
|
362
|
-
typeCompatibility: TYPE_COMPATIBILITY,
|
|
363
|
-
// Ledger type limitations in circuits
|
|
364
|
-
ledgerTypeLimits: LEDGER_TYPE_LIMITS,
|
|
365
|
-
// Common compilation errors with fixes
|
|
366
|
-
commonErrors: COMMON_ERRORS,
|
|
367
|
-
// Common mistakes that cause compilation failures
|
|
368
|
-
commonMistakes: [
|
|
369
|
-
{
|
|
370
|
-
wrong: "ledger { field: Type; }",
|
|
371
|
-
correct: "export ledger field: Type;",
|
|
372
|
-
error: 'parse error: found "{" looking for an identifier',
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
wrong: "circuit fn(): Void",
|
|
376
|
-
correct: "circuit fn(): []",
|
|
377
|
-
error: 'parse error: found "{" looking for ";"',
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
wrong: "pragma language_version >= 0.14.0;",
|
|
381
|
-
correct: RECOMMENDED_PRAGMA,
|
|
382
|
-
error: "version mismatch or parse error",
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
wrong: "enum State { a, b }",
|
|
386
|
-
correct: "export enum State { a, b }",
|
|
387
|
-
error: "enum not accessible from TypeScript",
|
|
388
|
-
},
|
|
389
|
-
{
|
|
390
|
-
wrong: "if (witness_val == x)",
|
|
391
|
-
correct: "if (disclose(witness_val == x))",
|
|
392
|
-
error: "implicit disclosure error",
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
wrong: "Cell<Field>",
|
|
396
|
-
correct: "Field",
|
|
397
|
-
error: "unbound identifier Cell (deprecated)",
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
wrong: "public_key(sk)",
|
|
401
|
-
correct: 'persistentHash<Vector<2, Bytes<32>>>([pad(32, "midnight:pk:"), sk])',
|
|
402
|
-
error: 'unbound identifier "public_key"',
|
|
403
|
-
},
|
|
404
|
-
{
|
|
405
|
-
wrong: "counter.value()",
|
|
406
|
-
correct: "// Read via witness or TypeScript SDK",
|
|
407
|
-
error: 'operation "value" undefined for Counter',
|
|
408
|
-
},
|
|
409
|
-
{
|
|
410
|
-
wrong: "Choice::rock (Rust-style)",
|
|
411
|
-
correct: "Choice.rock (dot notation)",
|
|
412
|
-
error: 'parse error: found ":" looking for ")"',
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
wrong: "witness fn(): T { ... }",
|
|
416
|
-
correct: "witness fn(): T; // declaration only, no body",
|
|
417
|
-
error: "parse error after witness declaration",
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
wrong: "pure function helper(): T",
|
|
421
|
-
correct: "pure circuit helper(): T",
|
|
422
|
-
error: 'unbound identifier "function"',
|
|
423
|
-
},
|
|
424
|
-
{
|
|
425
|
-
wrong: "amount as Bytes<32> // direct Uint to Bytes",
|
|
426
|
-
correct: "(amount as Field) as Bytes<32> // go through Field",
|
|
427
|
-
error: "cannot cast from type Uint<64> to type Bytes<32>",
|
|
428
|
-
},
|
|
429
|
-
{
|
|
430
|
-
wrong: "ledger.insert(key, a + b) // arithmetic result",
|
|
431
|
-
correct: "ledger.insert(key, (a + b) as Uint<64>) // cast result",
|
|
432
|
-
error: "expected type Uint<64> but received Uint<0..N>",
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
wrong: "export circuit fn(param: T): [] { ledger.insert(param, v); }",
|
|
436
|
-
correct: "export circuit fn(param: T): [] { const d = disclose(param); ledger.insert(d, v); }",
|
|
437
|
-
error: "potential witness-value disclosure must be declared",
|
|
438
|
-
},
|
|
439
|
-
],
|
|
440
|
-
syntaxReference: compactReference,
|
|
441
|
-
sections: [
|
|
442
|
-
"Quick Start Template",
|
|
443
|
-
"Pragma (Version Declaration)",
|
|
444
|
-
"Imports",
|
|
445
|
-
"Ledger Declarations",
|
|
446
|
-
"Data Types",
|
|
447
|
-
"Built-in Functions",
|
|
448
|
-
"Type Compatibility",
|
|
449
|
-
"Ledger Type Limits",
|
|
450
|
-
"Circuits",
|
|
451
|
-
"Witnesses",
|
|
452
|
-
"Constructor",
|
|
453
|
-
"Common Patterns",
|
|
454
|
-
"Common Operations",
|
|
455
|
-
"Assertions",
|
|
456
|
-
"Common Mistakes to Avoid",
|
|
457
|
-
"Common Errors & Fixes",
|
|
458
|
-
"Exports for TypeScript",
|
|
459
|
-
"Reference Contracts",
|
|
460
|
-
],
|
|
461
|
-
referenceContracts: REFERENCE_CONTRACTS.map((rc) => ({
|
|
462
|
-
name: rc.name,
|
|
463
|
-
repo: rc.repo,
|
|
464
|
-
description: rc.description,
|
|
465
|
-
})),
|
|
466
|
-
note: `⚠️ CALL THIS TOOL BEFORE generating ANY Compact code!
|
|
467
|
-
Use quickStartTemplate as your base. Check commonMistakes BEFORE submitting code.
|
|
468
|
-
|
|
469
|
-
KEY RULES:
|
|
470
|
-
1. public_key() is NOT a builtin - use persistentHash pattern
|
|
471
|
-
2. Counter.value() NOT available in circuits - use witnesses
|
|
472
|
-
3. Map.lookup()/Set.member() ARE available in circuits (verified)
|
|
473
|
-
4. Arithmetic results need casting: (a + b) as Uint<64>
|
|
474
|
-
5. Uint→Bytes needs two casts: (amount as Field) as Bytes<32>
|
|
475
|
-
6. Circuit params touching ledger need disclose(): const d = disclose(param);
|
|
476
|
-
|
|
477
|
-
Compact is NOT TypeScript - don't guess syntax, use this reference!
|
|
478
|
-
Version: ${COMPACT_VERSION.min}-${COMPACT_VERSION.max} (updated: ${COMPACT_VERSION.lastUpdated}).`,
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
const resolved = resolveRepo(repoName);
|
|
483
|
-
if (!resolved) {
|
|
484
|
-
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
485
|
-
}
|
|
486
|
-
const reference = await releaseTracker.getLatestSyntaxReference(resolved.owner, resolved.repo);
|
|
487
|
-
if (!reference || reference.syntaxFiles.length === 0) {
|
|
488
|
-
// Fallback: get example contracts as syntax reference
|
|
489
|
-
const versionInfo = await releaseTracker.getVersionInfo(resolved.owner, resolved.repo);
|
|
490
|
-
const version = versionInfo.latestStableRelease?.tag || "main";
|
|
491
|
-
return {
|
|
492
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
493
|
-
version,
|
|
494
|
-
warning: "No grammar documentation found. Use example contracts as reference.",
|
|
495
|
-
syntaxFiles: [],
|
|
496
|
-
examplePaths: ["examples/", "test/", "contracts/"],
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
return {
|
|
500
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
501
|
-
version: reference.version,
|
|
502
|
-
syntaxFiles: reference.syntaxFiles.map((f) => ({
|
|
503
|
-
path: f.path,
|
|
504
|
-
content: f.content,
|
|
505
|
-
})),
|
|
506
|
-
note: `This is the authoritative syntax reference at version ${reference.version}. Use this to ensure contracts are compilable.`,
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
// ============================================================================
|
|
510
|
-
// COMPOUND TOOLS - Reduce multiple API calls to single operations
|
|
511
|
-
// These tools combine related operations to minimize round-trips and token usage
|
|
512
|
-
// ============================================================================
|
|
513
|
-
/**
|
|
514
|
-
* Compound tool: Full upgrade check
|
|
515
|
-
* Combines: getVersionInfo + checkBreakingChanges + getMigrationGuide
|
|
516
|
-
* Reduces 3 tool calls to 1, saving ~60% tokens
|
|
517
|
-
*/
|
|
518
|
-
export async function upgradeCheck(input) {
|
|
519
|
-
const repoName = input?.repo || "compact";
|
|
520
|
-
const currentVersion = input.currentVersion;
|
|
521
|
-
const progressToken = input._meta?.progressToken;
|
|
522
|
-
logger.debug("Running compound upgrade check", {
|
|
523
|
-
repo: repoName,
|
|
524
|
-
currentVersion,
|
|
525
|
-
});
|
|
526
|
-
const resolved = resolveRepo(repoName);
|
|
527
|
-
if (!resolved) {
|
|
528
|
-
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
529
|
-
}
|
|
530
|
-
// Send progress: Starting
|
|
531
|
-
if (progressToken) {
|
|
532
|
-
sendProgressNotification(progressToken, 1, 4, "Fetching version info...");
|
|
533
|
-
}
|
|
534
|
-
// Fetch all data in parallel
|
|
535
|
-
const [versionInfo, outdatedInfo, breakingChanges] = await Promise.all([
|
|
536
|
-
releaseTracker.getVersionInfo(resolved.owner, resolved.repo),
|
|
537
|
-
releaseTracker.isOutdated(resolved.owner, resolved.repo, currentVersion),
|
|
538
|
-
releaseTracker.getBreakingChangesSince(resolved.owner, resolved.repo, currentVersion),
|
|
539
|
-
]);
|
|
540
|
-
// Send progress: Fetched version data
|
|
541
|
-
if (progressToken) {
|
|
542
|
-
sendProgressNotification(progressToken, 2, 4, "Checking breaking changes...");
|
|
543
|
-
}
|
|
544
|
-
const latestVersion = versionInfo.latestStableRelease?.tag || versionInfo.latestRelease?.tag;
|
|
545
|
-
// Only fetch migration guide if there are breaking changes
|
|
546
|
-
let migrationGuide = null;
|
|
547
|
-
if (breakingChanges.length > 0 && latestVersion) {
|
|
548
|
-
// Send progress: Fetching migration guide
|
|
549
|
-
if (progressToken) {
|
|
550
|
-
sendProgressNotification(progressToken, 3, 4, "Generating migration guide...");
|
|
551
|
-
}
|
|
552
|
-
migrationGuide = await releaseTracker.getMigrationGuide(resolved.owner, resolved.repo, currentVersion, latestVersion);
|
|
553
|
-
}
|
|
554
|
-
// Send progress: Complete
|
|
555
|
-
if (progressToken) {
|
|
556
|
-
sendProgressNotification(progressToken, 4, 4, "Analysis complete");
|
|
557
|
-
}
|
|
558
|
-
// Compute upgrade urgency
|
|
559
|
-
const urgency = computeUpgradeUrgency(outdatedInfo, breakingChanges.length);
|
|
560
|
-
return {
|
|
561
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
562
|
-
currentVersion,
|
|
563
|
-
// Version summary
|
|
564
|
-
version: {
|
|
565
|
-
latest: latestVersion || "No releases",
|
|
566
|
-
latestStable: versionInfo.latestStableRelease?.tag || "No stable releases",
|
|
567
|
-
publishedAt: versionInfo.latestRelease?.publishedAt || null,
|
|
568
|
-
isOutdated: outdatedInfo.isOutdated,
|
|
569
|
-
versionsBehind: outdatedInfo.versionsBehind,
|
|
570
|
-
},
|
|
571
|
-
// Breaking changes summary
|
|
572
|
-
breakingChanges: {
|
|
573
|
-
count: breakingChanges.length,
|
|
574
|
-
hasBreakingChanges: breakingChanges.length > 0,
|
|
575
|
-
items: breakingChanges.slice(0, 10), // Limit to avoid token bloat
|
|
576
|
-
},
|
|
577
|
-
// Migration guide (only if needed)
|
|
578
|
-
migration: migrationGuide
|
|
579
|
-
? {
|
|
580
|
-
steps: migrationGuide.migrationSteps,
|
|
581
|
-
deprecations: migrationGuide.deprecations,
|
|
582
|
-
newFeatures: migrationGuide.newFeatures.slice(0, 5),
|
|
583
|
-
}
|
|
584
|
-
: null,
|
|
585
|
-
// Actionable recommendation
|
|
586
|
-
urgency,
|
|
587
|
-
recommendation: generateUpgradeRecommendation(urgency, breakingChanges.length, outdatedInfo),
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* Compound tool: Full repository context
|
|
592
|
-
* Combines: getVersionInfo + getLatestSyntax + listExamples (filtered)
|
|
593
|
-
* Provides everything needed to start working with a repo
|
|
594
|
-
*/
|
|
595
|
-
export async function getFullRepoContext(input) {
|
|
596
|
-
const repoName = input?.repo || "compact";
|
|
597
|
-
const progressToken = input._meta?.progressToken;
|
|
598
|
-
logger.debug("Getting full repo context", { repo: repoName });
|
|
599
|
-
const resolved = resolveRepo(repoName);
|
|
600
|
-
if (!resolved) {
|
|
601
|
-
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
602
|
-
}
|
|
603
|
-
// Send progress: Starting
|
|
604
|
-
if (progressToken) {
|
|
605
|
-
sendProgressNotification(progressToken, 1, 4, "Fetching version info...");
|
|
606
|
-
}
|
|
607
|
-
// Fetch version info
|
|
608
|
-
const versionInfo = await releaseTracker.getVersionInfo(resolved.owner, resolved.repo);
|
|
609
|
-
const version = versionInfo.latestStableRelease?.tag ||
|
|
610
|
-
versionInfo.latestRelease?.tag ||
|
|
611
|
-
"main";
|
|
612
|
-
// Send progress: Fetched version
|
|
613
|
-
if (progressToken) {
|
|
614
|
-
sendProgressNotification(progressToken, 2, 4, "Loading syntax reference...");
|
|
615
|
-
}
|
|
616
|
-
// Conditionally fetch syntax reference
|
|
617
|
-
let syntaxRef = null;
|
|
618
|
-
if (input.includeSyntax !== false) {
|
|
619
|
-
syntaxRef = await releaseTracker.getLatestSyntaxReference(resolved.owner, resolved.repo);
|
|
620
|
-
}
|
|
621
|
-
// Send progress: Loading examples
|
|
622
|
-
if (progressToken) {
|
|
623
|
-
sendProgressNotification(progressToken, 3, 4, "Gathering examples...");
|
|
624
|
-
}
|
|
625
|
-
// Get relevant examples for this repo
|
|
626
|
-
let examples = [];
|
|
627
|
-
if (input.includeExamples !== false) {
|
|
628
|
-
// Filter examples relevant to this repo type
|
|
629
|
-
const repoType = getRepoType(repoName);
|
|
630
|
-
examples = EXAMPLES.filter((ex) => repoType === "all" || ex.category === repoType || repoType === "compact")
|
|
631
|
-
.slice(0, 5)
|
|
632
|
-
.map((ex) => ({
|
|
633
|
-
name: ex.name,
|
|
634
|
-
description: ex.description,
|
|
635
|
-
complexity: ex.complexity,
|
|
636
|
-
}));
|
|
637
|
-
}
|
|
638
|
-
// Send progress: Complete
|
|
639
|
-
if (progressToken) {
|
|
640
|
-
sendProgressNotification(progressToken, 4, 4, "Context ready");
|
|
641
|
-
}
|
|
642
|
-
return {
|
|
643
|
-
repository: `${resolved.owner}/${resolved.repo}`,
|
|
644
|
-
// Quick start info
|
|
645
|
-
quickStart: {
|
|
646
|
-
version,
|
|
647
|
-
installCommand: getInstallCommand(repoName, version),
|
|
648
|
-
docsUrl: `https://github.com/${resolved.owner}/${resolved.repo}`,
|
|
649
|
-
},
|
|
650
|
-
// Version context
|
|
651
|
-
version: {
|
|
652
|
-
current: version,
|
|
653
|
-
stable: versionInfo.latestStableRelease?.tag || null,
|
|
654
|
-
publishedAt: versionInfo.latestRelease?.publishedAt || null,
|
|
655
|
-
recentReleases: versionInfo.recentReleases.slice(0, 3).map((r) => ({
|
|
656
|
-
tag: r.tag,
|
|
657
|
-
date: r.publishedAt.split("T")[0],
|
|
658
|
-
})),
|
|
659
|
-
},
|
|
660
|
-
// Syntax reference (condensed)
|
|
661
|
-
syntax: syntaxRef
|
|
662
|
-
? {
|
|
663
|
-
version: syntaxRef.version,
|
|
664
|
-
files: syntaxRef.syntaxFiles.map((f) => f.path),
|
|
665
|
-
// Include first file content as primary reference
|
|
666
|
-
primaryReference: syntaxRef.syntaxFiles[0]?.content?.slice(0, 2000) || null,
|
|
667
|
-
}
|
|
668
|
-
: null,
|
|
669
|
-
// Relevant examples
|
|
670
|
-
examples,
|
|
671
|
-
note: `Use this context to write ${repoName} code at version ${version}. For detailed syntax, use midnight-get-latest-syntax.`,
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
// Helper functions for compound tools
|
|
675
|
-
function computeUpgradeUrgency(outdatedInfo, breakingCount) {
|
|
676
|
-
if (!outdatedInfo.isOutdated)
|
|
677
|
-
return "none";
|
|
678
|
-
if (breakingCount === 0 && outdatedInfo.versionsBehind <= 2)
|
|
679
|
-
return "low";
|
|
680
|
-
if (breakingCount <= 2 && outdatedInfo.versionsBehind <= 5)
|
|
681
|
-
return "medium";
|
|
682
|
-
if (breakingCount <= 5)
|
|
683
|
-
return "high";
|
|
684
|
-
return "critical";
|
|
685
|
-
}
|
|
686
|
-
function generateUpgradeRecommendation(urgency, breakingCount, outdatedInfo) {
|
|
687
|
-
switch (urgency) {
|
|
688
|
-
case "none":
|
|
689
|
-
return "✅ You're on the latest version. No action needed.";
|
|
690
|
-
case "low":
|
|
691
|
-
return `📦 Minor update available (${outdatedInfo.versionsBehind} versions behind). Safe to upgrade at your convenience.`;
|
|
692
|
-
case "medium":
|
|
693
|
-
return `⚠️ Update recommended. ${breakingCount} breaking change(s) to review. Plan upgrade within 2 weeks.`;
|
|
694
|
-
case "high":
|
|
695
|
-
return `🔶 Important update. ${breakingCount} breaking changes require attention. Schedule upgrade soon.`;
|
|
696
|
-
case "critical":
|
|
697
|
-
return `🚨 Critical update needed! ${breakingCount} breaking changes and ${outdatedInfo.versionsBehind} versions behind. Upgrade immediately.`;
|
|
698
|
-
default:
|
|
699
|
-
return "Check the breaking changes and plan your upgrade.";
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
function getRepoType(repoName) {
|
|
703
|
-
const name = repoName.toLowerCase();
|
|
704
|
-
if (name.includes("counter"))
|
|
705
|
-
return "counter";
|
|
706
|
-
if (name.includes("bboard"))
|
|
707
|
-
return "bboard";
|
|
708
|
-
if (name.includes("token") || name.includes("dex"))
|
|
709
|
-
return "token";
|
|
710
|
-
if (name.includes("voting"))
|
|
711
|
-
return "voting";
|
|
712
|
-
return "all";
|
|
713
|
-
}
|
|
714
|
-
function getInstallCommand(repoName, version) {
|
|
715
|
-
const name = repoName.toLowerCase();
|
|
716
|
-
if (name === "compact" || name.includes("compact")) {
|
|
717
|
-
return `npx @aspect-sh/pnpm dlx @midnight-ntwrk/create-midnight-app@${version}`;
|
|
718
|
-
}
|
|
719
|
-
if (name === "midnight-js" || name.includes("js")) {
|
|
720
|
-
return `npm install @midnight-ntwrk/midnight-js@${version}`;
|
|
721
|
-
}
|
|
722
|
-
return `git clone https://github.com/midnight-ntwrk/${repoName}.git && cd ${repoName} && git checkout ${version}`;
|
|
723
|
-
}
|
|
724
|
-
//# sourceMappingURL=handlers.js.map
|