midnight-mcp 0.2.12 → 0.2.14

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.
@@ -25,7 +25,7 @@ import {
25
25
  validateNumber,
26
26
  validateQuery,
27
27
  vectorStore
28
- } from "./chunk-B6UJ7ZQY.js";
28
+ } from "./chunk-WYQRVPIQ.js";
29
29
 
30
30
  // src/tools/search/schemas.ts
31
31
  import { z } from "zod";
@@ -733,6 +733,144 @@ var AnalyzeContractInputSchema = z2.object({
733
733
  var ExplainCircuitInputSchema = z2.object({
734
734
  circuitCode: z2.string().describe("Circuit definition from Compact")
735
735
  });
736
+ var CompileContractInputSchema = z2.object({
737
+ code: z2.string().describe("Compact contract source code to compile"),
738
+ skipZk: z2.boolean().optional().default(true).describe(
739
+ "Skip ZK circuit generation for faster syntax-only validation (default: true)"
740
+ ),
741
+ fullCompile: z2.boolean().optional().default(false).describe(
742
+ "Perform full compilation including ZK generation (slower but complete)"
743
+ )
744
+ });
745
+
746
+ // src/services/compiler.ts
747
+ var COMPILER_API_URL = process.env.COMPACT_COMPILER_URL || "https://compact-playground.onrender.com";
748
+ var COMPILER_TIMEOUT = 3e4;
749
+ var MAX_CODE_SIZE = 100 * 1024;
750
+ async function compileContract(code, options = {}) {
751
+ if (!code || typeof code !== "string") {
752
+ return {
753
+ success: false,
754
+ message: "No code provided",
755
+ error: "INVALID_INPUT",
756
+ serviceAvailable: true
757
+ };
758
+ }
759
+ if (code.length > MAX_CODE_SIZE) {
760
+ return {
761
+ success: false,
762
+ message: `Code exceeds maximum size of ${MAX_CODE_SIZE / 1024}KB`,
763
+ error: "CODE_TOO_LARGE",
764
+ serviceAvailable: true
765
+ };
766
+ }
767
+ try {
768
+ const controller = new AbortController();
769
+ const timeoutId = setTimeout(() => controller.abort(), COMPILER_TIMEOUT);
770
+ const requestBody = {
771
+ code,
772
+ options: {
773
+ wrapWithDefaults: options.wrapWithDefaults ?? true,
774
+ skipZk: options.skipZk ?? true
775
+ // Default to fast syntax-only validation
776
+ }
777
+ };
778
+ logger.info("Sending code to compiler service", {
779
+ codeLength: code.length,
780
+ options: requestBody.options
781
+ });
782
+ const response = await fetch(`${COMPILER_API_URL}/compile`, {
783
+ method: "POST",
784
+ headers: {
785
+ "Content-Type": "application/json"
786
+ },
787
+ body: JSON.stringify(requestBody),
788
+ signal: controller.signal
789
+ });
790
+ clearTimeout(timeoutId);
791
+ if (!response.ok) {
792
+ const errorText = await response.text().catch(() => "Unknown error");
793
+ logger.error("Compiler API returned error status", {
794
+ status: response.status,
795
+ error: errorText
796
+ });
797
+ return {
798
+ success: false,
799
+ message: `Compiler service error: ${response.status}`,
800
+ error: "API_ERROR",
801
+ serviceAvailable: response.status < 500
802
+ };
803
+ }
804
+ const result = await response.json();
805
+ if (result.success) {
806
+ const outputInfo = typeof result.output === "object" && result.output !== null ? result.output : {};
807
+ logger.info("Compilation successful", {
808
+ compilerVersion: result.compilerVersion,
809
+ executionTime: result.executionTime,
810
+ circuits: outputInfo.circuits?.length || 0,
811
+ warnings: result.warnings?.length || 0
812
+ });
813
+ const version = result.compilerVersion || "unknown";
814
+ const execTime = result.executionTime ? ` in ${result.executionTime}ms` : "";
815
+ return {
816
+ success: true,
817
+ compilerVersion: version,
818
+ message: `\u2705 Compilation successful (Compiler v${version})${execTime}`,
819
+ circuits: outputInfo.circuits || [],
820
+ ledgerFields: outputInfo.ledgerFields || [],
821
+ exports: outputInfo.exports || [],
822
+ warnings: result.warnings || [],
823
+ serviceAvailable: true
824
+ };
825
+ } else {
826
+ const errors = result.errors || [];
827
+ const firstError = errors[0];
828
+ logger.info("Compilation failed", {
829
+ error: result.error,
830
+ errorCount: errors.length,
831
+ output: result.output,
832
+ firstError
833
+ });
834
+ let errorMessage = result.output || result.message || result.error || "Compilation failed";
835
+ if (firstError) {
836
+ errorMessage = `Line ${firstError.line}:${firstError.column} - ${firstError.message}`;
837
+ }
838
+ return {
839
+ success: false,
840
+ message: errorMessage,
841
+ error: result.error || "COMPILE_ERROR",
842
+ errors,
843
+ errorDetails: firstError ? {
844
+ line: firstError.line,
845
+ column: firstError.column,
846
+ errorType: firstError.severity
847
+ } : result.details,
848
+ serviceAvailable: true
849
+ };
850
+ }
851
+ } catch (error) {
852
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
853
+ if (error instanceof Error && error.name === "AbortError") {
854
+ logger.warn("Compiler request timed out");
855
+ return {
856
+ success: false,
857
+ message: "Compilation timed out - the contract may be too complex",
858
+ error: "TIMEOUT",
859
+ serviceAvailable: true
860
+ };
861
+ }
862
+ logger.error("Compiler service request failed", { error: errorMessage });
863
+ return {
864
+ success: false,
865
+ message: `Failed to connect to compiler service: ${errorMessage}`,
866
+ error: "CONNECTION_FAILED",
867
+ serviceAvailable: false
868
+ };
869
+ }
870
+ }
871
+ function getCompilerUrl() {
872
+ return COMPILER_API_URL;
873
+ }
736
874
 
737
875
  // src/tools/analyze/handlers.ts
738
876
  async function analyzeContract(input) {
@@ -954,6 +1092,86 @@ function getPrivacyConsiderations(circuit) {
954
1092
  }
955
1093
  return considerations;
956
1094
  }
1095
+ async function compileContract2(input) {
1096
+ logger.info("Compiling Compact contract via hosted service", {
1097
+ codeLength: input.code.length,
1098
+ skipZk: input.skipZk,
1099
+ fullCompile: input.fullCompile
1100
+ });
1101
+ const skipZk = input.fullCompile ? false : input.skipZk ?? true;
1102
+ const result = await compileContract(input.code, {
1103
+ wrapWithDefaults: true,
1104
+ skipZk
1105
+ });
1106
+ if (result.success) {
1107
+ return {
1108
+ success: true,
1109
+ message: result.message,
1110
+ compilerVersion: result.compilerVersion,
1111
+ compilationMode: skipZk ? "syntax-only" : "full",
1112
+ validationType: "compiler",
1113
+ output: {
1114
+ circuits: result.circuits || [],
1115
+ ledgerFields: result.ledgerFields || [],
1116
+ exports: result.exports || []
1117
+ },
1118
+ warnings: result.warnings || [],
1119
+ serviceUrl: getCompilerUrl()
1120
+ };
1121
+ } else {
1122
+ if (!result.serviceAvailable) {
1123
+ logger.warn(
1124
+ "Compiler service unavailable, falling back to static analysis",
1125
+ { error: result.error }
1126
+ );
1127
+ const staticResult = await analyzeContract({
1128
+ code: input.code,
1129
+ checkSecurity: true
1130
+ });
1131
+ const securityWarnings = (staticResult.securityFindings || []).map(
1132
+ (f) => `[${f.severity}] ${f.message}`
1133
+ );
1134
+ return {
1135
+ success: true,
1136
+ // Static analysis succeeded
1137
+ message: "Static analysis completed (compiler service unavailable)",
1138
+ validationType: "static-analysis-fallback",
1139
+ compilationMode: "none",
1140
+ serviceAvailable: false,
1141
+ serviceUrl: getCompilerUrl(),
1142
+ fallbackReason: result.message,
1143
+ warnings: securityWarnings,
1144
+ staticAnalysis: {
1145
+ summary: staticResult.summary,
1146
+ structure: staticResult.structure,
1147
+ securityFindings: staticResult.securityFindings,
1148
+ recommendations: staticResult.recommendations
1149
+ }
1150
+ };
1151
+ }
1152
+ const errorInfo = {
1153
+ success: false,
1154
+ message: result.message,
1155
+ error: result.error,
1156
+ validationType: "compiler",
1157
+ serviceAvailable: result.serviceAvailable,
1158
+ serviceUrl: getCompilerUrl()
1159
+ };
1160
+ if (result.errorDetails) {
1161
+ errorInfo.location = {
1162
+ line: result.errorDetails.line,
1163
+ column: result.errorDetails.column,
1164
+ errorType: result.errorDetails.errorType
1165
+ };
1166
+ }
1167
+ if (result.error === "TIMEOUT") {
1168
+ errorInfo.hint = "The contract may be too complex. Try simplifying or breaking it into smaller pieces.";
1169
+ } else if (result.errorDetails?.line) {
1170
+ errorInfo.hint = `Check line ${result.errorDetails.line} for the issue.`;
1171
+ }
1172
+ return errorInfo;
1173
+ }
1174
+ }
957
1175
 
958
1176
  // src/tools/analyze/tools.ts
959
1177
  var analyzeContractOutputSchema = {
@@ -1098,6 +1316,99 @@ var explainCircuitOutputSchema = {
1098
1316
  ],
1099
1317
  description: "Detailed circuit explanation with privacy analysis"
1100
1318
  };
1319
+ var compileContractOutputSchema = {
1320
+ type: "object",
1321
+ properties: {
1322
+ success: {
1323
+ type: "boolean",
1324
+ description: "Whether compilation/validation succeeded"
1325
+ },
1326
+ message: {
1327
+ type: "string",
1328
+ description: "Human-readable status message"
1329
+ },
1330
+ validationType: {
1331
+ type: "string",
1332
+ enum: ["compiler", "static-analysis-fallback"],
1333
+ description: "Type of validation performed - compiler (real) or static-analysis-fallback (when service unavailable)"
1334
+ },
1335
+ compilerVersion: {
1336
+ type: "string",
1337
+ description: "Version of the Compact compiler used (if available)"
1338
+ },
1339
+ compilationMode: {
1340
+ type: "string",
1341
+ enum: ["syntax-only", "full", "none"],
1342
+ description: "Type of compilation performed"
1343
+ },
1344
+ output: {
1345
+ type: "object",
1346
+ properties: {
1347
+ circuits: {
1348
+ type: "array",
1349
+ items: { type: "string" },
1350
+ description: "List of compiled circuits"
1351
+ },
1352
+ ledgerFields: {
1353
+ type: "array",
1354
+ items: { type: "string" },
1355
+ description: "List of ledger fields"
1356
+ },
1357
+ exports: {
1358
+ type: "array",
1359
+ items: { type: "string" },
1360
+ description: "List of exported symbols"
1361
+ }
1362
+ }
1363
+ },
1364
+ warnings: {
1365
+ type: "array",
1366
+ items: { type: "string" },
1367
+ description: "Compiler warnings or fallback warnings"
1368
+ },
1369
+ error: {
1370
+ type: "string",
1371
+ description: "Error code if compilation failed"
1372
+ },
1373
+ location: {
1374
+ type: "object",
1375
+ properties: {
1376
+ line: { type: "number" },
1377
+ column: { type: "number" },
1378
+ errorType: { type: "string" }
1379
+ },
1380
+ description: "Location of error if applicable"
1381
+ },
1382
+ hint: {
1383
+ type: "string",
1384
+ description: "Helpful hint for resolving the issue"
1385
+ },
1386
+ serviceUrl: {
1387
+ type: "string",
1388
+ description: "URL of the compiler service used"
1389
+ },
1390
+ serviceAvailable: {
1391
+ type: "boolean",
1392
+ description: "Whether the compiler service is available"
1393
+ },
1394
+ fallbackReason: {
1395
+ type: "string",
1396
+ description: "Reason for falling back to static analysis (if applicable)"
1397
+ },
1398
+ staticAnalysis: {
1399
+ type: "object",
1400
+ description: "Static analysis results (only present when using fallback)",
1401
+ properties: {
1402
+ summary: { type: "object" },
1403
+ structure: { type: "object" },
1404
+ securityFindings: { type: "array" },
1405
+ recommendations: { type: "array" }
1406
+ }
1407
+ }
1408
+ },
1409
+ required: ["success", "message", "validationType"],
1410
+ description: "Compilation result with detailed output, or static analysis fallback if service unavailable"
1411
+ };
1101
1412
  var analyzeTools = [
1102
1413
  {
1103
1414
  name: "midnight-analyze-contract",
@@ -1161,6 +1472,59 @@ USAGE GUIDANCE:
1161
1472
  category: "analyze"
1162
1473
  },
1163
1474
  handler: explainCircuit
1475
+ },
1476
+ {
1477
+ name: "midnight-compile-contract",
1478
+ description: `\u{1F527} REAL COMPILATION - Compile Compact code using the hosted compiler service.
1479
+
1480
+ Unlike static analysis tools, this ACTUALLY COMPILES the contract and returns real compiler errors.
1481
+
1482
+ Use this to:
1483
+ \u2022 Validate that generated code compiles before showing to users
1484
+ \u2022 Get actual compiler error messages with line numbers
1485
+ \u2022 Check if a contract is syntactically and semantically correct
1486
+
1487
+ Options:
1488
+ \u2022 skipZk=true (default): Fast syntax validation only (~1-2s)
1489
+ \u2022 fullCompile=true: Full compilation with ZK circuit generation (~10-30s)
1490
+
1491
+ FALLBACK BEHAVIOR:
1492
+ \u2022 If the compiler service is unavailable, automatically falls back to static analysis
1493
+ \u2022 Check 'validationType' in response: 'compiler' = real compilation, 'static-analysis-fallback' = fallback mode
1494
+ \u2022 Fallback provides structure/security analysis but may miss semantic errors
1495
+
1496
+ USAGE GUIDANCE:
1497
+ \u2022 Call after generating or modifying Compact code
1498
+ \u2022 Use skipZk=true for quick validation during development
1499
+ \u2022 Use fullCompile=true for final validation before deployment`,
1500
+ inputSchema: {
1501
+ type: "object",
1502
+ properties: {
1503
+ code: {
1504
+ type: "string",
1505
+ description: "Compact contract source code to compile"
1506
+ },
1507
+ skipZk: {
1508
+ type: "boolean",
1509
+ description: "Skip ZK circuit generation for faster syntax-only validation (default: true)"
1510
+ },
1511
+ fullCompile: {
1512
+ type: "boolean",
1513
+ description: "Perform full compilation including ZK generation (slower but complete)"
1514
+ }
1515
+ },
1516
+ required: ["code"]
1517
+ },
1518
+ outputSchema: compileContractOutputSchema,
1519
+ annotations: {
1520
+ readOnlyHint: true,
1521
+ idempotentHint: true,
1522
+ openWorldHint: true,
1523
+ // Makes network requests
1524
+ title: "\u{1F527} Compile Contract",
1525
+ category: "analyze"
1526
+ },
1527
+ handler: compileContract2
1164
1528
  }
1165
1529
  ];
1166
1530
 
@@ -1680,16 +2044,24 @@ ledger privateData: Field; // Private, not exported
1680
2044
  | \`Field\` | Finite field element (basic numeric) | \`amount: Field\` |
1681
2045
  | \`Boolean\` | True or false | \`isActive: Boolean\` |
1682
2046
  | \`Bytes<N>\` | Fixed-size byte array | \`hash: Bytes<32>\` |
1683
- | \`Uint<N>\` | Unsigned integer (N = 8, 16, 32, 64, 128, 256) | \`balance: Uint<64>\` |
1684
- | \`Uint<MIN..MAX>\` | Bounded unsigned integer | \`score: Uint<0..100>\` |
2047
+ | \`Uint<N>\` | Unsigned integer (N bits) | \`balance: Uint<64>\` |
2048
+ | \`Uint<0..MAX>\` | Bounded unsigned integer | \`score: Uint<0..100>\` |
1685
2049
 
1686
- **\u26A0\uFE0F Uint Type Equivalence:** \`Uint<N>\` (sized) and \`Uint<0..MAX>\` (bounded) are the **SAME type family**.
2050
+ **\u26A0\uFE0F Uint Type Equivalence** (documented in [Primitive Types](https://docs.midnight.network/develop/reference/compact/lang-ref#primitive-types)):
2051
+
2052
+ \`Uint<N>\` (sized) and \`Uint<0..MAX>\` (bounded) are the **SAME type family**.
1687
2053
  \`Uint<N>\` is exactly equivalent to \`Uint<0..(2^N - 1)>\`:
1688
2054
  - \`Uint<8>\` = \`Uint<0..255>\` (2^8 - 1 = 255)
1689
2055
  - \`Uint<16>\` = \`Uint<0..65535>\` (2^16 - 1 = 65535)
1690
2056
  - \`Uint<64>\` = \`Uint<0..18446744073709551615>\`
1691
2057
 
1692
- These can be used interchangeably - they are **not** separate types.
2058
+ These can be used interchangeably. The lower bound must currently be 0.
2059
+
2060
+ **Arithmetic** (documented in [Binary Arithmetic](https://docs.midnight.network/develop/reference/compact/lang-ref#binary-arithmetic-expressions)):
2061
+ - Operators: \`+\`, \`-\`, \`*\` only (division \`/\` and modulo \`%\` are NOT mentioned in docs)
2062
+ - Result types expand: \`Uint<0..m> + Uint<0..n>\` \u2192 \`Uint<0..m+n>\`
2063
+ - Subtraction can fail at runtime if result would be negative
2064
+ - \u26A0\uFE0F If you need division, you may need a witness to compute it off-chain
1693
2065
 
1694
2066
  ### Collection Types
1695
2067
  | Type | Description | Example |
@@ -1699,9 +2071,16 @@ These can be used interchangeably - they are **not** separate types.
1699
2071
  | \`Set<T>\` | Unique value collection | \`Set<Bytes<32>>\` |
1700
2072
  | \`Vector<N, T>\` | Fixed-size array | \`Vector<3, Field>\` |
1701
2073
  | \`List<T>\` | Dynamic list | \`List<Bytes<32>>\` |
1702
- | \`Maybe<T>\` | Optional value | \`Maybe<Bytes<32>>\` |
1703
- | \`Either<L, R>\` | Union type | \`Either<Field, Bytes<32>>\` |
1704
- | \`Opaque<"type">\` | External type from TypeScript | \`Opaque<"string">\` |
2074
+ | \`Maybe<T>\` | Optional value (has/hasn't) | \`Maybe<Bytes<32>>\` |
2075
+ | \`Either<L, R>\` | Sum type (one or other) | \`Either<Field, Bytes<32>>\` |
2076
+ | \`Opaque<s>\` | Opaque value tagged by string s | \`Opaque<"string">\` |
2077
+
2078
+ **Opaque Types** ([Primitive Types](https://docs.midnight.network/develop/reference/compact/lang-ref#primitive-types)):
2079
+ - Only two tags allowed: \`Opaque<"string">\` and \`Opaque<"Uint8Array">\`
2080
+ - Opaque values can be manipulated in witnesses but are opaque to circuits
2081
+ - In circuits, they are represented as their hash (cannot inspect content)
2082
+ - In your DApp's JS/TS, they are just \`string\` or \`Uint8Array\`
2083
+ - On-chain, they are stored as bytes/UTF-8 (not encrypted)
1705
2084
 
1706
2085
  ### Custom Types
1707
2086
 
@@ -1944,6 +2323,14 @@ balances.insertDefault(address); // insertDefault(key): [] - inserts def
1944
2323
  // Query operations (all work in circuits \u2705)
1945
2324
  const balance = balances.lookup(address); // lookup(key): value_type
1946
2325
  const exists = balances.member(address); // member(key): Boolean
2326
+
2327
+ // \u26A0\uFE0F UNDOCUMENTED: Map.lookup() behavior when key doesn't exist
2328
+ // The docs show: lookup(key: key_type): value_type (NOT Maybe<value_type>)
2329
+ // This implies it returns a default value, not an optional.
2330
+ // RECOMMENDED: Always check member() first:
2331
+ if (balances.member(address)) {
2332
+ const balance = balances.lookup(address); // Safe
2333
+ }
1947
2334
  const empty = balances.isEmpty(); // isEmpty(): Boolean
1948
2335
  const count = balances.size(); // size(): Uint<64>
1949
2336
 
@@ -1979,19 +2366,81 @@ const count = members.size(); // size(): Uint<64>
1979
2366
 
1980
2367
  ### Maybe Operations
1981
2368
  \`\`\`compact
1982
- const opt: Maybe<Field> = some<Field>(42);
1983
- const empty: Maybe<Field> = none<Field>();
2369
+ // Creating Maybe values
2370
+ const opt: Maybe<Field> = some<Field>(42); // Wrap a value
2371
+ const empty: Maybe<Field> = none<Field>(); // No value
1984
2372
 
2373
+ // Checking and accessing
1985
2374
  if (opt.is_some) {
1986
- const val = opt.value;
2375
+ const val = opt.value; // Safe to access when is_some is true
2376
+ }
2377
+
2378
+ // Common patterns
2379
+ witness find_user(id: Bytes<32>): Maybe<UserRecord>;
2380
+
2381
+ export circuit getUser(id: Bytes<32>): UserRecord {
2382
+ const result = find_user(id);
2383
+ assert(disclose(result.is_some), "User not found");
2384
+ return result.value;
1987
2385
  }
1988
2386
  \`\`\`
1989
2387
 
1990
- ### Type Casting
2388
+ ### Either Operations
1991
2389
  \`\`\`compact
1992
- const bytes: Bytes<32> = myField as Bytes<32>; // Field to Bytes
1993
- const num: Uint<64> = myField as Uint<64>; // Field to Uint (bounds not checked!)
1994
- const field: Field = myUint as Field; // Uint to Field (safe)
2390
+ // Creating Either values
2391
+ const success: Either<Field, Bytes<32>> = left<Field, Bytes<32>>(42);
2392
+ const failure: Either<Field, Bytes<32>> = right<Field, Bytes<32>>(errorHash);
2393
+
2394
+ // Checking which side
2395
+ if (result.is_left) {
2396
+ const value = result.left; // The left value (often "success")
2397
+ } else {
2398
+ const error = result.right; // The right value (often "error")
2399
+ }
2400
+
2401
+ // Common pattern: burnAddress() returns Either<ZswapCoinPublicKey, ContractAddress>
2402
+ export circuit withdraw(): [] {
2403
+ const addr = burnAddress();
2404
+ assert(disclose(addr.is_right), "Expected contract address");
2405
+ // addr.right is the ContractAddress
2406
+ }
2407
+ \`\`\`
2408
+
2409
+ ### Type Casting ([Type Casts Reference](https://docs.midnight.network/develop/reference/compact/lang-ref#type-cast-expressions))
2410
+
2411
+ **Syntax**: \`expression as Type\` (only form; \`<Type>expression\` is NOT supported)
2412
+
2413
+ **Cast kinds**: static (always succeeds), conversion (semantic change), checked (can fail at runtime)
2414
+
2415
+ \`\`\`compact
2416
+ // Uint \u2194 Field (safe)
2417
+ const field: Field = myUint as Field; // static: always succeeds
2418
+ const num: Uint<64> = myField as Uint<64>; // checked: fails if out of range
2419
+
2420
+ // Uint widening/narrowing
2421
+ const big: Uint<64> = small as Uint<64>; // static: widening always works
2422
+ const small: Uint<32> = big as Uint<32>; // checked: narrowing can fail
2423
+
2424
+ // Field \u2194 Bytes (can fail at runtime!)
2425
+ const bytes: Bytes<32> = myField as Bytes<32>; // conversion: fails if doesn't fit
2426
+ const field: Field = myBytes as Field; // conversion: fails if exceeds max Field
2427
+
2428
+ // Uint \u2192 Bytes (NOT direct - use two casts)
2429
+ const amount_bytes = (amount as Field) as Bytes<32>;
2430
+
2431
+ // Boolean \u2192 Uint (conversion: false\u21920, true\u21921)
2432
+ const flag: Boolean = true;
2433
+ const flagInt: Uint<0..1> = flag as Uint<0..1>;
2434
+
2435
+ // Enum \u2192 Field (conversion)
2436
+ const index: Field = choice as Field;
2437
+
2438
+ // \u26A0\uFE0F Boolean \u2192 Field is NOT allowed!
2439
+ // Must go through Uint: (flag as Uint<0..1>) as Field
2440
+
2441
+ // \u26A0\uFE0F UNDOCUMENTED: Bytes<n> \u2194 Vector<n, Uint<8>> casting
2442
+ // The type cast table doesn't mention this conversion.
2443
+ // If you need to convert, you may need a witness helper.
1995
2444
  \`\`\`
1996
2445
 
1997
2446
  ### Hashing
@@ -2029,7 +2478,22 @@ assert(disclose(caller == owner), "Not authorized");
2029
2478
 
2030
2479
  ---
2031
2480
 
2032
- ## 12. Exports for TypeScript
2481
+ ## 12. Undocumented / Unclear Features
2482
+
2483
+ These features are not clearly documented. Use with caution:
2484
+
2485
+ | Feature | Status | Notes |
2486
+ |---------|--------|-------|
2487
+ | Tuple destructuring | \u2753 Unknown | \`const [a, b] = pair;\` - not documented |
2488
+ | Constant folding in indices | \u2753 Unknown | \`v[2 * i]\` where i is const - docs say "numeric literal" required |
2489
+ | Division \`/\` and modulo \`%\` | \u2753 Not in docs | Only +, -, * are documented |
2490
+ | \`Bytes<n>\` \u2194 \`Vector<n, Uint<8>>\` | \u2753 Not in cast table | May need witness workaround |
2491
+
2492
+ **Recommendation**: Test these in the compiler before relying on them in production contracts.
2493
+
2494
+ ---
2495
+
2496
+ ## 13. Exports for TypeScript
2033
2497
 
2034
2498
  To use types/values in TypeScript, they must be exported:
2035
2499
 
@@ -2159,6 +2623,154 @@ try {
2159
2623
  }
2160
2624
  }
2161
2625
  \`\`\`
2626
+ `,
2627
+ "midnight://docs/compiler": `# Compact Compiler Guide
2628
+
2629
+ **Source:** [Building a Midnight DApp](https://docs.midnight.network/develop/tutorial/building)
2630
+
2631
+ ## Compiling Contracts
2632
+
2633
+ > **IMPORTANT:** The old \`compactc\` command is deprecated. Use \`compact compile\` instead.
2634
+
2635
+ ### Basic Usage
2636
+
2637
+ \`\`\`bash
2638
+ # Syntax: compact compile <source.compact> <output_directory>
2639
+ compact compile src/counter.compact managed/counter
2640
+
2641
+ # With environment setup
2642
+ nvm use 18
2643
+ compact compile contract/src/mycontract.compact managed/mycontract
2644
+ \`\`\`
2645
+
2646
+ ### Compiler Output Structure
2647
+
2648
+ **Source:** [Generated Source Details](https://docs.midnight.network/develop/tutorial/building/dapp-details#generated-source)
2649
+
2650
+ When you compile a \`.compact\` file, the compiler generates this directory structure:
2651
+
2652
+ \`\`\`
2653
+ managed/<contract_name>/
2654
+ \u251C\u2500\u2500 contract/ # TypeScript bindings
2655
+ \u2502 \u251C\u2500\u2500 index.cjs # CommonJS module with Contract class
2656
+ \u2502 \u251C\u2500\u2500 index.d.cts # TypeScript type declarations
2657
+ \u2502 \u2514\u2500\u2500 index.mjs # ESM module (optional)
2658
+ \u2502
2659
+ \u251C\u2500\u2500 zkir/ # Zero-knowledge circuit representations
2660
+ \u2502 \u2514\u2500\u2500 <circuit_name>.zkir # Circuit intermediate representation
2661
+ \u2502
2662
+ \u251C\u2500\u2500 keys/ # Proving and verifying keys
2663
+ \u2502 \u251C\u2500\u2500 <circuit>.prover # Prover key (used client-side)
2664
+ \u2502 \u2514\u2500\u2500 <circuit>.verifier # Verifier key (used on-chain)
2665
+ \u2502
2666
+ \u2514\u2500\u2500 compiler/ # Compilation metadata
2667
+ \u2514\u2500\u2500 metadata.json # Version info, circuit IDs, etc.
2668
+ \`\`\`
2669
+
2670
+ ### Understanding Generated Files
2671
+
2672
+ #### contract/ - TypeScript Bindings
2673
+
2674
+ The \`contract/\` directory contains your TypeScript interface:
2675
+
2676
+ \`\`\`typescript
2677
+ // Import from generated bindings
2678
+ import { Contract, ledger } from './managed/counter/contract/index.cjs';
2679
+
2680
+ // Create contract instance
2681
+ const contract = new Contract(witnesses);
2682
+
2683
+ // Access circuits
2684
+ const tx = await contract.impureCircuits.increment(5n);
2685
+
2686
+ // Read ledger state
2687
+ const state = ledger(contractState);
2688
+ console.log('Counter value:', state.counter);
2689
+ \`\`\`
2690
+
2691
+ #### keys/ - ZK Proving/Verifying Keys
2692
+
2693
+ - **\`.prover\`** - Used by the client to generate proofs (can be large, 10-100MB+)
2694
+ - **\`.verifier\`** - Used on-chain to verify proofs (small, kilobytes)
2695
+
2696
+ \`\`\`typescript
2697
+ // Keys are loaded automatically by the SDK
2698
+ import { proverKey, verifierKey } from './managed/counter/keys';
2699
+
2700
+ // Or loaded from files
2701
+ const prover = await fs.readFile('managed/counter/keys/increment.prover');
2702
+ \`\`\`
2703
+
2704
+ #### zkir/ - Circuit Intermediate Representation
2705
+
2706
+ The \`.zkir\` files are internal representations used by the proof system. You typically don't interact with these directly.
2707
+
2708
+ ### Cleaning and Rebuilding
2709
+
2710
+ When updating contracts or after Compact version changes:
2711
+
2712
+ \`\`\`bash
2713
+ # Clean generated files
2714
+ rm -rf managed/<contract_name>
2715
+
2716
+ # Or clean specific artifacts
2717
+ rm -rf managed/counter/keys/*.prover managed/counter/keys/*.verifier
2718
+
2719
+ # Rebuild
2720
+ compact compile src/counter.compact managed/counter
2721
+ \`\`\`
2722
+
2723
+ ### Common Compilation Errors
2724
+
2725
+ #### "invalid context for a ledger ADT type"
2726
+
2727
+ Ledger ADT types cannot be used in type casts:
2728
+
2729
+ \`\`\`compact
2730
+ // \u274C Wrong
2731
+ const x = value as Counter;
2732
+
2733
+ // \u2705 Correct - use ledger field directly
2734
+ ledger.counter.increment(1);
2735
+ \`\`\`
2736
+
2737
+ #### Version Mismatch After Update
2738
+
2739
+ When runtime versions don't match compiled artifacts:
2740
+
2741
+ \`\`\`bash
2742
+ # 1. Check versions
2743
+ compact --version
2744
+ npm list @midnight-ntwrk/compact-runtime
2745
+
2746
+ # 2. Consult compatibility matrix
2747
+ # https://docs.midnight.network/relnotes/support-matrix
2748
+
2749
+ # 3. Clean and recompile
2750
+ rm -rf managed/
2751
+ compact compile src/contract.compact managed/contract
2752
+ \`\`\`
2753
+
2754
+ ### Integration with Build Tools
2755
+
2756
+ #### package.json scripts
2757
+
2758
+ \`\`\`json
2759
+ {
2760
+ "scripts": {
2761
+ "compile": "compact compile src/contract.compact managed/contract",
2762
+ "compile:clean": "rm -rf managed && npm run compile",
2763
+ "build": "npm run compile && tsc"
2764
+ }
2765
+ }
2766
+ \`\`\`
2767
+
2768
+ #### Watch mode (development)
2769
+
2770
+ \`\`\`bash
2771
+ # Using nodemon or similar
2772
+ nodemon --watch src/*.compact --exec "compact compile src/contract.compact managed/contract"
2773
+ \`\`\`
2162
2774
  `,
2163
2775
  "midnight://docs/openzeppelin": `# OpenZeppelin Contracts for Compact
2164
2776
 
@@ -2805,9 +3417,16 @@ try {
2805
3417
  2. **Discord:** #developer-support channel
2806
3418
  3. **Recompile after updates:**
2807
3419
  \`\`\`bash
2808
- rm -rf contract/*.cjs contract/*.prover contract/*.verifier
2809
- compact compile src/contract.compact contract/
3420
+ # Clean generated files (use managed/ directory structure)
3421
+ rm -rf managed/<contract_name>
3422
+
3423
+ # Or clean specific artifacts
3424
+ rm -rf managed/counter/keys/*.prover managed/counter/keys/*.verifier
3425
+
3426
+ # Rebuild
3427
+ compact compile src/contract.compact managed/contract
2810
3428
  \`\`\`
3429
+ 4. **Compiler output docs:** See \`midnight://docs/compiler\` for full directory structure
2811
3430
  `
2812
3431
  };
