pandora-cli-skills 1.1.32 → 1.1.33

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.
@@ -131,6 +131,7 @@ function createCommandRouter(deps = {}) {
131
131
  suggest: async (handlerArgs, handlerContext) => runSuggestCommand(handlerArgs, handlerContext),
132
132
  resolve: async (handlerArgs, handlerContext) => runResolveCommand(handlerArgs, handlerContext),
133
133
  lp: async (handlerArgs, handlerContext) => runLpCommand(handlerArgs, handlerContext),
134
+ schema: async (handlerArgs, handlerContext) => deps.runSchemaCommand(handlerArgs, handlerContext),
134
135
  launch: async (handlerArgs, handlerContext) => {
135
136
  if (handlerContext.outputMode === 'json') {
136
137
  throw new CliError(
@@ -0,0 +1,56 @@
1
+ function requireDep(deps, name) {
2
+ if (!deps || typeof deps[name] !== 'function') {
3
+ throw new Error(`createRunLpCommand requires deps.${name}()`);
4
+ }
5
+ return deps[name];
6
+ }
7
+
8
+ /**
9
+ * Creates the `lp` command runner.
10
+ * @param {object} deps
11
+ * @returns {(args: string[], context: {outputMode: string}) => Promise<void>}
12
+ */
13
+ function createRunLpCommand(deps) {
14
+ const includesHelpFlag = requireDep(deps, 'includesHelpFlag');
15
+ const emitSuccess = requireDep(deps, 'emitSuccess');
16
+ const commandHelpPayload = requireDep(deps, 'commandHelpPayload');
17
+ const parseLpFlags = requireDep(deps, 'parseLpFlags');
18
+ const runLp = requireDep(deps, 'runLp');
19
+ const renderSingleEntityTable = requireDep(deps, 'renderSingleEntityTable');
20
+ const CliError = requireDep(deps, 'CliError');
21
+
22
+ return async function runLpCommand(args, context) {
23
+ if (includesHelpFlag(args)) {
24
+ if (context.outputMode === 'json') {
25
+ emitSuccess(
26
+ context.outputMode,
27
+ 'lp.help',
28
+ commandHelpPayload(
29
+ 'pandora [--output table|json] lp add|remove|positions [--market-address <address>] [--wallet <address>] [--amount-usdc <n>] [--lp-tokens <n>] [--dry-run|--execute] [--chain-id <id>] [--rpc-url <url>] [--private-key <hex>] [--usdc <address>] [--deadline-seconds <n>] [--indexer-url <url>] [--timeout-ms <ms>]',
30
+ ),
31
+ );
32
+ } else {
33
+ // eslint-disable-next-line no-console
34
+ console.log(
35
+ 'Usage: pandora [--output table|json] lp add|remove|positions [--market-address <address>] [--wallet <address>] [--amount-usdc <n>] [--lp-tokens <n>] [--dry-run|--execute] [--chain-id <id>] [--rpc-url <url>] [--private-key <hex>] [--usdc <address>] [--deadline-seconds <n>] [--indexer-url <url>] [--timeout-ms <ms>]',
36
+ );
37
+ }
38
+ return;
39
+ }
40
+ const options = parseLpFlags(args);
41
+ let payload;
42
+ try {
43
+ payload = await runLp(options);
44
+ } catch (err) {
45
+ if (err && err.code) {
46
+ throw new CliError(err.code, err.message || 'lp command failed.', err.details);
47
+ }
48
+ throw err;
49
+ }
50
+ emitSuccess(context.outputMode, 'lp', payload, renderSingleEntityTable);
51
+ };
52
+ }
53
+
54
+ module.exports = {
55
+ createRunLpCommand,
56
+ };
@@ -0,0 +1,156 @@
1
+ function requireDep(deps, name) {
2
+ if (!deps || typeof deps[name] !== 'function') {
3
+ throw new Error(`createParseLpFlags requires deps.${name}()`);
4
+ }
5
+ return deps[name];
6
+ }
7
+
8
+ function requireNumericDep(deps, name) {
9
+ const value = deps ? deps[name] : undefined;
10
+ if (!Number.isFinite(value)) {
11
+ throw new Error(`createParseLpFlags requires numeric deps.${name}`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ /**
17
+ * Creates parser for `lp add|remove|positions` command flags.
18
+ * @param {object} deps
19
+ * @returns {(args: string[]) => object}
20
+ */
21
+ function createParseLpFlags(deps) {
22
+ const CliError = requireDep(deps, 'CliError');
23
+ const parseAddressFlag = requireDep(deps, 'parseAddressFlag');
24
+ const requireFlagValue = requireDep(deps, 'requireFlagValue');
25
+ const parsePositiveNumber = requireDep(deps, 'parsePositiveNumber');
26
+ const parseInteger = requireDep(deps, 'parseInteger');
27
+ const parsePositiveInteger = requireDep(deps, 'parsePositiveInteger');
28
+ const isValidPrivateKey = requireDep(deps, 'isValidPrivateKey');
29
+ const defaultTimeoutMs = requireNumericDep(deps, 'defaultTimeoutMs');
30
+
31
+ return function parseLpFlags(args) {
32
+ const action = args[0];
33
+ if (!action || !['add', 'remove', 'positions'].includes(action)) {
34
+ throw new CliError('INVALID_ARGS', 'lp requires subcommand add|remove|positions.');
35
+ }
36
+
37
+ const rest = args.slice(1);
38
+ const options = {
39
+ action,
40
+ marketAddress: null,
41
+ wallet: null,
42
+ amountUsdc: null,
43
+ lpTokens: null,
44
+ chainId: null,
45
+ dryRun: false,
46
+ execute: false,
47
+ rpcUrl: null,
48
+ privateKey: null,
49
+ usdc: null,
50
+ deadlineSeconds: 1800,
51
+ indexerUrl: null,
52
+ timeoutMs: defaultTimeoutMs,
53
+ };
54
+
55
+ for (let i = 0; i < rest.length; i += 1) {
56
+ const token = rest[i];
57
+ if (token === '--market-address') {
58
+ options.marketAddress = parseAddressFlag(requireFlagValue(rest, i, '--market-address'), '--market-address');
59
+ i += 1;
60
+ continue;
61
+ }
62
+ if (token === '--wallet') {
63
+ options.wallet = parseAddressFlag(requireFlagValue(rest, i, '--wallet'), '--wallet');
64
+ i += 1;
65
+ continue;
66
+ }
67
+ if (token === '--amount-usdc') {
68
+ options.amountUsdc = parsePositiveNumber(requireFlagValue(rest, i, '--amount-usdc'), '--amount-usdc');
69
+ i += 1;
70
+ continue;
71
+ }
72
+ if (token === '--lp-tokens') {
73
+ options.lpTokens = parsePositiveNumber(requireFlagValue(rest, i, '--lp-tokens'), '--lp-tokens');
74
+ i += 1;
75
+ continue;
76
+ }
77
+ if (token === '--chain-id') {
78
+ options.chainId = parseInteger(requireFlagValue(rest, i, '--chain-id'), '--chain-id');
79
+ i += 1;
80
+ continue;
81
+ }
82
+ if (token === '--rpc-url') {
83
+ options.rpcUrl = requireFlagValue(rest, i, '--rpc-url');
84
+ i += 1;
85
+ continue;
86
+ }
87
+ if (token === '--private-key') {
88
+ const value = requireFlagValue(rest, i, '--private-key');
89
+ if (!isValidPrivateKey(value)) {
90
+ throw new CliError('INVALID_FLAG_VALUE', '--private-key must be 0x + 64 hex chars.');
91
+ }
92
+ options.privateKey = value;
93
+ i += 1;
94
+ continue;
95
+ }
96
+ if (token === '--usdc') {
97
+ options.usdc = parseAddressFlag(requireFlagValue(rest, i, '--usdc'), '--usdc');
98
+ i += 1;
99
+ continue;
100
+ }
101
+ if (token === '--deadline-seconds') {
102
+ options.deadlineSeconds = parsePositiveInteger(requireFlagValue(rest, i, '--deadline-seconds'), '--deadline-seconds');
103
+ if (options.deadlineSeconds < 60) {
104
+ throw new CliError('INVALID_FLAG_VALUE', '--deadline-seconds must be >= 60.');
105
+ }
106
+ i += 1;
107
+ continue;
108
+ }
109
+ if (token === '--indexer-url') {
110
+ options.indexerUrl = requireFlagValue(rest, i, '--indexer-url');
111
+ i += 1;
112
+ continue;
113
+ }
114
+ if (token === '--timeout-ms') {
115
+ options.timeoutMs = parsePositiveInteger(requireFlagValue(rest, i, '--timeout-ms'), '--timeout-ms');
116
+ i += 1;
117
+ continue;
118
+ }
119
+ if (token === '--dry-run') {
120
+ options.dryRun = true;
121
+ continue;
122
+ }
123
+ if (token === '--execute') {
124
+ options.execute = true;
125
+ continue;
126
+ }
127
+ throw new CliError('UNKNOWN_FLAG', `Unknown flag for lp ${action}: ${token}`);
128
+ }
129
+
130
+ if (action === 'positions') {
131
+ if (!options.wallet) {
132
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing wallet address. Use --wallet <address>.');
133
+ }
134
+ return options;
135
+ }
136
+
137
+ if (!options.marketAddress) {
138
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing market address. Use --market-address <address>.');
139
+ }
140
+ if (action === 'add' && options.amountUsdc === null) {
141
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing liquidity amount. Use --amount-usdc <amount>.');
142
+ }
143
+ if (action === 'remove' && options.lpTokens === null) {
144
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing LP token amount. Use --lp-tokens <amount>.');
145
+ }
146
+ if (options.dryRun === options.execute) {
147
+ throw new CliError('INVALID_ARGS', 'Use exactly one mode: --dry-run or --execute.');
148
+ }
149
+
150
+ return options;
151
+ };
152
+ }
153
+
154
+ module.exports = {
155
+ createParseLpFlags,
156
+ };
@@ -0,0 +1,242 @@
1
+ function requireDep(deps, name) {
2
+ if (!deps || typeof deps[name] !== 'function') {
3
+ throw new Error(`Polymarket parser factory requires deps.${name}()`);
4
+ }
5
+ return deps[name];
6
+ }
7
+
8
+ function requireNumericDep(deps, name) {
9
+ const value = deps ? deps[name] : undefined;
10
+ if (!Number.isFinite(value)) {
11
+ throw new Error(`Polymarket parser factory requires numeric deps.${name}`);
12
+ }
13
+ return value;
14
+ }
15
+
16
+ /**
17
+ * Creates parser for shared polymarket auth/network flags.
18
+ * @param {object} deps
19
+ * @returns {(args: string[], actionLabel: string) => object}
20
+ */
21
+ function createParsePolymarketSharedFlags(deps) {
22
+ const CliError = requireDep(deps, 'CliError');
23
+ const requireFlagValue = requireDep(deps, 'requireFlagValue');
24
+ const parseAddressFlag = requireDep(deps, 'parseAddressFlag');
25
+ const isValidPrivateKey = requireDep(deps, 'isValidPrivateKey');
26
+ const isSecureHttpUrlOrLocal = requireDep(deps, 'isSecureHttpUrlOrLocal');
27
+
28
+ return function parsePolymarketSharedFlags(args, actionLabel) {
29
+ const options = {
30
+ rpcUrl: null,
31
+ privateKey: null,
32
+ funder: null,
33
+ };
34
+
35
+ for (let i = 0; i < args.length; i += 1) {
36
+ const token = args[i];
37
+ if (token === '--rpc-url') {
38
+ const rpcUrl = requireFlagValue(args, i, '--rpc-url');
39
+ if (!isSecureHttpUrlOrLocal(rpcUrl)) {
40
+ throw new CliError(
41
+ 'INVALID_FLAG_VALUE',
42
+ '--rpc-url must use https:// (or http://localhost/127.0.0.1 for local testing).',
43
+ );
44
+ }
45
+ options.rpcUrl = rpcUrl;
46
+ i += 1;
47
+ continue;
48
+ }
49
+ if (token === '--private-key') {
50
+ const value = requireFlagValue(args, i, '--private-key');
51
+ if (!isValidPrivateKey(value)) {
52
+ throw new CliError('INVALID_FLAG_VALUE', '--private-key must be 0x + 64 hex chars.');
53
+ }
54
+ options.privateKey = value;
55
+ i += 1;
56
+ continue;
57
+ }
58
+ if (token === '--funder') {
59
+ options.funder = parseAddressFlag(requireFlagValue(args, i, '--funder'), '--funder');
60
+ i += 1;
61
+ continue;
62
+ }
63
+ throw new CliError('UNKNOWN_FLAG', `Unknown flag for polymarket ${actionLabel}: ${token}`);
64
+ }
65
+
66
+ return options;
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Creates parser for `polymarket approve`.
72
+ * @param {object} deps
73
+ * @returns {(args: string[]) => object}
74
+ */
75
+ function createParsePolymarketApproveFlags(deps) {
76
+ const CliError = requireDep(deps, 'CliError');
77
+ const parsePolymarketSharedFlags = requireDep(deps, 'parsePolymarketSharedFlags');
78
+
79
+ return function parsePolymarketApproveFlags(args) {
80
+ const options = {
81
+ dryRun: false,
82
+ execute: false,
83
+ rpcUrl: null,
84
+ privateKey: null,
85
+ funder: null,
86
+ };
87
+
88
+ const sharedArgs = [];
89
+ for (let i = 0; i < args.length; i += 1) {
90
+ const token = args[i];
91
+ if (token === '--dry-run') {
92
+ options.dryRun = true;
93
+ continue;
94
+ }
95
+ if (token === '--execute') {
96
+ options.execute = true;
97
+ continue;
98
+ }
99
+ sharedArgs.push(token);
100
+ }
101
+
102
+ if (options.dryRun === options.execute) {
103
+ throw new CliError('INVALID_ARGS', 'polymarket approve requires exactly one mode: --dry-run or --execute.');
104
+ }
105
+
106
+ const shared = parsePolymarketSharedFlags(sharedArgs, 'approve');
107
+ options.rpcUrl = shared.rpcUrl;
108
+ options.privateKey = shared.privateKey;
109
+ options.funder = shared.funder;
110
+ return options;
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Creates parser for `polymarket trade`.
116
+ * @param {object} deps
117
+ * @returns {(args: string[]) => object}
118
+ */
119
+ function createParsePolymarketTradeFlags(deps) {
120
+ const CliError = requireDep(deps, 'CliError');
121
+ const requireFlagValue = requireDep(deps, 'requireFlagValue');
122
+ const parsePositiveNumber = requireDep(deps, 'parsePositiveNumber');
123
+ const parsePositiveInteger = requireDep(deps, 'parsePositiveInteger');
124
+ const parsePolymarketSharedFlags = requireDep(deps, 'parsePolymarketSharedFlags');
125
+ const isSecureHttpUrlOrLocal = requireDep(deps, 'isSecureHttpUrlOrLocal');
126
+ const defaultTimeoutMs = requireNumericDep(deps, 'defaultTimeoutMs');
127
+
128
+ return function parsePolymarketTradeFlags(args) {
129
+ const options = {
130
+ conditionId: null,
131
+ slug: null,
132
+ token: null,
133
+ tokenId: null,
134
+ side: 'buy',
135
+ amountUsdc: null,
136
+ dryRun: false,
137
+ execute: false,
138
+ host: null,
139
+ timeoutMs: defaultTimeoutMs,
140
+ rpcUrl: null,
141
+ privateKey: null,
142
+ funder: null,
143
+ };
144
+
145
+ const sharedArgs = [];
146
+ for (let i = 0; i < args.length; i += 1) {
147
+ const token = args[i];
148
+ if (token === '--condition-id' || token === '--market-id') {
149
+ options.conditionId = requireFlagValue(args, i, token);
150
+ i += 1;
151
+ continue;
152
+ }
153
+ if (token === '--slug') {
154
+ options.slug = requireFlagValue(args, i, '--slug');
155
+ i += 1;
156
+ continue;
157
+ }
158
+ if (token === '--token') {
159
+ const value = String(requireFlagValue(args, i, '--token')).trim().toLowerCase();
160
+ if (!['yes', 'no'].includes(value)) {
161
+ throw new CliError('INVALID_FLAG_VALUE', '--token must be yes|no.');
162
+ }
163
+ options.token = value;
164
+ i += 1;
165
+ continue;
166
+ }
167
+ if (token === '--token-id') {
168
+ options.tokenId = requireFlagValue(args, i, '--token-id');
169
+ i += 1;
170
+ continue;
171
+ }
172
+ if (token === '--side') {
173
+ const value = String(requireFlagValue(args, i, '--side')).trim().toLowerCase();
174
+ if (!['buy', 'sell'].includes(value)) {
175
+ throw new CliError('INVALID_FLAG_VALUE', '--side must be buy|sell.');
176
+ }
177
+ options.side = value;
178
+ i += 1;
179
+ continue;
180
+ }
181
+ if (token === '--amount-usdc') {
182
+ options.amountUsdc = parsePositiveNumber(requireFlagValue(args, i, '--amount-usdc'), '--amount-usdc');
183
+ i += 1;
184
+ continue;
185
+ }
186
+ if (token === '--polymarket-host') {
187
+ const host = requireFlagValue(args, i, '--polymarket-host');
188
+ if (!isSecureHttpUrlOrLocal(host)) {
189
+ throw new CliError(
190
+ 'INVALID_FLAG_VALUE',
191
+ '--polymarket-host must use https:// (or http://localhost/127.0.0.1 for local testing).',
192
+ );
193
+ }
194
+ options.host = host;
195
+ i += 1;
196
+ continue;
197
+ }
198
+ if (token === '--timeout-ms') {
199
+ options.timeoutMs = parsePositiveInteger(requireFlagValue(args, i, '--timeout-ms'), '--timeout-ms');
200
+ i += 1;
201
+ continue;
202
+ }
203
+ if (token === '--dry-run') {
204
+ options.dryRun = true;
205
+ continue;
206
+ }
207
+ if (token === '--execute') {
208
+ options.execute = true;
209
+ continue;
210
+ }
211
+ sharedArgs.push(token);
212
+ }
213
+
214
+ if (options.dryRun === options.execute) {
215
+ throw new CliError('INVALID_ARGS', 'polymarket trade requires exactly one mode: --dry-run or --execute.');
216
+ }
217
+ if (options.amountUsdc === null) {
218
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing --amount-usdc <amount>.');
219
+ }
220
+ if (!options.tokenId && !options.token) {
221
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Provide --token yes|no (or --token-id <id>).');
222
+ }
223
+ if (!options.tokenId && !options.conditionId && !options.slug) {
224
+ throw new CliError(
225
+ 'MISSING_REQUIRED_FLAG',
226
+ 'Provide --condition-id <id> or --slug <slug> when --token-id is not set.',
227
+ );
228
+ }
229
+
230
+ const shared = parsePolymarketSharedFlags(sharedArgs, 'trade');
231
+ options.rpcUrl = shared.rpcUrl;
232
+ options.privateKey = shared.privateKey;
233
+ options.funder = shared.funder;
234
+ return options;
235
+ };
236
+ }
237
+
238
+ module.exports = {
239
+ createParsePolymarketSharedFlags,
240
+ createParsePolymarketApproveFlags,
241
+ createParsePolymarketTradeFlags,
242
+ };
@@ -0,0 +1,102 @@
1
+ function requireDep(deps, name) {
2
+ if (!deps || typeof deps[name] !== 'function') {
3
+ throw new Error(`createParseResolveFlags requires deps.${name}()`);
4
+ }
5
+ return deps[name];
6
+ }
7
+
8
+ /**
9
+ * Creates the resolve command flags parser.
10
+ * @param {object} deps
11
+ * @returns {(args: string[]) => object}
12
+ */
13
+ function createParseResolveFlags(deps) {
14
+ const CliError = requireDep(deps, 'CliError');
15
+ const parseAddressFlag = requireDep(deps, 'parseAddressFlag');
16
+ const requireFlagValue = requireDep(deps, 'requireFlagValue');
17
+ const parseInteger = requireDep(deps, 'parseInteger');
18
+ const isValidPrivateKey = requireDep(deps, 'isValidPrivateKey');
19
+
20
+ return function parseResolveFlags(args) {
21
+ const options = {
22
+ pollAddress: null,
23
+ answer: null,
24
+ reason: null,
25
+ dryRun: false,
26
+ execute: false,
27
+ chainId: null,
28
+ rpcUrl: null,
29
+ privateKey: null,
30
+ };
31
+
32
+ for (let i = 0; i < args.length; i += 1) {
33
+ const token = args[i];
34
+ if (token === '--poll-address') {
35
+ options.pollAddress = parseAddressFlag(requireFlagValue(args, i, '--poll-address'), '--poll-address');
36
+ i += 1;
37
+ continue;
38
+ }
39
+ if (token === '--answer') {
40
+ const answer = requireFlagValue(args, i, '--answer').toLowerCase();
41
+ if (!['yes', 'no', 'invalid'].includes(answer)) {
42
+ throw new CliError('INVALID_FLAG_VALUE', '--answer must be yes|no|invalid.');
43
+ }
44
+ options.answer = answer;
45
+ i += 1;
46
+ continue;
47
+ }
48
+ if (token === '--reason') {
49
+ options.reason = requireFlagValue(args, i, '--reason');
50
+ i += 1;
51
+ continue;
52
+ }
53
+ if (token === '--dry-run') {
54
+ options.dryRun = true;
55
+ continue;
56
+ }
57
+ if (token === '--execute') {
58
+ options.execute = true;
59
+ continue;
60
+ }
61
+ if (token === '--chain-id') {
62
+ options.chainId = parseInteger(requireFlagValue(args, i, '--chain-id'), '--chain-id');
63
+ i += 1;
64
+ continue;
65
+ }
66
+ if (token === '--rpc-url') {
67
+ options.rpcUrl = requireFlagValue(args, i, '--rpc-url');
68
+ i += 1;
69
+ continue;
70
+ }
71
+ if (token === '--private-key') {
72
+ const value = requireFlagValue(args, i, '--private-key');
73
+ if (!isValidPrivateKey(value)) {
74
+ throw new CliError('INVALID_FLAG_VALUE', '--private-key must be 0x + 64 hex chars.');
75
+ }
76
+ options.privateKey = value;
77
+ i += 1;
78
+ continue;
79
+ }
80
+ throw new CliError('UNKNOWN_FLAG', `Unknown flag for resolve: ${token}`);
81
+ }
82
+
83
+ if (!options.pollAddress) {
84
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing poll address. Use --poll-address <address>.');
85
+ }
86
+ if (!options.answer) {
87
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing answer. Use --answer yes|no|invalid.');
88
+ }
89
+ if (!options.reason) {
90
+ throw new CliError('MISSING_REQUIRED_FLAG', 'Missing reason. Use --reason <text>.');
91
+ }
92
+ if (options.dryRun === options.execute) {
93
+ throw new CliError('INVALID_ARGS', 'Use exactly one mode: --dry-run or --execute.');
94
+ }
95
+
96
+ return options;
97
+ };
98
+ }
99
+
100
+ module.exports = {
101
+ createParseResolveFlags,
102
+ };