pandora-cli-skills 1.1.36 → 1.1.37
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/cli/lib/error_recovery_service.cjs +51 -0
- package/cli/lib/parsers/mirror_remaining_flags.cjs +580 -0
- package/cli/lib/schema_command_service.cjs +18 -7
- package/cli/pandora.cjs +29 -511
- package/package.json +1 -1
- package/tests/cli/cli.integration.test.cjs +6 -0
- package/tests/unit/new-features.test.cjs +72 -0
|
@@ -39,6 +39,18 @@ function buildPolymarketPreflightCommand(cliName) {
|
|
|
39
39
|
return `${cliName} polymarket preflight`;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function buildMirrorDeployRetryCommand(cliName) {
|
|
43
|
+
return `${cliName} mirror deploy --dry-run --plan-file <plan-file>`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildMirrorSyncRetryCommand(cliName) {
|
|
47
|
+
return `${cliName} mirror sync once --paper --pandora-market-address <address> --polymarket-market-id <id>`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function buildMcpRestartCommand(cliName) {
|
|
51
|
+
return `${cliName} mcp`;
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
/**
|
|
43
55
|
* Build deterministic Next-Best-Action recovery hints for JSON errors.
|
|
44
56
|
* @param {{cliName?: string}} [options]
|
|
@@ -83,6 +95,45 @@ function createErrorRecoveryService(options = {}) {
|
|
|
83
95
|
command: buildPolymarketPreflightCommand(cliName),
|
|
84
96
|
retryable: true,
|
|
85
97
|
};
|
|
98
|
+
case 'MIRROR_DEPLOY_FAILED':
|
|
99
|
+
case 'MIRROR_GO_FAILED':
|
|
100
|
+
case 'MIRROR_GO_VERIFY_FAILED':
|
|
101
|
+
case 'MIRROR_GO_PREFLIGHT_FAILED':
|
|
102
|
+
return {
|
|
103
|
+
action: 'Re-run mirror deploy/verify in dry-run mode',
|
|
104
|
+
command: buildMirrorDeployRetryCommand(cliName),
|
|
105
|
+
retryable: true,
|
|
106
|
+
};
|
|
107
|
+
case 'MIRROR_SYNC_FAILED':
|
|
108
|
+
case 'MIRROR_GO_SYNC_FAILED':
|
|
109
|
+
case 'MIRROR_SYNC_PREFLIGHT_FAILED':
|
|
110
|
+
case 'MIRROR_SYNC_DAEMON_START_FAILED':
|
|
111
|
+
case 'MIRROR_SYNC_DAEMON_STOP_FAILED':
|
|
112
|
+
case 'MIRROR_SYNC_DAEMON_STATUS_FAILED':
|
|
113
|
+
return {
|
|
114
|
+
action: 'Run a bounded mirror sync iteration to isolate the failing gate',
|
|
115
|
+
command: buildMirrorSyncRetryCommand(cliName),
|
|
116
|
+
retryable: true,
|
|
117
|
+
};
|
|
118
|
+
case 'MCP_EXECUTE_INTENT_REQUIRED':
|
|
119
|
+
return {
|
|
120
|
+
action: 'Retry MCP tools/call with execute intent enabled',
|
|
121
|
+
command: buildMcpRestartCommand(cliName),
|
|
122
|
+
retryable: true,
|
|
123
|
+
};
|
|
124
|
+
case 'MCP_LONG_RUNNING_MODE_BLOCKED':
|
|
125
|
+
return {
|
|
126
|
+
action: 'Switch to a bounded command variant for MCP',
|
|
127
|
+
command: `${cliName} mirror sync once --help`,
|
|
128
|
+
retryable: true,
|
|
129
|
+
};
|
|
130
|
+
case 'MCP_TOOL_FAILED':
|
|
131
|
+
case 'UNKNOWN_TOOL':
|
|
132
|
+
return {
|
|
133
|
+
action: 'Inspect available MCP tools and retry with a supported tool name',
|
|
134
|
+
command: `${cliName} --output json schema`,
|
|
135
|
+
retryable: true,
|
|
136
|
+
};
|
|
86
137
|
case 'MISSING_REQUIRED_FLAG':
|
|
87
138
|
case 'MISSING_FLAG_VALUE':
|
|
88
139
|
case 'INVALID_FLAG_VALUE':
|
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
function requireDep(deps, name) {
|
|
2
|
+
if (!deps || typeof deps[name] !== 'function') {
|
|
3
|
+
throw new Error(`mirror remaining parser requires deps.${name}()`);
|
|
4
|
+
}
|
|
5
|
+
return deps[name];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function parseDefaultIndexerTimeoutMs(deps) {
|
|
9
|
+
const value = deps && Number.isFinite(deps.defaultIndexerTimeoutMs) ? Number(deps.defaultIndexerTimeoutMs) : 60_000;
|
|
10
|
+
return value > 0 ? value : 60_000;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates the mirror browse parser.
|
|
15
|
+
* @param {object} deps
|
|
16
|
+
* @returns {(args: string[]) => object}
|
|
17
|
+
*/
|
|
18
|
+
function createParseMirrorBrowseFlags(deps) {
|
|
19
|
+
const CliError = requireDep(deps, 'CliError');
|
|
20
|
+
const requireFlagValue = requireDep(deps, 'requireFlagValue');
|
|
21
|
+
const parseProbabilityPercent = requireDep(deps, 'parseProbabilityPercent');
|
|
22
|
+
const parsePositiveNumber = requireDep(deps, 'parsePositiveNumber');
|
|
23
|
+
const parseDateLikeFlag = requireDep(deps, 'parseDateLikeFlag');
|
|
24
|
+
const parsePositiveInteger = requireDep(deps, 'parsePositiveInteger');
|
|
25
|
+
const parseInteger = requireDep(deps, 'parseInteger');
|
|
26
|
+
|
|
27
|
+
return function parseMirrorBrowseFlags(args) {
|
|
28
|
+
const options = {
|
|
29
|
+
minYesPct: null,
|
|
30
|
+
maxYesPct: null,
|
|
31
|
+
minVolume24h: 0,
|
|
32
|
+
closesAfter: null,
|
|
33
|
+
closesBefore: null,
|
|
34
|
+
questionContains: null,
|
|
35
|
+
limit: 10,
|
|
36
|
+
chainId: null,
|
|
37
|
+
polymarketGammaUrl: null,
|
|
38
|
+
polymarketGammaMockUrl: null,
|
|
39
|
+
polymarketMockUrl: null,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
43
|
+
const token = args[i];
|
|
44
|
+
if (token === '--min-yes-pct') {
|
|
45
|
+
options.minYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--min-yes-pct'), '--min-yes-pct');
|
|
46
|
+
i += 1;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (token === '--max-yes-pct') {
|
|
50
|
+
options.maxYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--max-yes-pct'), '--max-yes-pct');
|
|
51
|
+
i += 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (token === '--min-volume-24h') {
|
|
55
|
+
options.minVolume24h = parsePositiveNumber(requireFlagValue(args, i, '--min-volume-24h'), '--min-volume-24h');
|
|
56
|
+
i += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (token === '--closes-after') {
|
|
60
|
+
options.closesAfter = parseDateLikeFlag(requireFlagValue(args, i, '--closes-after'), '--closes-after');
|
|
61
|
+
i += 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (token === '--closes-before') {
|
|
65
|
+
options.closesBefore = parseDateLikeFlag(requireFlagValue(args, i, '--closes-before'), '--closes-before');
|
|
66
|
+
i += 1;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (token === '--question-contains') {
|
|
70
|
+
options.questionContains = requireFlagValue(args, i, '--question-contains');
|
|
71
|
+
i += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (token === '--limit') {
|
|
75
|
+
options.limit = parsePositiveInteger(requireFlagValue(args, i, '--limit'), '--limit');
|
|
76
|
+
i += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (token === '--chain-id') {
|
|
80
|
+
options.chainId = parseInteger(requireFlagValue(args, i, '--chain-id'), '--chain-id');
|
|
81
|
+
i += 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (token === '--polymarket-gamma-url') {
|
|
85
|
+
options.polymarketGammaUrl = requireFlagValue(args, i, '--polymarket-gamma-url');
|
|
86
|
+
i += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (token === '--polymarket-gamma-mock-url') {
|
|
90
|
+
options.polymarketGammaMockUrl = requireFlagValue(args, i, '--polymarket-gamma-mock-url');
|
|
91
|
+
i += 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (token === '--polymarket-mock-url') {
|
|
95
|
+
options.polymarketMockUrl = requireFlagValue(args, i, '--polymarket-mock-url');
|
|
96
|
+
i += 1;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror browse: ${token}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (options.minYesPct !== null && options.maxYesPct !== null && options.minYesPct > options.maxYesPct) {
|
|
103
|
+
throw new CliError('INVALID_ARGS', '--min-yes-pct cannot be greater than --max-yes-pct.');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return options;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Creates the mirror verify parser.
|
|
112
|
+
* @param {object} deps
|
|
113
|
+
* @returns {(args: string[]) => object}
|
|
114
|
+
*/
|
|
115
|
+
function createParseMirrorVerifyFlags(deps) {
|
|
116
|
+
const CliError = requireDep(deps, 'CliError');
|
|
117
|
+
const parseAddressFlag = requireDep(deps, 'parseAddressFlag');
|
|
118
|
+
const requireFlagValue = requireDep(deps, 'requireFlagValue');
|
|
119
|
+
|
|
120
|
+
return function parseMirrorVerifyFlags(args) {
|
|
121
|
+
const options = {
|
|
122
|
+
pandoraMarketAddress: null,
|
|
123
|
+
polymarketMarketId: null,
|
|
124
|
+
polymarketSlug: null,
|
|
125
|
+
includeSimilarity: false,
|
|
126
|
+
withRules: false,
|
|
127
|
+
allowRuleMismatch: false,
|
|
128
|
+
trustDeploy: false,
|
|
129
|
+
manifestFile: null,
|
|
130
|
+
polymarketHost: null,
|
|
131
|
+
polymarketGammaUrl: null,
|
|
132
|
+
polymarketGammaMockUrl: null,
|
|
133
|
+
polymarketMockUrl: null,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
137
|
+
const token = args[i];
|
|
138
|
+
if (token === '--pandora-market-address' || token === '--market-address') {
|
|
139
|
+
options.pandoraMarketAddress = parseAddressFlag(requireFlagValue(args, i, token), token);
|
|
140
|
+
i += 1;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (token === '--polymarket-market-id') {
|
|
144
|
+
options.polymarketMarketId = requireFlagValue(args, i, '--polymarket-market-id');
|
|
145
|
+
i += 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (token === '--polymarket-slug') {
|
|
149
|
+
options.polymarketSlug = requireFlagValue(args, i, '--polymarket-slug');
|
|
150
|
+
i += 1;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (token === '--include-similarity') {
|
|
154
|
+
options.includeSimilarity = true;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (token === '--with-rules') {
|
|
158
|
+
options.withRules = true;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (token === '--allow-rule-mismatch') {
|
|
162
|
+
options.allowRuleMismatch = true;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (token === '--trust-deploy') {
|
|
166
|
+
options.trustDeploy = true;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (token === '--manifest-file') {
|
|
170
|
+
options.manifestFile = requireFlagValue(args, i, '--manifest-file');
|
|
171
|
+
i += 1;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (token === '--polymarket-host') {
|
|
175
|
+
options.polymarketHost = requireFlagValue(args, i, '--polymarket-host');
|
|
176
|
+
i += 1;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (token === '--polymarket-gamma-url') {
|
|
180
|
+
options.polymarketGammaUrl = requireFlagValue(args, i, '--polymarket-gamma-url');
|
|
181
|
+
i += 1;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (token === '--polymarket-gamma-mock-url') {
|
|
185
|
+
options.polymarketGammaMockUrl = requireFlagValue(args, i, '--polymarket-gamma-mock-url');
|
|
186
|
+
i += 1;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (token === '--polymarket-mock-url') {
|
|
190
|
+
options.polymarketMockUrl = requireFlagValue(args, i, '--polymarket-mock-url');
|
|
191
|
+
i += 1;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror verify: ${token}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!options.pandoraMarketAddress) {
|
|
198
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'Missing --pandora-market-address <address> (alias: --market-address).');
|
|
199
|
+
}
|
|
200
|
+
if (!options.polymarketMarketId && !options.polymarketSlug) {
|
|
201
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror verify requires --polymarket-market-id <id> or --polymarket-slug <slug>.');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return options;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Creates the mirror status parser.
|
|
210
|
+
* @param {object} deps
|
|
211
|
+
* @returns {(args: string[]) => object}
|
|
212
|
+
*/
|
|
213
|
+
function createParseMirrorStatusFlags(deps) {
|
|
214
|
+
const CliError = requireDep(deps, 'CliError');
|
|
215
|
+
const parseAddressFlag = requireDep(deps, 'parseAddressFlag');
|
|
216
|
+
const requireFlagValue = requireDep(deps, 'requireFlagValue');
|
|
217
|
+
const parsePositiveInteger = requireDep(deps, 'parsePositiveInteger');
|
|
218
|
+
const parsePositiveNumber = requireDep(deps, 'parsePositiveNumber');
|
|
219
|
+
const defaultIndexerTimeoutMs = parseDefaultIndexerTimeoutMs(deps);
|
|
220
|
+
|
|
221
|
+
return function parseMirrorStatusFlags(args) {
|
|
222
|
+
const options = {
|
|
223
|
+
stateFile: null,
|
|
224
|
+
strategyHash: null,
|
|
225
|
+
withLive: false,
|
|
226
|
+
trustDeploy: false,
|
|
227
|
+
manifestFile: null,
|
|
228
|
+
pandoraMarketAddress: null,
|
|
229
|
+
polymarketMarketId: null,
|
|
230
|
+
polymarketSlug: null,
|
|
231
|
+
driftTriggerBps: 150,
|
|
232
|
+
hedgeTriggerUsdc: 10,
|
|
233
|
+
indexerUrl: null,
|
|
234
|
+
timeoutMs: defaultIndexerTimeoutMs,
|
|
235
|
+
polymarketHost: null,
|
|
236
|
+
polymarketGammaUrl: null,
|
|
237
|
+
polymarketGammaMockUrl: null,
|
|
238
|
+
polymarketMockUrl: null,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
242
|
+
const token = args[i];
|
|
243
|
+
if (token === '--state-file') {
|
|
244
|
+
options.stateFile = requireFlagValue(args, i, '--state-file');
|
|
245
|
+
i += 1;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (token === '--strategy-hash') {
|
|
249
|
+
const value = requireFlagValue(args, i, '--strategy-hash');
|
|
250
|
+
if (!/^[a-f0-9]{16}$/i.test(value)) {
|
|
251
|
+
throw new CliError('INVALID_FLAG_VALUE', '--strategy-hash must be a 16-character hex value.');
|
|
252
|
+
}
|
|
253
|
+
options.strategyHash = value.toLowerCase();
|
|
254
|
+
i += 1;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (token === '--with-live') {
|
|
258
|
+
options.withLive = true;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (token === '--trust-deploy') {
|
|
262
|
+
options.trustDeploy = true;
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (token === '--manifest-file') {
|
|
266
|
+
options.manifestFile = requireFlagValue(args, i, '--manifest-file');
|
|
267
|
+
i += 1;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (token === '--pandora-market-address' || token === '--market-address') {
|
|
271
|
+
options.pandoraMarketAddress = parseAddressFlag(requireFlagValue(args, i, token), token);
|
|
272
|
+
i += 1;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (token === '--polymarket-market-id') {
|
|
276
|
+
options.polymarketMarketId = requireFlagValue(args, i, '--polymarket-market-id');
|
|
277
|
+
i += 1;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (token === '--polymarket-slug') {
|
|
281
|
+
options.polymarketSlug = requireFlagValue(args, i, '--polymarket-slug');
|
|
282
|
+
i += 1;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (token === '--drift-trigger-bps') {
|
|
286
|
+
options.driftTriggerBps = parsePositiveInteger(requireFlagValue(args, i, '--drift-trigger-bps'), '--drift-trigger-bps');
|
|
287
|
+
i += 1;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (token === '--hedge-trigger-usdc') {
|
|
291
|
+
options.hedgeTriggerUsdc = parsePositiveNumber(requireFlagValue(args, i, '--hedge-trigger-usdc'), '--hedge-trigger-usdc');
|
|
292
|
+
i += 1;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (token === '--indexer-url') {
|
|
296
|
+
options.indexerUrl = requireFlagValue(args, i, '--indexer-url');
|
|
297
|
+
i += 1;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (token === '--timeout-ms') {
|
|
301
|
+
options.timeoutMs = parsePositiveInteger(requireFlagValue(args, i, '--timeout-ms'), '--timeout-ms');
|
|
302
|
+
i += 1;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (token === '--polymarket-host') {
|
|
306
|
+
options.polymarketHost = requireFlagValue(args, i, '--polymarket-host');
|
|
307
|
+
i += 1;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (token === '--polymarket-gamma-url') {
|
|
311
|
+
options.polymarketGammaUrl = requireFlagValue(args, i, '--polymarket-gamma-url');
|
|
312
|
+
i += 1;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (token === '--polymarket-gamma-mock-url') {
|
|
316
|
+
options.polymarketGammaMockUrl = requireFlagValue(args, i, '--polymarket-gamma-mock-url');
|
|
317
|
+
i += 1;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (token === '--polymarket-mock-url') {
|
|
321
|
+
options.polymarketMockUrl = requireFlagValue(args, i, '--polymarket-mock-url');
|
|
322
|
+
i += 1;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror status: ${token}`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (!options.stateFile && !options.strategyHash) {
|
|
329
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror status requires --state-file <path> or --strategy-hash <hash>.');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return options;
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Creates the mirror close parser.
|
|
338
|
+
* @param {object} deps
|
|
339
|
+
* @returns {(args: string[]) => object}
|
|
340
|
+
*/
|
|
341
|
+
function createParseMirrorCloseFlags(deps) {
|
|
342
|
+
const CliError = requireDep(deps, 'CliError');
|
|
343
|
+
const parseAddressFlag = requireDep(deps, 'parseAddressFlag');
|
|
344
|
+
const requireFlagValue = requireDep(deps, 'requireFlagValue');
|
|
345
|
+
|
|
346
|
+
return function parseMirrorCloseFlags(args) {
|
|
347
|
+
const options = {
|
|
348
|
+
pandoraMarketAddress: null,
|
|
349
|
+
polymarketMarketId: null,
|
|
350
|
+
polymarketSlug: null,
|
|
351
|
+
execute: false,
|
|
352
|
+
dryRun: false,
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
356
|
+
const token = args[i];
|
|
357
|
+
if (token === '--pandora-market-address' || token === '--market-address') {
|
|
358
|
+
options.pandoraMarketAddress = parseAddressFlag(requireFlagValue(args, i, token), token);
|
|
359
|
+
i += 1;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (token === '--polymarket-market-id') {
|
|
363
|
+
options.polymarketMarketId = requireFlagValue(args, i, '--polymarket-market-id');
|
|
364
|
+
i += 1;
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
if (token === '--polymarket-slug') {
|
|
368
|
+
options.polymarketSlug = requireFlagValue(args, i, '--polymarket-slug');
|
|
369
|
+
i += 1;
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (token === '--dry-run') {
|
|
373
|
+
options.dryRun = true;
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
if (token === '--execute') {
|
|
377
|
+
options.execute = true;
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror close: ${token}`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (!options.pandoraMarketAddress) {
|
|
384
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'Missing --pandora-market-address <address> (alias: --market-address).');
|
|
385
|
+
}
|
|
386
|
+
if (!options.polymarketMarketId && !options.polymarketSlug) {
|
|
387
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror close requires --polymarket-market-id <id> or --polymarket-slug <slug>.');
|
|
388
|
+
}
|
|
389
|
+
if (options.dryRun === options.execute) {
|
|
390
|
+
throw new CliError('INVALID_ARGS', 'mirror close requires exactly one mode: --dry-run or --execute.');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return options;
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Creates the mirror lp-explain parser.
|
|
399
|
+
* @param {object} deps
|
|
400
|
+
* @returns {(args: string[]) => object}
|
|
401
|
+
*/
|
|
402
|
+
function createParseMirrorLpExplainFlags(deps) {
|
|
403
|
+
const CliError = requireDep(deps, 'CliError');
|
|
404
|
+
const requireFlagValue = requireDep(deps, 'requireFlagValue');
|
|
405
|
+
const parsePositiveNumber = requireDep(deps, 'parsePositiveNumber');
|
|
406
|
+
const parseProbabilityPercent = requireDep(deps, 'parseProbabilityPercent');
|
|
407
|
+
const parseNonNegativeInteger = requireDep(deps, 'parseNonNegativeInteger');
|
|
408
|
+
|
|
409
|
+
return function parseMirrorLpExplainFlags(args) {
|
|
410
|
+
const options = {
|
|
411
|
+
liquidityUsdc: null,
|
|
412
|
+
sourceYesPct: null,
|
|
413
|
+
distributionYes: null,
|
|
414
|
+
distributionNo: null,
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
418
|
+
const token = args[i];
|
|
419
|
+
if (token === '--liquidity-usdc') {
|
|
420
|
+
options.liquidityUsdc = parsePositiveNumber(requireFlagValue(args, i, '--liquidity-usdc'), '--liquidity-usdc');
|
|
421
|
+
i += 1;
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (token === '--source-yes-pct') {
|
|
425
|
+
options.sourceYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--source-yes-pct'), '--source-yes-pct');
|
|
426
|
+
i += 1;
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (token === '--distribution-yes') {
|
|
430
|
+
options.distributionYes = parseNonNegativeInteger(requireFlagValue(args, i, '--distribution-yes'), '--distribution-yes');
|
|
431
|
+
i += 1;
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
if (token === '--distribution-no') {
|
|
435
|
+
options.distributionNo = parseNonNegativeInteger(requireFlagValue(args, i, '--distribution-no'), '--distribution-no');
|
|
436
|
+
i += 1;
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror lp-explain: ${token}`);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (options.liquidityUsdc === null) {
|
|
443
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror lp-explain requires --liquidity-usdc <n>.');
|
|
444
|
+
}
|
|
445
|
+
if (
|
|
446
|
+
(options.distributionYes === null && options.distributionNo !== null) ||
|
|
447
|
+
(options.distributionYes !== null && options.distributionNo === null)
|
|
448
|
+
) {
|
|
449
|
+
throw new CliError('INVALID_ARGS', 'Provide both --distribution-yes and --distribution-no together.');
|
|
450
|
+
}
|
|
451
|
+
if (
|
|
452
|
+
options.distributionYes !== null &&
|
|
453
|
+
options.distributionNo !== null &&
|
|
454
|
+
options.distributionYes + options.distributionNo !== 1_000_000_000
|
|
455
|
+
) {
|
|
456
|
+
throw new CliError('INVALID_ARGS', '--distribution-yes + --distribution-no must equal 1000000000.');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return options;
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Creates the mirror simulate parser.
|
|
465
|
+
* @param {object} deps
|
|
466
|
+
* @returns {(args: string[]) => object}
|
|
467
|
+
*/
|
|
468
|
+
function createParseMirrorSimulateFlags(deps) {
|
|
469
|
+
const CliError = requireDep(deps, 'CliError');
|
|
470
|
+
const requireFlagValue = requireDep(deps, 'requireFlagValue');
|
|
471
|
+
const parsePositiveNumber = requireDep(deps, 'parsePositiveNumber');
|
|
472
|
+
const parseProbabilityPercent = requireDep(deps, 'parseProbabilityPercent');
|
|
473
|
+
const parseNonNegativeInteger = requireDep(deps, 'parseNonNegativeInteger');
|
|
474
|
+
const parsePositiveInteger = requireDep(deps, 'parsePositiveInteger');
|
|
475
|
+
const parseCsvNumberList = requireDep(deps, 'parseCsvNumberList');
|
|
476
|
+
|
|
477
|
+
return function parseMirrorSimulateFlags(args) {
|
|
478
|
+
const options = {
|
|
479
|
+
liquidityUsdc: null,
|
|
480
|
+
sourceYesPct: null,
|
|
481
|
+
targetYesPct: null,
|
|
482
|
+
polymarketYesPct: null,
|
|
483
|
+
distributionYes: null,
|
|
484
|
+
distributionNo: null,
|
|
485
|
+
feeTier: 3000,
|
|
486
|
+
hedgeRatio: 1,
|
|
487
|
+
hedgeCostBps: 35,
|
|
488
|
+
volumeScenarios: null,
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
492
|
+
const token = args[i];
|
|
493
|
+
if (token === '--liquidity-usdc') {
|
|
494
|
+
options.liquidityUsdc = parsePositiveNumber(requireFlagValue(args, i, '--liquidity-usdc'), '--liquidity-usdc');
|
|
495
|
+
i += 1;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
if (token === '--source-yes-pct') {
|
|
499
|
+
options.sourceYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--source-yes-pct'), '--source-yes-pct');
|
|
500
|
+
i += 1;
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
if (token === '--target-yes-pct') {
|
|
504
|
+
options.targetYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--target-yes-pct'), '--target-yes-pct');
|
|
505
|
+
i += 1;
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
if (token === '--polymarket-yes-pct') {
|
|
509
|
+
options.polymarketYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--polymarket-yes-pct'), '--polymarket-yes-pct');
|
|
510
|
+
i += 1;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
if (token === '--distribution-yes') {
|
|
514
|
+
options.distributionYes = parseNonNegativeInteger(requireFlagValue(args, i, '--distribution-yes'), '--distribution-yes');
|
|
515
|
+
i += 1;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
if (token === '--distribution-no') {
|
|
519
|
+
options.distributionNo = parseNonNegativeInteger(requireFlagValue(args, i, '--distribution-no'), '--distribution-no');
|
|
520
|
+
i += 1;
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
if (token === '--fee-tier') {
|
|
524
|
+
options.feeTier = parsePositiveInteger(requireFlagValue(args, i, '--fee-tier'), '--fee-tier');
|
|
525
|
+
i += 1;
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
if (token === '--hedge-ratio') {
|
|
529
|
+
options.hedgeRatio = parsePositiveNumber(requireFlagValue(args, i, '--hedge-ratio'), '--hedge-ratio');
|
|
530
|
+
i += 1;
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
if (token === '--hedge-cost-bps') {
|
|
534
|
+
options.hedgeCostBps = parseNonNegativeInteger(requireFlagValue(args, i, '--hedge-cost-bps'), '--hedge-cost-bps');
|
|
535
|
+
i += 1;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (token === '--volume-scenarios') {
|
|
539
|
+
options.volumeScenarios = parseCsvNumberList(requireFlagValue(args, i, '--volume-scenarios'), '--volume-scenarios');
|
|
540
|
+
i += 1;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror simulate: ${token}`);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (options.liquidityUsdc === null) {
|
|
547
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror simulate requires --liquidity-usdc <n>.');
|
|
548
|
+
}
|
|
549
|
+
if (
|
|
550
|
+
(options.distributionYes === null && options.distributionNo !== null) ||
|
|
551
|
+
(options.distributionYes !== null && options.distributionNo === null)
|
|
552
|
+
) {
|
|
553
|
+
throw new CliError('INVALID_ARGS', 'Provide both --distribution-yes and --distribution-no together.');
|
|
554
|
+
}
|
|
555
|
+
if (
|
|
556
|
+
options.distributionYes !== null &&
|
|
557
|
+
options.distributionNo !== null &&
|
|
558
|
+
options.distributionYes + options.distributionNo !== 1_000_000_000
|
|
559
|
+
) {
|
|
560
|
+
throw new CliError('INVALID_ARGS', '--distribution-yes + --distribution-no must equal 1000000000.');
|
|
561
|
+
}
|
|
562
|
+
if (![500, 3000, 10000].includes(options.feeTier)) {
|
|
563
|
+
throw new CliError('INVALID_FLAG_VALUE', '--fee-tier must be one of 500, 3000, 10000.');
|
|
564
|
+
}
|
|
565
|
+
if (options.hedgeRatio > 5) {
|
|
566
|
+
throw new CliError('INVALID_FLAG_VALUE', '--hedge-ratio must be <= 5.');
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return options;
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
module.exports = {
|
|
574
|
+
createParseMirrorBrowseFlags,
|
|
575
|
+
createParseMirrorVerifyFlags,
|
|
576
|
+
createParseMirrorStatusFlags,
|
|
577
|
+
createParseMirrorCloseFlags,
|
|
578
|
+
createParseMirrorLpExplainFlags,
|
|
579
|
+
createParseMirrorSimulateFlags,
|
|
580
|
+
};
|
|
@@ -462,19 +462,30 @@ function createRunSchemaCommand(deps) {
|
|
|
462
462
|
}
|
|
463
463
|
|
|
464
464
|
function runSchemaCommand(args, context) {
|
|
465
|
+
if (Array.isArray(args) && (args.includes('--help') || args.includes('-h'))) {
|
|
466
|
+
if (context.outputMode === 'json') {
|
|
467
|
+
emitSuccess(context.outputMode, 'schema.help', {
|
|
468
|
+
usage: 'pandora --output json schema',
|
|
469
|
+
});
|
|
470
|
+
} else {
|
|
471
|
+
// eslint-disable-next-line no-console
|
|
472
|
+
console.log('Usage: pandora --output json schema');
|
|
473
|
+
// eslint-disable-next-line no-console
|
|
474
|
+
console.log('');
|
|
475
|
+
// eslint-disable-next-line no-console
|
|
476
|
+
console.log('Notes:');
|
|
477
|
+
// eslint-disable-next-line no-console
|
|
478
|
+
console.log(' - schema payload is available only in --output json mode.');
|
|
479
|
+
}
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
465
483
|
if (context.outputMode !== 'json') {
|
|
466
484
|
throw new CliError('INVALID_USAGE', 'The schema command is only supported in --output json mode.', {
|
|
467
485
|
hints: ['Run `pandora --output json schema`'],
|
|
468
486
|
});
|
|
469
487
|
}
|
|
470
488
|
|
|
471
|
-
if (Array.isArray(args) && (args.includes('--help') || args.includes('-h'))) {
|
|
472
|
-
emitSuccess(context.outputMode, 'schema.help', {
|
|
473
|
-
usage: 'pandora --output json schema',
|
|
474
|
-
});
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
489
|
if (Array.isArray(args) && args.length > 0) {
|
|
479
490
|
throw new CliError('INVALID_ARGS', 'schema does not accept additional flags or positional arguments.', {
|
|
480
491
|
hints: ['Run `pandora --output json schema` without extra arguments.'],
|
package/cli/pandora.cjs
CHANGED
|
@@ -19,6 +19,14 @@ const {
|
|
|
19
19
|
createParseMirrorSyncFlags,
|
|
20
20
|
createParseMirrorSyncDaemonSelectorFlags,
|
|
21
21
|
} = require('./lib/parsers/mirror_sync_flags.cjs');
|
|
22
|
+
const {
|
|
23
|
+
createParseMirrorBrowseFlags,
|
|
24
|
+
createParseMirrorVerifyFlags,
|
|
25
|
+
createParseMirrorStatusFlags,
|
|
26
|
+
createParseMirrorCloseFlags,
|
|
27
|
+
createParseMirrorLpExplainFlags,
|
|
28
|
+
createParseMirrorSimulateFlags,
|
|
29
|
+
} = require('./lib/parsers/mirror_remaining_flags.cjs');
|
|
22
30
|
const {
|
|
23
31
|
createParsePolymarketSharedFlags,
|
|
24
32
|
createParsePolymarketApproveFlags,
|
|
@@ -1114,295 +1122,6 @@ function runTargetScript(targetScript, passThroughArgs) {
|
|
|
1114
1122
|
process.exit(result.status === null ? 1 : result.status);
|
|
1115
1123
|
}
|
|
1116
1124
|
|
|
1117
|
-
function parseMirrorBrowseFlags(args) {
|
|
1118
|
-
const options = {
|
|
1119
|
-
minYesPct: null,
|
|
1120
|
-
maxYesPct: null,
|
|
1121
|
-
minVolume24h: 0,
|
|
1122
|
-
closesAfter: null,
|
|
1123
|
-
closesBefore: null,
|
|
1124
|
-
questionContains: null,
|
|
1125
|
-
limit: 10,
|
|
1126
|
-
chainId: null,
|
|
1127
|
-
polymarketGammaUrl: null,
|
|
1128
|
-
polymarketGammaMockUrl: null,
|
|
1129
|
-
polymarketMockUrl: null,
|
|
1130
|
-
};
|
|
1131
|
-
|
|
1132
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1133
|
-
const token = args[i];
|
|
1134
|
-
if (token === '--min-yes-pct') {
|
|
1135
|
-
options.minYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--min-yes-pct'), '--min-yes-pct');
|
|
1136
|
-
i += 1;
|
|
1137
|
-
continue;
|
|
1138
|
-
}
|
|
1139
|
-
if (token === '--max-yes-pct') {
|
|
1140
|
-
options.maxYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--max-yes-pct'), '--max-yes-pct');
|
|
1141
|
-
i += 1;
|
|
1142
|
-
continue;
|
|
1143
|
-
}
|
|
1144
|
-
if (token === '--min-volume-24h') {
|
|
1145
|
-
options.minVolume24h = parsePositiveNumber(requireFlagValue(args, i, '--min-volume-24h'), '--min-volume-24h');
|
|
1146
|
-
i += 1;
|
|
1147
|
-
continue;
|
|
1148
|
-
}
|
|
1149
|
-
if (token === '--closes-after') {
|
|
1150
|
-
options.closesAfter = parseDateLikeFlag(requireFlagValue(args, i, '--closes-after'), '--closes-after');
|
|
1151
|
-
i += 1;
|
|
1152
|
-
continue;
|
|
1153
|
-
}
|
|
1154
|
-
if (token === '--closes-before') {
|
|
1155
|
-
options.closesBefore = parseDateLikeFlag(requireFlagValue(args, i, '--closes-before'), '--closes-before');
|
|
1156
|
-
i += 1;
|
|
1157
|
-
continue;
|
|
1158
|
-
}
|
|
1159
|
-
if (token === '--question-contains') {
|
|
1160
|
-
options.questionContains = requireFlagValue(args, i, '--question-contains');
|
|
1161
|
-
i += 1;
|
|
1162
|
-
continue;
|
|
1163
|
-
}
|
|
1164
|
-
if (token === '--limit') {
|
|
1165
|
-
options.limit = parsePositiveInteger(requireFlagValue(args, i, '--limit'), '--limit');
|
|
1166
|
-
i += 1;
|
|
1167
|
-
continue;
|
|
1168
|
-
}
|
|
1169
|
-
if (token === '--chain-id') {
|
|
1170
|
-
options.chainId = parseInteger(requireFlagValue(args, i, '--chain-id'), '--chain-id');
|
|
1171
|
-
i += 1;
|
|
1172
|
-
continue;
|
|
1173
|
-
}
|
|
1174
|
-
if (token === '--polymarket-gamma-url') {
|
|
1175
|
-
options.polymarketGammaUrl = requireFlagValue(args, i, '--polymarket-gamma-url');
|
|
1176
|
-
i += 1;
|
|
1177
|
-
continue;
|
|
1178
|
-
}
|
|
1179
|
-
if (token === '--polymarket-gamma-mock-url') {
|
|
1180
|
-
options.polymarketGammaMockUrl = requireFlagValue(args, i, '--polymarket-gamma-mock-url');
|
|
1181
|
-
i += 1;
|
|
1182
|
-
continue;
|
|
1183
|
-
}
|
|
1184
|
-
if (token === '--polymarket-mock-url') {
|
|
1185
|
-
options.polymarketMockUrl = requireFlagValue(args, i, '--polymarket-mock-url');
|
|
1186
|
-
i += 1;
|
|
1187
|
-
continue;
|
|
1188
|
-
}
|
|
1189
|
-
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror browse: ${token}`);
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
if (options.minYesPct !== null && options.maxYesPct !== null && options.minYesPct > options.maxYesPct) {
|
|
1193
|
-
throw new CliError('INVALID_ARGS', '--min-yes-pct cannot be greater than --max-yes-pct.');
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
return options;
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
function parseMirrorVerifyFlags(args) {
|
|
1200
|
-
const options = {
|
|
1201
|
-
pandoraMarketAddress: null,
|
|
1202
|
-
polymarketMarketId: null,
|
|
1203
|
-
polymarketSlug: null,
|
|
1204
|
-
includeSimilarity: false,
|
|
1205
|
-
withRules: false,
|
|
1206
|
-
allowRuleMismatch: false,
|
|
1207
|
-
trustDeploy: false,
|
|
1208
|
-
manifestFile: null,
|
|
1209
|
-
polymarketHost: null,
|
|
1210
|
-
polymarketGammaUrl: null,
|
|
1211
|
-
polymarketGammaMockUrl: null,
|
|
1212
|
-
polymarketMockUrl: null,
|
|
1213
|
-
};
|
|
1214
|
-
|
|
1215
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1216
|
-
const token = args[i];
|
|
1217
|
-
if (token === '--pandora-market-address' || token === '--market-address') {
|
|
1218
|
-
options.pandoraMarketAddress = parseAddressFlag(
|
|
1219
|
-
requireFlagValue(args, i, token),
|
|
1220
|
-
token,
|
|
1221
|
-
);
|
|
1222
|
-
i += 1;
|
|
1223
|
-
continue;
|
|
1224
|
-
}
|
|
1225
|
-
if (token === '--polymarket-market-id') {
|
|
1226
|
-
options.polymarketMarketId = requireFlagValue(args, i, '--polymarket-market-id');
|
|
1227
|
-
i += 1;
|
|
1228
|
-
continue;
|
|
1229
|
-
}
|
|
1230
|
-
if (token === '--polymarket-slug') {
|
|
1231
|
-
options.polymarketSlug = requireFlagValue(args, i, '--polymarket-slug');
|
|
1232
|
-
i += 1;
|
|
1233
|
-
continue;
|
|
1234
|
-
}
|
|
1235
|
-
if (token === '--include-similarity') {
|
|
1236
|
-
options.includeSimilarity = true;
|
|
1237
|
-
continue;
|
|
1238
|
-
}
|
|
1239
|
-
if (token === '--with-rules') {
|
|
1240
|
-
options.withRules = true;
|
|
1241
|
-
continue;
|
|
1242
|
-
}
|
|
1243
|
-
if (token === '--allow-rule-mismatch') {
|
|
1244
|
-
options.allowRuleMismatch = true;
|
|
1245
|
-
continue;
|
|
1246
|
-
}
|
|
1247
|
-
if (token === '--trust-deploy') {
|
|
1248
|
-
options.trustDeploy = true;
|
|
1249
|
-
continue;
|
|
1250
|
-
}
|
|
1251
|
-
if (token === '--manifest-file') {
|
|
1252
|
-
options.manifestFile = requireFlagValue(args, i, '--manifest-file');
|
|
1253
|
-
i += 1;
|
|
1254
|
-
continue;
|
|
1255
|
-
}
|
|
1256
|
-
if (token === '--polymarket-host') {
|
|
1257
|
-
options.polymarketHost = requireFlagValue(args, i, '--polymarket-host');
|
|
1258
|
-
i += 1;
|
|
1259
|
-
continue;
|
|
1260
|
-
}
|
|
1261
|
-
if (token === '--polymarket-gamma-url') {
|
|
1262
|
-
options.polymarketGammaUrl = requireFlagValue(args, i, '--polymarket-gamma-url');
|
|
1263
|
-
i += 1;
|
|
1264
|
-
continue;
|
|
1265
|
-
}
|
|
1266
|
-
if (token === '--polymarket-gamma-mock-url') {
|
|
1267
|
-
options.polymarketGammaMockUrl = requireFlagValue(args, i, '--polymarket-gamma-mock-url');
|
|
1268
|
-
i += 1;
|
|
1269
|
-
continue;
|
|
1270
|
-
}
|
|
1271
|
-
if (token === '--polymarket-mock-url') {
|
|
1272
|
-
options.polymarketMockUrl = requireFlagValue(args, i, '--polymarket-mock-url');
|
|
1273
|
-
i += 1;
|
|
1274
|
-
continue;
|
|
1275
|
-
}
|
|
1276
|
-
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror verify: ${token}`);
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
if (!options.pandoraMarketAddress) {
|
|
1280
|
-
throw new CliError('MISSING_REQUIRED_FLAG', 'Missing --pandora-market-address <address> (alias: --market-address).');
|
|
1281
|
-
}
|
|
1282
|
-
if (!options.polymarketMarketId && !options.polymarketSlug) {
|
|
1283
|
-
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror verify requires --polymarket-market-id <id> or --polymarket-slug <slug>.');
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
return options;
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
function parseMirrorStatusFlags(args) {
|
|
1290
|
-
const options = {
|
|
1291
|
-
stateFile: null,
|
|
1292
|
-
strategyHash: null,
|
|
1293
|
-
withLive: false,
|
|
1294
|
-
trustDeploy: false,
|
|
1295
|
-
manifestFile: null,
|
|
1296
|
-
pandoraMarketAddress: null,
|
|
1297
|
-
polymarketMarketId: null,
|
|
1298
|
-
polymarketSlug: null,
|
|
1299
|
-
driftTriggerBps: 150,
|
|
1300
|
-
hedgeTriggerUsdc: 10,
|
|
1301
|
-
indexerUrl: null,
|
|
1302
|
-
timeoutMs: DEFAULT_INDEXER_TIMEOUT_MS,
|
|
1303
|
-
polymarketHost: null,
|
|
1304
|
-
polymarketGammaUrl: null,
|
|
1305
|
-
polymarketGammaMockUrl: null,
|
|
1306
|
-
polymarketMockUrl: null,
|
|
1307
|
-
};
|
|
1308
|
-
|
|
1309
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1310
|
-
const token = args[i];
|
|
1311
|
-
if (token === '--state-file') {
|
|
1312
|
-
options.stateFile = requireFlagValue(args, i, '--state-file');
|
|
1313
|
-
i += 1;
|
|
1314
|
-
continue;
|
|
1315
|
-
}
|
|
1316
|
-
if (token === '--strategy-hash') {
|
|
1317
|
-
const value = requireFlagValue(args, i, '--strategy-hash');
|
|
1318
|
-
if (!/^[a-f0-9]{16}$/i.test(value)) {
|
|
1319
|
-
throw new CliError('INVALID_FLAG_VALUE', '--strategy-hash must be a 16-character hex value.');
|
|
1320
|
-
}
|
|
1321
|
-
options.strategyHash = value.toLowerCase();
|
|
1322
|
-
i += 1;
|
|
1323
|
-
continue;
|
|
1324
|
-
}
|
|
1325
|
-
if (token === '--with-live') {
|
|
1326
|
-
options.withLive = true;
|
|
1327
|
-
continue;
|
|
1328
|
-
}
|
|
1329
|
-
if (token === '--trust-deploy') {
|
|
1330
|
-
options.trustDeploy = true;
|
|
1331
|
-
continue;
|
|
1332
|
-
}
|
|
1333
|
-
if (token === '--manifest-file') {
|
|
1334
|
-
options.manifestFile = requireFlagValue(args, i, '--manifest-file');
|
|
1335
|
-
i += 1;
|
|
1336
|
-
continue;
|
|
1337
|
-
}
|
|
1338
|
-
if (token === '--pandora-market-address' || token === '--market-address') {
|
|
1339
|
-
options.pandoraMarketAddress = parseAddressFlag(
|
|
1340
|
-
requireFlagValue(args, i, token),
|
|
1341
|
-
token,
|
|
1342
|
-
);
|
|
1343
|
-
i += 1;
|
|
1344
|
-
continue;
|
|
1345
|
-
}
|
|
1346
|
-
if (token === '--polymarket-market-id') {
|
|
1347
|
-
options.polymarketMarketId = requireFlagValue(args, i, '--polymarket-market-id');
|
|
1348
|
-
i += 1;
|
|
1349
|
-
continue;
|
|
1350
|
-
}
|
|
1351
|
-
if (token === '--polymarket-slug') {
|
|
1352
|
-
options.polymarketSlug = requireFlagValue(args, i, '--polymarket-slug');
|
|
1353
|
-
i += 1;
|
|
1354
|
-
continue;
|
|
1355
|
-
}
|
|
1356
|
-
if (token === '--drift-trigger-bps') {
|
|
1357
|
-
options.driftTriggerBps = parsePositiveInteger(requireFlagValue(args, i, '--drift-trigger-bps'), '--drift-trigger-bps');
|
|
1358
|
-
i += 1;
|
|
1359
|
-
continue;
|
|
1360
|
-
}
|
|
1361
|
-
if (token === '--hedge-trigger-usdc') {
|
|
1362
|
-
options.hedgeTriggerUsdc = parsePositiveNumber(requireFlagValue(args, i, '--hedge-trigger-usdc'), '--hedge-trigger-usdc');
|
|
1363
|
-
i += 1;
|
|
1364
|
-
continue;
|
|
1365
|
-
}
|
|
1366
|
-
if (token === '--indexer-url') {
|
|
1367
|
-
options.indexerUrl = requireFlagValue(args, i, '--indexer-url');
|
|
1368
|
-
i += 1;
|
|
1369
|
-
continue;
|
|
1370
|
-
}
|
|
1371
|
-
if (token === '--timeout-ms') {
|
|
1372
|
-
options.timeoutMs = parsePositiveInteger(requireFlagValue(args, i, '--timeout-ms'), '--timeout-ms');
|
|
1373
|
-
i += 1;
|
|
1374
|
-
continue;
|
|
1375
|
-
}
|
|
1376
|
-
if (token === '--polymarket-host') {
|
|
1377
|
-
options.polymarketHost = requireFlagValue(args, i, '--polymarket-host');
|
|
1378
|
-
i += 1;
|
|
1379
|
-
continue;
|
|
1380
|
-
}
|
|
1381
|
-
if (token === '--polymarket-gamma-url') {
|
|
1382
|
-
options.polymarketGammaUrl = requireFlagValue(args, i, '--polymarket-gamma-url');
|
|
1383
|
-
i += 1;
|
|
1384
|
-
continue;
|
|
1385
|
-
}
|
|
1386
|
-
if (token === '--polymarket-gamma-mock-url') {
|
|
1387
|
-
options.polymarketGammaMockUrl = requireFlagValue(args, i, '--polymarket-gamma-mock-url');
|
|
1388
|
-
i += 1;
|
|
1389
|
-
continue;
|
|
1390
|
-
}
|
|
1391
|
-
if (token === '--polymarket-mock-url') {
|
|
1392
|
-
options.polymarketMockUrl = requireFlagValue(args, i, '--polymarket-mock-url');
|
|
1393
|
-
i += 1;
|
|
1394
|
-
continue;
|
|
1395
|
-
}
|
|
1396
|
-
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror status: ${token}`);
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
|
-
if (!options.stateFile && !options.strategyHash) {
|
|
1400
|
-
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror status requires --state-file <path> or --strategy-hash <hash>.');
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
return options;
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
1125
|
function buildMirrorSyncStrategy(options) {
|
|
1407
1126
|
return {
|
|
1408
1127
|
mode: options.mode,
|
|
@@ -1504,222 +1223,6 @@ function buildMirrorSyncDaemonCliArgs(options, shared) {
|
|
|
1504
1223
|
return args;
|
|
1505
1224
|
}
|
|
1506
1225
|
|
|
1507
|
-
function parseMirrorCloseFlags(args) {
|
|
1508
|
-
const options = {
|
|
1509
|
-
pandoraMarketAddress: null,
|
|
1510
|
-
polymarketMarketId: null,
|
|
1511
|
-
polymarketSlug: null,
|
|
1512
|
-
execute: false,
|
|
1513
|
-
dryRun: false,
|
|
1514
|
-
};
|
|
1515
|
-
|
|
1516
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1517
|
-
const token = args[i];
|
|
1518
|
-
if (token === '--pandora-market-address' || token === '--market-address') {
|
|
1519
|
-
options.pandoraMarketAddress = parseAddressFlag(
|
|
1520
|
-
requireFlagValue(args, i, token),
|
|
1521
|
-
token,
|
|
1522
|
-
);
|
|
1523
|
-
i += 1;
|
|
1524
|
-
continue;
|
|
1525
|
-
}
|
|
1526
|
-
if (token === '--polymarket-market-id') {
|
|
1527
|
-
options.polymarketMarketId = requireFlagValue(args, i, '--polymarket-market-id');
|
|
1528
|
-
i += 1;
|
|
1529
|
-
continue;
|
|
1530
|
-
}
|
|
1531
|
-
if (token === '--polymarket-slug') {
|
|
1532
|
-
options.polymarketSlug = requireFlagValue(args, i, '--polymarket-slug');
|
|
1533
|
-
i += 1;
|
|
1534
|
-
continue;
|
|
1535
|
-
}
|
|
1536
|
-
if (token === '--dry-run') {
|
|
1537
|
-
options.dryRun = true;
|
|
1538
|
-
continue;
|
|
1539
|
-
}
|
|
1540
|
-
if (token === '--execute') {
|
|
1541
|
-
options.execute = true;
|
|
1542
|
-
continue;
|
|
1543
|
-
}
|
|
1544
|
-
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror close: ${token}`);
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
if (!options.pandoraMarketAddress) {
|
|
1548
|
-
throw new CliError('MISSING_REQUIRED_FLAG', 'Missing --pandora-market-address <address> (alias: --market-address).');
|
|
1549
|
-
}
|
|
1550
|
-
if (!options.polymarketMarketId && !options.polymarketSlug) {
|
|
1551
|
-
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror close requires --polymarket-market-id <id> or --polymarket-slug <slug>.');
|
|
1552
|
-
}
|
|
1553
|
-
if (options.dryRun === options.execute) {
|
|
1554
|
-
throw new CliError('INVALID_ARGS', 'mirror close requires exactly one mode: --dry-run or --execute.');
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
return options;
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
function parseMirrorLpExplainFlags(args) {
|
|
1561
|
-
const options = {
|
|
1562
|
-
liquidityUsdc: null,
|
|
1563
|
-
sourceYesPct: null,
|
|
1564
|
-
distributionYes: null,
|
|
1565
|
-
distributionNo: null,
|
|
1566
|
-
};
|
|
1567
|
-
|
|
1568
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1569
|
-
const token = args[i];
|
|
1570
|
-
if (token === '--liquidity-usdc') {
|
|
1571
|
-
options.liquidityUsdc = parsePositiveNumber(requireFlagValue(args, i, '--liquidity-usdc'), '--liquidity-usdc');
|
|
1572
|
-
i += 1;
|
|
1573
|
-
continue;
|
|
1574
|
-
}
|
|
1575
|
-
if (token === '--source-yes-pct') {
|
|
1576
|
-
options.sourceYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--source-yes-pct'), '--source-yes-pct');
|
|
1577
|
-
i += 1;
|
|
1578
|
-
continue;
|
|
1579
|
-
}
|
|
1580
|
-
if (token === '--distribution-yes') {
|
|
1581
|
-
options.distributionYes = parseNonNegativeInteger(
|
|
1582
|
-
requireFlagValue(args, i, '--distribution-yes'),
|
|
1583
|
-
'--distribution-yes',
|
|
1584
|
-
);
|
|
1585
|
-
i += 1;
|
|
1586
|
-
continue;
|
|
1587
|
-
}
|
|
1588
|
-
if (token === '--distribution-no') {
|
|
1589
|
-
options.distributionNo = parseNonNegativeInteger(
|
|
1590
|
-
requireFlagValue(args, i, '--distribution-no'),
|
|
1591
|
-
'--distribution-no',
|
|
1592
|
-
);
|
|
1593
|
-
i += 1;
|
|
1594
|
-
continue;
|
|
1595
|
-
}
|
|
1596
|
-
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror lp-explain: ${token}`);
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
if (options.liquidityUsdc === null) {
|
|
1600
|
-
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror lp-explain requires --liquidity-usdc <n>.');
|
|
1601
|
-
}
|
|
1602
|
-
if (
|
|
1603
|
-
(options.distributionYes === null && options.distributionNo !== null) ||
|
|
1604
|
-
(options.distributionYes !== null && options.distributionNo === null)
|
|
1605
|
-
) {
|
|
1606
|
-
throw new CliError('INVALID_ARGS', 'Provide both --distribution-yes and --distribution-no together.');
|
|
1607
|
-
}
|
|
1608
|
-
if (
|
|
1609
|
-
options.distributionYes !== null &&
|
|
1610
|
-
options.distributionNo !== null &&
|
|
1611
|
-
options.distributionYes + options.distributionNo !== 1_000_000_000
|
|
1612
|
-
) {
|
|
1613
|
-
throw new CliError('INVALID_ARGS', '--distribution-yes + --distribution-no must equal 1000000000.');
|
|
1614
|
-
}
|
|
1615
|
-
|
|
1616
|
-
return options;
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
function parseMirrorSimulateFlags(args) {
|
|
1620
|
-
const options = {
|
|
1621
|
-
liquidityUsdc: null,
|
|
1622
|
-
sourceYesPct: null,
|
|
1623
|
-
targetYesPct: null,
|
|
1624
|
-
polymarketYesPct: null,
|
|
1625
|
-
distributionYes: null,
|
|
1626
|
-
distributionNo: null,
|
|
1627
|
-
feeTier: 3000,
|
|
1628
|
-
hedgeRatio: 1,
|
|
1629
|
-
hedgeCostBps: 35,
|
|
1630
|
-
volumeScenarios: null,
|
|
1631
|
-
};
|
|
1632
|
-
|
|
1633
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1634
|
-
const token = args[i];
|
|
1635
|
-
if (token === '--liquidity-usdc') {
|
|
1636
|
-
options.liquidityUsdc = parsePositiveNumber(requireFlagValue(args, i, '--liquidity-usdc'), '--liquidity-usdc');
|
|
1637
|
-
i += 1;
|
|
1638
|
-
continue;
|
|
1639
|
-
}
|
|
1640
|
-
if (token === '--source-yes-pct') {
|
|
1641
|
-
options.sourceYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--source-yes-pct'), '--source-yes-pct');
|
|
1642
|
-
i += 1;
|
|
1643
|
-
continue;
|
|
1644
|
-
}
|
|
1645
|
-
if (token === '--target-yes-pct') {
|
|
1646
|
-
options.targetYesPct = parseProbabilityPercent(requireFlagValue(args, i, '--target-yes-pct'), '--target-yes-pct');
|
|
1647
|
-
i += 1;
|
|
1648
|
-
continue;
|
|
1649
|
-
}
|
|
1650
|
-
if (token === '--polymarket-yes-pct') {
|
|
1651
|
-
options.polymarketYesPct = parseProbabilityPercent(
|
|
1652
|
-
requireFlagValue(args, i, '--polymarket-yes-pct'),
|
|
1653
|
-
'--polymarket-yes-pct',
|
|
1654
|
-
);
|
|
1655
|
-
i += 1;
|
|
1656
|
-
continue;
|
|
1657
|
-
}
|
|
1658
|
-
if (token === '--distribution-yes') {
|
|
1659
|
-
options.distributionYes = parseNonNegativeInteger(
|
|
1660
|
-
requireFlagValue(args, i, '--distribution-yes'),
|
|
1661
|
-
'--distribution-yes',
|
|
1662
|
-
);
|
|
1663
|
-
i += 1;
|
|
1664
|
-
continue;
|
|
1665
|
-
}
|
|
1666
|
-
if (token === '--distribution-no') {
|
|
1667
|
-
options.distributionNo = parseNonNegativeInteger(
|
|
1668
|
-
requireFlagValue(args, i, '--distribution-no'),
|
|
1669
|
-
'--distribution-no',
|
|
1670
|
-
);
|
|
1671
|
-
i += 1;
|
|
1672
|
-
continue;
|
|
1673
|
-
}
|
|
1674
|
-
if (token === '--fee-tier') {
|
|
1675
|
-
options.feeTier = parsePositiveInteger(requireFlagValue(args, i, '--fee-tier'), '--fee-tier');
|
|
1676
|
-
i += 1;
|
|
1677
|
-
continue;
|
|
1678
|
-
}
|
|
1679
|
-
if (token === '--hedge-ratio') {
|
|
1680
|
-
options.hedgeRatio = parsePositiveNumber(requireFlagValue(args, i, '--hedge-ratio'), '--hedge-ratio');
|
|
1681
|
-
i += 1;
|
|
1682
|
-
continue;
|
|
1683
|
-
}
|
|
1684
|
-
if (token === '--hedge-cost-bps') {
|
|
1685
|
-
options.hedgeCostBps = parseNonNegativeInteger(requireFlagValue(args, i, '--hedge-cost-bps'), '--hedge-cost-bps');
|
|
1686
|
-
i += 1;
|
|
1687
|
-
continue;
|
|
1688
|
-
}
|
|
1689
|
-
if (token === '--volume-scenarios') {
|
|
1690
|
-
options.volumeScenarios = parseCsvNumberList(requireFlagValue(args, i, '--volume-scenarios'), '--volume-scenarios');
|
|
1691
|
-
i += 1;
|
|
1692
|
-
continue;
|
|
1693
|
-
}
|
|
1694
|
-
throw new CliError('UNKNOWN_FLAG', `Unknown flag for mirror simulate: ${token}`);
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
if (options.liquidityUsdc === null) {
|
|
1698
|
-
throw new CliError('MISSING_REQUIRED_FLAG', 'mirror simulate requires --liquidity-usdc <n>.');
|
|
1699
|
-
}
|
|
1700
|
-
if (
|
|
1701
|
-
(options.distributionYes === null && options.distributionNo !== null) ||
|
|
1702
|
-
(options.distributionYes !== null && options.distributionNo === null)
|
|
1703
|
-
) {
|
|
1704
|
-
throw new CliError('INVALID_ARGS', 'Provide both --distribution-yes and --distribution-no together.');
|
|
1705
|
-
}
|
|
1706
|
-
if (
|
|
1707
|
-
options.distributionYes !== null &&
|
|
1708
|
-
options.distributionNo !== null &&
|
|
1709
|
-
options.distributionYes + options.distributionNo !== 1_000_000_000
|
|
1710
|
-
) {
|
|
1711
|
-
throw new CliError('INVALID_ARGS', '--distribution-yes + --distribution-no must equal 1000000000.');
|
|
1712
|
-
}
|
|
1713
|
-
if (![500, 3000, 10000].includes(options.feeTier)) {
|
|
1714
|
-
throw new CliError('INVALID_FLAG_VALUE', '--fee-tier must be one of 500, 3000, 10000.');
|
|
1715
|
-
}
|
|
1716
|
-
if (options.hedgeRatio > 5) {
|
|
1717
|
-
throw new CliError('INVALID_FLAG_VALUE', '--hedge-ratio must be <= 5.');
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
return options;
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
1226
|
async function buildDoctorReport(options) {
|
|
1724
1227
|
return getDoctorServiceInstance().buildDoctorReport(options);
|
|
1725
1228
|
}
|
|
@@ -4674,6 +4177,21 @@ const parseMirrorSyncDaemonSelectorFlagsFromModule = createParseMirrorSyncDaemon
|
|
|
4674
4177
|
CliError,
|
|
4675
4178
|
requireFlagValue,
|
|
4676
4179
|
});
|
|
4180
|
+
const parseMirrorBrowseFlagsFromModule = createParseMirrorBrowseFlags({
|
|
4181
|
+
...sharedParserDeps,
|
|
4182
|
+
parseDateLikeFlag,
|
|
4183
|
+
});
|
|
4184
|
+
const parseMirrorVerifyFlagsFromModule = createParseMirrorVerifyFlags(sharedParserDeps);
|
|
4185
|
+
const parseMirrorStatusFlagsFromModule = createParseMirrorStatusFlags({
|
|
4186
|
+
...sharedParserDeps,
|
|
4187
|
+
defaultIndexerTimeoutMs: DEFAULT_INDEXER_TIMEOUT_MS,
|
|
4188
|
+
});
|
|
4189
|
+
const parseMirrorCloseFlagsFromModule = createParseMirrorCloseFlags(sharedParserDeps);
|
|
4190
|
+
const parseMirrorLpExplainFlagsFromModule = createParseMirrorLpExplainFlags(sharedParserDeps);
|
|
4191
|
+
const parseMirrorSimulateFlagsFromModule = createParseMirrorSimulateFlags({
|
|
4192
|
+
...sharedParserDeps,
|
|
4193
|
+
parseCsvNumberList,
|
|
4194
|
+
});
|
|
4677
4195
|
const parsePolymarketSharedFlagsFromModule = createParsePolymarketSharedFlags({
|
|
4678
4196
|
CliError,
|
|
4679
4197
|
requireFlagValue,
|
|
@@ -5251,18 +4769,18 @@ const runMirrorCommand = createRunMirrorCommand({
|
|
|
5251
4769
|
maybeLoadIndexerEnv,
|
|
5252
4770
|
maybeLoadTradeEnv,
|
|
5253
4771
|
resolveIndexerUrl,
|
|
5254
|
-
parseMirrorBrowseFlags,
|
|
4772
|
+
parseMirrorBrowseFlags: parseMirrorBrowseFlagsFromModule,
|
|
5255
4773
|
parseMirrorPlanFlags: parseMirrorPlanFlagsFromModule,
|
|
5256
4774
|
parseMirrorDeployFlags: parseMirrorDeployFlagsFromModule,
|
|
5257
|
-
parseMirrorVerifyFlags,
|
|
5258
|
-
parseMirrorStatusFlags,
|
|
4775
|
+
parseMirrorVerifyFlags: parseMirrorVerifyFlagsFromModule,
|
|
4776
|
+
parseMirrorStatusFlags: parseMirrorStatusFlagsFromModule,
|
|
5259
4777
|
parseMirrorSyncFlags: parseMirrorSyncFlagsFromModule,
|
|
5260
4778
|
parseMirrorSyncDaemonSelectorFlags: parseMirrorSyncDaemonSelectorFlagsFromModule,
|
|
5261
4779
|
parseMirrorGoFlags: parseMirrorGoFlagsFromModule,
|
|
5262
|
-
parseMirrorCloseFlags,
|
|
5263
|
-
parseMirrorLpExplainFlags,
|
|
4780
|
+
parseMirrorCloseFlags: parseMirrorCloseFlagsFromModule,
|
|
4781
|
+
parseMirrorLpExplainFlags: parseMirrorLpExplainFlagsFromModule,
|
|
5264
4782
|
parseMirrorHedgeCalcFlags: parseMirrorHedgeCalcFlagsFromModule,
|
|
5265
|
-
parseMirrorSimulateFlags,
|
|
4783
|
+
parseMirrorSimulateFlags: parseMirrorSimulateFlagsFromModule,
|
|
5266
4784
|
buildMirrorPlan,
|
|
5267
4785
|
deployMirror,
|
|
5268
4786
|
verifyMirror,
|
package/package.json
CHANGED
|
@@ -1057,6 +1057,12 @@ test('schema command requires --output json mode', () => {
|
|
|
1057
1057
|
assert.match(result.output, /only supported in --output json mode/i);
|
|
1058
1058
|
});
|
|
1059
1059
|
|
|
1060
|
+
test('schema --help succeeds in table mode', () => {
|
|
1061
|
+
const result = runCli(['schema', '--help']);
|
|
1062
|
+
assert.equal(result.status, 0);
|
|
1063
|
+
assert.match(String(result.stdout || ''), /Usage:\s+pandora --output json schema/);
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1060
1066
|
test('schema command returns envelope schema plus command descriptors', () => {
|
|
1061
1067
|
const result = runCli(['--output', 'json', 'schema']);
|
|
1062
1068
|
assert.equal(result.status, 0);
|
|
@@ -46,6 +46,7 @@ const {
|
|
|
46
46
|
const { runMirrorSync } = require('../../cli/lib/mirror_sync_service.cjs');
|
|
47
47
|
const { createRunMirrorCommand } = require('../../cli/lib/mirror_command_service.cjs');
|
|
48
48
|
const { resolveForkRuntime } = require('../../cli/lib/fork_runtime_service.cjs');
|
|
49
|
+
const { createErrorRecoveryService } = require('../../cli/lib/error_recovery_service.cjs');
|
|
49
50
|
const { createParseTradeFlags } = require('../../cli/lib/parsers/trade_flags.cjs');
|
|
50
51
|
const { createParseWatchFlags } = require('../../cli/lib/parsers/watch_flags.cjs');
|
|
51
52
|
const { createParseAutopilotFlags } = require('../../cli/lib/parsers/autopilot_flags.cjs');
|
|
@@ -1929,3 +1930,74 @@ test('createRunMirrorCommand sync help reports run|once|start usage and daemon s
|
|
|
1929
1930
|
assert.match(payload.daemonLifecycle.stop, /--pid-file <path>\|--strategy-hash <hash>/);
|
|
1930
1931
|
assert.match(payload.daemonLifecycle.status, /--pid-file <path>\|--strategy-hash <hash>/);
|
|
1931
1932
|
});
|
|
1933
|
+
|
|
1934
|
+
test('error recovery service returns hints for all mapped codes', () => {
|
|
1935
|
+
const recovery = createErrorRecoveryService({ cliName: 'pandora' });
|
|
1936
|
+
const mappedCodes = [
|
|
1937
|
+
'TRADE_RISK_GUARD',
|
|
1938
|
+
'ALLOWANCE_READ_FAILED',
|
|
1939
|
+
'APPROVE_SIMULATION_FAILED',
|
|
1940
|
+
'APPROVE_EXECUTION_FAILED',
|
|
1941
|
+
'TRADE_EXECUTION_FAILED',
|
|
1942
|
+
'POLYMARKET_APPROVE_FAILED',
|
|
1943
|
+
'POLYMARKET_PROXY_APPROVAL_REQUIRES_MANUAL_EXECUTION',
|
|
1944
|
+
'POLYMARKET_TRADE_FAILED',
|
|
1945
|
+
'POLYMARKET_PREFLIGHT_FAILED',
|
|
1946
|
+
'POLYMARKET_CHECK_FAILED',
|
|
1947
|
+
'POLYMARKET_MARKET_RESOLUTION_FAILED',
|
|
1948
|
+
'MIRROR_DEPLOY_FAILED',
|
|
1949
|
+
'MIRROR_SYNC_FAILED',
|
|
1950
|
+
'MCP_EXECUTE_INTENT_REQUIRED',
|
|
1951
|
+
'MCP_LONG_RUNNING_MODE_BLOCKED',
|
|
1952
|
+
'MCP_TOOL_FAILED',
|
|
1953
|
+
'UNKNOWN_TOOL',
|
|
1954
|
+
'MISSING_REQUIRED_FLAG',
|
|
1955
|
+
'MISSING_FLAG_VALUE',
|
|
1956
|
+
'INVALID_FLAG_VALUE',
|
|
1957
|
+
'UNKNOWN_FLAG',
|
|
1958
|
+
'INVALID_ARGS',
|
|
1959
|
+
'INVALID_USAGE',
|
|
1960
|
+
'INVALID_OUTPUT_MODE',
|
|
1961
|
+
'UNSUPPORTED_OUTPUT_MODE',
|
|
1962
|
+
'UNKNOWN_COMMAND',
|
|
1963
|
+
];
|
|
1964
|
+
|
|
1965
|
+
for (const code of mappedCodes) {
|
|
1966
|
+
const result = recovery.getRecoveryForError({ code });
|
|
1967
|
+
assert.equal(Boolean(result), true, `Expected recovery hint for ${code}`);
|
|
1968
|
+
assert.equal(typeof result.action, 'string');
|
|
1969
|
+
assert.equal(result.action.length > 0, true);
|
|
1970
|
+
assert.equal(typeof result.command, 'string');
|
|
1971
|
+
assert.equal(result.command.length > 0, true);
|
|
1972
|
+
assert.equal(typeof result.retryable, 'boolean');
|
|
1973
|
+
}
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1976
|
+
test('error recovery service falls through to null for unmapped codes', () => {
|
|
1977
|
+
const recovery = createErrorRecoveryService({ cliName: 'pandora' });
|
|
1978
|
+
assert.equal(recovery.getRecoveryForError({ code: 'SOME_NEW_CODE' }), null);
|
|
1979
|
+
assert.equal(recovery.getRecoveryForError({ code: '' }), null);
|
|
1980
|
+
assert.equal(recovery.getRecoveryForError(null), null);
|
|
1981
|
+
});
|
|
1982
|
+
|
|
1983
|
+
test('error recovery service builds deterministic command hints for key flows', () => {
|
|
1984
|
+
const recovery = createErrorRecoveryService({ cliName: 'pandora' });
|
|
1985
|
+
|
|
1986
|
+
const tradeRetry = recovery.getRecoveryForError({
|
|
1987
|
+
code: 'TRADE_RISK_GUARD',
|
|
1988
|
+
details: {
|
|
1989
|
+
marketAddress: TEST_MARKET,
|
|
1990
|
+
side: 'no',
|
|
1991
|
+
amountUsdc: 12.5,
|
|
1992
|
+
},
|
|
1993
|
+
});
|
|
1994
|
+
assert.equal(tradeRetry.command.includes(`--market-address ${TEST_MARKET}`), true);
|
|
1995
|
+
assert.equal(tradeRetry.command.includes('--side no'), true);
|
|
1996
|
+
assert.equal(tradeRetry.command.includes('--amount-usdc 12.5'), true);
|
|
1997
|
+
|
|
1998
|
+
const mirrorSyncRetry = recovery.getRecoveryForError({ code: 'MIRROR_SYNC_FAILED' });
|
|
1999
|
+
assert.equal(mirrorSyncRetry.command, 'pandora mirror sync once --paper --pandora-market-address <address> --polymarket-market-id <id>');
|
|
2000
|
+
|
|
2001
|
+
const mcpRetry = recovery.getRecoveryForError({ code: 'MCP_EXECUTE_INTENT_REQUIRED' });
|
|
2002
|
+
assert.equal(mcpRetry.command, 'pandora mcp');
|
|
2003
|
+
});
|