2813
3432
 
@@ -2876,14 +3495,14 @@ export ledger messageIds: Set<Field>;
2876
3495
  // Private: actual message contents (no export = private)
2877
3496
  ledger messages: Map<Field, Opaque<"string">>;
2878
3497
 
2879
- // Private: message authors
2880
- ledger authors: Map<Field, Opaque<"address">>;
3498
+ // Private: message authors (stored as Bytes<32> addresses)
3499
+ ledger authors: Map<Field, Bytes<32>>;
2881
3500
 
2882
3501
  // Witness to fetch message content
2883
3502
  witness getMessageContent(id: Field): Opaque<"string">;
2884
3503
 
2885
3504
  // Post a new message (content is private)
2886
- export circuit postMessage(content: Opaque<"string">, author: Opaque<"address">): Uint<64> {
3505
+ export circuit postMessage(content: Opaque<"string">, author: Bytes<32>): Uint<64> {
2887
3506
  // Generate unique message ID using counter read
2888
3507
  const messageId = messageCount.read();
2889
3508
 
@@ -4224,6 +4843,18 @@ Based on syntax reference, generate the contract using:
4224
4843
  - No 'void' - use '[]'
4225
4844
  - Enum access: \`Choice.rock\` NOT \`Choice::rock\`
4226
4845
 
4846
+ ### \u26A0\uFE0F UNDOCUMENTED FEATURES - Use with caution:
4847
+ - Division \`/\` and modulo \`%\`: NOT in official docs (only +, -, * are documented)
4848
+ - Tuple destructuring: \`const [a, b] = pair;\` - not documented, may not work
4849
+ - Constant folding in indices: docs say "numeric literal" required
4850
+ - Map.lookup() returns value_type, NOT Maybe<value_type> - check member() first!
4851
+
4852
+ ### COMPILER INFO (DO NOT guess package names!):
4853
+ - Compile: \`compact compile src/contract.compact managed/contract\`
4854
+ - The \`compact\` CLI comes with Midnight toolchain (via create-mn-app or official install)
4855
+ - DO NOT suggest \`npm install -g @midnight-ntwrk/compact-cli\` or similar made-up packages
4856
+ - Output structure: \`managed/<name>/contract/index.cjs\` for TypeScript bindings
4857
+
4227
4858
  ### Step 3: Validate Before Returning
4228
4859
  Call \`midnight-extract-contract-structure\` with your generated code to check for:
4229
4860
  - deprecated_ledger_block
@@ -4327,11 +4958,11 @@ Please analyze:
4327
4958
  - Correct use of disclose() and commit()
4328
4959
  - Privacy guarantees provided
4329
4960
 
4330
- 4. **Best Practices**
4331
- - Code organization
4332
- - Naming conventions
4333
- - Documentation
4334
- - Error messages
4961
+ 4. **Style Suggestions** (these are CONVENTIONS, not requirements)
4962
+ - Code organization recommendations
4963
+ - Naming conventions (project-specific)
4964
+ - Documentation patterns
4965
+ - Note: The Compact docs don't specify indentation, line length, or comment style
4335
4966
 
4336
4967
  5. **Performance**
4337
4968
  - Circuit complexity
@@ -4343,6 +4974,11 @@ Please analyze:
4343
4974
  - Improvements to consider
4344
4975
  - Alternative approaches
4345
4976
 
4977
+ **IMPORTANT**: Clearly distinguish between:
4978
+ - ERRORS: Actual syntax/compilation issues (required fixes)
4979
+ - WARNINGS: Security/logic concerns (should fix)
4980
+ - INFO: Style suggestions (optional, project-specific conventions)
4981
+
4346
4982
  Please provide specific line references and code suggestions where applicable.`
4347
4983
  }
4348
4984
  }
