@conquest-eth/tools 0.0.0 → 0.0.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.
Files changed (178) hide show
  1. package/README.md +20 -51
  2. package/dist/cli-tool-generator.d.ts +2 -1
  3. package/dist/cli-tool-generator.d.ts.map +1 -1
  4. package/dist/cli.js +61 -32
  5. package/dist/cli.js.map +1 -1
  6. package/dist/contracts/space-info.d.ts.map +1 -1
  7. package/dist/contracts/space-info.js +22 -1
  8. package/dist/contracts/space-info.js.map +1 -1
  9. package/dist/fleet/resolve.d.ts +1 -1
  10. package/dist/fleet/resolve.d.ts.map +1 -1
  11. package/dist/fleet/resolve.js +5 -4
  12. package/dist/fleet/resolve.js.map +1 -1
  13. package/dist/fleet/send.d.ts.map +1 -1
  14. package/dist/fleet/send.js +8 -8
  15. package/dist/fleet/send.js.map +1 -1
  16. package/dist/index.d.ts +6 -32
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +21 -128
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp.d.ts +14 -0
  21. package/dist/mcp.d.ts.map +1 -0
  22. package/dist/mcp.js +29 -0
  23. package/dist/mcp.js.map +1 -0
  24. package/dist/planet/acquire.d.ts +3 -2
  25. package/dist/planet/acquire.d.ts.map +1 -1
  26. package/dist/planet/acquire.js +6 -4
  27. package/dist/planet/acquire.js.map +1 -1
  28. package/dist/planet/exit.d.ts.map +1 -1
  29. package/dist/planet/exit.js +1 -0
  30. package/dist/planet/exit.js.map +1 -1
  31. package/dist/planet/manager.d.ts +63 -0
  32. package/dist/planet/manager.d.ts.map +1 -1
  33. package/dist/planet/manager.js +125 -2
  34. package/dist/planet/manager.js.map +1 -1
  35. package/dist/planet/withdraw.d.ts +17 -0
  36. package/dist/planet/withdraw.d.ts.map +1 -0
  37. package/dist/planet/withdraw.js +25 -0
  38. package/dist/planet/withdraw.js.map +1 -0
  39. package/dist/storage/interface.d.ts +6 -0
  40. package/dist/storage/interface.d.ts.map +1 -1
  41. package/dist/storage/json-storage.d.ts +1 -0
  42. package/dist/storage/json-storage.d.ts.map +1 -1
  43. package/dist/storage/json-storage.js +10 -1
  44. package/dist/storage/json-storage.js.map +1 -1
  45. package/dist/tool-handling/cli-tool-generator.d.ts +22 -0
  46. package/dist/tool-handling/cli-tool-generator.d.ts.map +1 -0
  47. package/dist/tool-handling/cli-tool-generator.js +345 -0
  48. package/dist/tool-handling/cli-tool-generator.js.map +1 -0
  49. package/dist/tool-handling/cli.d.ts +19 -0
  50. package/dist/tool-handling/cli.d.ts.map +1 -0
  51. package/dist/tool-handling/cli.js +472 -0
  52. package/dist/tool-handling/cli.js.map +1 -0
  53. package/dist/tool-handling/index.d.ts +15 -0
  54. package/dist/tool-handling/index.d.ts.map +1 -0
  55. package/dist/tool-handling/index.js +32 -0
  56. package/dist/tool-handling/index.js.map +1 -0
  57. package/dist/tool-handling/mcp.d.ts +22 -0
  58. package/dist/tool-handling/mcp.d.ts.map +1 -0
  59. package/dist/tool-handling/mcp.js +88 -0
  60. package/dist/tool-handling/mcp.js.map +1 -0
  61. package/dist/tool-handling/types.d.ts +72 -0
  62. package/dist/tool-handling/types.d.ts.map +1 -0
  63. package/dist/tool-handling/types.js +10 -0
  64. package/dist/tool-handling/types.js.map +1 -0
  65. package/dist/tools/acquire_planets.d.ts +7 -5
  66. package/dist/tools/acquire_planets.d.ts.map +1 -1
  67. package/dist/tools/acquire_planets.js +28 -42
  68. package/dist/tools/acquire_planets.js.map +1 -1
  69. package/dist/tools/exit_planets.d.ts +7 -3
  70. package/dist/tools/exit_planets.d.ts.map +1 -1
  71. package/dist/tools/exit_planets.js +20 -9
  72. package/dist/tools/exit_planets.js.map +1 -1
  73. package/dist/tools/get_my_planets.d.ts +3 -2
  74. package/dist/tools/get_my_planets.d.ts.map +1 -1
  75. package/dist/tools/get_my_planets.js +5 -4
  76. package/dist/tools/get_my_planets.js.map +1 -1
  77. package/dist/tools/get_native_token_balance.d.ts +6 -0
  78. package/dist/tools/get_native_token_balance.d.ts.map +1 -0
  79. package/dist/tools/get_native_token_balance.js +64 -0
  80. package/dist/tools/get_native_token_balance.js.map +1 -0
  81. package/dist/tools/get_pending_exits.d.ts +2 -1
  82. package/dist/tools/get_pending_exits.d.ts.map +1 -1
  83. package/dist/tools/get_pending_exits.js +5 -4
  84. package/dist/tools/get_pending_exits.js.map +1 -1
  85. package/dist/tools/get_pending_fleets.d.ts +2 -1
  86. package/dist/tools/get_pending_fleets.d.ts.map +1 -1
  87. package/dist/tools/get_pending_fleets.js +5 -4
  88. package/dist/tools/get_pending_fleets.js.map +1 -1
  89. package/dist/tools/get_planets_around.d.ts +8 -4
  90. package/dist/tools/get_planets_around.d.ts.map +1 -1
  91. package/dist/tools/get_planets_around.js +40 -15
  92. package/dist/tools/get_planets_around.js.map +1 -1
  93. package/dist/tools/get_play_token_balance.d.ts +6 -0
  94. package/dist/tools/get_play_token_balance.d.ts.map +1 -0
  95. package/dist/tools/get_play_token_balance.js +80 -0
  96. package/dist/tools/get_play_token_balance.js.map +1 -0
  97. package/dist/tools/index.d.ts +7 -1
  98. package/dist/tools/index.d.ts.map +1 -1
  99. package/dist/tools/index.js +7 -1
  100. package/dist/tools/index.js.map +1 -1
  101. package/dist/tools/missiv_get_user.d.ts +6 -0
  102. package/dist/tools/missiv_get_user.d.ts.map +1 -0
  103. package/dist/tools/missiv_get_user.js +50 -0
  104. package/dist/tools/missiv_get_user.js.map +1 -0
  105. package/dist/tools/missiv_register.d.ts +6 -0
  106. package/dist/tools/missiv_register.d.ts.map +1 -0
  107. package/dist/tools/missiv_register.js +103 -0
  108. package/dist/tools/missiv_register.js.map +1 -0
  109. package/dist/tools/resolve_fleet.d.ts +3 -2
  110. package/dist/tools/resolve_fleet.d.ts.map +1 -1
  111. package/dist/tools/resolve_fleet.js +5 -4
  112. package/dist/tools/resolve_fleet.js.map +1 -1
  113. package/dist/tools/send_fleet.d.ts +3 -2
  114. package/dist/tools/send_fleet.d.ts.map +1 -1
  115. package/dist/tools/send_fleet.js +16 -15
  116. package/dist/tools/send_fleet.js.map +1 -1
  117. package/dist/tools/simulate.d.ts +14 -0
  118. package/dist/tools/simulate.d.ts.map +1 -0
  119. package/dist/tools/simulate.js +123 -0
  120. package/dist/tools/simulate.js.map +1 -0
  121. package/dist/tools/simulate_multiple.d.ts +17 -0
  122. package/dist/tools/simulate_multiple.d.ts.map +1 -0
  123. package/dist/tools/simulate_multiple.js +166 -0
  124. package/dist/tools/simulate_multiple.js.map +1 -0
  125. package/dist/tools/verify_exit_status.d.ts +5 -3
  126. package/dist/tools/verify_exit_status.d.ts.map +1 -1
  127. package/dist/tools/verify_exit_status.js +12 -8
  128. package/dist/tools/verify_exit_status.js.map +1 -1
  129. package/dist/tools/withdraw.d.ts +9 -0
  130. package/dist/tools/withdraw.d.ts.map +1 -0
  131. package/dist/tools/withdraw.js +86 -0
  132. package/dist/tools/withdraw.js.map +1 -0
  133. package/dist/types.d.ts +31 -28
  134. package/dist/types.d.ts.map +1 -1
  135. package/dist/types.js +1 -33
  136. package/dist/types.js.map +1 -1
  137. package/dist/util/time.d.ts +0 -30
  138. package/dist/util/time.d.ts.map +1 -1
  139. package/dist/util/time.js +0 -36
  140. package/dist/util/time.js.map +1 -1
  141. package/package.json +80 -77
  142. package/src/cli.ts +88 -59
  143. package/src/contracts/space-info.ts +24 -1
  144. package/src/fleet/resolve.ts +5 -4
  145. package/src/fleet/send.ts +9 -8
  146. package/src/index.ts +28 -162
  147. package/src/mcp.ts +46 -0
  148. package/src/planet/acquire.ts +6 -6
  149. package/src/planet/exit.ts +1 -0
  150. package/src/planet/manager.ts +163 -0
  151. package/src/planet/withdraw.ts +33 -0
  152. package/src/storage/interface.ts +7 -0
  153. package/src/storage/json-storage.ts +11 -1
  154. package/src/tool-handling/cli.ts +559 -0
  155. package/src/tool-handling/index.ts +45 -0
  156. package/src/tool-handling/mcp.ts +127 -0
  157. package/src/tool-handling/types.ts +86 -0
  158. package/src/tools/acquire_planets.ts +34 -60
  159. package/src/tools/exit_planets.ts +25 -12
  160. package/src/tools/get_native_token_balance.ts +72 -0
  161. package/src/tools/get_pending_exits.ts +8 -5
  162. package/src/tools/get_pending_fleets.ts +8 -5
  163. package/src/tools/get_planets_around.ts +45 -16
  164. package/src/tools/get_play_token_balance.ts +90 -0
  165. package/src/tools/index.ts +7 -1
  166. package/src/tools/missiv_get_user.ts +68 -0
  167. package/src/tools/missiv_register.ts +122 -0
  168. package/src/tools/resolve_fleet.ts +8 -5
  169. package/src/tools/send_fleet.ts +21 -18
  170. package/src/tools/simulate.ts +141 -0
  171. package/src/tools/simulate_multiple.ts +197 -0
  172. package/src/tools/verify_exit_status.ts +15 -11
  173. package/src/tools/withdraw.ts +100 -0
  174. package/src/types.ts +33 -71
  175. package/src/util/time.ts +0 -46
  176. package/src/cli-tool-generator.ts +0 -287
  177. package/src/helpers/index.ts +0 -59
  178. package/src/tools/get_my_planets.ts +0 -30
