pandora-cli-skills 1.1.30 → 1.1.32

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 (37) hide show
  1. package/cli/lib/cli_output_service.cjs +6 -0
  2. package/cli/lib/command_router.cjs +7 -1
  3. package/cli/lib/history_service.cjs +14 -21
  4. package/cli/lib/mirror_command_service.cjs +16 -0
  5. package/cli/lib/mirror_econ_service.cjs +25 -32
  6. package/cli/lib/mirror_handlers/browse.cjs +6 -0
  7. package/cli/lib/mirror_handlers/close.cjs +6 -0
  8. package/cli/lib/mirror_handlers/deploy.cjs +6 -0
  9. package/cli/lib/mirror_handlers/go.cjs +6 -0
  10. package/cli/lib/mirror_handlers/hedge_calc.cjs +6 -0
  11. package/cli/lib/mirror_handlers/lp_explain.cjs +6 -0
  12. package/cli/lib/mirror_handlers/plan.cjs +6 -0
  13. package/cli/lib/mirror_handlers/simulate.cjs +6 -0
  14. package/cli/lib/mirror_handlers/status.cjs +6 -0
  15. package/cli/lib/mirror_handlers/sync.cjs +6 -0
  16. package/cli/lib/mirror_handlers/verify.cjs +6 -0
  17. package/cli/lib/mirror_service.cjs +1 -5
  18. package/cli/lib/mirror_sync/execution.cjs +331 -0
  19. package/cli/lib/mirror_sync/gates.cjs +282 -0
  20. package/cli/lib/mirror_sync/planning.cjs +167 -0
  21. package/cli/lib/mirror_sync/state.cjs +48 -0
  22. package/cli/lib/mirror_sync_service.cjs +97 -599
  23. package/cli/lib/mirror_verify_service.cjs +11 -18
  24. package/cli/lib/parsers/autopilot_flags.cjs +1 -0
  25. package/cli/lib/parsers/mirror_deploy_flags.cjs +10 -2
  26. package/cli/lib/parsers/mirror_go_flags.cjs +1 -0
  27. package/cli/lib/parsers/mirror_hedge_calc_flags.cjs +187 -0
  28. package/cli/lib/parsers/mirror_plan_flags.cjs +151 -0
  29. package/cli/lib/parsers/mirror_sync_flags.cjs +1 -0
  30. package/cli/lib/parsers/trade_flags.cjs +187 -0
  31. package/cli/lib/parsers/watch_flags.cjs +1 -0
  32. package/cli/lib/polymarket_trade_adapter.cjs +23 -30
  33. package/cli/lib/scan_command_service.cjs +11 -0
  34. package/cli/lib/shared/constants.cjs +6 -0
  35. package/cli/lib/shared/utils.cjs +36 -0
  36. package/cli/pandora.cjs +42 -493
  37. package/package.json +1 -1
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Create CLI output helpers for success/error envelopes and table output.
3
+ * @param {{defaultSchemaVersion?: string, CliError: Function}} [options]
4
+ * @returns {{emitFailure: (outputMode: 'table'|'json', error: any) => void, emitSuccess: (outputMode: 'table'|'json', command: string, data: any, tableRenderer?: Function) => void}}
5
+ */
1
6
  function createCliOutputService(options = {}) {
2
7
  const defaultSchemaVersion =
3
8
  typeof options.defaultSchemaVersion === 'string' && options.defaultSchemaVersion.trim()
@@ -120,6 +125,7 @@ function createCliOutputService(options = {}) {
120
125
  };
121
126
  }
122
127
 
