pandora-cli-skills 1.1.57 → 1.1.59

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.
Files changed (58) hide show
  1. package/SKILL.md +1 -1
  2. package/cli/lib/mirror_service.cjs +41 -17
  3. package/cli/lib/mirror_verify_service.cjs +88 -65
  4. package/cli/lib/quant/abm_market.cjs +61 -2
  5. package/cli/lib/scan_command_service.cjs +1 -0
  6. package/cli/pandora.cjs +157 -160
  7. package/package.json +2 -8
  8. package/cli/lib/model_store.cjs +0 -292
  9. package/cli/lib/quant/copula.cjs +0 -399
  10. package/cli/lib/quant/importance_sampling.cjs +0 -223
  11. package/cli/lib/quant/mc_stats.cjs +0 -179
  12. package/cli/lib/quant/particle_filter.cjs +0 -311
  13. package/cli/lib/quant/rng.cjs +0 -206
  14. package/cli/lib/quant/variance_reduction.cjs +0 -148
  15. package/tests/cli/agent_workflow.integration.test.cjs +0 -301
  16. package/tests/cli/cli.integration.test.cjs +0 -6230
  17. package/tests/cli/mcp.integration.test.cjs +0 -427
  18. package/tests/cli/sports.integration.test.cjs +0 -445
  19. package/tests/cli/stream.integration.test.cjs +0 -218
  20. package/tests/helpers/cli_runner.cjs +0 -189
  21. package/tests/smoke/consumer-json-smoke.cjs +0 -217
  22. package/tests/smoke/pack-install-smoke.cjs +0 -302
  23. package/tests/unit/abm_market.test.cjs +0 -272
  24. package/tests/unit/brier_scoring.test.cjs +0 -74
  25. package/tests/unit/brier_watch_command.test.cjs +0 -121
  26. package/tests/unit/combinatorial_arb.test.cjs +0 -252
  27. package/tests/unit/core_command_flags.test.cjs +0 -113
  28. package/tests/unit/export_service.test.cjs +0 -87
  29. package/tests/unit/fork_preview_service.test.cjs +0 -249
  30. package/tests/unit/lp_command_service.test.cjs +0 -125
  31. package/tests/unit/lp_flags.test.cjs +0 -116
  32. package/tests/unit/market_admin_resolution_state.test.cjs +0 -71
  33. package/tests/unit/mirror_close_service.test.cjs +0 -56
  34. package/tests/unit/mirror_go_regressions.test.cjs +0 -479
  35. package/tests/unit/mirror_simulate_mc.test.cjs +0 -152
  36. package/tests/unit/model_calibrate.test.cjs +0 -142
  37. package/tests/unit/model_correlation.test.cjs +0 -147
  38. package/tests/unit/model_diagnose.test.cjs +0 -83
  39. package/tests/unit/new-features.test.cjs +0 -2756
  40. package/tests/unit/odds_history_service.test.cjs +0 -132
  41. package/tests/unit/polymarket_adapter.test.cjs +0 -81
  42. package/tests/unit/quant_core.test.cjs +0 -104
  43. package/tests/unit/quant_models.test.cjs +0 -85
  44. package/tests/unit/quant_stores.test.cjs +0 -134
  45. package/tests/unit/risk_guard_service.test.cjs +0 -175
  46. package/tests/unit/risk_state_store.test.cjs +0 -166
  47. package/tests/unit/sanity.test.cjs +0 -15
  48. package/tests/unit/scan_command_service.test.cjs +0 -68
  49. package/tests/unit/simulate_command_service.test.cjs +0 -91
  50. package/tests/unit/simulate_flags.test.cjs +0 -185
  51. package/tests/unit/simulate_handlers.test.cjs +0 -103
  52. package/tests/unit/sports_consensus.test.cjs +0 -103
  53. package/tests/unit/sports_creation.test.cjs +0 -102
  54. package/tests/unit/sports_resolve_plan.test.cjs +0 -103
  55. package/tests/unit/sports_sync.test.cjs +0 -92
  56. package/tests/unit/sports_timing.test.cjs +0 -127
  57. package/tests/unit/trade_market_type_service.test.cjs +0 -109
  58. package/tests/unit/venue_connector_factory.test.cjs +0 -67
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pandora-cli-skills
3
3
  summary: Canonical skill and operator guide for Pandora CLI including mirror, polymarket, resolve, and LP flows.
4
- version: 1.1.57
4
+ version: 1.1.59
5
5
  ---
6
6
 
7
7
  # Pandora CLI & Skills
@@ -3,7 +3,13 @@ const path = require('path');
3
3
  const crypto = require('crypto');
4
4
  const { computeLiquidityRecommendation, computeDistributionHint, normalizeProbability } = require('./mirror_sizing_service.cjs');
