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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Context
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ <p align="center">
2
+ <img src="https://mainnet.contextcdn.com/ced823d63df9dff0390d9ad0a4e1ad3905dd199a6c50758c18a5c92a203adbd7" alt="Context" width="100%" />
3
+ </p>
4
+
5
+ <h1 align="center">Context CLI</h1>
6
+ <p align="center">CLI for trading on <a href="https://context.markets">Context Markets</a> prediction markets. All output is JSON. Designed for AI agents.</p>
7
+
8
+ <p align="center">
9
+ <a href="https://www.npmjs.com/package/context-markets-cli"><img src="https://img.shields.io/npm/v/context-markets-cli" alt="npm" /></a>
10
+ <a href="https://github.com/contextwtf/context-cli/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License: MIT" /></a>
11
+ <a href="https://discord.gg/RVmzZsAyM4"><img src="https://img.shields.io/badge/Discord-Join-7289da" alt="Discord" /></a>
12
+ </p>
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npx context-markets-cli <command>
18
+ ```
19
+
20
+ Or install globally:
21
+
22
+ ```bash
23
+ npm install -g context-markets-cli
24
+ ```
25
+
26
+ ## Setup
27
+
28
+ ```bash
29
+ export CONTEXT_API_KEY="your-api-key"
30
+ export CONTEXT_PRIVATE_KEY="0x..." # required for trading/account commands
31
+ ```
32
+
33
+ Need an API key? Visit [context.markets](https://context.markets) or join our [Discord](https://discord.gg/RVmzZsAyM4).
34
+
35
+ ## Quick Start
36
+
37
+ ```bash
38
+ # Browse markets
39
+ context markets list --status active --limit 5
40
+
41
+ # Get quotes for a market
42
+ context markets quotes <market-id>
43
+
44
+ # Place a limit order
45
+ context orders create --market <id> --outcome yes --side buy --price 45 --size 10
46
+
47
+ # Check your portfolio
48
+ context portfolio get
49
+ ```
50
+
51
+ ## Commands
52
+
53
+ **Markets** — `markets list` · `markets get` · `markets quotes` · `markets orderbook` · `markets simulate` · `markets price-history` · `markets oracle` · `markets oracle-quotes` · `markets activity` · `markets create` · `markets global-activity`
54
+
55
+ **Orders** — `orders list` · `orders mine` · `orders get` · `orders recent` · `orders simulate` · `orders create` · `orders market` · `orders cancel` · `orders cancel-replace` · `orders bulk-create` · `orders bulk-cancel` · `orders bulk`
56
+
57
+ **Portfolio** — `portfolio get` · `portfolio claimable` · `portfolio stats` · `portfolio balance` · `portfolio token-balance`
58
+
59
+ **Account** — `account status` · `account setup` · `account mint-test-usdc` · `account deposit` · `account withdraw`
60
+
61
+ **Questions** — `questions submit` · `questions status` · `questions submit-and-wait`
62
+
63
+ **Gasless** — `setup` · `gasless-approve` · `gasless-deposit`
64
+
65
+ ## Key Concepts
66
+
67
+ - **Prices** are in cents (1–99). A price of 65 means $0.65 per share.
68
+ - **Outcomes** are `yes` or `no`. Each market is a binary question.
69
+ - **All output is JSON** to stdout. Errors are JSON to stderr with exit code 1.
70
+ - **Read-only commands** only need `CONTEXT_API_KEY`. **Trading commands** also need `CONTEXT_PRIVATE_KEY`.
71
+
72
+ ## Documentation
73
+
74
+ - **[Command Reference](https://docs.context.markets/agents/cli/commands)** — full list of commands with flags and response shapes
75
+ - **[CLI Guide](https://docs.context.markets/agents/cli)** — setup, authentication, and workflows
76
+ - **[Agent Workflows](https://docs.context.markets/agents/cli/workflows)** — common patterns for AI agent integration
77
+
78
+ ## Ecosystem
79
+
80
+ | Package | Description |
81
+ |---------|-------------|
82
+ | **[context-markets](https://github.com/contextwtf/context-sdk)** | TypeScript SDK for trading |
83
+ | **[@contextwtf/react](https://github.com/contextwtf/context-react)** | React hooks for market data and trading |
84
+ | **[@contextwtf/mcp](https://github.com/contextwtf/context-mcp)** | MCP server for AI agents |
85
+ | **[context-markets-cli](https://github.com/contextwtf/context-cli)** | CLI for trading from the terminal |
86
+ | **[context-skills](https://github.com/contextwtf/context-skills)** | AI agent skill files |
87
+ | **[context-plugin](https://github.com/contextwtf/context-plugin)** | Claude Code plugin |
88
+
89
+ ## License
90
+
91
+ MIT — see [LICENSE](./LICENSE) for details.
@@ -0,0 +1,207 @@
1
+ import {
2
+ formatAddress,
3
+ formatMoney,
4
+ truncate
5
+ } from "./chunk-IRVQREUN.js";
6
+ import {
7
+ tradingClient
8
+ } from "./chunk-BUZKJ7FR.js";
9
+ import {
10
+ fail,
11
+ out,
12
+ requirePositional
13
+ } from "./chunk-QC6BGRUQ.js";
14
+
15
+ // src/commands/account.ts
16
+ var HELP = `Usage: context account <subcommand> [options]
17
+
18
+ Subcommands:
19
+ status Check wallet status (balances, approvals)
20
+ setup Approve contracts for gasless trading
21
+ mint-test-usdc Mint test USDC on testnet
22
+ --amount <n> Amount to mint (default: 1000)
23
+
24
+ deposit <amount> Deposit USDC into the exchange
25
+ withdraw <amount> Withdraw USDC from the exchange
26
+
27
+ mint-complete-sets <market-id> <amount>
28
+ Mint complete sets of outcome tokens
29
+ burn-complete-sets <market-id> <amount>
30
+ Burn complete sets of outcome tokens
31
+ --credit-internal <true|false> Credit internal balance (default: true)
32
+
33
+ help Show this help text
34
+
35
+ All account commands require a signer (--private-key or CONTEXT_PRIVATE_KEY).
36
+
37
+ Global options:
38
+ --api-key <key> Context API key (or CONTEXT_API_KEY env)
39
+ --private-key <key> Private key for signing (or CONTEXT_PRIVATE_KEY env)`;
40
+ async function handleAccount(parsed) {
41
+ const { subcommand, positional, flags } = parsed;
42
+ switch (subcommand) {
43
+ case "status":
44
+ return status(flags);
45
+ case "setup":
46
+ return setup(flags);
47
+ case "mint-test-usdc":
48
+ return mintTestUsdc(flags);
49
+ case "deposit":
50
+ return deposit(positional, flags);
51
+ case "withdraw":
52
+ return withdraw(positional, flags);
53
+ case "mint-complete-sets":
54
+ return mintCompleteSets(positional, flags);
55
+ case "burn-complete-sets":
56
+ return burnCompleteSets(positional, flags);
57
+ case "relay-operator-approval":
58
+ return fail(
59
+ "Use `context gasless-approve` for gasless operator approval."
60
+ );
61
+ case "relay-deposit":
62
+ return fail(
63
+ "Use `context gasless-deposit <amount>` for gasless deposit."
64
+ );
65
+ case "help":
66
+ case void 0:
67
+ console.log(HELP);
68
+ return;
69
+ default:
70
+ fail(
71
+ `Unknown account subcommand: "${subcommand}". Run "context account help" for usage.`
72
+ );
73
+ }
74
+ }
75
+ async function status(flags) {
76
+ const ctx = tradingClient(flags);
77
+ const result = await ctx.account.status();
78
+ const s = result;
79
+ out(result, {
80
+ detail: [
81
+ ["Address", formatAddress(s.address)],
82
+ ["ETH Balance", s.ethBalance || "\u2014"],
83
+ ["USDC Allowance", s.usdcAllowance ? "\u2713 Approved" : "\u2717 None"],
84
+ ["Operator", s.isOperatorApproved ? "\u2713 Approved" : "\u2717 Not approved"],
85
+ ["Needs Setup", s.needsApprovals ? "Yes \u2014 run `context setup`" : "No"]
86
+ ]
87
+ });
88
+ }
89
+ async function setup(flags) {
90
+ const ctx = tradingClient(flags);
91
+ const result = await ctx.account.setup();
92
+ out(result, {
93
+ detail: [
94
+ ["Status", "\u2713 Contracts approved"]
95
+ ]
96
+ });
97
+ }
98
+ async function mintTestUsdc(flags) {
99
+ const amountRaw = flags["amount"];
100
+ let amount;
101
+ if (amountRaw) {
102
+ amount = parseFloat(amountRaw);
103
+ if (isNaN(amount) || amount <= 0) {
104
+ fail("--amount must be a positive number", { received: amountRaw });
105
+ }
106
+ }
107
+ const ctx = tradingClient(flags);
108
+ const result = await ctx.account.mintTestUsdc(amount);
109
+ const r = result;
110
+ out(result, {
111
+ detail: [
112
+ ["Status", "\u2713 Minted"],
113
+ ["Amount", formatMoney(r.amount ?? amount)],
114
+ ["Tx Hash", formatAddress(r.txHash || r.tx_hash)]
115
+ ]
116
+ });
117
+ }
118
+ async function deposit(positional, flags) {
119
+ const raw = requirePositional(
120
+ positional,
121
+ 0,
122
+ "amount",
123
+ "context account deposit <amount>"
124
+ );
125
+ const amount = parseFloat(raw);
126
+ if (isNaN(amount) || amount <= 0) {
127
+ fail("Deposit amount must be a positive number", { received: raw });
128
+ }
129
+ const ctx = tradingClient(flags);
130
+ const txHash = await ctx.account.deposit(amount);
131
+ out({ status: "deposited", amount_usdc: amount, tx_hash: txHash }, {
132
+ detail: [
133
+ ["Status", "\u2713 Deposited"],
134
+ ["Amount", formatMoney(amount)],
135
+ ["Tx Hash", formatAddress(txHash)]
136
+ ]
137
+ });
138
+ }
139
+ async function withdraw(positional, flags) {
140
+ const raw = requirePositional(
141
+ positional,
142
+ 0,
143
+ "amount",
144
+ "context account withdraw <amount>"
145
+ );
146
+ const amount = parseFloat(raw);
147
+ if (isNaN(amount) || amount <= 0) {
148
+ fail("Withdraw amount must be a positive number", { received: raw });
149
+ }
150
+ const ctx = tradingClient(flags);
151
+ const txHash = await ctx.account.withdraw(amount);
152
+ out({ status: "withdrawn", amount_usdc: amount, tx_hash: txHash }, {
153
+ detail: [
154
+ ["Status", "\u2713 Withdrawn"],
155
+ ["Amount", formatMoney(amount)],
156
+ ["Tx Hash", formatAddress(txHash)]
157
+ ]
158
+ });
159
+ }
160
+ async function mintCompleteSets(positional, flags) {
161
+ const usage = "context account mint-complete-sets <market-id> <amount>";
162
+ const marketId = requirePositional(positional, 0, "market-id", usage);
163
+ const amountRaw = requirePositional(positional, 1, "amount", usage);
164
+ const amount = parseFloat(amountRaw);
165
+ if (isNaN(amount) || amount <= 0) {
166
+ fail("Amount must be a positive number", { received: amountRaw });
167
+ }
168
+ const ctx = tradingClient(flags);
169
+ const txHash = await ctx.account.mintCompleteSets(marketId, amount);
170
+ out({ status: "minted", market_id: marketId, amount, tx_hash: txHash }, {
171
+ detail: [
172
+ ["Status", "\u2713 Minted complete sets"],
173
+ ["Market", truncate(marketId, 20)],
174
+ ["Amount", String(amount)],
175
+ ["Tx Hash", formatAddress(txHash)]
176
+ ]
177
+ });
178
+ }
179
+ async function burnCompleteSets(positional, flags) {
180
+ const usage = "context account burn-complete-sets <market-id> <amount>";
181
+ const marketId = requirePositional(positional, 0, "market-id", usage);
182
+ const amountRaw = requirePositional(positional, 1, "amount", usage);
183
+ const amount = parseFloat(amountRaw);
184
+ if (isNaN(amount) || amount <= 0) {
185
+ fail("Amount must be a positive number", { received: amountRaw });
186
+ }
187
+ const creditInternalRaw = flags["credit-internal"];
188
+ const creditInternal = creditInternalRaw !== "false";
189
+ const ctx = tradingClient(flags);
190
+ const txHash = await ctx.account.burnCompleteSets(
191
+ marketId,
192
+ amount,
193
+ creditInternal
194
+ );
195
+ out({ status: "burned", market_id: marketId, amount, credit_internal: creditInternal, tx_hash: txHash }, {
196
+ detail: [
197
+ ["Status", "\u2713 Burned complete sets"],
198
+ ["Market", truncate(marketId, 20)],
199
+ ["Amount", String(amount)],
200
+ ["Credit Internal", String(creditInternal)],
201
+ ["Tx Hash", formatAddress(txHash)]
202
+ ]
203
+ });
204
+ }
205
+ export {
206
+ handleAccount as default
207
+ };
@@ -0,0 +1,75 @@
1
+ import {
2
+ getOutputMode
3
+ } from "./chunk-QC6BGRUQ.js";
4
+
5
+ // src/ui/prompt.ts
6
+ import * as readline from "readline";
7
+ import chalk from "chalk";
8
+ var CancelError = class extends Error {
9
+ constructor() {
10
+ super("Cancelled.");
11
+ this.name = "CancelError";
12
+ }
13
+ };
14
+ var _shellRl = null;
15
+ function setShellReadline(rl) {
16
+ _shellRl = rl;
17
+ }
18
+ function confirm(message) {
19
+ const prompt = chalk.cyan(` ? ${message} ${chalk.dim("(Y/n)")} `);
20
+ if (_shellRl) {
21
+ return new Promise((resolve) => {
22
+ _shellRl.question(prompt, (answer) => {
23
+ const trimmed = answer.trim().toLowerCase();
24
+ resolve(trimmed === "" || trimmed === "y" || trimmed === "yes");
25
+ });
26
+ });
27
+ }
28
+ return new Promise((resolve) => {
29
+ const rl = readline.createInterface({
30
+ input: process.stdin,
31
+ output: process.stderr,
32
+ terminal: true
33
+ });
34
+ rl.question(prompt, (answer) => {
35
+ rl.close();
36
+ const trimmed = answer.trim().toLowerCase();
37
+ resolve(trimmed === "" || trimmed === "y" || trimmed === "yes");
38
+ });
39
+ });
40
+ }
41
+ async function confirmOrder(summary, flags) {
42
+ if (getOutputMode() === "json" || flags["yes"] === "true" || !process.stdout.isTTY) {
43
+ return;
44
+ }
45
+ console.log();
46
+ console.log(chalk.bold(" Order Summary"));
47
+ console.log(chalk.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
48
+ if (summary.market) console.log(` Market: ${summary.market}`);
49
+ console.log(` Side: ${summary.side.toUpperCase()} ${summary.outcome.toUpperCase()}`);
50
+ if (summary.price) console.log(` Price: ${summary.price}`);
51
+ if (summary.size) console.log(` Size: ${summary.size} shares`);
52
+ if (summary.estimatedCost) console.log(` Cost: ~${summary.estimatedCost}`);
53
+ console.log();
54
+ const confirmed = await confirm("Place this order?");
55
+ if (!confirmed) {
56
+ console.log(chalk.dim(" Cancelled."));
57
+ throw new CancelError();
58
+ }
59
+ }
60
+ async function confirmAction(message, flags) {
61
+ if (getOutputMode() === "json" || flags["yes"] === "true" || !process.stdout.isTTY) {
62
+ return;
63
+ }
64
+ const confirmed = await confirm(message);
65
+ if (!confirmed) {
66
+ console.log(chalk.dim(" Cancelled."));
67
+ throw new CancelError();
68
+ }
69
+ }
70
+
71
+ export {
72
+ setShellReadline,
73
+ confirmOrder,
74
+ confirmAction
75
+ };
@@ -0,0 +1,37 @@
1
+ import {
2
+ fail
3
+ } from "./chunk-QC6BGRUQ.js";
4
+
5
+ // src/client.ts
6
+ import { ContextClient } from "context-markets";
7
+ function readClient(flags = {}) {
8
+ const apiKey = flags["api-key"] ?? process.env.CONTEXT_API_KEY;
9
+ if (!apiKey) fail("Missing CONTEXT_API_KEY env var or --api-key flag");
10
+ const rpcUrl = flags["rpc-url"] ?? process.env.CONTEXT_RPC_URL;
11
+ const baseUrl = flags["base-url"] ?? process.env.CONTEXT_BASE_URL;
12
+ return new ContextClient({ apiKey, rpcUrl, baseUrl });
13
+ }
14
+ function tradingClient(flags = {}) {
15
+ const apiKey = flags["api-key"] ?? process.env.CONTEXT_API_KEY;
16
+ if (!apiKey) fail("Missing CONTEXT_API_KEY env var or --api-key flag");
17
+ const privateKey = flags["private-key"] ?? process.env.CONTEXT_PRIVATE_KEY;
18
+ if (!privateKey) {
19
+ fail(
20
+ "A private key is required for trading operations.",
21
+ { hint: "Set CONTEXT_PRIVATE_KEY env var or pass --private-key <key>" }
22
+ );
23
+ }
24
+ const rpcUrl = flags["rpc-url"] ?? process.env.CONTEXT_RPC_URL;
25
+ const baseUrl = flags["base-url"] ?? process.env.CONTEXT_BASE_URL;
26
+ return new ContextClient({
27
+ apiKey,
28
+ rpcUrl,
29
+ baseUrl,
30
+ signer: { privateKey }
31
+ });
32
+ }
33
+
34
+ export {
35
+ readClient,
36
+ tradingClient
37
+ };
@@ -0,0 +1,55 @@
1
+ // src/ui/format.ts
2
+ var DASH = "\u2014";
3
+ function formatPrice(value) {
4
+ if (value === null || value === void 0) return DASH;
5
+ const n = typeof value === "string" ? Number(value) : value;
6
+ if (n === 0) return DASH;
7
+ const cents = n / 1e4;
8
+ return `${cents.toFixed(cents % 1 === 0 ? 0 : 1)}\xA2`;
9
+ }
10
+ function formatMoney(value) {
11
+ if (value === null || value === void 0) return DASH;
12
+ const n = typeof value === "string" ? Number(value) : value;
13
+ if (n >= 1e6) return `$${(n / 1e6).toFixed(1)}M`;
14
+ if (n >= 1e3) return `$${(n / 1e3).toFixed(1)}K`;
15
+ return `$${n.toFixed(2)}`;
16
+ }
17
+ function formatVolume(value) {
18
+ if (value === null || value === void 0) return DASH;
19
+ const n = typeof value === "string" ? Number(value) : value;
20
+ const dollars = n / 1e6;
21
+ if (dollars >= 1e6) return `$${(dollars / 1e6).toFixed(1)}M`;
22
+ if (dollars >= 1e3) return `$${(dollars / 1e3).toFixed(1)}K`;
23
+ if (dollars >= 1) return `$${dollars.toFixed(2)}`;
24
+ if (dollars > 0) return `$${dollars.toFixed(2)}`;
25
+ return "$0.00";
26
+ }
27
+ function formatAddress(value) {
28
+ if (value === null || value === void 0) return DASH;
29
+ if (value.length <= 10) return value;
30
+ return `${value.slice(0, 6)}...${value.slice(-4)}`;
31
+ }
32
+ function truncate(value, maxLen) {
33
+ if (value === null || value === void 0) return DASH;
34
+ if (value.length <= maxLen) return value;
35
+ return value.slice(0, maxLen - 3) + "...";
36
+ }
37
+ function formatDate(value) {
38
+ if (value === null || value === void 0) return DASH;
39
+ const d = new Date(value);
40
+ return d.toLocaleDateString("en-US", {
41
+ month: "short",
42
+ day: "numeric",
43
+ year: "numeric",
44
+ timeZone: "UTC"
45
+ });
46
+ }
47
+
48
+ export {
49
+ formatPrice,
50
+ formatMoney,
51
+ formatVolume,
52
+ formatAddress,
53
+ truncate,
54
+ formatDate
55
+ };