openbroker 1.9.3 → 1.9.5

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 (42) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +31 -0
  3. package/SKILL.md +21 -4
  4. package/bin/cli.ts +4 -2
  5. package/dist/auto/cli.js +1 -1
  6. package/dist/auto/examples/price-alert.js +1 -1
  7. package/dist/auto/realtime.d.ts +45 -0
  8. package/dist/auto/realtime.d.ts.map +1 -0
  9. package/dist/auto/realtime.js +177 -0
  10. package/dist/auto/realtime.test.d.ts +2 -0
  11. package/dist/auto/realtime.test.d.ts.map +1 -0
  12. package/dist/auto/realtime.test.js +73 -0
  13. package/dist/auto/runtime.d.ts +3 -3
  14. package/dist/auto/runtime.d.ts.map +1 -1
  15. package/dist/auto/runtime.js +117 -45
  16. package/dist/auto/types.d.ts +2 -1
  17. package/dist/auto/types.d.ts.map +1 -1
  18. package/dist/core/client.d.ts +66 -1
  19. package/dist/core/client.d.ts.map +1 -1
  20. package/dist/core/client.js +141 -4
  21. package/dist/core/ws.d.ts +14 -2
  22. package/dist/core/ws.d.ts.map +1 -1
  23. package/dist/core/ws.js +53 -7
  24. package/dist/setup/install.js +100 -3
  25. package/dist/setup/package-catalog.d.ts +12 -0
  26. package/dist/setup/package-catalog.d.ts.map +1 -0
  27. package/dist/setup/package-catalog.js +36 -0
  28. package/dist/setup/package-catalog.test.d.ts +2 -0
  29. package/dist/setup/package-catalog.test.d.ts.map +1 -0
  30. package/dist/setup/package-catalog.test.js +31 -0
  31. package/package.json +5 -3
  32. package/scripts/auto/cli.ts +1 -1
  33. package/scripts/auto/examples/price-alert.ts +1 -1
  34. package/scripts/auto/realtime.test.ts +84 -0
  35. package/scripts/auto/realtime.ts +194 -0
  36. package/scripts/auto/runtime.ts +125 -47
  37. package/scripts/auto/types.ts +2 -1
  38. package/scripts/core/client.ts +175 -4
  39. package/scripts/core/ws.ts +57 -8
  40. package/scripts/setup/install.ts +110 -3
  41. package/scripts/setup/package-catalog.test.ts +50 -0
  42. package/scripts/setup/package-catalog.ts +49 -0