5
5
  const { resolvePolymarketMarket, fetchDepthForMarket, browsePolymarketMarkets } = require('./polymarket_trade_adapter.cjs');
6
- const { findBestPandoraMatch, fetchPandoraMarketContext, verifyMirrorPair, hashRules } = require('./mirror_verify_service.cjs');
6
+ const {
7
+ findBestPandoraMatch,
8
+ fetchPandoraMarketContext,
9
+ verifyMirrorPair,
10
+ hashRules,
11
+ preloadPandoraMatchCandidates,
12
+ } = require('./mirror_verify_service.cjs');
7
13
  const { deployPandoraAmmMarket } = require('./pandora_deploy_service.cjs');
8
14
  const { defaultManifestFile, upsertPair } = require('./mirror_manifest_store.cjs');
9
15
  const { round } = require('./shared/utils.cjs');
@@ -421,27 +427,45 @@ async function browseMirrorMarkets(options = {}) {
421
427
  limit: options.limit,
422
428
  });
423
429
 
430
+ let preloadedPandoraCandidates = null;
431
+ let preloadDuplicateCheckError = null;
432
+ if (options.indexerUrl) {
433
+ try {
434
+ preloadedPandoraCandidates = await preloadPandoraMatchCandidates({
435
+ indexerUrl: options.indexerUrl,
436
+ timeoutMs: options.timeoutMs,
437
+ chainId: options.chainId,
438
+ limit: 100,
439
+ });
440
+ } catch (err) {
441
+ preloadDuplicateCheckError = err;
442
+ }
443
+ }
444
+
424
445
  const items = [];
