moon-iq 0.2.0 → 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/src/index.ts DELETED
@@ -1,307 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command, Option } from "commander";
3
- import {
4
- clearCredentials,
5
- getConfig,
6
- getConfigOrDefault,
7
- getCredentials,
8
- getValidToken,
9
- login,
10
- refreshCredentials,
11
- } from "./auth";
12
- import { callToolWithAuth, TOOL_NAMES } from "./client";
13
- import {
14
- TOOL_DEFINITIONS,
15
- type ToolDefinition,
16
- type ToolOption,
17
- } from "./generated/client";
18
-
19
- const DEFAULT_BASE_URL = "https://moon-iq.com";
20
-
21
- const program = new Command();
22
-
23
- program.name("mooniq").description("Moon IQ CLI").version("0.2.0");
24
-
25
- program
26
- .command("login")
27
- .description("Log in to Moon IQ via OAuth")
28
- .option(
29
- "-b, --base-url <url>",
30
- "Base URL (default: https://moon-iq.com or from ~/.config/moon-iq/config.json)",
31
- )
32
- .action(async (options) => {
33
- const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
34
- const config = getConfigOrDefault(baseUrl);
35
-
36
- try {
37
- await login({ ...config, baseUrl });
38
- console.log("Logged in successfully.");
39
- } catch (error) {
40
- console.error("Login failed:", (error as Error).message);
41
- process.exit(1);
42
- }
43
- });
44
-
45
- program
46
- .command("logout")
47
- .description("Log out and clear stored credentials")
48
- .action(() => {
49
- clearCredentials();
50
- console.log("Logged out.");
51
- });
52
-
53
- program
54
- .command("whoami")
55
- .description("Show current user info")
56
- .action(async () => {
57
- let token = await getValidToken();
58
- if (!token) {
59
- console.error("Not logged in. Run `mooniq login` first.");
60
- process.exit(1);
61
- }
62
-
63
- const creds = getCredentials();
64
- const config = getConfig();
65
- const baseUrl =
66
- config?.baseUrl ?? creds?.baseUrl ?? DEFAULT_BASE_URL;
67
-
68
- let res = await fetch(`${baseUrl}/api/oauth/userinfo`, {
69
- headers: { Authorization: `Bearer ${token}` },
70
- });
71
-
72
- if (res.status === 401 && creds?.refreshToken && config && config.baseUrl === creds.baseUrl) {
73
- try {
74
- const newCreds = await refreshCredentials(creds, config);
75
- res = await fetch(`${baseUrl}/api/oauth/userinfo`, {
76
- headers: { Authorization: `Bearer ${newCreds.accessToken}` },
77
- });
78
- } catch {
79
- // Refresh failed, fall through
80
- }
81
- }
82
-
83
- if (!res.ok) {
84
- console.error("Failed to fetch user info:", res.status);
85
- process.exit(1);
86
- }
87
-
88
- const userinfo = await res.json();
89
- console.log(JSON.stringify(userinfo, null, 2));
90
- });
91
-
92
- program
93
- .command("run <tool_name>")
94
- .description("Run a tool by name. Use --input for JSON params.")
95
- .option(
96
- "-i, --input <json>",
97
- "Input parameters as JSON (omit for empty params)",
98
- )
99
- .option(
100
- "-b, --base-url <url>",
101
- "Base URL (default: from credentials or https://moon-iq.com)",
102
- )
103
- .addHelpText(
104
- "after",
105
- `
106
- Examples:
107
- mooniq run user_retrieve # no params
108
- mooniq run token_search --input '{"query":"SOL","chain":"solana"}' # with params
109
- `,
110
- )
111
- .action(async (toolName: string, options) => {
112
- const toolNames = TOOL_NAMES as readonly string[];
113
- if (!toolNames.includes(toolName)) {
114
- console.error(`Unknown tool: ${toolName}`);
115
- console.error(`Available tools: ${toolNames.slice(0, 10).join(", ")}...`);
116
- process.exit(1);
117
- }
118
-
119
- let params: Record<string, unknown> = {};
120
- if (options.input) {
121
- try {
122
- params = JSON.parse(options.input);
123
- } catch {
124
- console.error("Invalid JSON in --input");
125
- process.exit(1);
126
- }
127
- }
128
-
129
- const creds = getCredentials();
130
- const config = getConfig();
131
- const baseUrl =
132
- options.baseUrl ?? config?.baseUrl ?? creds?.baseUrl ?? DEFAULT_BASE_URL;
133
-
134
- try {
135
- const result = await callToolWithAuth(baseUrl, toolName, params);
136
- console.log(JSON.stringify(result, null, 2));
137
- } catch (error) {
138
- console.error("Tool call failed:", (error as Error).message);
139
- process.exit(1);
140
- }
141
- });
142
-
143
- program
144
- .command("tools")
145
- .description("List available tools")
146
- .action(() => {
147
- TOOL_NAMES.forEach((name) => console.log(name));
148
- });
149
-
150
- /**
151
- * Build hierarchical subcommands from tool definitions.
152
- * e.g., token_balance_list -> mooniq token balance list --wallet <wallet> --chain <chain>
153
- */
154
- function buildToolCommands(program: Command): void {
155
- // Build a tree structure from tool names
156
- type CommandNode = {
157
- children: Map<string, CommandNode>;
158
- tool?: ToolDefinition;
159
- };
160
-
161
- const root: CommandNode = { children: new Map() };
162
-
163
- // Build the tree
164
- for (const tool of TOOL_DEFINITIONS) {
165
- const parts = tool.name.split("_");
166
- let current = root;
167
-
168
- for (let i = 0; i < parts.length; i++) {
169
- const part = parts[i];
170
- if (!current.children.has(part)) {
171
- current.children.set(part, { children: new Map() });
172
- }
173
- current = current.children.get(part)!;
174
-
175
- // If this is the last part, attach the tool
176
- if (i === parts.length - 1) {
177
- current.tool = tool;
178
- }
179
- }
180
- }
181
-
182
- // Recursively create Commander commands
183
- function createCommands(node: CommandNode, parent: Command, path: string[]) {
184
- for (const [name, child] of node.children) {
185
- const currentPath = [...path, name];
186
-
187
- if (child.tool) {
188
- // This is a leaf node with a tool
189
- const cmd = parent
190
- .command(name)
191
- .description(child.tool.description || `Run ${child.tool.name}`);
192
-
193
- // Add options from the tool schema
194
- for (const opt of child.tool.options) {
195
- const optionFlag = createOptionFlag(opt);
196
- const option = new Option(optionFlag, opt.description);
197
-
198
- if (opt.choices) {
199
- option.choices(opt.choices);
200
- }
201
-
202
- if (opt.required) {
203
- cmd.addOption(option);
204
- } else {
205
- cmd.addOption(option);
206
- }
207
- }
208
-
209
- // Add base-url option
210
- cmd.option(
211
- "-b, --base-url <url>",
212
- "Base URL (default: from credentials or https://moon-iq.com)",
213
- );
214
-
215
- // Add action handler
216
- const toolName = child.tool.name;
217
- cmd.action(async (options) => {
218
- const params = buildParams(child.tool!.options, options);
219
-
220
- const creds = getCredentials();
221
- const config = getConfig();
222
- const baseUrl =
223
- options.baseUrl ??
224
- config?.baseUrl ??
225
- creds?.baseUrl ??
226
- DEFAULT_BASE_URL;
227
-
228
- try {
229
- const result = await callToolWithAuth(baseUrl, toolName, params);
230
- console.log(JSON.stringify(result, null, 2));
231
- } catch (error) {
232
- console.error("Tool call failed:", (error as Error).message);
233
- process.exit(1);
234
- }
235
- });
236
-
237
- // If there are more children, recurse
238
- if (child.children.size > 0) {
239
- createCommands(child, cmd, currentPath);
240
- }
241
- } else if (child.children.size > 0) {
242
- // This is an intermediate node
243
- const cmd = parent
244
- .command(name)
245
- .description(`${name} commands`);
246
-
247
- createCommands(child, cmd, currentPath);
248
- }
249
- }
250
- }
251
-
252
- createCommands(root, program, []);
253
- }
254
-
255
- /**
256
- * Create an option flag string for Commander
257
- */
258
- function createOptionFlag(opt: ToolOption): string {
259
- const kebabName = opt.name.replace(/([A-Z])/g, "-$1").toLowerCase();
260
-
261
- if (opt.type === "boolean") {
262
- return `--${kebabName}`;
263
- }
264
-
265
- const valuePlaceholder = `<${opt.name}>`;
266
- return `--${kebabName} ${valuePlaceholder}`;
267
- }
268
-
269
- /**
270
- * Build params object from options
271
- */
272
- function buildParams(
273
- toolOptions: ToolOption[],
274
- cmdOptions: Record<string, unknown>,
275
- ): Record<string, unknown> {
276
- const params: Record<string, unknown> = {};
277
-
278
- for (const opt of toolOptions) {
279
- // Convert kebab-case back to camelCase for lookup
280
- const kebabName = opt.name.replace(/([A-Z])/g, "-$1").toLowerCase();
281
- const camelName = kebabName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
282
-
283
- // Commander converts --some-option to someOption
284
- const value = cmdOptions[camelName] ?? cmdOptions[opt.name];
285
-
286
- if (value !== undefined) {
287
- // Convert types as needed
288
- if (opt.type === "number" && typeof value === "string") {
289
- params[opt.name] = parseFloat(value);
290
- } else if (opt.type === "boolean") {
291
- params[opt.name] = value === true || value === "true";
292
- } else {
293
- params[opt.name] = value;
294
- }
295
- } else if (!opt.required) {
296
- // Set null for optional params that weren't provided
297
- params[opt.name] = null;
298
- }
299
- }
300
-
301
- return params;
302
- }
303
-
304
- // Build all tool commands
305
- buildToolCommands(program);
306
-
307
- program.parse();
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "noEmit": true
7
- },
8
- "include": ["src/**/*", "tsup.config.ts"],
9
- "exclude": ["node_modules", "dist"]
10
- }
package/tsup.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- entry: ["src/index.ts"],
5
- format: ["esm"],
6
- target: "node18",
7
- outDir: "dist",
8
- clean: true,
9
- sourcemap: true,
10
- });