@@ -0,0 +1,100 @@
1
+ import {z} from 'zod';
2
+ import {createTool} from '../tool-handling/types.js';
3
+ import type {ConquestEnv} from '../types.js';
4
+
5
+ const schema = z.object({
6
+ coordinates: z
7
+ .array(
8
+ z.object({
9
+ x: z.number().describe('X coordinate of the planet'),
10
+ y: z.number().describe('Y coordinate of the planet'),
11
+ }),
12
+ )
13
+ .optional()
14
+ .describe(
15
+ 'Optional array of planet coordinates to withdraw tokens from. If not provided, automatically withdraws from all planets that have completed exits and are ready for withdrawal.',
16
+ ),
17
+ });
18
+
19
+ export const withdraw = createTool<typeof schema, ConquestEnv>({
20
+ description:
21
+ 'Withdraw staked tokens from planets that have completed their exit process. If coordinates are provided, withdraws from those specific planets. If no coordinates are provided, automatically finds and withdraws from all planets with completed exits that have not been withdrawn yet.',
22
+ schema,
23
+ execute: async (env, {coordinates}) => {
24
+ try {
25
+ // If coordinates are provided, withdraw from specific planets
26
+ if (coordinates && coordinates.length > 0) {
27
+ // Convert x,y coordinates to planet IDs
28
+ const planetIdsBigInt: bigint[] = [];
29
+ for (const coord of coordinates) {
30
+ const planetId = env.planetManager.getPlanetIdByCoordinates(coord.x, coord.y);
31
+ if (planetId === undefined) {
32
+ throw new Error(`No planet found at coordinates (${coord.x}, ${coord.y})`);
33
+ }
34
+ planetIdsBigInt.push(planetId);
35
+ }
36
+
37
+ // Call withdraw method
38
+ const result = await env.planetManager.withdraw(planetIdsBigInt);
39
+
40
+ return {
41
+ success: true,
42
+ result: {
43
+ transactionHash: result.hash,
44
+ coordinates: coordinates,
45
+ planetsWithdrawn: result.planetsWithdrawn.map((id) => id.toString()),
46
+ },
47
+ };
48
+ }
49
+
50
+ // No coordinates provided - automatically find and withdraw all ready exits
51
+ const withdrawableExits = await env.planetManager.getWithdrawableExits();
52
+
53
+ if (withdrawableExits.length === 0) {
54
+ return {
55
+ success: true,
56
+ result: {
57
+ message: 'No planets with completed exits ready for withdrawal',
58
+ planetsWithdrawn: [],
59
+ },
60
+ };
61
+ }
62
+
63
+ // Get coordinates for the withdrawable planets (for return value)
64
+ const withdrawableCoordinates = withdrawableExits
65
+ .map((exit) => {
66
+ const planet = env.planetManager.getPlanetInfo(exit.planetId);
67
+ return planet ? {x: planet.location.x, y: planet.location.y} : null;
68
+ })
69
+ .filter((c): c is {x: number; y: number} => c !== null);
70
+
71
+ // Withdraw all
72
+ const result = await env.planetManager.withdrawAll();
73
+
74
+ if (!result) {
75
+ return {
76
+ success: true,
77
+ result: {
78
+ message: 'No planets with completed exits ready for withdrawal',
79
+ planetsWithdrawn: [],
80
+ },
81
+ };
82
+ }
83
+
84
+ return {
85
+ success: true,
86
+ result: {
87
+ transactionHash: result.hash,
88
+ coordinates: withdrawableCoordinates,
89
+ planetsWithdrawn: result.planetsWithdrawn.map((id) => id.toString()),
90
+ message: `Successfully withdrew tokens from ${result.planetsWithdrawn.length} planet(s)`,
91
+ },
92
+ };
93
+ } catch (error) {
94
+ return {
95
+ success: false,
96
+ error: error instanceof Error ? error.message : String(error),
97
+ };
98
+ }
99
+ },
100
+ });
package/src/types.ts CHANGED
@@ -1,11 +1,36 @@
1
1
  import type {Address, PublicClient, WalletClient} from 'viem';