@@ -15,6 +15,8 @@ export class HyperliquidClient {
15
15
  szDecimalsMap = new Map();
16
16
  /** Maps coin name → dex info for HIP-3 assets. Main dex assets have dexName=null */
17
17
  coinDexMap = new Map();
18
+ /** Static positional universe per dex, used to join allDexsAssetCtxs WS pushes. */
19
+ dexUniverseMap = new Map();
18
20
  /** Cache of perpDexs list */
19
21
  perpDexsCache = null;
20
22
  /** Whether HIP-3 assets have been loaded into maps */
@@ -45,6 +47,13 @@ export class HyperliquidClient {
45
47
  spotMetaLoaded = false;
46
48
  /** HIP-4 outcome metadata cache */
47
49
  outcomeMeta = null;
50
+ /** Static main-dex universe retained while live asset contexts arrive over WebSocket. */
51
+ staticMeta = null;
52
+ /** Runtime-owned live data cache. CLI calls leave this detached and remain REST-only. */
53
+ realtime = null;
54
+ predictedFundingsCache = null;
55
+ predictedFundingsInFlight = null;
56
+ spotMetaCache = null;
48
57
  verbose = false;
49
58
  constructor(config) {
50
59
  this.config = config ?? loadConfig();
@@ -184,6 +193,10 @@ export class HyperliquidClient {
184
193
  get isTestnet() {
185
194
  return !isMainnet();
186
195
  }
196
+ /** Attach/detach the automation runtime's WebSocket-first data cache. */
197
+ setRealtimeDataProvider(provider) {
198
+ this.realtime = provider;
199
+ }
187
200
  /**
188
201
  * Returns vaultAddress param for SDK exchange calls.
189
202
  * Only used for vault trading (HYPERLIQUID_VAULT_ADDRESS set explicitly).
@@ -208,6 +221,10 @@ export class HyperliquidClient {
208
221
  }
209
222
  // ============ Market Data ============
210
223
  async getMetaAndAssetCtxs() {
224
+ const liveCtxs = this.realtime?.connected ? this.realtime.getMainAssetCtxs() : null;
225
+ if (this.staticMeta && liveCtxs) {
226
+ return { meta: this.staticMeta, assetCtxs: liveCtxs };
227
+ }
211
228
  if (this.meta)
212
229
  return this.meta;
213
230
  this.log('Fetching metaAndAssetCtxs...');
@@ -230,6 +247,8 @@ export class HyperliquidClient {
230
247
  assetCtxs: response[1],
231
248
  };
232
249
  this.meta = meta;
250
+ this.staticMeta = meta.meta;
251
+ this.dexUniverseMap.set('', meta.meta.universe.map((asset) => asset.name));
233
252
  // Build lookup maps for main dex
234
253
  meta.meta.universe.forEach((asset, index) => {
235
254
  this.assetMap.set(asset.name, index);
@@ -243,6 +262,29 @@ export class HyperliquidClient {
243
262
  }
244
263
  return meta;
245
264
  }
265
+ /**
266
+ * Warm only the native/main static universe for an automation runtime.
267
+ * Dynamic contexts arrive via allDexsAssetCtxs, and HIP-3 metadata is loaded
268
+ * on demand when a strategy references a prefixed market. This avoids the
269
+ * old startup burst that fetched every HIP-3 dex before the socket opened.
270
+ */
271
+ async initializeRealtimeMetadata() {
272
+ if (this.staticMeta)
273
+ return;
274
+ const response = await this.withRetry(() => this.info.metaAndAssetCtxs(), 'metaAndAssetCtxs(realtime-init)');
275
+ const meta = {
276
+ meta: { universe: response[0].universe },
277
+ assetCtxs: response[1],
278
+ };
279
+ this.meta = meta;
280
+ this.staticMeta = meta.meta;
281
+ this.dexUniverseMap.set('', meta.meta.universe.map((asset) => asset.name));
282
+ meta.meta.universe.forEach((asset, index) => {
283
+ this.assetMap.set(asset.name, index);
284
+ this.szDecimalsMap.set(asset.name, asset.szDecimals);
285
+ this.coinDexMap.set(asset.name, { dexName: null, dexIdx: 0, localName: asset.name });
286
+ });
287
+ }
246
288
  /**
247
289
  * Load HIP-3 perp dex assets into the asset/szDecimals maps.
248
290
  * Asset index formula: 100000 + dexIdx * 10000 + assetIdx
@@ -356,10 +398,14 @@ export class HyperliquidClient {
356
398
  if (asset.maxLeverage)
357
399
  this.hip3MaxLeverageMap.set(coinName, asset.maxLeverage);
358
400
  });
401
+ this.dexUniverseMap.set(dexName, universe.map((asset) => (asset.name.startsWith(`${dexName}:`) ? asset.name : `${dexName}:${asset.name}`)));
359
402
  }
360
403
  this.loadedHip3Dexes.add(dexName);
361
404
  }
362
405
  async getAllMids() {
406
+ const live = this.realtime?.connected ? this.realtime.getAllMids() : null;
407
+ if (live)
408
+ return { ...live };
363
409
  this.log('Fetching allMids...');
364
410
  let response;
365
411
  try {
@@ -449,8 +495,11 @@ export class HyperliquidClient {
449
495
  * Get spot market metadata
450
496
  */
451
497
  async getSpotMeta() {
498
+ if (this.spotMetaCache)
499
+ return this.spotMetaCache;
452
500
  this.log('Fetching spotMeta...');
453
501
  const data = await this.postInfo({ type: 'spotMeta' }, 'spotMeta');
502
+ this.spotMetaCache = data;
454
503
  this.log('spotMeta response:', JSON.stringify(data).slice(0, 500));
455
504
  return data;
456
505
  }
@@ -458,6 +507,23 @@ export class HyperliquidClient {
458
507
  * Get spot metadata with asset contexts (prices, volumes)
459
508
  */
460
509
  async getSpotMetaAndAssetCtxs() {
510
+ const liveMids = this.realtime?.connected ? this.realtime.getAllMids() : null;
511
+ if (liveMids) {
512
+ const meta = await this.getSpotMeta();
513
+ return {
514
+ meta,
515
+ assetCtxs: meta.universe.map((pair) => {
516
+ const price = liveMids[pair.name] ?? '0';
517
+ return {
518
+ coin: pair.name,
519
+ dayNtlVlm: '0',
520
+ markPx: price,
521
+ midPx: price,
522
+ prevDayPx: price,
523
+ };
524
+ }),
525
+ };
526
+ }
461
527
  this.log('Fetching spotMetaAndAssetCtxs...');
462
528
  const data = await this.postInfo({ type: 'spotMetaAndAssetCtxs' }, 'spotMetaAndAssetCtxs');
463
529
  this.log('spotMetaAndAssetCtxs response:', JSON.stringify(data).slice(0, 500));
@@ -767,6 +833,10 @@ export class HyperliquidClient {
767
833
  * Get user's spot token balances
768
834
  */
769
835
  async getSpotBalances(user) {
836
+ const target = user ?? this.address;
837
+ const live = this.realtime?.connected ? this.realtime.getSpotBalances(target) : null;
838
+ if (live)
839
+ return live;
770
840
  this.log('Fetching spotClearinghouseState for:', user ?? this.address);
771
841
  const data = await this.postInfo({
772
842
  type: 'spotClearinghouseState',
@@ -804,6 +874,30 @@ export class HyperliquidClient {
804
874
  * Get predicted funding rates across venues
805
875
  */
806
876
  async getPredictedFundings() {
877
+ const ttlMs = 60_000;
878
+ if (this.predictedFundingsCache && Date.now() - this.predictedFundingsCache.timestamp < ttlMs) {
879
+ return this.predictedFundingsCache.value;
880
+ }
881
+ if (this.predictedFundingsInFlight)
882
+ return this.predictedFundingsInFlight;
883
+ this.predictedFundingsInFlight = this.fetchPredictedFundings();
884
+ try {
885
+ const value = await this.predictedFundingsInFlight;
886
+ this.predictedFundingsCache = { value, timestamp: Date.now() };
887
+ return value;
888
+ }
889
+ catch (error) {
890
+ if (this.predictedFundingsCache) {
891
+ this.log('predictedFundings refresh failed; using stale cache:', this.describeError(error));
892
+ return this.predictedFundingsCache.value;
893
+ }
894
+ throw error;
895
+ }
896
+ finally {
897
+ this.predictedFundingsInFlight = null;
898
+ }
899
+ }
900
+ async fetchPredictedFundings() {
807
901
  this.log('Fetching predictedFundings...');
808
902
  const baseUrl = isMainnet()
809
903
  ? 'https://api.hyperliquid.xyz'
@@ -817,8 +911,13 @@ export class HyperliquidClient {
817
911
  },
818
912
  body: JSON.stringify({ type: 'predictedFundings' }),
819
913
  });
914
+ if (!response.ok) {
915
+ throw new Error(`predictedFundings failed: HTTP ${response.status} ${response.statusText}`);
916
+ }
820
917
  const data = await response.json();
821
- this.log('predictedFundings response length:', data?.length);
918
+ if (!Array.isArray(data))
919
+ throw new Error('predictedFundings returned malformed payload');
920
+ this.log('predictedFundings response length:', data.length);
822
921
  return data;
823
922
  }
824
923
  /**
@@ -826,6 +925,9 @@ export class HyperliquidClient {
826
925
  * Returns best bid/ask and depth
827
926
  */
828
927
  async getL2Book(coin) {
928
+ const live = this.realtime?.connected ? await this.realtime.getL2Book(coin) : null;
929
+ if (live)
930
+ return this.normalizeL2Book(live.levels);
829
931
  this.log('Fetching l2Book for:', coin);
830
932
  // API accepts prefixed names directly (e.g., "xyz:CL")
831
933
  let response;
@@ -842,8 +944,11 @@ export class HyperliquidClient {
842
944
  if (!response || !Array.isArray(response.levels)) {
843
945
  throw new Error(`l2Book(${coin}) returned empty/malformed payload.`);
844
946
  }
845
- const bids = (response.levels[0] ?? []);
846
- const asks = (response.levels[1] ?? []);
947
+ return this.normalizeL2Book(response.levels);
948
+ }
949
+ normalizeL2Book(levels) {
950
+ const bids = levels[0] ?? [];
951
+ const asks = levels[1] ?? [];
847
952
  const bestBid = bids.length > 0 ? parseFloat(bids[0].px) : 0;
848
953
  const bestAsk = asks.length > 0 ? parseFloat(asks[0].px) : 0;
849
954
  const midPrice = (bestBid + bestAsk) / 2;
@@ -959,6 +1064,26 @@ export class HyperliquidClient {
959
1064
  this.meta = null;
960
1065
  // Keep the asset/szDecimals/coinDex maps - they don't change
961
1066
  }
1067
+ /** Join an allDexsAssetCtxs WebSocket payload with the cached static universes. */
1068
+ fundingRatesFromWs(ctxs) {
1069
+ const rates = new Map();
1070
+ for (const [dexName, values] of ctxs) {
1071
+ const universe = this.dexUniverseMap.get(dexName || '');
1072
+ if (!universe)
1073
+ continue;
1074
+ for (let index = 0; index < Math.min(universe.length, values.length); index++) {
1075
+ const coin = universe[index];
1076
+ const value = values[index];
1077
+ if (!coin || !value)
1078
+ continue;
1079
+ rates.set(coin, {
1080
+ rate: Number(value.funding ?? 0),
1081
+ premium: Number(value.premium ?? 0),
1082
+ });
1083
+ }
1084
+ }
1085
+ return rates;
1086
+ }
962
1087
  /**
963
1088
  * Get all loaded asset names (main + HIP-3)
964
1089
  */
@@ -1362,6 +1487,10 @@ export class HyperliquidClient {
1362
1487
  return data;
1363
1488
  }
1364
1489
  async getUserState(user, dex) {
1490
+ const target = user ?? this.address;
1491
+ const live = this.realtime?.connected ? this.realtime.getUserState(target, dex) : null;
1492
+ if (live)
1493
+ return live;
1365
1494
  this.log('Fetching clearinghouseState for:', user ?? this.address, dex ? `dex: ${dex}` : '');
1366
1495
  const params = { user: user ?? this.address };
1367
1496
  if (dex !== undefined)
@@ -1504,6 +1633,10 @@ export class HyperliquidClient {
1504
1633
  * For standard accounts: aggregates margin summaries from each dex.
1505
1634
  */
1506
1635
  async getUserStateAll(user) {
1636
+ const target = user ?? this.address;
1637
+ const live = this.realtime?.connected ? this.realtime.getUserStateAll(target) : null;
1638
+ if (live)
1639
+ return live;
1507
1640
  await this.getMetaAndAssetCtxs(); // Ensure HIP-3 dex list is loaded
1508
1641
  const unified = await this.isUnifiedAccount(user);
1509
1642
  const mainState = await this.getUserState(user);
@@ -1539,7 +1672,11 @@ export class HyperliquidClient {
1539
1672
  return this.mergeUserStateAll(perDex, unified, spotBalances);
1540
1673
  }
1541
1674
  async getOpenOrders(user) {
1542
- this.log('Fetching openOrders for:', user ?? this.address);
1675
+ const target = user ?? this.address;
1676
+ const live = this.realtime?.connected ? this.realtime.getOpenOrders(target) : null;
1677
+ if (live)
1678
+ return live;
1679
+ this.log('Fetching openOrders for:', target);
1543
1680
  await this.getMetaAndAssetCtxs(); // Ensure HIP-3 dex list is loaded
1544
1681
  // Fetch main dex orders
1545
1682
  const orders = await this.withRetry(() => this.info.openOrders({ user: user ?? this.address }), 'openOrders');
package/dist/core/ws.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ISubscription } from '@nktkas/hyperliquid';
2
2
  import type { UserEventsWsEvent } from '@nktkas/hyperliquid';
3
- import type { ClearinghouseState } from './types.js';
3
+ import type { ClearinghouseState, OpenOrder } from './types.js';
4
4
  export interface WsEventMap {
5
5
  /** L2 order book snapshot for a specific coin */
6
6
  l2Book: {
@@ -69,6 +69,12 @@ export interface WsEventMap {
69
69
  entryNtl?: string;
70
70
  }>;
71
71
  };
72
+ /** Complete open-order snapshot for one user + dex (empty dex = native/main). */
73
+ openOrders: {
74
+ user: string;
75
+ dex: string;
76
+ orders: OpenOrder[];
77
+ };
72
78
  /** Order status changed (filled, canceled, rejected, etc.) */
73
79
  orderUpdate: {
74
80
  order: {
@@ -134,6 +140,7 @@ export declare class WebSocketManager {
134
140
  private subscriptions;
135
141
  private handlers;
136
142
  private _connected;
143
+ private closing;
137
144
  private verbose;
138
145
  constructor(verbose?: boolean);
139
146
  private log;
@@ -172,6 +179,8 @@ export declare class WebSocketManager {
172
179
  * `getSpotBalances` REST polling in the collateral gate.
173
180
  */
174
181
  subscribeSpotState(user: `0x${string}`): Promise<ISubscription>;
182
+ /** Subscribe to complete open-order snapshots for one dex. */
183
+ subscribeOpenOrders(user: `0x${string}`, dex?: string): Promise<ISubscription>;
175
184
  /**
176
185
  * Subscribe to order lifecycle events (fill, cancel, reject, etc.).
177
186
  * This is the most important subscription for trading automations.
@@ -189,11 +198,14 @@ export declare class WebSocketManager {
189
198
  /**
190
199
  * Start all subscriptions needed for the automation runtime:
191
200
  * - allMids (price feed)
201
+ * - allDexsAssetCtxs (funding / mark / oracle contexts)
202
+ * - allDexsClearinghouseState + spotState (positions, margin, balances)
203
+ * - openOrders for main + requested HIP-3 dexes
192
204
  * - orderUpdates (order lifecycle)
193
205
  * - userFills (trade fills)
194
206
  * - userEvents (liquidations, funding payments, system cancels)
195
207
  */
196
- subscribeAll(user: `0x${string}`): Promise<void>;
208
+ subscribeAll(user: `0x${string}`, dexNames?: string[]): Promise<void>;
197
209
  }
198
210
  export declare function getWebSocket(verbose?: boolean): WebSocketManager;
199
211
  export declare function resetWebSocket(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../scripts/core/ws.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../scripts/core/ws.ts"],"names":[],"mappings":"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"}
package/dist/core/ws.js CHANGED
@@ -9,6 +9,7 @@ export class WebSocketManager {
9
9
  subscriptions = [];
10
10
  handlers = new Map();
11
11
  _connected = false;
12
+ closing = false;
12
13
  verbose;
13
14
  constructor(verbose = false) {
14
15
  this.verbose = verbose;
@@ -27,14 +28,36 @@ export class WebSocketManager {
27
28
  this.transport = new WebSocketTransport({
28
29
  isTestnet: !isMainnet(),
29
30
  resubscribe: true, // auto-resubscribe on reconnect
31
+ reconnect: { maxRetries: Infinity },
32
+ });
33
+ const socket = this.transport.socket;
34
+ socket.addEventListener('open', () => {
35
+ if (this._connected)
36
+ return;
37
+ this._connected = true;
38
+ this.emit('connected', undefined);
39
+ this.log('Connected to', isMainnet() ? 'mainnet' : 'testnet');
40
+ });
41
+ socket.addEventListener('close', () => {
42
+ if (!this._connected)
43
+ return;
44
+ this._connected = false;
45
+ this.emit('disconnected', { reason: this.closing ? 'manual close' : 'socket closed' });
46
+ this.log(this.closing ? 'Closed' : 'Disconnected; transport will reconnect');
47
+ });
48
+ socket.addEventListener('error', () => {
49
+ this.emit('error', { error: new Error('Hyperliquid WebSocket transport error') });
30
50
  });
31
51
  this.client = new SubscriptionClient({ transport: this.transport });
32
52
  await this.transport.ready();
33
- this._connected = true;
34
- this.emit('connected', undefined);
35
- this.log('Connected to', isMainnet() ? 'mainnet' : 'testnet');
53
+ if (!this._connected) {
54
+ this._connected = true;
55
+ this.emit('connected', undefined);
56
+ this.log('Connected to', isMainnet() ? 'mainnet' : 'testnet');
57
+ }
36
58
  }
37
59
  async close() {
60
+ this.closing = true;
38
61
  for (const sub of this.subscriptions) {
39
62
  try {
40
63
  await sub.unsubscribe();
@@ -50,9 +73,12 @@ export class WebSocketManager {
50
73
  this.transport = null;
51
74
  this.client = null;
52
75
  }
53
- this._connected = false;
54
- this.emit('disconnected', { reason: 'manual close' });
55
- this.log('Closed');
76
+ if (this._connected) {
77
+ this._connected = false;
78
+ this.emit('disconnected', { reason: 'manual close' });
79
+ this.log('Closed');
80
+ }
81
+ this.closing = false;
56
82
  }
57
83
  // ── Event system ───────────────────────────────────────────────
58
84
  on(event, handler) {
@@ -162,6 +188,18 @@ export class WebSocketManager {
162
188
  });
163
189
  return this.trackSub(sub);
164
190
  }
191
+ /** Subscribe to complete open-order snapshots for one dex. */
192
+ async subscribeOpenOrders(user, dex = '') {
193
+ const client = this.ensureClient();
194
+ const sub = await client.openOrders({ user, dex }, (data) => {
195
+ this.emit('openOrders', {
196
+ user: data.user,
197
+ dex: data.dex,
198
+ orders: data.orders,
199
+ });
200
+ });
201
+ return this.trackSub(sub);
202
+ }
165
203
  /**
166
204
  * Subscribe to order lifecycle events (fill, cancel, reject, etc.).
167
205
  * This is the most important subscription for trading automations.
@@ -232,15 +270,23 @@ export class WebSocketManager {
232
270
  /**
233
271
  * Start all subscriptions needed for the automation runtime:
234
272
  * - allMids (price feed)
273
+ * - allDexsAssetCtxs (funding / mark / oracle contexts)
274
+ * - allDexsClearinghouseState + spotState (positions, margin, balances)
275
+ * - openOrders for main + requested HIP-3 dexes
235
276
  * - orderUpdates (order lifecycle)
236
277
  * - userFills (trade fills)
237
278
  * - userEvents (liquidations, funding payments, system cancels)
238
279
  */
239
- async subscribeAll(user) {
280
+ async subscribeAll(user, dexNames = []) {
240
281
  await this.connect();
241
282
  this.log('Subscribing to all feeds for', user);
242
283
  await Promise.all([
243
284
  this.subscribeAllMids(),
285
+ this.subscribeAllDexsAssetCtxs(),
286
+ this.subscribeAllDexsClearinghouseState(user),
287
+ this.subscribeSpotState(user),
288
+ this.subscribeOpenOrders(user),
289
+ ...dexNames.map((dex) => this.subscribeOpenOrders(user, dex)),
244
290
  this.subscribeOrderUpdates(user),
245
291
  this.subscribeUserFills(user),
246
292
  this.subscribeUserEvents(user),
@@ -5,19 +5,54 @@ import * as path from 'path';
5
5
  import { homedir } from 'os';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { spawnSync } from 'child_process';
8
+ import { INSTALLABLE_PACKAGES, packageSpec, resolveInstallablePackage, } from './package-catalog.js';
8
9
  const __filename = fileURLToPath(import.meta.url);
9
10
  const __dirname = path.dirname(__filename);
10
11
  const packageRoot = path.resolve(__dirname, '../..');
11
- const args = new Set(process.argv.slice(2));
12
+ const rawArgs = process.argv.slice(2);
13
+ const args = new Set(rawArgs);
14
+ function positionalArgs() {
15
+ const positionals = [];
16
+ for (let index = 0; index < rawArgs.length; index++) {
17
+ const arg = rawArgs[index];
18
+ if (arg === '--tag') {
19
+ index++;
20
+ continue;
21
+ }
22
+ if (!arg.startsWith('-'))
23
+ positionals.push(arg);
24
+ }
25
+ return positionals;
26
+ }
27
+ function optionValue(flag) {
28
+ const index = rawArgs.indexOf(flag);
29
+ if (index < 0)
30
+ return null;
31
+ const value = rawArgs[index + 1];
32
+ if (!value || value.startsWith('-'))
33
+ fail(`${flag} requires a value`);
34
+ return value;
35
+ }
12
36
  function printUsage() {
13
37
  console.log(`
14
- OpenBroker Harness Installer
15
- ============================
38
+ OpenBroker Installer
39
+ ====================
16
40
 
17
41
  Usage:
42
+ openbroker install <package> [--tag <version>] [--dry]
43
+ openbroker install --list
18
44
  openbroker install --codex [options]
19
45
  npx openbroker@latest install --codex [options]
20
46
 
47
+ Companion packages:
48
+ monitoring Install the local automation dashboard
49
+ extended Install the Extended Exchange CLI
50
+
51
+ Package options:
52
+ --tag <tag> Install a release tag or exact version (default: latest)
53
+ --dry Print the npm command without installing
54
+ --list List supported companion packages
55
+
21
56
  Harnesses:
22
57
  --codex Install the OpenBroker skill for Codex
23
58
 
@@ -74,6 +109,55 @@ function installGlobalCli() {
74
109
  fail('global CLI installation failed. Fix the npm permission error, then rerun with --skip-cli.');
75
110
  }
76
111
  }
112
+ function printInstallablePackages() {
113
+ console.log('Installable OpenBroker packages:\n');
114
+ for (const entry of INSTALLABLE_PACKAGES) {
115
+ console.log(` ${entry.key.padEnd(12)} ${entry.packageName.padEnd(26)} ${entry.description}`);
116
+ }
117
+ console.log('\nInstall or upgrade with: openbroker install <package>');
118
+ }
119
+ function installCompanionPackage(target) {
120
+ const entry = resolveInstallablePackage(target);
121
+ if (!entry) {
122
+ printInstallablePackages();
123
+ fail(`unknown installable package: ${target}`);
124
+ }
125
+ const allowedFlags = new Set(['--tag', '--dry']);
126
+ const unsupported = rawArgs.filter((arg, index) => (arg.startsWith('-')
127
+ && !allowedFlags.has(arg)
128
+ && rawArgs[index - 1] !== '--tag'));
129
+ if (unsupported.length > 0)
130
+ fail(`unsupported package option: ${unsupported[0]}`);
131
+ const tag = optionValue('--tag') ?? 'latest';
132
+ let spec;
133
+ try {
134
+ spec = packageSpec(entry, tag);
135
+ }
136
+ catch (error) {
137
+ fail(error instanceof Error ? error.message : String(error));
138
+ }
139
+ const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
140
+ const npmArgs = ['install', '--global', spec];
141
+ console.log(`OpenBroker — Install ${entry.key}`);
142
+ console.log('================================\n');
143
+ console.log(`Package: ${spec}`);
144
+ console.log(`Command: ${npmCommand} ${npmArgs.join(' ')}`);
145
+ if (args.has('--dry')) {
146
+ console.log('\nDry run only; nothing was installed.');
147
+ return;
148
+ }
149
+ const result = spawnSync(npmCommand, npmArgs, { stdio: 'inherit' });
150
+ if (result.error)
151
+ fail(`could not start npm: ${result.error.message}`);
152
+ if (result.status !== 0) {
153
+ fail(`installation failed for ${entry.packageName}; resolve the npm error and retry`);
154
+ }
155
+ console.log(`\n✅ ${entry.packageName} installed successfully.`);
156
+ console.log(`Available command: ${entry.command}`);
157
+ console.log('\nNext steps:');
158
+ for (const step of entry.nextSteps)
159
+ console.log(` ${step}`);
160
+ }
77
161
  function runApiWalletSetup() {
78
162
  const onboardPath = path.join(packageRoot, 'scripts', 'setup', 'onboard.ts');
79
163
  console.log('\nStarting restricted API-wallet onboarding...\n');
@@ -94,6 +178,19 @@ function main() {
94
178
  printUsage();
95
179
  return;
96
180
  }
181
+ if (args.has('--list')) {
182
+ printInstallablePackages();
183
+ return;
184
+ }
185
+ const positionals = positionalArgs();
186
+ if (positionals.length > 0) {
187
+ if (positionals.length > 1)
188
+ fail(`expected one package name, received: ${positionals.join(' ')}`);
189
+ if (args.has('--codex'))
190
+ fail('choose either a companion package or the --codex harness installer');
191
+ installCompanionPackage(positionals[0]);
192
+ return;
193
+ }
97
194
  if (!args.has('--codex')) {
98
195
  printUsage();
99
196
  fail('choose a supported harness flag such as --codex');
@@ -0,0 +1,12 @@
1
+ export interface InstallablePackage {
2
+ key: string;
3
+ aliases: string[];
4
+ packageName: string;
5
+ command: string;
6
+ description: string;
7
+ nextSteps: string[];
8
+ }
9
+ export declare const INSTALLABLE_PACKAGES: InstallablePackage[];
10
+ export declare function resolveInstallablePackage(input: string): InstallablePackage | null;
11
+ export declare function packageSpec(entry: InstallablePackage, tag?: string): string;
12
+ //# sourceMappingURL=package-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-catalog.d.ts","sourceRoot":"","sources":["../../scripts/setup/package-catalog.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,oBAAoB,EAAE,kBAAkB,EAuBpD,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAOlF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,SAAW,GAAG,MAAM,CAK7E"}
@@ -0,0 +1,36 @@
1
+ export const INSTALLABLE_PACKAGES = [
2
+ {
3
+ key: 'monitoring',
4
+ aliases: ['openbroker-monitoring'],
5
+ packageName: 'openbroker-monitoring',
6
+ command: 'openbroker-monitoring',
7
+ description: 'Local automation dashboard and optional audit observer',
8
+ nextSteps: [
9
+ 'openbroker-monitoring serve --host 127.0.0.1 --port 3001',
10
+ 'Open http://127.0.0.1:3001',
11
+ ],
12
+ },
13
+ {
14
+ key: 'extended',
15
+ aliases: ['openbroker-extended'],
16
+ packageName: 'openbroker-extended',
17
+ command: 'openbroker-ex',
18
+ description: 'Extended Exchange trading CLI and library',
19
+ nextSteps: [
20
+ 'openbroker-ex --help',
21
+ 'openbroker-ex setup',
22
+ ],
23
+ },
24
+ ];
25
+ export function resolveInstallablePackage(input) {
26
+ const normalized = input.trim().toLowerCase();
27
+ return INSTALLABLE_PACKAGES.find((entry) => (entry.key === normalized
28
+ || entry.packageName === normalized
29
+ || entry.aliases.includes(normalized))) ?? null;
30
+ }
31
+ export function packageSpec(entry, tag = 'latest') {
32
+ if (!/^[a-z0-9][a-z0-9._-]*$/i.test(tag)) {
33
+ throw new Error(`invalid package tag or version: ${tag}`);
34
+ }
35
+ return `${entry.packageName}@${tag}`;
36
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=package-catalog.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-catalog.test.d.ts","sourceRoot":"","sources":["../../scripts/setup/package-catalog.test.ts"],"names":[],"mappings":""}