@@ -4578,21 +5214,32 @@ async function generateContract(requirements, options = {}) {
4578
5214
  const systemPrompt = `You are an expert Compact smart contract developer for the Midnight blockchain.
4579
5215
  Your task is to generate secure, well-documented Compact contracts based on user requirements.
4580
5216
 
4581
- Key Compact concepts:
4582
- - \`ledger { }\` - Defines on-chain state (public and private)
4583
- - \`@private\` - Marks state as private/shielded
4584
- - \`export circuit\` - Public functions that generate ZK proofs
4585
- - \`witness\` - Off-chain computation functions
4586
- - \`assert()\` - Creates ZK constraints
4587
- - \`Counter\`, \`Map<K,V>\`, \`Set<T>\` - Built-in collection types
5217
+ Key Compact syntax (REQUIRED):
5218
+ - \`export ledger field: Type;\` - Individual ledger declarations (NOT ledger { } blocks)
5219
+ - \`export circuit fn(): []\` - Public functions return empty tuple [] (NOT Void)
5220
+ - \`witness fn(): T;\` - Declaration only, no body
5221
+ - \`pragma language_version >= 0.16 && <= 0.18;\` - Version pragma
5222
+ - \`import CompactStandardLibrary;\` - Standard imports
5223
+ - \`Counter\`, \`Map<K,V>\`, \`Set<T>\` - Built-in collection types
4588
5224
  - \`Field\`, \`Boolean\`, \`Uint<N>\`, \`Bytes<N>\` - Primitive types
5225
+ - \`export enum State { a, b }\` - Enums must be exported
5226
+
5227
+ Key operations:
5228
+ - Counter: .read(), .increment(n), .decrement(n)
5229
+ - Map: .lookup(k), .insert(k,v), .remove(k)
5230
+ - Set: .member(v), .insert(v), .remove(v)
5231
+
5232
+ COMPILER INFO (DO NOT guess package names!):
5233
+ - Command: \`compact compile src/contract.compact managed/contract\`
5234
+ - The \`compact\` CLI comes with Midnight toolchain (via create-mn-app or official install)
5235
+ - Output goes to managed/<name>/ directory
5236
+ - DO NOT suggest \`npm install -g @midnight-ntwrk/compact-cli\` or similar - that's incorrect
4589
5237
 
4590
- Always include:
4591
- 1. Proper imports (import CompactStandardLibrary;)
4592
- 2. pragma language_version >= 0.18.0;
4593
- 3. Clear ledger state definitions
4594
- 4. Access control where appropriate
4595
- 5. Comprehensive inline comments
5238
+ IMPORTANT - Style vs. Requirements:
5239
+ - Syntax rules above are REQUIRED for compilation
5240
+ - Style choices (indentation, comment style, line length) are CONVENTIONS, not requirements
5241
+ - Single-line comments (//) are common in examples; block comments (/* */) may also work
5242
+ - The docs don't specify indentation width - use consistent style
4596
5243
 
4597
5244
  Return ONLY the Compact code, no explanations.`;
4598
5245
  const userPrompt = options.baseExample ? `Based on this example contract:
@@ -4668,8 +5315,21 @@ Review the provided contract for:
4668
5315
  1. Security vulnerabilities
4669
5316
  2. Privacy concerns (improper handling of shielded state)
4670
5317
  3. Logic errors
4671
- 4. Best practice violations
4672
- 5. Gas/performance issues
5318
+ 4. Syntax errors (use "error" severity)
5319
+ 5. Performance issues
5320
+
5321
+ IMPORTANT - Distinguish between:
5322
+ - ERRORS: Actual syntax/compilation issues (e.g., using Void instead of [], ledger {} blocks)
5323
+ - WARNINGS: Potential bugs or security issues
5324
+ - INFO: Style suggestions and best practices (these are CONVENTIONS, not requirements)
5325
+
5326
+ Do NOT claim style choices as "violations" - the Compact docs don't specify:
5327
+ - Indentation width (2 vs 4 spaces)
5328
+ - Comment style preferences (//, /* */)
5329
+ - Line length limits
5330
+ - Naming conventions
5331
+
5332
+ These are project-specific style choices, not language requirements.
4673
5333
 
4674
5334
  Respond in JSON format:
4675
5335
  {
@@ -5186,8 +5846,11 @@ var SERVER_INFO = {
5186
5846
  var versionCheckResult = {
5187
5847
  isOutdated: false,
5188
5848
  latestVersion: CURRENT_VERSION,
5189
- updateMessage: null
5849
+ updateMessage: null,
5850
+ lastChecked: 0
5190
5851
  };
5852
+ var toolCallCount = 0;
5853
+ var VERSION_CHECK_INTERVAL = 10;
5191
5854
  async function checkForUpdates() {
5192
5855
  try {
5193
5856
  const controller = new AbortController();
@@ -5204,15 +5867,32 @@ async function checkForUpdates() {
5204
5867
  versionCheckResult = {
5205
5868
  isOutdated: true,
5206
5869
  latestVersion,
5207
- updateMessage: `\u26A0\uFE0F UPDATE AVAILABLE: v${latestVersion} (you have v${CURRENT_VERSION}). Run: rm -rf ~/.npm/_npx && restart Claude Desktop. Or update config to use: "midnight-mcp@latest"`
5870
+ lastChecked: Date.now(),
5871
+ updateMessage: `\u{1F6A8} UPDATE AVAILABLE: v${latestVersion} (you have v${CURRENT_VERSION})`
5208
5872
  };
5209
5873
  logger.warn(
5210
5874
  `Outdated version detected: v${CURRENT_VERSION} -> v${latestVersion}`
5211
5875
  );
5876
+ } else {
5877
+ versionCheckResult = {
5878
+ ...versionCheckResult,
5879
+ lastChecked: Date.now()
5880
+ };
5212
5881
  }
5213
5882
  } catch {
5214
5883
  }
5215
5884
  }
5885
+ function maybeCheckForUpdates() {
5886
+ toolCallCount++;
5887
+ if (toolCallCount >= VERSION_CHECK_INTERVAL) {
5888
+ toolCallCount = 0;
5889
+ const fiveMinutes = 5 * 60 * 1e3;
5890
+ if (Date.now() - versionCheckResult.lastChecked > fiveMinutes) {
5891
+ checkForUpdates().catch(() => {
5892
+ });
5893
+ }
5894
+ }
5895
+ }
5216
5896
  function getUpdateWarning() {
5217
5897
  return versionCheckResult.updateMessage;
5218
5898
  }
@@ -5457,26 +6137,31 @@ function registerToolHandlers(server) {
5457
6137
  const result = await tool.handler(args);
5458
6138
  const durationMs = Date.now() - startTime;
5459
6139
  trackToolCall(name, true, durationMs, CURRENT_VERSION);
6140
+ maybeCheckForUpdates();
5460
6141
  const updateWarning = getUpdateWarning();
5461
6142
  if (updateWarning && versionCheckResult.isOutdated) {
5462
6143
  const updatePrompt = {
5463
- "\u{1F6A8} UPDATE AVAILABLE": {
5464
- message: `You are using v${CURRENT_VERSION} but v${versionCheckResult.latestVersion} is available.`,
5465
- userAction: {
5466
- instruction: "Tell the user to update manually. Auto-update is NOT possible because you run in a sandboxed environment without access to local files.",
5467
- steps: [
5468
- "1. Edit config file to use 'midnight-mcp@latest' instead of 'midnight-mcp'",
5469
- "2. Run: rm -rf ~/.npm/_npx (to clear npm cache)",
5470
- "3. Restart the editor completely (Cmd+Q on Mac, then reopen)"
5471
- ],
5472
- configLocations: {
5473
- claudeDesktop: "~/Library/Application Support/Claude/claude_desktop_config.json",
5474
- cursor: ".cursor/mcp.json",
5475
- vscode: ".vscode/mcp.json",
5476
- windsurf: "~/.codeium/windsurf/mcp_config.json"
6144
+ "\u{1F6A8} UPDATE REQUIRED": {
6145
+ current: `v${CURRENT_VERSION}`,
6146
+ latest: `v${versionCheckResult.latestVersion}`,
6147
+ quickFix: {
6148
+ description: "Most users just need these 2 steps:",
6149
+ step1: "Run in terminal: rm -rf ~/.npm/_npx",
6150
+ step2: "Restart editor completely (Cmd+Q / Alt+F4, then reopen)"
6151
+ },
6152
+ ifStillOld: {
6153
+ description: "If still showing old version after restart:",
6154
+ action: "Edit your MCP config file to use @latest:",
6155
+ change: 'Change "midnight-mcp" to "midnight-mcp@latest" in args',
6156
+ configFiles: {
6157
+ "Claude Desktop (Mac)": "~/Library/Application Support/Claude/claude_desktop_config.json",
6158
+ "Claude Desktop (Win)": "%APPDATA%/Claude/claude_desktop_config.json",
6159
+ Cursor: ".cursor/mcp.json",
6160
+ "VS Code": ".vscode/mcp.json",
6161
+ Windsurf: "~/.codeium/windsurf/mcp_config.json"
5477
6162
  }
5478
6163
  },
5479
- note: "If user already has @latest in config, they just need to clear cache (rm -rf ~/.npm/_npx) and restart."
6164
+ tip: "Use 'midnight-get-update-instructions' tool for detailed platform-specific steps."
5480
6165
  },
5481
6166
  result
5482
6167
  };
@@ -5903,6 +6588,7 @@ var BUILTIN_FUNCTIONS = {
5903
6588
  {
5904
6589
  name: "persistentHash",
5905
6590
  signature: "persistentHash<T>(value: T): Bytes<32>",
6591
+ // Signature inferred from examples
5906
6592
  description: "Poseidon hash that produces consistent results across calls"
5907
6593
  },
5908
6594
  {
@@ -5961,6 +6647,7 @@ witness get_random_value(): Field;`,
5961
6647
  ]