2
- import type {PlanetInfo} from 'conquest-eth-v0-contracts';
2
+ import type {PlanetInfo, SpaceInfo} from 'conquest-eth-v0-contracts';
3
3
  import type {Abi_IOuterSpace} from 'conquest-eth-v0-contracts/abis/IOuterSpace.js';
4
- import type {CallToolResult} from '@modelcontextprotocol/sdk/types.js';
5
- import {z} from 'zod';
6
4
  import type {FleetManager} from './fleet/manager.js';
7
5
  import type {PlanetManager} from './planet/manager.js';
8
6
 
7
+ /**
8
+ * Configuration options for creating the ConquestEnv
9
+ */
10
+ export interface EnvFactoryOptions {
11
+ /** RPC URL for the Ethereum network */
12
+ rpcUrl: string;
13
+ /** Contract address of the game */
14
+ gameContract: `0x${string}`;
15
+ /** Optional private key for sending transactions */
16
+ privateKey?: `0x${string}`;
17
+ /** Path to storage directory (default: './data') */
18
+ storagePath?: string;
19
+ }
20
+
21
+ /**
22
+ * Environment type for Conquest tools
23
+ * Contains the managers needed for tool execution
24
+ */
25
+ export interface ConquestEnv {
26
+ fleetManager: FleetManager;
27
+ planetManager: PlanetManager;
28
+ spaceInfo: SpaceInfo;
29
+ contractConfig: ContractConfig;
30
+ clients: ClientsWithOptionalWallet;
31
+ options: EnvFactoryOptions;
32
+ }
33
+
9
34
  export interface StorageConfig {
10
35
  type: 'json' | 'sqlite';
11
36
  dataDir?: string; // Default: `${cwd}/data`
@@ -32,7 +57,9 @@ export interface ContractConfig {
32
57
  timePerDistance: bigint;
33
58
  exitDuration: bigint;
34
59
  acquireNumSpaceships: number;
35
- [key: string]: bigint | number;
60
+ stakingToken: `0x${string}`;
61
+ numTokensPerNativeToken: bigint;
62
+ [key: string]: bigint | number | `0x${string}`;
36
63
  }
37
64
 
38
65
  export interface ExternalPlanet {
@@ -66,6 +93,8 @@ export interface PendingExit {
66
93
  completed: boolean; // Whether exit has completed
67
94
  interrupted: boolean; // Whether exit was interrupted by attack
68
95
  lastCheckedAt: number; // Last time status was verified against contract
96
+ withdrawn: boolean; // Whether tokens have been withdrawn
97
+ withdrawnAt?: number; // Timestamp when tokens were withdrawn
69
98
  }
70
99
 
71
100
  export interface PlanetWithDistance {
@@ -109,70 +138,3 @@ export interface FleetResolution {
109
138
  fleetSender: `0x${string}`; // Address that sent the fleet
110
139
  operator: `0x${string}`; // Address that committed the transaction
111
140
  }
112
-
113
- // Tool types for MCP server refactoring
114
- export type ToolEnvironment = {
115
- // Function to send status updates during tool execution (required)
116
- sendStatus: (message: string) => Promise<void>;
117
- // Fleet manager for fleet operations
118
- fleetManager: FleetManager;
119
- // Planet manager for planet operations
120
- planetManager: PlanetManager;
121
- };
122
-
123
- // Result returned by tool execute functions
124
- export type ToolResult =
125
- | {success: true; result: Record<string, any>}
126
- | {success: false; error: string; stack?: string};
127
-
128
- // Tool definition with execute, schema, and description
129
- export type Tool<S extends z.ZodObject<any> = z.ZodObject<any>> = {
130
- description: string;
131
- schema: S;
132
- execute: (env: ToolEnvironment, params: z.infer<S>) => Promise<ToolResult>;
133
- };
134
-
135
- // Helper function to create a tool with automatic type inference
136
- export function createTool<S extends z.ZodObject<any>>(config: {
137
- description: string;
138
- schema: S;
139
- execute: (env: ToolEnvironment, params: z.infer<S>) => Promise<ToolResult>;
140
- }): Tool<S> {
141
- return config;
142
- }
143
-
144
- // Convert ToolResult to CallToolResult format
145
- export function convertToCallToolResult(result: ToolResult): CallToolResult {
146
- // Import stringifyWithBigInt to handle BigInt serialization
147
- const stringifyWithBigInt = (obj: any, space?: number): string => {
148
- return JSON.stringify(
149
- obj,
150
- (_key, value) => (typeof value === 'bigint' ? value.toString() : value),
151
- space,
152
- );
153
- };
154
-
155
- if (result.success === false) {
156
- return {
157
- content: [
158
- {
159
- type: 'text' as const,
160
- text: stringifyWithBigInt({
161
- error: result.error,
162
- ...(result.stack ? {stack: result.stack} : {}),
163
- }),
164
- },
165
- ],
166
- isError: true,
167
- };
168
- }
169
-
170
- return {
171
- content: [
172
- {
173
- type: 'text' as const,
174
- text: stringifyWithBigInt(result.result, 2),
175
- },
176
- ],
177
- };
178
- }
package/src/util/time.ts CHANGED
@@ -5,52 +5,6 @@ export function getCurrentTimestamp(): number {
5
5
  return Math.floor(Date.now() / 1000);
6
6
  }
7
7
 
8
- /**
9
- * Calculate estimated arrival time based on distance and timePerDistance
10
- *
11
- * @param distance - The distance between planets
12
- * @param timePerDistance - Time multiplier from contract config (seconds per distance unit)
13
- * @param genesis - Genesis timestamp from contract config
14
- * @returns Estimated arrival time in seconds
15
- */
16
- export function calculateEstimatedArrivalTime(params: {
17
- startTime: bigint;
18
- distance: bigint;
19
- timePerDistance: bigint;
20
- }): number {
21
- const {startTime, distance, timePerDistance} = params;
22
- const travelTime = Number(distance) * Number(timePerDistance);
23
- return Number(startTime) + travelTime;
24
- }
25
-
26
- /**
27
- * Calculate when the resolve window opens
28
- * A fleet can be resolved after it arrives and the resolve window has passed
29
- *
30
- * @param estimatedArrivalTime - When the fleet is estimated to arrive
31
- * @param resolveWindow - The resolve window duration in seconds from contract config
32
- * @returns The timestamp when the fleet can be resolved
33
- */
34
- export function calculateResolveWindowOpen(
35
- estimatedArrivalTime: number,
36
- resolveWindow: bigint,
37
- ): number {
38
- return estimatedArrivalTime + Number(resolveWindow);
39
- }
40
-
41
- /**
42
- * Check if a fleet can be resolved now
43
- *
44
- * @param estimatedArrivalTime - When the fleet was estimated to arrive
45
- * @param resolveWindow - The resolve window duration in seconds
46
- * @returns True if the fleet can be resolved now
47
- */
48
- export function canResolveNow(estimatedArrivalTime: number, resolveWindow: bigint): boolean {
49
- const currentTime = getCurrentTimestamp();
50
- const resolveWindowOpen = calculateResolveWindowOpen(estimatedArrivalTime, resolveWindow);
51
- return currentTime >= resolveWindowOpen;
52
- }
53
-
54
8
  /**
55
9
  * Format timestamp as ISO string
56
10
  */
@@ -1,287 +0,0 @@
1
- import {Command} from 'commander';
2
- import {z} from 'zod';
3
- import type {Tool, ToolEnvironment, StorageConfig} from './types.js';
4
- import {getClients} from 'tools-ethereum/helpers';
5
- import {getChain} from 'tools-ethereum/helpers';
6
- import {createSpaceInfo} from './contracts/space-info.js';
7
- import {JsonFleetStorage} from './storage/json-storage.js';
8
- import {FleetManager} from './fleet/manager.js';
9
- import {PlanetManager} from './planet/manager.js';
10
- import type {ClientsWithOptionalWallet, ContractConfig, GameContract} from './types.js';
11
- import {SpaceInfo} from 'conquest-eth-v0-contracts';
12
- import {Abi_IOuterSpace} from 'conquest-eth-v0-contracts/abis/IOuterSpace.js';
13
-
14
- /**
15
- * CLI configuration parameters
16
- */
17
- export interface CliConfig {
18
- chain: any;
19
- privateKey?: `0x${string}`;
20
- gameContract: `0x${string}`;
21
- ethereum?: boolean;
22
- storageConfig: StorageConfig;
23
- }
24
-
25
- /**
26
- * Convert Zod schema field to commander.js option definition
27
- */
28
- function zodFieldToOption(name: string, field: z.ZodTypeAny): string {
29
- if (field instanceof z.ZodBoolean) {
30
- return `--${name}`;
31
- }
32
- return `--${name} <value>`;
33
- }
34
-
35
- /**
36
- * Parse option value based on Zod type
37
- */
38
- function parseOptionValue(field: z.ZodTypeAny, value: any): any {
39
- if (field instanceof z.ZodArray) {
40
- return typeof value === 'string' ? value.split(',').map((v) => v.trim()) : value;
41
- }
42
- if (field instanceof z.ZodNumber) {
43
- return Number(value);
44
- }
45
- if (field instanceof z.ZodBoolean) {
46
- return value === true || value === 'true';
47
- }
48
- return value;
49
- }
50
-
51
- /**
52
- * Extract description from Zod schema field
53
- */
54
- function getFieldDescription(field: z.ZodTypeAny): string {
55
- return (field as any).description || 'No description available';
56
- }
57
-
58
- /**
59
- * Check if a Zod field is optional
60
- */
61
- function isOptionalField(field: z.ZodTypeAny): boolean {
62
- return field instanceof z.ZodOptional || field.isOptional?.();
63
- }
64
-
65
- /**
66
- * Create a CLI tool environment for executing tools
67
- */
68
- async function createCliToolEnvironment(config: CliConfig): Promise<ToolEnvironment> {
69
- const {gameContract: gameContractAddress, chain, storageConfig} = config;
70
-
71
- // Get clients
72
- const clients = getClients({chain, privateKey: config.privateKey}) as ClientsWithOptionalWallet;
73
-
74
- // Initialize game contract
75
- const gameContract: GameContract = {
76
- address: gameContractAddress,
77
- abi: Abi_IOuterSpace,
78
- };
79
-
80
- // Initialize SpaceInfo
81
- const {spaceInfo, contractConfig} = await createSpaceInfo(clients, gameContract);
82
-
83
- // Initialize storage
84
- const storage = new JsonFleetStorage(storageConfig.dataDir || './data');
85
-
86
- // Initialize managers
87
- const fleetManager = new FleetManager(clients, gameContract, spaceInfo, contractConfig, storage);
88
- const planetManager = new PlanetManager(
89
- clients,
90
- gameContract,
91
- spaceInfo,
92
- contractConfig,
93
- storage,
94
- );
95
-
96
- return {
97
- fleetManager,
98
- planetManager,
99
- sendStatus: async (message: string) => {
100
- console.log(`[Status] ${message}`);
101
- },
102
- };
103
- }
104
-
105
- /**
106
- * Parse and validate parameters against Zod schema
107
- */
108
- async function parseAndValidateParams(
109
- schema: z.ZodObject<any>,
110
- options: Record<string, any>,
111
- ): Promise<any> {
112
- try {
113
- return await schema.parseAsync(options);
114
- } catch (error) {
115
- if (error instanceof z.ZodError) {
116
- console.error('Parameter validation error:');
117
- for (const err of error.issues) {
118
- console.error(` - ${err.path.join('.')}: ${err.message}`);
119
- }
120
- }
121
- throw error;
122
- }
123
- }
124
-
125
- /**
126
- * Format tool result for CLI output
127
- */
128
- function formatToolResult(result: {
129
- success: boolean;
130
- result?: any;
131
- error?: string;
132
- stack?: string;
133
- }): void {
134
- if (result.success) {
135
- console.log(JSON.stringify(result.result, null, 2));
136
- } else {
137
- console.error(
138
- JSON.stringify(
139
- {error: result.error, ...(result.stack ? {stack: result.stack} : {})},
140
- null,
141
- 2,
142
- ),
143
- );
144
- process.exit(1);
145
- }
146
- }
147
-
148
- /**
149
- * Generate a single tool command from tool definition
150
- */
151
- export function generateToolCommand(
152
- program: Command,
153
- toolName: string,
154
- tool: Tool<z.ZodObject<any>>,
155
- ): void {
156
- const shape = tool.schema.shape;
157
- const cmd = program.command(toolName).description(tool.description);
158
-
159
- // Add options for each schema field
160
- for (const [fieldName, field] of Object.entries(shape)) {
161
- const actualField = isOptionalField(field as z.ZodTypeAny)
162
- ? (field as z.ZodOptional<any>).unwrap()
163
- : field;
164
-
165
- // Handle nested objects by flattening them
166
- if (actualField instanceof z.ZodObject) {
167
- const nestedShape = actualField.shape;
168
- for (const [nestedKey, nestedField] of Object.entries(nestedShape)) {
169
- const optionName = `${fieldName}-${nestedKey}`;
170
- const optionDef = zodFieldToOption(optionName, nestedField);
171
- const description = getFieldDescription(nestedField);
172
- cmd.option(optionDef, description);
173
- }
174
- } else {
175
- const optionDef = zodFieldToOption(fieldName, actualField);
176
- const description = getFieldDescription(actualField);
177
-
178
- if (isOptionalField(field as z.ZodTypeAny)) {
179
- cmd.option(optionDef, description);
180
- } else {
181
- cmd.requiredOption(optionDef, description);
182
- }
183
- }
184
- }
185
-
186
- cmd.action(async (options: Record<string, any>) => {
187
- try {
188
- const globalOptions = program.opts();
189
-
190
- // Get global options
191
- const rpcUrl = options.rpcUrl || globalOptions.rpcUrl || process.env.RPC_URL;
192
- const gameContract =
193
- options.gameContract || globalOptions.gameContract || process.env.GAME_CONTRACT;
194
- const ethereum =
195
- options.ethereum ?? globalOptions.ethereum ?? process.env.ETHEREUM_TOOLS === 'true';
196
- const privateKey = options.privateKey || globalOptions.privateKey || process.env.PRIVATE_KEY;
197
- const storageType =
198
- options.storage || globalOptions.storage || process.env.STORAGE_TYPE || 'json';
199
- const storagePath =
200
- options.storagePath || globalOptions.storagePath || process.env.STORAGE_PATH || './data';
201
-
202
- // Validate required options
203
- if (!rpcUrl) {
204
- console.error('Error: --rpc-url option or RPC_URL environment variable is required');
205
- process.exit(1);
206
- }
207
- if (!gameContract) {
208
- console.error(
209
- 'Error: --game-contract option or GAME_CONTRACT environment variable is required',
210
- );
211
- process.exit(1);
212
- }
213
-
214
- // Get chain
215
- const chain = await getChain(rpcUrl);
216
-
217
- // Parse and validate parameters
218
- const params: Record<string, any> = {};
219
- for (const [fieldName, field] of Object.entries(shape)) {
220
- const actualField = isOptionalField(field as z.ZodTypeAny)
221
- ? (field as z.ZodOptional<any>).unwrap()
222
- : field;
223
-
224
- if (actualField instanceof z.ZodObject) {
225
- // Handle nested object - reconstruct from flattened options
226
- const nestedResult: Record<string, any> = {};
227
- const nestedShape = actualField.shape;
228
- for (const [nestedKey, nestedField] of Object.entries(nestedShape)) {
229
- const optionName = `${fieldName}-${nestedKey}`;
230
- if (options[optionName] !== undefined) {
231
- nestedResult[nestedKey] = parseOptionValue(nestedField, options[optionName]);
232
- }
233
- }
234
- params[fieldName] = nestedResult;
235
- } else {
236
- const value = options[fieldName];
237
- if (value !== undefined) {
238
- params[fieldName] = parseOptionValue(actualField, value);
239
- }
240
- }
241
- }
242
-
243
- const validatedParams = await parseAndValidateParams(tool.schema, params);
244
-
245
- // Create environment and execute
246
- const env = await createCliToolEnvironment({
247
- chain,
248
- privateKey: privateKey as `0x${string}`,
249
- gameContract: gameContract as `0x${string}`,
250
- ethereum,
251
- storageConfig: {
252
- type: storageType as 'json' | 'sqlite',
253
- dataDir: storagePath,
254
- },
255
- });
256
-
257
- const result = await tool.execute(env, validatedParams);
258
- formatToolResult(result);
259
- } catch (error) {
260
- if (error instanceof Error) {
261
- console.error(
262
- JSON.stringify(
263
- {error: error.message, ...(error.stack ? {stack: error.stack} : {})},
264
- null,
265
- 2,
266
- ),
267
- );
268
- } else {
269
- console.error(JSON.stringify({error: String(error)}, null, 2));
270
- }
271
- process.exit(1);
272
- }
273
- });
274
- }
275
-
276
- /**
277
- * Register all tool commands from a tools object
278
- */
279
- export function registerAllToolCommands(program: Command, tools: Record<string, Tool>): void {
280
- for (const [toolName, tool] of Object.entries(tools)) {
281
- // Skip the file that's not a tool
282
- if (toolName === 'default') continue;
283
-
284
- // Keep snake_case for CLI command names (1:1 mapping with tool names)
285
- generateToolCommand(program, toolName, tool);
286
- }
287
- }
@@ -1,59 +0,0 @@
1
- import type {Tool, ToolEnvironment} from '../types.js';
2
- import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import type {FleetManager} from '../fleet/manager.js';
4
- import type {PlanetManager} from '../planet/manager.js';
5
- import {convertToCallToolResult} from '../types.js';
6
-
7
- // Helper function to handle BigInt serialization in JSON.stringify
8
- export function stringifyWithBigInt(obj: any, space?: number): string {
9
- return JSON.stringify(
10
- obj,
11
- (_key, value) => (typeof value === 'bigint' ? value.toString() : value),
12
- space,
13
- );
14
- }
15
-
16
- // Create tool environment with sendStatus
17
- export function createToolEnvironment(
18
- server: McpServer,
19
- fleetManager: FleetManager,
20
- planetManager: PlanetManager,
21
- ): ToolEnvironment {
22
- return {
23
- sendStatus: async (_message: string) => {
24
- // TODO: Implement progress notifications when sessionId is available
25
- // For now, this is a no-op since we don't have sessionId in the current architecture
26
- },
27
- fleetManager,
28
- planetManager,
29
- };
30
- }
31
-
32
- // Register tool with MCP server
33
- export function registerTool({
34
- server,
35
- name,
36
- tool,
37
- fleetManager,
38
- planetManager,
39
- }: {
40
- server: McpServer;
41
- name: string;
42
- tool: Tool<any>;
43
- fleetManager: FleetManager;
44
- planetManager: PlanetManager;
45
- }): void {
46
- server.registerTool(
47
- name,
48
- {
49
- description: tool.description,
50
- inputSchema: tool.schema as any,
51
- },
52
- async (params: unknown) => {
53
- const env = createToolEnvironment(server, fleetManager, planetManager);
54
-
55
- const result = await tool.execute(env, params as any);
56
- return convertToCallToolResult(result);
57
- },
58
- );
59
- }
@@ -1,30 +0,0 @@
1
- import {z} from 'zod';
2
- import {createTool} from '../types.js';
3
-
4
- export const get_my_planets = createTool({
5
- description: 'Get all planets owned by the current user address.',
6
- schema: z.object({
7
- radius: z.number().max(50).describe('Search radius around origin (0,0) to find planets'),
8
- }),
9
- execute: async (env, {radius}) => {
10
- try {
11
- const planets = await env.planetManager.getMyPlanets(radius);
12
-
13
- return {
14
- success: true,
15
- result: {
16
- planets: planets.map(({info, state}) => ({
17
- planetId: info.location.id.toString(),
18
- location: info.location,
19
- ...state,
20
- })),
21
- },
22
- };
23
- } catch (error) {
24
- return {
25
- success: false,
26
- error: error instanceof Error ? error.message : String(error),
27
- };
28
- }
29
- },
30
- });