context-markets-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,217 @@
1
+ // src/ui/output.ts
2
+ import chalk from "chalk";
3
+
4
+ // src/ui/table.ts
5
+ import Table from "cli-table3";
6
+ var ROUNDED_CHARS = {
7
+ top: "\u2500",
8
+ "top-mid": "\u252C",
9
+ "top-left": "\u256D",
10
+ "top-right": "\u256E",
11
+ bottom: "\u2500",
12
+ "bottom-mid": "\u2534",
13
+ "bottom-left": "\u2570",
14
+ "bottom-right": "\u256F",
15
+ left: "\u2502",
16
+ "left-mid": "\u251C",
17
+ mid: "\u2500",
18
+ "mid-mid": "\u253C",
19
+ right: "\u2502",
20
+ "right-mid": "\u2524",
21
+ middle: "\u2502"
22
+ };
23
+ function getByPath(obj, path) {
24
+ const tokens = path.replace(/\[(\d+)\]/g, ".$1").split(".");
25
+ let current = obj;
26
+ for (const token of tokens) {
27
+ if (current == null || typeof current !== "object") return void 0;
28
+ current = current[token];
29
+ }
30
+ return current;
31
+ }
32
+ function makeTable(data, columns, emptyMessage, numbered) {
33
+ if (data.length === 0) {
34
+ return emptyMessage ?? "No results.";
35
+ }
36
+ const head = [];
37
+ const colWidths = [];
38
+ if (numbered) {
39
+ head.push("#");
40
+ colWidths.push(null);
41
+ }
42
+ for (const col of columns) {
43
+ head.push(col.label);
44
+ colWidths.push(col.width ?? null);
45
+ }
46
+ const table = new Table({
47
+ head,
48
+ chars: ROUNDED_CHARS,
49
+ colWidths,
50
+ style: { head: [], border: [] }
51
+ });
52
+ for (let i = 0; i < data.length; i++) {
53
+ const row = [];
54
+ if (numbered) {
55
+ row.push(String(i + 1));
56
+ }
57
+ for (const col of columns) {
58
+ const raw = getByPath(data[i], col.key);
59
+ if (col.format) {
60
+ row.push(col.format(raw));
61
+ } else {
62
+ row.push(raw == null ? "" : String(raw));
63
+ }
64
+ }
65
+ table.push(row);
66
+ }
67
+ return table.toString();
68
+ }
69
+ function makeDetailTable(rows) {
70
+ const table = new Table({
71
+ chars: ROUNDED_CHARS,
72
+ style: { head: [], border: [] }
73
+ });
74
+ for (const [label, value] of rows) {
75
+ table.push([label, value]);
76
+ }
77
+ return table.toString();
78
+ }
79
+
80
+ // src/ui/output.ts
81
+ var replacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
82
+ function resolveOutputMode(flags) {
83
+ const explicit = flags["output"] || flags["o"];
84
+ if (explicit === "json") return "json";
85
+ if (explicit === "table") return "table";
86
+ return process.stdout.isTTY ? "table" : "json";
87
+ }
88
+ var _onResults = null;
89
+ function onResults(cb) {
90
+ _onResults = cb;
91
+ }
92
+ function printOut(data, mode, config) {
93
+ if (mode === "json") {
94
+ console.log(JSON.stringify(data, replacer, 2));
95
+ return;
96
+ }
97
+ if (!config) {
98
+ console.log(JSON.stringify(data, replacer, 2));
99
+ return;
100
+ }
101
+ if (config.detail) {
102
+ console.log(makeDetailTable(config.detail));
103
+ return;
104
+ }
105
+ if (config.columns) {
106
+ const items = config.rows || (Array.isArray(data) ? data : [data]);
107
+ console.log(
108
+ makeTable(items, config.columns, config.emptyMessage, config.numbered)
109
+ );
110
+ if (config.numbered && _onResults) {
111
+ _onResults(items, config.cursor);
112
+ }
113
+ if (config.cursor) {
114
+ const showing = config.total ? `Showing ${items.length} of ${config.total}` : `Showing ${items.length}`;
115
+ console.log(chalk.dim(` ${showing} \xB7 Next: --cursor ${config.cursor}`));
116
+ }
117
+ return;
118
+ }
119
+ console.log(JSON.stringify(data, replacer, 2));
120
+ }
121
+ var FailError = class extends Error {
122
+ constructor(message) {
123
+ super(message);
124
+ this.name = "FailError";
125
+ }
126
+ };
127
+ function printFail(message, mode, details) {
128
+ if (mode === "json") {
129
+ const payload = { error: message };
130
+ if (details !== void 0) payload.details = details;
131
+ console.error(JSON.stringify(payload, replacer, 2));
132
+ } else {
133
+ console.error(chalk.red(`\u2717 ${message}`));
134
+ if (details && typeof details === "object" && details !== null && "usage" in details) {
135
+ console.error(
136
+ chalk.dim(` Usage: ${details.usage}`)
137
+ );
138
+ }
139
+ }
140
+ }
141
+
142
+ // src/format.ts
143
+ var _mode = "json";
144
+ function setOutputMode(flags) {
145
+ _mode = resolveOutputMode(flags);
146
+ }
147
+ function getOutputMode() {
148
+ return _mode;
149
+ }
150
+ function out(data, config) {
151
+ printOut(data, _mode, config);
152
+ }
153
+ function fail(message, details) {
154
+ printFail(message, _mode, details);
155
+ throw new FailError(message);
156
+ }
157
+ function parseArgs(argv) {
158
+ const args = argv.slice(2);
159
+ const command = args[0] ?? "help";
160
+ const positional = [];
161
+ const flags = {};
162
+ let i = 1;
163
+ while (i < args.length) {
164
+ const arg = args[i];
165
+ if (arg.startsWith("--")) {
166
+ const eqIdx = arg.indexOf("=");
167
+ if (eqIdx !== -1) {
168
+ flags[arg.slice(2, eqIdx)] = arg.slice(eqIdx + 1);
169
+ i += 1;
170
+ } else {
171
+ const key = arg.slice(2);
172
+ const next = args[i + 1];
173
+ if (next !== void 0 && !next.startsWith("--")) {
174
+ flags[key] = next;
175
+ i += 2;
176
+ } else {
177
+ flags[key] = "true";
178
+ i += 1;
179
+ }
180
+ }
181
+ } else if (arg === "-o" && i + 1 < args.length) {
182
+ flags["output"] = args[i + 1];
183
+ i += 2;
184
+ } else {
185
+ positional.push(arg);
186
+ i += 1;
187
+ }
188
+ }
189
+ const subcommand = positional.length > 0 ? positional.shift() : void 0;
190
+ return { command, subcommand, positional, flags };
191
+ }
192
+ function requireFlag(flags, key, usage) {
193
+ const value = flags[key];
194
+ if (!value || value === "true") {
195
+ fail(`Missing required flag: --${key}`, { usage });
196
+ }
197
+ return value;
198
+ }
199
+ function requirePositional(positional, index, name, usage) {
200
+ const value = positional[index];
201
+ if (!value) {
202
+ fail(`Missing required argument: <${name}>`, { usage });
203
+ }
204
+ return value;
205
+ }
206
+
207
+ export {
208
+ onResults,
209
+ printFail,
210
+ setOutputMode,
211
+ getOutputMode,
212
+ out,
213
+ fail,
214
+ parseArgs,
215
+ requireFlag,
216
+ requirePositional
217
+ };
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ fail,
4
+ getOutputMode,
5
+ parseArgs,
6
+ printFail,
7
+ setOutputMode
8
+ } from "./chunk-QC6BGRUQ.js";
9
+
10
+ // src/cli.ts
11
+ var HELP_TEXT = `Usage: context <command> [subcommand] [options]
12
+
13
+ Commands:
14
+ markets Browse and search prediction markets
15
+ orders Manage orders (create, cancel, list)
16
+ portfolio View positions and balances
17
+ account Wallet status, deposits, withdrawals
18
+ questions Submit questions for AI market generation
19
+ guides [topic] View usage guides
20
+ shell Interactive mode
21
+
22
+ Onboarding:
23
+ setup Guided wallet setup wizard
24
+ approve Approve the operator for gasless trading
25
+ deposit Deposit USDC into the exchange
26
+ gasless-approve Gasless operator approval via relayer (no gas)
27
+ gasless-deposit <amount> Gasless USDC deposit via permit (no gas)
28
+
29
+ Options:
30
+ -o, --output <table|json> Output format (auto-detects TTY)
31
+ --api-key <key> Context API key (or CONTEXT_API_KEY env)
32
+ --private-key <key> Private key (or CONTEXT_PRIVATE_KEY env)
33
+ --rpc-url <url> Base Sepolia RPC URL (or CONTEXT_RPC_URL env)
34
+ --yes Skip confirmations (for automation)
35
+
36
+ Run "context help" for this message, or "context <command> help" for details.`;
37
+ var REVERT_REASONS = {
38
+ "5452414e534645525f46524f4d5f4641494c4544": "USDC transfer failed \u2014 insufficient wallet balance",
39
+ "494e53554646494349454e545f42414c414e4345": "Insufficient balance",
40
+ "4e4f545f415554484f52495a4544": "Not authorized"
41
+ };
42
+ function decodeRevertHex(hex) {
43
+ const match = hex.match(/08c379a0[0-9a-f]{128}([0-9a-f]+)/i);
44
+ if (!match) return null;
45
+ const reasonHex = match[1].replace(/0+$/, "");
46
+ for (const [known, label] of Object.entries(REVERT_REASONS)) {
47
+ if (reasonHex.toLowerCase().includes(known.toLowerCase())) return label;
48
+ }
49
+ try {
50
+ const bytes = Buffer.from(reasonHex, "hex");
51
+ const text = bytes.toString("utf8").replace(/[^\x20-\x7E]/g, "");
52
+ if (text.length > 2) return text;
53
+ } catch {
54
+ }
55
+ return null;
56
+ }
57
+ function cleanErrorMessage(raw) {
58
+ const zodMatch = raw.match(/✖\s*(.+?)(?:\n\s*→\s*at\s+(\w+))?$/s);
59
+ if (zodMatch) {
60
+ const detail = zodMatch[1].trim();
61
+ const field = zodMatch[2];
62
+ return field ? `Invalid --${field}: ${detail}` : detail;
63
+ }
64
+ if (raw.includes("exceeds the balance of the account")) {
65
+ return "Insufficient ETH for gas. Fund your wallet with testnet ETH on Base Sepolia.";
66
+ }
67
+ const revertMatch = raw.match(/reverted.*?reason:\s*(0x[0-9a-f]+)/i);
68
+ if (revertMatch) {
69
+ const decoded = decodeRevertHex(revertMatch[1]);
70
+ if (decoded) return decoded;
71
+ }
72
+ if (raw.includes("UserOperation reverted")) {
73
+ const hexMatch = raw.match(/(0x[0-9a-f]{64,})/i);
74
+ if (hexMatch) {
75
+ const decoded = decodeRevertHex(hexMatch[1]);
76
+ if (decoded) return decoded;
77
+ }
78
+ return "Transaction reverted \u2014 check your wallet balance and approvals.";
79
+ }
80
+ if (raw.includes("Docs: https://viem.sh") || raw.includes("Version: viem@")) {
81
+ const detailsMatch = raw.match(/Details:\s*(.+?)(?:\n|$)/);
82
+ if (detailsMatch) return detailsMatch[1].trim();
83
+ return raw.split("\n")[0].trim();
84
+ }
85
+ return raw;
86
+ }
87
+ async function main() {
88
+ const parsed = parseArgs(process.argv);
89
+ setOutputMode(parsed.flags);
90
+ if (parsed.command === "help" && process.stdout.isTTY && process.stdin.isTTY) {
91
+ const { runShell } = await import("./shell-XBM2FEIR.js");
92
+ await runShell();
93
+ return;
94
+ }
95
+ try {
96
+ switch (parsed.command) {
97
+ case "markets": {
98
+ const mod = await import("./markets-WZCKLKJR.js");
99
+ await mod.default(parsed);
100
+ break;
101
+ }
102
+ case "questions": {
103
+ const mod = await import("./questions-P6AUM6D4.js");
104
+ await mod.default(parsed);
105
+ break;
106
+ }
107
+ case "orders": {
108
+ const mod = await import("./orders-IA2XKE5J.js");
109
+ await mod.default(parsed);
110
+ break;
111
+ }
112
+ case "portfolio": {
113
+ const mod = await import("./portfolio-73RM2RAQ.js");
114
+ await mod.default(parsed);
115
+ break;
116
+ }
117
+ case "account": {
118
+ const mod = await import("./account-DL4WGQCC.js");
119
+ await mod.default(parsed);
120
+ break;
121
+ }
122
+ case "setup":
123
+ case "approve":
124
+ case "deposit":
125
+ case "gasless-approve":
126
+ case "gasless-deposit": {
127
+ const mod = await import("./setup-KDTGKF6O.js");
128
+ const positional = parsed.subcommand ? [parsed.subcommand, ...parsed.positional] : parsed.positional;
129
+ await mod.default({ ...parsed, subcommand: parsed.command, positional });
130
+ break;
131
+ }
132
+ case "guides": {
133
+ const mod = await import("./guides-Y2YWEZCY.js");
134
+ await mod.default(parsed);
135
+ break;
136
+ }
137
+ case "shell": {
138
+ const { runShell } = await import("./shell-XBM2FEIR.js");
139
+ await runShell();
140
+ break;
141
+ }
142
+ case "help":
143
+ console.log(HELP_TEXT);
144
+ break;
145
+ default:
146
+ fail(`Unknown command: "${parsed.command}". Run "context help" for usage.`);
147
+ }
148
+ } catch (err) {
149
+ if (err instanceof Error && err.name === "CancelError") {
150
+ process.exit(0);
151
+ }
152
+ if (err instanceof Error && err.name === "FailError") {
153
+ process.exit(1);
154
+ }
155
+ const raw = err instanceof Error ? err.message : String(err);
156
+ const message = raw.includes("Cannot find module") ? `Command module not yet implemented: ${parsed.command}` : cleanErrorMessage(raw);
157
+ printFail(message, getOutputMode());
158
+ process.exit(1);
159
+ }
160
+ }
161
+ main();
@@ -0,0 +1,101 @@
1
+ import {
2
+ fail
3
+ } from "./chunk-QC6BGRUQ.js";
4
+
5
+ // src/commands/guides.ts
6
+ import { readFileSync, readdirSync } from "fs";
7
+ import { join, basename } from "path";
8
+ import chalk from "chalk";
9
+ var SKILLS_DIR = join(import.meta.dir, "../../skills");
10
+ function loadGuideIndex() {
11
+ const guides = /* @__PURE__ */ new Map();
12
+ let files;
13
+ try {
14
+ files = readdirSync(SKILLS_DIR).filter((f) => f.endsWith(".md"));
15
+ } catch {
16
+ return guides;
17
+ }
18
+ for (const file of files) {
19
+ const slug = basename(file, ".md");
20
+ const content = readFileSync(join(SKILLS_DIR, file), "utf-8");
21
+ const descMatch = content.match(/^description:\s*(.+)$/m);
22
+ const description = descMatch ? descMatch[1].trim() : "";
23
+ guides.set(slug, { description, file });
24
+ }
25
+ return guides;
26
+ }
27
+ function renderMarkdown(content) {
28
+ const lines = content.split("\n");
29
+ const output = [];
30
+ let inFrontmatter = false;
31
+ let inCodeBlock = false;
32
+ for (const line of lines) {
33
+ if (line.trim() === "---") {
34
+ inFrontmatter = !inFrontmatter;
35
+ continue;
36
+ }
37
+ if (inFrontmatter) continue;
38
+ if (line.trim().startsWith("```")) {
39
+ inCodeBlock = !inCodeBlock;
40
+ if (inCodeBlock) {
41
+ output.push(chalk.dim(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
42
+ } else {
43
+ output.push(chalk.dim(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
44
+ }
45
+ continue;
46
+ }
47
+ if (inCodeBlock) {
48
+ output.push(chalk.dim(" \u2502 ") + line);
49
+ continue;
50
+ }
51
+ if (line.startsWith("# ")) {
52
+ output.push("");
53
+ output.push(chalk.bold(line.slice(2)));
54
+ output.push("");
55
+ continue;
56
+ }
57
+ if (line.startsWith("## ")) {
58
+ output.push("");
59
+ output.push(chalk.bold(line.slice(3)));
60
+ output.push(chalk.dim("\u2500".repeat(line.length - 3)));
61
+ continue;
62
+ }
63
+ if (line.startsWith("### ")) {
64
+ output.push("");
65
+ output.push(chalk.bold.dim(line.slice(4)));
66
+ continue;
67
+ }
68
+ output.push(line);
69
+ }
70
+ return output.join("\n");
71
+ }
72
+ async function handleGuides(parsed) {
73
+ const topic = parsed.subcommand;
74
+ const guides = loadGuideIndex();
75
+ if (!topic) {
76
+ console.log();
77
+ console.log(chalk.bold(" Available Guides"));
78
+ console.log(chalk.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
79
+ console.log();
80
+ for (const [slug, info] of guides) {
81
+ console.log(
82
+ ` ${chalk.bold(slug.padEnd(20))} ${chalk.dim(info.description)}`
83
+ );
84
+ }
85
+ console.log();
86
+ console.log(chalk.dim(" Usage: context guides <topic>"));
87
+ console.log();
88
+ return;
89
+ }
90
+ const guide = guides.get(topic);
91
+ if (!guide) {
92
+ fail(
93
+ `Unknown guide: "${topic}". Run "context guides" to see available guides.`
94
+ );
95
+ }
96
+ const content = readFileSync(join(SKILLS_DIR, guide.file), "utf-8");
97
+ console.log(renderMarkdown(content));
98
+ }
99
+ export {
100
+ handleGuides as default
101
+ };