425
446
  for (const entry of polymarket.items || []) {
426
447
  let existingMirror = null;
427
448
  if (options.indexerUrl) {
428
- try {
429
- const match = await findBestPandoraMatch({
430
- indexerUrl: options.indexerUrl,
431
- timeoutMs: options.timeoutMs,
432
- chainId: options.chainId,
433
- sourceQuestion: entry.question,
434
- limit: 100,
435
- });
436
- if (match.best && match.best.similarity && Number(match.best.similarity.score) >= 0.86) {
437
- existingMirror = {
438
- marketAddress: match.best.marketAddress,
439
- similarity: match.best.similarity.score,
440
- };
449
+ if (preloadDuplicateCheckError) {
450
+ diagnostics.push(
451
+ `Duplicate-check skipped for "${entry.slug || entry.marketId || entry.question || 'market'}": ${preloadDuplicateCheckError && preloadDuplicateCheckError.message ? preloadDuplicateCheckError.message : String(preloadDuplicateCheckError)}`,
452
+ );
453
+ } else {
454
+ try {
455
+ const match = await findBestPandoraMatch({
456
+ sourceQuestion: entry.question,
457
+ candidateSet: preloadedPandoraCandidates,
458
+ });
459
+ if (match.best && match.best.similarity && Number(match.best.similarity.score) >= 0.86) {
460
+ existingMirror = {
461
+ marketAddress: match.best.marketAddress,
462
+ similarity: match.best.similarity.score,
463
+ };
464
+ }
465
+ diagnostics.push(...(match.diagnostics || []));
466
+ } catch (err) {
467
+ diagnostics.push(`Duplicate-check skipped for "${entry.slug || entry.marketId || entry.question || 'market'}": ${err && err.message ? err.message : String(err)}`);
441
468
  }
442
- diagnostics.push(...(match.diagnostics || []));
443
- } catch (err) {
444
- diagnostics.push(`Duplicate-check skipped for "${entry.slug || entry.marketId || entry.question || 'market'}": ${err && err.message ? err.message : String(err)}`);
445
469
  }
446
470
  }
447
471
 
@@ -161,6 +161,91 @@ async function fetchPandoraMarketContext(options = {}) {
161
161
  };
162
162
  }
163
163
 
164
+ function buildPandoraMatchCandidates(markets, pollsMap) {
165
+ const rows = [];
166
+
167
+ for (const market of Array.isArray(markets) ? markets : []) {
168
+ const pollAddress = String(market && market.pollAddress ? market.pollAddress : '').trim();
169
+ const poll = pollsMap.get(pollAddress.toLowerCase()) || pollsMap.get(pollAddress);
170
+ const question = poll && poll.question ? String(poll.question) : null;
171
+ if (!question) continue;
172
+
173
+ rows.push({
174
+ marketAddress: market.id,
175
+ pollAddress: market.pollAddress,
176
+ question,
177
+ status: toOptionalNumber(poll && poll.status),
178
+ rules: poll && poll.rules ? String(poll.rules) : null,
179
+ yesPct: derivePandoraYesPct(market),
180
+ closeTimestamp: toOptionalNumber(market.marketCloseTimestamp),
181
+ chainId: toOptionalNumber(market.chainId),
182
+ marketType: market.marketType || null,
183
+ });
184
+ }
185
+
186
+ return rows;
187
+ }
188
+
189
+ function scorePandoraMatchCandidates(sourceQuestion, candidates) {
190
+ const rows = (Array.isArray(candidates) ? candidates : []).map((candidate) => ({
191
+ ...candidate,
192
+ similarity: questionSimilarityBreakdown(sourceQuestion, candidate.question),
193
+ }));
194
+
195
+ rows.sort((a, b) => (b.similarity.score || 0) - (a.similarity.score || 0));
196
+
197
+ const diagnostics = [];
198
+ const best = rows[0] || null;
199
+ if (!best) diagnostics.push('No Pandora candidate markets with poll questions were found.');
200
+
201
+ return {
202
+ generatedAt: new Date().toISOString(),
203
+ best,
204
+ candidateCount: rows.length,
205
+ diagnostics,
206
+ };
207
+ }
208
+
209
+ async function preloadPandoraMatchCandidates(options = {}) {
210
+ const client = createIndexerClient(options.indexerUrl, options.timeoutMs);
211
+
212
+ const page = await client.list({
213
+ queryName: 'marketss',
214
+ filterType: 'marketsFilter',
215
+ fields: ['id', 'chainId', 'marketType', 'pollAddress', 'marketCloseTimestamp', 'yesChance', 'reserveYes', 'reserveNo'],
216
+ variables: {
217
+ where: {
218
+ ...(options.chainId !== null && options.chainId !== undefined ? { chainId: options.chainId } : {}),
219
+ },
220
+ orderBy: 'createdAt',
221
+ orderDirection: 'desc',
222
+ before: null,
223
+ after: null,
224
+ limit: Math.max(25, Math.min(Number(options.limit) || 150, 500)),
225
+ },
226
+ });
227
+
228
+ const markets = Array.isArray(page.items) ? page.items : [];
229
+ const pollIds = Array.from(
230
+ new Set(
231
+ markets
232
+ .map((market) => String(market && market.pollAddress ? market.pollAddress : '').trim())
233
+ .filter(Boolean),
234
+ ),
235
+ );
236
+
237
+ const pollsMap = await client.getManyByIds({
238
+ queryName: 'polls',
239
+ fields: ['id', 'question', 'status', 'deadlineEpoch', 'rules'],
240
+ ids: pollIds,
241
+ });
242
+
243
+ return {
244
+ generatedAt: new Date().toISOString(),
245
+ candidates: buildPandoraMatchCandidates(markets, pollsMap),
246
+ };
247
+ }
248
+
164
249
  function buildGateChecks({
165
250
  similarity,
166
251
  confidenceThreshold,
@@ -325,71 +410,8 @@ async function verifyMirrorPair(options = {}) {
325
410
  }
326
411
 
327
412
  async function findBestPandoraMatch(options = {}) {
328
- const diagnostics = [];
329
- const client = createIndexerClient(options.indexerUrl, options.timeoutMs);
330
-
331
- const page = await client.list({
332
- queryName: 'marketss',
333
- filterType: 'marketsFilter',
334
- fields: ['id', 'chainId', 'marketType', 'pollAddress', 'marketCloseTimestamp', 'yesChance', 'reserveYes', 'reserveNo'],
335
- variables: {
336
- where: {
337
- ...(options.chainId !== null && options.chainId !== undefined ? { chainId: options.chainId } : {}),
338
- },
339
- orderBy: 'createdAt',
340
- orderDirection: 'desc',
341
- before: null,
342
- after: null,
343
- limit: Math.max(25, Math.min(Number(options.limit) || 150, 500)),
344
- },
345
- });
346
-
347
- const markets = Array.isArray(page.items) ? page.items : [];
348
- const pollIds = Array.from(
349
- new Set(
350
- markets
351
- .map((market) => String(market && market.pollAddress ? market.pollAddress : '').trim())
352
- .filter(Boolean),
353
- ),
354
- );
355
-
356
- const pollsMap = await client.getManyByIds({
357
- queryName: 'polls',
358
- fields: ['id', 'question', 'status', 'deadlineEpoch', 'rules'],
359
- ids: pollIds,
360
- });
361
-
362
- const rows = [];
363
- for (const market of markets) {
364
- const poll = pollsMap.get(String(market.pollAddress || '').toLowerCase()) || pollsMap.get(String(market.pollAddress || ''));
365
- const question = poll && poll.question ? String(poll.question) : null;
366
- if (!question) continue;
367
-
368
- const similarity = questionSimilarityBreakdown(options.sourceQuestion, question);
369
- rows.push({
370
- marketAddress: market.id,
371
- pollAddress: market.pollAddress,
372
- question,
373
- similarity,
374
- status: toOptionalNumber(poll && poll.status),
375
- rules: poll && poll.rules ? String(poll.rules) : null,
376
- yesPct: derivePandoraYesPct(market),
377
- closeTimestamp: toOptionalNumber(market.marketCloseTimestamp),
378
- chainId: toOptionalNumber(market.chainId),
379
- marketType: market.marketType || null,
380
- });
381
- }
382
-
383
- rows.sort((a, b) => (b.similarity.score || 0) - (a.similarity.score || 0));
384
- const best = rows[0] || null;
385
- if (!best) diagnostics.push('No Pandora candidate markets with poll questions were found.');
386
-
387
- return {
388
- generatedAt: new Date().toISOString(),
389
- best,
390
- candidateCount: rows.length,
391
- diagnostics,
392
- };
413
+ const candidateSet = options.candidateSet || (await preloadPandoraMatchCandidates(options));
414
+ return scorePandoraMatchCandidates(options.sourceQuestion, candidateSet && candidateSet.candidates);
393
415
  }
394
416
 
395
417
  module.exports = {
@@ -400,5 +422,6 @@ module.exports = {
400
422
  questionSimilarityBreakdown,
401
423
  fetchPandoraMarketContext,
402
424
  verifyMirrorPair,
425
+ preloadPandoraMatchCandidates,
403
426
  findBestPandoraMatch,
404
427
  };
@@ -1,5 +1,3 @@
1
- const { createRng } = require('./rng.cjs');
2
- const { mean, standardDeviation } = require('./mc_stats.cjs');
3
1
  const { createQuantError } = require('./errors.cjs');
4
2
 
5
3
  const ABM_SCHEMA_VERSION = '1.0.0';
@@ -10,6 +8,67 @@ function clamp(value, min, max) {
10
8
  return Math.min(max, Math.max(min, value));
11
9
  }
12
10
 
11
+ function createRng(seed) {
12
+ let state = Number.isInteger(seed) ? seed >>> 0 : 1;
13
+
14
+ function next() {
15
+ state += 0x6d2b79f5;
16
+ let t = Math.imul(state ^ (state >>> 15), 1 | state);
17
+ t ^= t + Math.imul(t ^ (t >>> 7), 61 | t);
18
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
19
+ }
20
+
21
+ let spare = null;
22
+ function nextNormal(meanValue = 0, stdDev = 1) {
23
+ if (spare !== null) {
24
+ const value = spare;
25
+ spare = null;
26
+ return meanValue + value * stdDev;
27
+ }
28
+
29
+ let u1 = next();
30
+ let u2 = next();
31
+ if (u1 <= Number.EPSILON) u1 = Number.EPSILON;
32
+ if (u2 <= Number.EPSILON) u2 = Number.EPSILON;
33
+
34
+ const radius = Math.sqrt(-2 * Math.log(u1));
35
+ const theta = 2 * Math.PI * u2;
36
+ const z0 = radius * Math.cos(theta);
37
+ const z1 = radius * Math.sin(theta);
38
+ spare = z1;
39
+ return meanValue + z0 * stdDev;
40
+ }
41
+
42
+ return {
43
+ next,
44
+ nextNormal,
45
+ };
46
+ }
47
+
48
+ function mean(values) {
49
+ if (!Array.isArray(values) || values.length === 0) {
50
+ return 0;
51
+ }
52
+ let total = 0;
53
+ for (const value of values) {
54
+ total += value;
55
+ }
56
+ return total / values.length;
57
+ }
58
+
59
+ function standardDeviation(values) {
60
+ if (!Array.isArray(values) || values.length === 0) {
61
+ return 0;
62
+ }
63
+ const average = mean(values);
64
+ let variance = 0;
65
+ for (const value of values) {
66
+ const delta = value - average;
67
+ variance += delta * delta;
68
+ }
69
+ return Math.sqrt(variance / values.length);
70
+ }
71
+
13
72
  function validatePositiveInteger(value, name) {
14
73
  const numeric = Number(value);
15
74
  if (!Number.isInteger(numeric) || numeric <= 0) {
@@ -7,6 +7,7 @@ const SCAN_USAGE =
7
7
  'pandora [--output table|json] scan [--limit <n>] [--after <cursor>] [--before <cursor>] [--order-by <field>] [--order-direction asc|desc] [--chain-id <id>] [--creator <address>] [--poll-address <address>] [--market-type <type>|--type <type>] [--where-json <json>] [--active|--resolved|--expiring-soon] [--expiring-hours <n>] [--min-tvl <usdc>] [--hedgeable] [--expand] [--with-odds]';
8
8
 
9
9
  const SCAN_NOTES = [
10
+ 'scan is a top-level alias for `markets scan`; prefer `markets scan` in docs and scripts.',
10
11
  'scan always returns expanded market payloads with odds included.',
11
12
  '--with-odds is accepted for backward compatibility and is effectively a no-op.',
12
13
  '--min-tvl applies a client-side filter against current TVL in USDC units.',