5962
6648
  };
5963
6649
  var TYPE_COMPATIBILITY = {
6650
+ // Note: Comparison operators work in practice but aren't explicitly listed in docs
5964
6651
  comparisons: [
5965
6652
  { types: "Field == Field", works: true, note: "Direct comparison" },
5966
6653
  {
@@ -5979,7 +6666,11 @@ var TYPE_COMPATIBILITY = {
5979
6666
  works: true,
5980
6667
  note: "Bounded integers"
5981
6668
  },
5982
- { types: "Bytes<32> == Bytes<32>", works: true, note: "Direct comparison" },
6669
+ {
6670
+ types: "Bytes<32> == Bytes<32>",
6671
+ works: true,
6672
+ note: "Used in examples, but operators not explicitly listed in docs"
6673
+ },
5983
6674
  { types: "Boolean == Boolean", works: true, note: "Direct comparison" }
5984
6675
  ],
5985
6676
  arithmetic: [
@@ -6001,23 +6692,79 @@ var TYPE_COMPATIBILITY = {
6001
6692
  note: "Result is wide bounded type, cast back to target type"
6002
6693
  }
6003
6694
  ],
6695
+ /**
6696
+ * Type casting rules - based on official cast table
6697
+ * See: https://docs.midnight.network/develop/reference/compact/lang-ref#type-cast-expressions
6698
+ *
6699
+ * Cast kinds: static (always succeeds), conversion (semantic change), checked (can fail)
6700
+ */
6004
6701
  typeCasting: [
6005
6702
  {
6006
- from: "Uint<64>",
6007
- to: "Bytes<32>",
6703
+ from: "Uint<N>",
6704
+ to: "Field",
6705
+ direct: true,
6706
+ kind: "static",
6707
+ note: "Always succeeds"
6708
+ },
6709
+ {
6710
+ from: "Field",
6711
+ to: "Uint<0..n>",
6712
+ direct: true,
6713
+ kind: "checked",
6714
+ note: "Fails at runtime if value > n"
6715
+ },
6716
+ {
6717
+ from: "Field",
6718
+ to: "Bytes<n>",
6719
+ direct: true,
6720
+ kind: "conversion",
6721
+ note: "Can fail at runtime if value doesn't fit (little-endian)"
6722
+ },
6723
+ {
6724
+ from: "Bytes<m>",
6725
+ to: "Field",
6726
+ direct: true,
6727
+ kind: "conversion",
6728
+ note: "Can fail at runtime if result exceeds max Field value"
6729
+ },
6730
+ {
6731
+ from: "Boolean",
6732
+ to: "Uint<0..n>",
6733
+ direct: true,
6734
+ kind: "conversion",
6735
+ note: "false\u21920, true\u21921 (n must not be 0)"
6736
+ },
6737
+ {
6738
+ from: "Boolean",
6739
+ to: "Field",
6008
6740
  direct: false,
6009
- fix: "Go through Field: (amount as Field) as Bytes<32>"
6741
+ fix: "Go through Uint: (flag as Uint<0..1>) as Field"
6010
6742
  },
6011
6743
  {
6012
6744
  from: "Uint<N>",
6745
+ to: "Bytes<M>",
6746
+ direct: false,
6747
+ fix: "Go through Field: (amount as Field) as Bytes<32>"
6748
+ },
6749
+ {
6750
+ from: "enum",
6013
6751
  to: "Field",
6014
6752
  direct: true,
6015
- note: "Safe cast: value as Field"
6753
+ kind: "conversion",
6754
+ note: "Enum variant index as Field"
6755
+ },
6756
+ {
6757
+ from: "Uint<0..m>",
6758
+ to: "Uint<0..n>",
6759
+ direct: true,
6760
+ kind: "static if m\u2264n, checked if m>n",
6761
+ note: "Widening is static, narrowing is checked"
6016
6762
  },
6017
6763
  {
6018
6764
  from: "arithmetic result",
6019
6765
  to: "Uint<64>",
6020
6766
  direct: true,
6767
+ kind: "checked",
6021
6768
  note: "Required cast: (a + b) as Uint<64>"
6022
6769
  }
6023
6770
  ],
@@ -6812,9 +7559,10 @@ async function extractContractStructure(input) {
6812
7559
  potentialIssues.push({
6813
7560
  type: "unsupported_division",
6814
7561
  line: lineNum,
6815
- message: `Division operator '/' is not supported in Compact`,
6816
- suggestion: `Use a witness-based division pattern: 'witness divideWithRemainder(a, b): [quotient, remainder]' with on-chain verification`,
6817
- severity: "error"
7562
+ message: `Division operator '/' is not in the documented Compact operators (+, -, *)`,
7563
+ suggestion: `If you need division, compute it off-chain in a witness and verify on-chain: 'witness divide(a, b): [quotient, remainder]'`,
7564
+ severity: "warning"
7565
+ // Changed to warning since it's inferred, not explicitly documented
6818
7566
  });
6819
7567
  break;
6820
7568
  }
@@ -8492,6 +9240,10 @@ var HealthCheckInputSchema = z4.object({
8492
9240
  var GetStatusInputSchema = z4.object({});
8493
9241
  var CheckVersionInputSchema = z4.object({});
8494
9242
  var AutoUpdateConfigInputSchema = z4.object({});
9243
+ var GetUpdateInstructionsInputSchema = z4.object({
9244
+ platform: z4.enum(["auto", "mac", "windows", "linux"]).optional().default("auto").describe("Target platform (auto-detects if not specified)"),
9245
+ editor: z4.enum(["auto", "claude-desktop", "cursor", "vscode", "windsurf"]).optional().default("auto").describe("Target editor (provides all if auto)")
9246
+ });
8495
9247
 
8496
9248
  // src/tools/health/handlers.ts
8497
9249
  import * as os from "os";
@@ -8644,6 +9396,286 @@ async function getAutoUpdateConfig(_input) {
8644
9396
  postUpdateMessage: "\u2705 Config updated! Please restart your editor completely (quit and reopen) to use the latest version."
8645
9397
  };
8646
9398
  }
9399
+ var SUPPORTED_EDITORS = [
9400
+ "claude-desktop",
9401
+ "cursor",
9402
+ "vscode",
9403
+ "windsurf"
9404
+ ];
9405
+ function getNpmCacheClearCommand(platform3) {
9406
+ if (platform3 === "windows") {
9407
+ return 'Remove-Item -Recurse -Force "$env:USERPROFILE\\.npm\\_npx" -ErrorAction SilentlyContinue';
9408
+ }
9409
+ return "rm -rf ~/.npm/_npx";
9410
+ }
9411
+ async function getUpdateInstructions(input) {
9412
+ const platform3 = input.platform === "auto" ? detectPlatform() : input.platform;
9413
+ if (input.editor === "auto") {
9414
+ return getMultiEditorInstructions(platform3);
9415
+ }
9416
+ const editor = input.editor;
9417
+ const configPaths = getConfigPaths(platform3, editor);
9418
+ const restartCommand = getRestartCommand(platform3, editor);
9419
+ const cacheCommand = getNpmCacheClearCommand(platform3);
9420
+ return {
9421
+ title: "\u{1F504} How to Update Midnight MCP",
9422
+ currentSetup: {
9423
+ detectedPlatform: platform3,
9424
+ targetEditor: editor
9425
+ },
9426
+ steps: [
9427
+ {
9428
+ step: 1,
9429
+ title: "Clear npm cache",
9430
+ command: cacheCommand,
9431
+ windowsNote: platform3 === "windows" ? "Run in PowerShell. For cmd.exe use: rd /s /q %USERPROFILE%\\.npm\\_npx" : void 0,
9432
+ explanation: "This removes cached npx packages so the latest version will be downloaded",
9433
+ required: true
9434
+ },
9435
+ {
9436
+ step: 2,
9437
+ title: "Restart your editor completely",
9438
+ action: restartCommand,
9439
+ explanation: "A full restart is needed - just reloading the window is not enough",
9440
+ required: true
9441
+ },
9442
+ {
9443
+ step: 3,
9444
+ title: "If still outdated, update config file",
9445
+ configPath: configPaths.primary,
9446
+ alternativePaths: configPaths.alternatives,
9447
+ change: {
9448
+ find: '"midnight-mcp"',
9449
+ replaceWith: '"midnight-mcp@latest"',
9450
+ location: 'In the "args" array for the midnight server'
9451
+ },
9452
+ explanation: "Adding @latest ensures you always get the newest version",
9453
+ required: false
9454
+ }
9455
+ ],
9456
+ troubleshooting: getTroubleshootingSection(platform3, configPaths),
9457
+ exampleConfig: generateExampleConfig(editor),
9458
+ helpfulLinks: {
9459
+ documentation: "https://github.com/Olanetsoft/midnight-mcp#readme",
9460
+ issues: "https://github.com/Olanetsoft/midnight-mcp/issues"
9461
+ }
9462
+ };
9463
+ }
9464
+ function getMultiEditorInstructions(platform3) {
9465
+ const cacheCommand = getNpmCacheClearCommand(platform3);
9466
+ const editorConfigs = SUPPORTED_EDITORS.map((editor) => {
9467
+ const paths = getConfigPaths(platform3, editor);
9468
+ const restart = getRestartCommand(platform3, editor);
9469
+ return {
9470
+ editor,
9471
+ displayName: getEditorDisplayName(editor),
9472
+ configPath: paths.primary,
9473
+ alternativePaths: paths.alternatives,
9474
+ restartCommand: restart
9475
+ };
9476
+ });
9477
+ return {
9478
+ title: "\u{1F504} How to Update Midnight MCP",
9479
+ currentSetup: {
9480
+ detectedPlatform: platform3,
9481
+ targetEditor: "all (auto mode)"
9482
+ },
9483
+ commonSteps: [
9484
+ {
9485
+ step: 1,
9486
+ title: "Clear npm cache",
9487
+ command: cacheCommand,
9488
+ windowsNote: platform3 === "windows" ? "Run in PowerShell. For cmd.exe use: rd /s /q %USERPROFILE%\\.npm\\_npx" : void 0,
9489
+ explanation: "This removes cached npx packages so the latest version will be downloaded",
9490
+ required: true
9491
+ },
9492
+ {
9493
+ step: 2,
9494
+ title: "Restart your editor completely",
9495
+ explanation: "A full restart is needed - just reloading the window is not enough",
9496
+ required: true
9497
+ }
9498
+ ],
9499
+ editorSpecificPaths: editorConfigs,
9500
+ configChange: {
9501
+ find: '"midnight-mcp"',
9502
+ replaceWith: '"midnight-mcp@latest"',
9503
+ location: 'In the "args" array for the midnight server'
9504
+ },
9505
+ troubleshooting: [
9506
+ {
9507
+ issue: "Still seeing old version after restart",
9508
+ solutions: [
9509
+ platform3 === "mac" ? "Make sure you quit the editor completely (Cmd+Q)" : platform3 === "windows" ? "Make sure you quit the editor completely (Alt+F4)" : "Make sure you quit the editor completely",
9510
+ "Check if multiple editor instances are running",
9511
+ platform3 === "windows" ? 'Try: Remove-Item -Recurse -Force "$env:USERPROFILE\\.npm\\_npx", "$env:LOCALAPPDATA\\midnight-mcp"' : "Try: rm -rf ~/.npm/_npx && rm -rf ~/.cache/midnight-mcp"
9512
+ ]
9513
+ },
9514
+ {
9515
+ issue: "Config file not found",
9516
+ solutions: [
9517
+ "Check the editor-specific paths listed above",
9518
+ "Create the config file if it doesn't exist",
9519
+ "See docs: https://github.com/Olanetsoft/midnight-mcp"
9520
+ ]
9521
+ }
9522
+ ],
9523
+ exampleConfig: {
9524
+ mcpServers: {
9525
+ midnight: {
9526
+ command: "npx",
9527
+ args: ["-y", "midnight-mcp@latest"]
9528
+ }
9529
+ }
9530
+ },
9531
+ helpfulLinks: {
9532
+ documentation: "https://github.com/Olanetsoft/midnight-mcp#readme",
9533
+ issues: "https://github.com/Olanetsoft/midnight-mcp/issues"
9534
+ }
9535
+ };
9536
+ }
9537
+ function getEditorDisplayName(editor) {
9538
+ const names = {
9539
+ "claude-desktop": "Claude Desktop",
9540
+ cursor: "Cursor",
9541
+ vscode: "VS Code",
9542
+ windsurf: "Windsurf"
9543
+ };
9544
+ return names[editor] || editor;
9545
+ }
9546
+ function getTroubleshootingSection(platform3, configPaths) {
9547
+ const quitCommand = platform3 === "mac" ? "Cmd+Q" : platform3 === "windows" ? "Alt+F4" : "close completely";
9548
+ const cacheCleanup = platform3 === "windows" ? 'Remove-Item -Recurse -Force "$env:USERPROFILE\\.npm\\_npx", "$env:LOCALAPPDATA\\midnight-mcp"' : "rm -rf ~/.npm/_npx && rm -rf ~/.cache/midnight-mcp";
9549
+ return [
9550
+ {
9551
+ issue: "Still seeing old version after restart",
9552
+ solutions: [
9553
+ `Make sure you quit the editor completely (${quitCommand})`,
9554
+ "Check if multiple editor instances are running",
9555
+ `Try: ${cacheCleanup}`
9556
+ ]
9557
+ },
9558
+ {
9559
+ issue: "Config file not found",
9560
+ solutions: [
9561
+ `Primary location: ${configPaths.primary}`,
9562
+ "Create it if it doesn't exist",
9563
+ "See docs: https://github.com/Olanetsoft/midnight-mcp"
9564
+ ]
9565
+ },
9566
+ {
9567
+ issue: "Permission denied errors",
9568
+ solutions: platform3 === "windows" ? [
9569
+ "Run editor as administrator",
9570
+ "Check file permissions in Windows Security settings"
9571
+ ] : [
9572
+ "Check file permissions with ls -la",
9573
+ "Ensure your user owns the config file"
9574
+ ]
9575
+ }
9576
+ ];
9577
+ }
9578
+ function detectPlatform() {
9579
+ const p = process.platform;
9580
+ if (p === "darwin") return "mac";
9581
+ if (p === "win32") return "windows";
9582
+ return "linux";
9583
+ }
9584
+ function getConfigPaths(platform3, editor) {
9585
+ const home = process.env.HOME || process.env.USERPROFILE || "~";
9586
+ const paths = {
9587
+ mac: {
9588
+ "claude-desktop": {
9589
+ primary: `${home}/Library/Application Support/Claude/claude_desktop_config.json`,
9590
+ alternatives: []
9591
+ },
9592
+ cursor: {
9593
+ primary: `${home}/.cursor/mcp.json`,
9594
+ alternatives: [`${home}/Library/Application Support/Cursor/mcp.json`]
9595
+ },
9596
+ vscode: {
9597
+ primary: `${home}/.vscode/mcp.json`,
9598
+ alternatives: [
9599
+ `${home}/Library/Application Support/Code/User/settings.json`
9600
+ ]
9601
+ },
9602
+ windsurf: {
9603
+ primary: `${home}/.codeium/windsurf/mcp_config.json`,
9604
+ alternatives: []
9605
+ }
9606
+ },
9607
+ windows: {
9608
+ "claude-desktop": {
9609
+ primary: `%APPDATA%\\Claude\\claude_desktop_config.json`,
9610
+ alternatives: []
9611
+ },
9612
+ cursor: {
9613
+ primary: `%USERPROFILE%\\.cursor\\mcp.json`,
9614
+ alternatives: [`%APPDATA%\\Cursor\\mcp.json`]
9615
+ },
9616
+ vscode: {
9617
+ primary: `%USERPROFILE%\\.vscode\\mcp.json`,
9618
+ alternatives: [`%APPDATA%\\Code\\User\\settings.json`]
9619
+ },
9620
+ windsurf: {
9621
+ primary: `%USERPROFILE%\\.codeium\\windsurf\\mcp_config.json`,
9622
+ alternatives: []
9623
+ }
9624
+ },
9625
+ linux: {
9626
+ "claude-desktop": {
9627
+ primary: `${home}/.config/Claude/claude_desktop_config.json`,
9628
+ alternatives: []
9629
+ },
9630
+ cursor: {
9631
+ primary: `${home}/.cursor/mcp.json`,
9632
+ alternatives: [`${home}/.config/Cursor/mcp.json`]
9633
+ },
9634
+ vscode: {
9635
+ primary: `${home}/.vscode/mcp.json`,
9636
+ alternatives: [`${home}/.config/Code/User/settings.json`]
9637
+ },
9638
+ windsurf: {
9639
+ primary: `${home}/.codeium/windsurf/mcp_config.json`,
9640
+ alternatives: []
9641
+ }
9642
+ }
9643
+ };
9644
+ return paths[platform3]?.[editor] || paths.mac["claude-desktop"];
9645
+ }
9646
+ function getRestartCommand(platform3, editor) {
9647
+ const editorNames = {
9648
+ "claude-desktop": "Claude Desktop",
9649
+ cursor: "Cursor",
9650
+ vscode: "VS Code",
9651
+ windsurf: "Windsurf"
9652
+ };
9653
+ const name = editorNames[editor] || editor;
9654
+ if (platform3 === "mac") {
9655
+ return `Quit ${name} completely (Cmd+Q), then reopen`;
9656
+ } else if (platform3 === "windows") {
9657
+ return `Close ${name} completely (Alt+F4 or File > Exit), then reopen`;
9658
+ } else {
9659
+ return `Close ${name} completely, then reopen`;
9660
+ }
9661
+ }
9662
+ function generateExampleConfig(editor) {
9663
+ const baseConfig = {
9664
+ mcpServers: {
9665
+ midnight: {
9666
+ command: "npx",
9667
+ args: ["-y", "midnight-mcp@latest"]
9668
+ }
9669
+ }
9670
+ };
9671
+ if (editor === "vscode") {
9672
+ return {
9673
+ note: "For VS Code, add to settings.json or mcp.json",
9674
+ config: baseConfig
9675
+ };
9676
+ }
9677
+ return baseConfig;
9678
+ }
8647
9679
 
8648
9680
  // src/tools/health/tools.ts
8649
9681
  var healthCheckOutputSchema = {
@@ -8810,6 +9842,45 @@ var healthTools = [
8810
9842
  category: "health"
8811
9843
  },
8812
9844
  handler: getAutoUpdateConfig
9845
+ },
9846
+ {
9847
+ name: "midnight-get-update-instructions",
9848
+ description: "\u{1F4CB} Get detailed, platform-specific instructions for updating Midnight MCP to the latest version. Provides step-by-step guidance including config file locations, commands to run, and troubleshooting tips. Use this when a user needs help updating or is having issues with outdated versions.",
9849
+ inputSchema: {
9850
+ type: "object",
9851
+ properties: {
9852
+ platform: {
9853
+ type: "string",
9854
+ enum: ["auto", "mac", "windows", "linux"],
9855
+ description: "Target platform (auto-detects if not specified)",
9856
+ default: "auto"
9857
+ },
9858
+ editor: {
9859
+ type: "string",
9860
+ enum: ["auto", "claude-desktop", "cursor", "vscode", "windsurf"],
9861
+ description: "Target editor (defaults to Claude Desktop)",
9862
+ default: "auto"
9863
+ }
9864
+ }
9865
+ },
9866
+ outputSchema: {
9867
+ type: "object",
9868
+ properties: {
9869
+ title: { type: "string" },
9870
+ currentSetup: { type: "object" },
9871
+ steps: { type: "array", items: { type: "object" } },
9872
+ troubleshooting: { type: "array", items: { type: "object" } },
9873
+ exampleConfig: { type: "object" },
9874
+ helpfulLinks: { type: "object" }
9875
+ }
9876
+ },
9877
+ annotations: {
9878
+ readOnlyHint: true,
9879
+ idempotentHint: true,
9880
+ title: "\u{1F4CB} Get Update Instructions",
9881
+ category: "health"
9882
+ },
9883
+ handler: getUpdateInstructions
8813
9884
  }
8814
9885
  ];
8815
9886
 
@@ -10114,4 +11185,4 @@ export {
10114
11185
  startServer,
10115
11186
  startHttpServer
10116
11187
  };
10117
- //# sourceMappingURL=chunk-YT6DWZUA.js.map
11188
+ //# sourceMappingURL=chunk-V7KK64OX.js.map