128
+ /** Public CLI output service factory export. */
123
129
  module.exports = {
124
130
  createCliOutputService,
125
131
  };
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Build the top-level command dispatcher for `pandora`.
3
+ * The returned function routes parsed command/args/context to subcommand handlers.
4
+ * @param {object} deps
5
+ * @returns {(command: string|undefined, args: string[], context: {outputMode: 'table'|'json'}) => Promise<void>}
6
+ */
1
7
  function createCommandRouter(deps = {}) {
2
8
  const {
3
9
  CliError,
@@ -156,7 +162,7 @@ function createCommandRouter(deps = {}) {
156
162
  };
157
163
  }
158
164
 
165
+ /** Public command-router factory export. */
159
166
  module.exports = {
160
167
  createCommandRouter,
161
168
  };
162
-
@@ -1,24 +1,17 @@
1
1
  const { createIndexerClient } = require('./indexer_client.cjs');
2
- const { round } = require('./shared/utils.cjs');
2
+ const { round, toOptionalNumber } = require('./shared/utils.cjs');
3
3
 
4
4
  const USDC_DECIMALS = 6;
5
5
  const HISTORY_SCHEMA_VERSION = '1.0.0';
6
6
 
7
- function toNumber(value) {
8
- if (value === null || value === undefined || value === '') return null;
9
- const numeric = Number(value);
10
- if (!Number.isFinite(numeric)) return null;
11
- return numeric;
12
- }
13
-
14
7
  function toUsdc(raw) {
15
- const numeric = toNumber(raw);
8
+ const numeric = toOptionalNumber(raw);
16
9
  if (numeric === null) return null;
17
10
  return round(numeric / 10 ** USDC_DECIMALS, 6);
18
11
  }
19
12
 
20
13
  function normalizeProbabilityFromYesChance(rawYesChance) {
21
- const raw = toNumber(rawYesChance);
14
+ const raw = toOptionalNumber(rawYesChance);
22
15
  if (raw === null) return null;
23
16
  if (raw >= 0 && raw <= 1) return raw;
24
17
  if (raw > 1 && raw <= 100) return raw / 100;
@@ -29,8 +22,8 @@ function computeYesProbabilityFromMarket(market) {
29
22
  const yesChanceProb = normalizeProbabilityFromYesChance(market && market.yesChance);
30
23
  if (yesChanceProb !== null && yesChanceProb >= 0 && yesChanceProb <= 1) return yesChanceProb;
31
24
 
32
- const reserveYes = toNumber(market && market.reserveYes);
33
- const reserveNo = toNumber(market && market.reserveNo);
25
+ const reserveYes = toOptionalNumber(market && market.reserveYes);
26
+ const reserveNo = toOptionalNumber(market && market.reserveNo);
34
27
  if (reserveYes === null || reserveNo === null) return null;
35
28
  const total = reserveYes + reserveNo;
36
29
  if (!Number.isFinite(total) || total <= 0) return null;
@@ -112,21 +105,21 @@ function buildSummary(items) {
112
105
  };
113
106
 
114
107
  for (const item of items) {
115
- const collateral = toNumber(item.collateralAmountUsdc) || 0;
108
+ const collateral = toOptionalNumber(item.collateralAmountUsdc) || 0;
116
109
  summary.grossVolumeUsdc += collateral;
117
110
 
118
111
  if (item.status === 'open') {
119
112
  summary.openCount += 1;
120
- summary.unrealizedPnlApproxUsdc += toNumber(item.pnlUnrealizedApproxUsdc) || 0;
113
+ summary.unrealizedPnlApproxUsdc += toOptionalNumber(item.pnlUnrealizedApproxUsdc) || 0;
121
114
  } else if (item.status === 'won') {
122
115
  summary.wonCount += 1;
123
- summary.realizedPnlApproxUsdc += toNumber(item.pnlRealizedApproxUsdc) || 0;
116
+ summary.realizedPnlApproxUsdc += toOptionalNumber(item.pnlRealizedApproxUsdc) || 0;
124
117
  } else if (item.status === 'lost') {
125
118
  summary.lostCount += 1;
126
- summary.realizedPnlApproxUsdc += toNumber(item.pnlRealizedApproxUsdc) || 0;
119
+ summary.realizedPnlApproxUsdc += toOptionalNumber(item.pnlRealizedApproxUsdc) || 0;
127
120
  } else {
128
121
  summary.closedOtherCount += 1;
129
- summary.realizedPnlApproxUsdc += toNumber(item.pnlRealizedApproxUsdc) || 0;
122
+ summary.realizedPnlApproxUsdc += toOptionalNumber(item.pnlRealizedApproxUsdc) || 0;
130
123
  }
131
124
  }
132
125
 
@@ -141,15 +134,15 @@ function sortHistoryItems(items, orderBy, orderDirection) {
141
134
  const dir = String(orderDirection || 'desc').toLowerCase() === 'asc' ? 1 : -1;
142
135
  const pick = (item) => {
143
136
  if (orderBy === 'pnl') {
144
- return toNumber(item.pnlRealizedApproxUsdc) ?? toNumber(item.pnlUnrealizedApproxUsdc) ?? -Infinity;
137
+ return toOptionalNumber(item.pnlRealizedApproxUsdc) ?? toOptionalNumber(item.pnlUnrealizedApproxUsdc) ?? -Infinity;
145
138
  }
146
139
  if (orderBy === 'entry-price') {
147
- return toNumber(item.entryPriceUsdcPerToken) ?? -Infinity;
140
+ return toOptionalNumber(item.entryPriceUsdcPerToken) ?? -Infinity;
148
141
  }
149
142
  if (orderBy === 'mark-price') {
150
- return toNumber(item.markPriceUsdcPerToken) ?? -Infinity;
143
+ return toOptionalNumber(item.markPriceUsdcPerToken) ?? -Infinity;
151
144
  }
152
- return toNumber(item.timestamp) ?? 0;
145
+ return toOptionalNumber(item.timestamp) ?? 0;
153
146
  };
154
147
 
155
148
  items.sort((a, b) => {
@@ -1,12 +1,27 @@
1
+ /**
2
+ * Canonical usage string for `mirror go`.
3
+ * Exported for CLI help rendering and integration tests.
4
+ * @type {string}
5
+ */
1
6
  const MIRROR_GO_USAGE =
2
7
  'pandora [--output table|json] mirror go --polymarket-market-id <id>|--polymarket-slug <slug> [--liquidity-usdc <n>] [--fee-tier 500|3000|10000] [--max-imbalance <n>] [--arbiter <address>] [--category <n>] [--paper|--dry-run|--execute-live|--execute] [--auto-sync] [--sync-once] [--sync-interval-ms <ms>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--chain-id <id>] [--rpc-url <url>] [--private-key <hex>] [--funder <address>] [--usdc <address>] [--oracle <address>] [--factory <address>] [--sources <url...>] [--manifest-file <path>] [--trust-deploy] [--skip-gate] [--polymarket-host <url>] [--polymarket-gamma-url <url>] [--polymarket-gamma-mock-url <url>] [--polymarket-mock-url <url>] [--with-rules] [--include-similarity] [--min-close-lead-seconds <n>]';
3
8
 
9
+ /**
10
+ * Canonical usage string for `mirror sync`.
11
+ * Exported for CLI help rendering and integration tests.
12
+ * @type {string}
13
+ */
4
14
  const MIRROR_SYNC_USAGE =
5
15
  'pandora [--output table|json] mirror sync run|once|start --pandora-market-address <address>|--market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--paper|--dry-run|--execute-live|--execute] [--private-key <hex>] [--funder <address>] [--usdc <address>] [--trust-deploy] [--manifest-file <path>] [--skip-gate] [--daemon] [--stream|--no-stream] [--interval-ms <ms>] [--drift-trigger-bps <n>] [--hedge-trigger-usdc <n>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--depth-slippage-bps <n>] [--min-time-to-close-sec <n>] [--iterations <n>] [--state-file <path>] [--kill-switch-file <path>] [--chain-id <id>] [--rpc-url <url>] [--polymarket-host <url>] [--polymarket-gamma-url <url>] [--polymarket-gamma-mock-url <url>] [--polymarket-mock-url <url>] [--webhook-url <url>] [--telegram-bot-token <token>] [--telegram-chat-id <id>] [--discord-webhook-url <url>]';
6
16
 
7
17
  const INVALID_SUBCOMMAND_MESSAGE =
8
18
  'mirror requires subcommand: browse|plan|deploy|verify|lp-explain|hedge-calc|simulate|go|sync|status|close';
9
19
 
20
+ /**
21
+ * Build the `mirror` subcommand dispatcher with lazy-loaded action handlers.
22
+ * @param {object} deps
23
+ * @returns {(args: string[], context: {outputMode: 'table'|'json'}) => Promise<any>}
24
+ */
10
25
  function createRunMirrorCommand(deps) {
11
26
  const {
12
27
  CliError,
@@ -126,6 +141,7 @@ function createRunMirrorCommand(deps) {
126
141
  };
127
142
  }
128
143
 
144
+ /** Public mirror command service exports. */
129
145
  module.exports = {
130
146
  MIRROR_GO_USAGE,
131
147
  MIRROR_SYNC_USAGE,
@@ -1,5 +1,5 @@
1
1
  const { computeDistributionHint, normalizeProbability } = require('./mirror_sizing_service.cjs');
2
- const { round, clamp } = require('./shared/utils.cjs');
2
+ const { round, clamp, toOptionalNumber } = require('./shared/utils.cjs');
3
3
 
4
4
  const MIRROR_LP_EXPLAIN_SCHEMA_VERSION = '1.0.0';
5
5
  const MIRROR_HEDGE_CALC_SCHEMA_VERSION = '1.0.0';
@@ -7,15 +7,8 @@ const MIRROR_SIMULATE_SCHEMA_VERSION = '1.0.0';
7
7
  const USDC_DECIMALS = 6;
8
8
  const USDC_SCALE = 10 ** USDC_DECIMALS;
9
9
 
10
- function toNumber(value) {
11
- if (value === null || value === undefined || value === '') return null;
12
- const numeric = Number(value);
13
- if (!Number.isFinite(numeric)) return null;
14
- return numeric;
15
- }
16
-
17
10
  function toRawUsdc(usdc) {
18
- const numeric = toNumber(usdc);
11
+ const numeric = toOptionalNumber(usdc);
19
12
  if (numeric === null) return null;
20
13
  return BigInt(Math.round(numeric * USDC_SCALE));
21
14
  }
@@ -26,7 +19,7 @@ function rawUsdcToNumber(rawValue) {
26
19
  }
27
20
 
28
21
  function toPercent(value) {
29
- const numeric = toNumber(value);
22
+ const numeric = toOptionalNumber(value);
30
23
  if (numeric === null) return null;
31
24
  if (numeric >= 0 && numeric <= 100) return round(numeric, 6);
32
25
  return null;
@@ -42,8 +35,8 @@ function resolveDistribution(options = {}) {
42
35
  const diagnostics = [];
43
36
  const sourceYesPct = toPercent(options.sourceYesPct);
44
37
 
45
- const explicitYes = toNumber(options.distributionYes);
46
- const explicitNo = toNumber(options.distributionNo);
38
+ const explicitYes = toOptionalNumber(options.distributionYes);
39
+ const explicitNo = toOptionalNumber(options.distributionNo);
47
40
  if (explicitYes !== null || explicitNo !== null) {
48
41
  if (explicitYes === null || explicitNo === null) {
49
42
  throw new Error('distributionYes and distributionNo must both be provided together.');
@@ -85,8 +78,8 @@ function resolveDistribution(options = {}) {
85
78
  }
86
79
 
87
80
  function deriveYesPctFromReserves(reserveYesUsdc, reserveNoUsdc) {
88
- const yesReserve = toNumber(reserveYesUsdc);
89
- const noReserve = toNumber(reserveNoUsdc);
81
+ const yesReserve = toOptionalNumber(reserveYesUsdc);
82
+ const noReserve = toOptionalNumber(reserveNoUsdc);
90
83
  if (yesReserve === null || noReserve === null) return null;
91
84
  const total = yesReserve + noReserve;
92
85
  if (!Number.isFinite(total) || total <= 0) return null;
@@ -99,8 +92,8 @@ function computeCompleteSetAllocation(options = {}) {
99
92
  throw new Error('liquidityUsdc must be a positive number.');
100
93
  }
101
94
 
102
- const distributionYes = toNumber(options.distributionYes);
103
- const distributionNo = toNumber(options.distributionNo);
95
+ const distributionYes = toOptionalNumber(options.distributionYes);
96
+ const distributionNo = toOptionalNumber(options.distributionNo);
104
97
  if (!Number.isInteger(distributionYes) || !Number.isInteger(distributionNo)) {
105
98
  throw new Error('distributionYes and distributionNo must be integers.');
106
99
  }
@@ -154,9 +147,9 @@ function computeCompleteSetAllocation(options = {}) {
154
147
  }
155
148
 
156
149
  function simulateDirectionalSwap(options = {}) {
157
- const reserveYes = Math.max(0, toNumber(options.reserveYesUsdc) || 0);
158
- const reserveNo = Math.max(0, toNumber(options.reserveNoUsdc) || 0);
159
- const volumeUsdc = Math.max(0, toNumber(options.volumeUsdc) || 0);
150
+ const reserveYes = Math.max(0, toOptionalNumber(options.reserveYesUsdc) || 0);
151
+ const reserveNo = Math.max(0, toOptionalNumber(options.reserveNoUsdc) || 0);
152
+ const volumeUsdc = Math.max(0, toOptionalNumber(options.volumeUsdc) || 0);
160
153
  const feeTier = Number.isFinite(Number(options.feeTier)) ? Number(options.feeTier) : 3000;
161
154
  const feeRate = clamp(feeTier / 1_000_000, 0, 0.1);
162
155
  const side = String(options.side || 'none').toLowerCase();
@@ -215,8 +208,8 @@ function simulateDirectionalSwap(options = {}) {
215
208
 
216
209
  function solveVolumeForTargetYesPct(options = {}) {
217
210
  const targetYesPct = toPercent(options.targetYesPct);
218
- const reserveYesUsdc = toNumber(options.reserveYesUsdc);
219
- const reserveNoUsdc = toNumber(options.reserveNoUsdc);
211
+ const reserveYesUsdc = toOptionalNumber(options.reserveYesUsdc);
212
+ const reserveNoUsdc = toOptionalNumber(options.reserveNoUsdc);
220
213
  const feeTier = Number.isFinite(Number(options.feeTier)) ? Number(options.feeTier) : 3000;
221
214
 
222
215
  if (targetYesPct === null || reserveYesUsdc === null || reserveNoUsdc === null) {
@@ -267,7 +260,7 @@ function solveVolumeForTargetYesPct(options = {}) {
267
260
 
268
261
  function normalizeVolumeScenarios(value, liquidityUsdc) {
269
262
  const fallback = () => {
270
- const liq = Math.max(1, toNumber(liquidityUsdc) || 0);
263
+ const liq = Math.max(1, toOptionalNumber(liquidityUsdc) || 0);
271
264
  return [
272
265
  round(liq * 0.25, 6),
273
266
  round(liq * 0.5, 6),
@@ -277,7 +270,7 @@ function normalizeVolumeScenarios(value, liquidityUsdc) {
277
270
  };
278
271
 
279
272
  if (Array.isArray(value)) {
280
- const parsed = value.map((item) => toNumber(item)).filter((item) => Number.isFinite(item) && item >= 0).map((item) => round(item, 6));
273
+ const parsed = value.map((item) => toOptionalNumber(item)).filter((item) => Number.isFinite(item) && item >= 0).map((item) => round(item, 6));
281
274
  return parsed.length ? parsed : fallback();
282
275
  }
283
276
 
@@ -285,7 +278,7 @@ function normalizeVolumeScenarios(value, liquidityUsdc) {
285
278
  if (raw) {
286
279
  const parsed = raw
287
280
  .split(',')
288
- .map((entry) => toNumber(entry.trim()))
281
+ .map((entry) => toOptionalNumber(entry.trim()))
289
282
  .filter((entry) => Number.isFinite(entry) && entry >= 0)
290
283
  .map((entry) => round(entry, 6));
291
284
  return parsed.length ? parsed : fallback();
@@ -295,13 +288,13 @@ function normalizeVolumeScenarios(value, liquidityUsdc) {
295
288
  }
296
289
 
297
290
  function computeHedgeMetrics(options = {}) {
298
- const reserveYesUsdc = toNumber(options.reserveYesUsdc) || 0;
299
- const reserveNoUsdc = toNumber(options.reserveNoUsdc) || 0;
300
- const excessYesUsdc = toNumber(options.excessYesUsdc) || 0;
301
- const excessNoUsdc = toNumber(options.excessNoUsdc) || 0;
302
- const hedgeRatio = clamp(toNumber(options.hedgeRatio) || 1, 0, 5);
291
+ const reserveYesUsdc = toOptionalNumber(options.reserveYesUsdc) || 0;
292
+ const reserveNoUsdc = toOptionalNumber(options.reserveNoUsdc) || 0;
293
+ const excessYesUsdc = toOptionalNumber(options.excessYesUsdc) || 0;
294
+ const excessNoUsdc = toOptionalNumber(options.excessNoUsdc) || 0;
295
+ const hedgeRatio = clamp(toOptionalNumber(options.hedgeRatio) || 1, 0, 5);
303
296
  const polymarketYesPct = toPercent(options.polymarketYesPct);
304
- const hedgeCostBps = Math.max(0, toNumber(options.hedgeCostBps) || 35);
297
+ const hedgeCostBps = Math.max(0, toOptionalNumber(options.hedgeCostBps) || 35);
305
298
  const feeTier = Number.isFinite(Number(options.feeTier)) ? Number(options.feeTier) : 3000;
306
299
  const feeRate = clamp(feeTier / 1_000_000, 0, 0.1);
307
300
 
@@ -444,8 +437,8 @@ function buildMirrorSimulate(options = {}) {
444
437
  : 'none';
445
438
 
446
439
  const feeTier = Number.isFinite(Number(options.feeTier)) ? Number(options.feeTier) : 3000;
447
- const hedgeRatio = clamp(toNumber(options.hedgeRatio) || 1, 0, 5);
448
- const hedgeCostBps = Math.max(0, toNumber(options.hedgeCostBps) || 35);
440
+ const hedgeRatio = clamp(toOptionalNumber(options.hedgeRatio) || 1, 0, 5);
441
+ const hedgeCostBps = Math.max(0, toOptionalNumber(options.hedgeCostBps) || 35);
449
442
  const polymarketYesPct = toPercent(
450
443
  options.polymarketYesPct !== undefined ? options.polymarketYesPct : (targetYesPct !== null ? targetYesPct : 50),
451
444
  );
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror browse` command execution.
3
+ * Emits help or filtered mirror browse results through CLI output services.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorBrowse({ shared, context, deps }) {
2
8
  const {
3
9
  includesHelpFlag,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror close` command execution.
3
+ * Builds and emits a close plan payload for dry-run/operator workflows.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorClose({ shared, context, deps }) {
2
8
  const {
3
9
  includesHelpFlag,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror deploy` command execution.
3
+ * Parses deploy flags, invokes deploy service, and emits deploy payloads.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorDeploy({ shared, context, deps }) {
2
8
  const {
3
9
  includesHelpFlag,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror go` command execution.
3
+ * Orchestrates plan -> deploy -> verify -> optional sync/trade flow and emits a combined payload.
4
+ * @param {{shared: object, context: object, deps: object, mirrorGoUsage: string}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorGo({ shared, context, deps, mirrorGoUsage }) {
2
8
  const {
3
9
  CliError,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror hedge-calc` command execution.
3
+ * Resolves optional market context and emits hedge sizing diagnostics.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorHedgeCalc({ shared, context, deps }) {
2
8
  const {
3
9
  CliError,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror lp-explain` command execution.
3
+ * Produces and emits LP inventory/price-balance explanation payloads.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorLpExplain({ shared, context, deps }) {
2
8
  const {
3
9
  includesHelpFlag,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror plan` command execution.
3
+ * Resolves source market inputs and emits mirror plan payloads.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorPlan({ shared, context, deps }) {
2
8
  const {
3
9
  includesHelpFlag,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror simulate` command execution.
3
+ * Computes scenario projections and emits simulation payloads.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorSimulate({ shared, context, deps }) {
2
8
  const {
3
9
  includesHelpFlag,
@@ -1,5 +1,11 @@
1
1
  const path = require('path');
2
2
 
3
+ /**
4
+ * Handle `mirror status` command execution.
5
+ * Reads sync state and optionally enriches with live verification/position diagnostics.
6
+ * @param {{actionArgs: string[], shared: object, context: object, deps: object}} params
7
+ * @returns {Promise<void>}
8
+ */
3
9
  module.exports = async function handleMirrorStatus({ actionArgs, shared, context, deps }) {
4
10
  const {
5
11
  CliError,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror sync` command execution (`run|once|start|stop|status`).
3
+ * Orchestrates sync runtime, daemon lifecycle, and structured output emission.
4
+ * @param {{shared: object, context: object, deps: object, mirrorSyncUsage: string}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorSync({ shared, context, deps, mirrorSyncUsage }) {
2
8
  const {
3
9
  CliError,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Handle `mirror verify` command execution.
3
+ * Runs pair verification and emits similarity/rules/gate diagnostics.
4
+ * @param {{shared: object, context: object, deps: object}} params
5
+ * @returns {Promise<void>}
6
+ */
1
7
  module.exports = async function handleMirrorVerify({ shared, context, deps }) {
2
8
  const {
3
9
  includesHelpFlag,
@@ -6,16 +6,12 @@ const { resolvePolymarketMarket, fetchDepthForMarket, browsePolymarketMarkets }
6
6
  const { findBestPandoraMatch, fetchPandoraMarketContext, verifyMirrorPair, hashRules } = require('./mirror_verify_service.cjs');
7
7
  const { deployPandoraAmmMarket } = require('./pandora_deploy_service.cjs');
8
8
  const { defaultManifestFile, upsertPair } = require('./mirror_manifest_store.cjs');
9
- const { round: roundFinite } = require('./shared/utils.cjs');
9
+ const { round } = require('./shared/utils.cjs');
10
10
 
11
11
  const MIRROR_PLAN_SCHEMA_VERSION = '1.0.0';
12
12
  const MIRROR_DEPLOY_SCHEMA_VERSION = '1.0.0';
13
13
  const MIRROR_BROWSE_SCHEMA_VERSION = '1.0.0';
14
14
 
15
- function round(value, decimals = 6) {
16
- return roundFinite(Number(value), decimals);
17
- }
18
-
19
15
  function createServiceError(code, message, details = undefined) {
20
16
  const err = new Error(message);
21
17
  err.code = code;