@hoox-sh/hoox-shared 1.2.0 → 1.3.0

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.
@@ -39,6 +39,7 @@ var KV_AGENT_OPENAI_KEY = "agent:openai_key";
39
39
  var KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key";
40
40
  var KV_AGENT_GOOGLE_KEY = "agent:google_key";
41
41
  var KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary";
42
+ var KV_GLOBAL_KILL_SWITCH = "global:kill_switch";
42
43
  var KV_HEALTH_CHECK = "health_check";
43
44
  var KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check";
44
45
  var QUEUE_MODE_FAILOVER = "queue_failover";
@@ -68,6 +69,7 @@ var KVKeys = {
68
69
  KV_AGENT_ANTHROPIC_KEY,
69
70
  KV_AGENT_GOOGLE_KEY,
70
71
  KV_DASHBOARD_AI_HEALTH_SUMMARY,
72
+ KV_GLOBAL_KILL_SWITCH,
71
73
  KV_HEALTH_CHECK,
72
74
  KV_HOUSEKEEPING_LAST_CHECK,
73
75
  QUEUE_MODE_FAILOVER,
@@ -17,7 +17,11 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
18
  // src/operator-transport.ts
19
19
  function stripTrailingSlashes(url) {
20
- return url.replace(/\/+$/, "");
20
+ let end = url.length;
21
+ while (end > 0 && url.charCodeAt(end - 1) === 47) {
22
+ end -= 1;
23
+ }
24
+ return end === url.length ? url : url.slice(0, end);
21
25
  }
22
26
  function parseTransport(raw) {
23
27
  if (!raw)
@@ -64,7 +68,7 @@ function hasOperatorClientCredentials(profile) {
64
68
  return Boolean(profile.accessClientId && profile.accessClientSecret);
65
69
  }
66
70
  function operatorUrl(profile, path) {
67
- const base = profile.apiBase.replace(/\/+$/, "");
71
+ const base = stripTrailingSlashes(profile.apiBase);
68
72
  const p = path.startsWith("/") ? path : `/${path}`;
69
73
  return `${base}${p}`;
70
74
  }
package/dist/index.d.ts CHANGED
@@ -18,6 +18,8 @@ export type { StandardResponse, ApiSuccessResponse, ApiErrorResponse, ApiRespons
18
18
  export { TradeActionSchema, WebhookPayloadSchema, TradeQueueMessageSchema, TradeSignalSchema, PositionSchema, BalanceSchema, } from "./types";
19
19
  export type { TradeAction, WebhookPayload, TradeQueueMessage, TradeSignal, } from "./types";
20
20
  export { KVKeys } from "./kvKeys";
21
+ export { KILL_SWITCH_KEYS, KILL_SWITCH_ACTIVE_PREFIX, isTruthyKillSwitchFlag, checkKillSwitch, isTradingPaused, } from "./kill-switch";
22
+ export type { KillSwitchFailMode, KillSwitchResult, CheckKillSwitchOptions, KillSwitchKv, } from "./kill-switch";
21
23
  export { toError, Errors, createJsonResponse, createSuccessResponse, createErrorResponse, } from "./errors";
22
24
  export { ExchangeRouter } from "./exchange-client";
23
25
  export type { ExchangeName, ExchangeConfig, TradeParams, OrderResponse, Position, IExchangeProvider, ClientCreateOptions, } from "./exchange-client";
@@ -53,8 +55,8 @@ export { restoreSession, saveSession } from "./session";
53
55
  export type { SessionState } from "./session";
54
56
  export { formatRelativeTime as formatRelativeTimeFromTime } from "./format-time";
55
57
  export type { ViewId, ModalState, WorkerStatus, WorkerInfo, TradeSide, Trade, AlertSeverity, Alert, LogLevel, LogEntry, SystemMetrics, ConnectionStatus, LogFilter, NotificationPreferences, CliErrorType, CliErrorDetails, } from "./types";
56
- export { getHooxHome, resolveHooxPath, isWithinHooxHome, getRelativeHooxPath, getHooxRepoPath, getHooxConfigDir, getHooxDataDir, getHooxWranglerPath, getHooxStatePath, isHooxSetupRoot, findHooxSetupRoot, resolveHooxRuntimeRoot, getTuiEntryCandidates, } from "./path-utils";
57
- export type { HooxPath, RuntimeRootSource, RuntimeRootResult, } from "./path-utils";
58
+ export { getHooxHome, resolveHooxPath, isWithinHooxHome, getRelativeHooxPath, getHooxRepoPath, getHooxConfigDir, getHooxDataDir, getHooxWranglerPath, getHooxStatePath, isHooxSetupRoot, findHooxSetupRoot, resolveHooxRuntimeRoot, getTuiEntryCandidates, getRememberedMonorepoPath, getRememberedMonorepoRoot, rememberMonorepoRoot, } from "./path-utils";
59
+ export type { HooxPath, RuntimeRootSource, RuntimeRootResult, RememberedMonorepo, } from "./path-utils";
58
60
  export { DASHBOARD_WORKER_PREFIX, DASHBOARD_SECTION_PREFIX, DASHBOARD_FIELD_KV_OVERRIDES, DASHBOARD_SECTIONS_NOT_FLAT_KV, DASHBOARD_SECTIONS_UI_SKIP, DASHBOARD_WORKER_IDS, buildDashboardKvKey, isDashboardSectionFlatKv, isDashboardSectionEditable, stripJsonc, parseDashboardManifest, dashboardWorkerDir, kvManifestFromDashboardManifests, loadDashboardKvManifestFromRoot, loadDashboardManifestsFromRoot, } from "./dashboard-manifest";
59
61
  export type { DashboardFieldType, DashboardFieldKind, DashboardFieldOption, DashboardSettingField, DashboardSection, WorkerDashboardManifest, DashboardWorkerId, DashboardKvManifestKey, DashboardKvManifest, } from "./dashboard-manifest";
60
62
  export { AGENT_CONFIG_KV_KEY, AGENT_CONFIG_EMBEDDED_FIELDS, DASHBOARD_SECTIONS_AGENT_CONFIG, isAgentConfigEmbeddedField, isAgentConfigSection, parseAgentConfigJson, serializeAgentConfigForKv, getAgentConfigEmbeddedValue, setAgentConfigEmbeddedValue, expandAgentConfigToFieldMap, applyAgentConfigFieldUpdates, } from "./agent-config-fields";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -17,7 +17,11 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
18
  // src/operator-transport.ts
19
19
  function stripTrailingSlashes(url) {
20
- return url.replace(/\/+$/, "");
20
+ let end = url.length;
21
+ while (end > 0 && url.charCodeAt(end - 1) === 47) {
22
+ end -= 1;
23
+ }
24
+ return end === url.length ? url : url.slice(0, end);
21
25
  }
22
26
  function parseTransport(raw) {
23
27
  if (!raw)
@@ -64,7 +68,7 @@ function hasOperatorClientCredentials(profile) {
64
68
  return Boolean(profile.accessClientId && profile.accessClientSecret);
65
69
  }
66
70
  function operatorUrl(profile, path) {
67
- const base = profile.apiBase.replace(/\/+$/, "");
71
+ const base = stripTrailingSlashes(profile.apiBase);
68
72
  const p = path.startsWith("/") ? path : `/${path}`;
69
73
  return `${base}${p}`;
70
74
  }
@@ -278,6 +282,7 @@ var KV_AGENT_OPENAI_KEY = "agent:openai_key";
278
282
  var KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key";
279
283
  var KV_AGENT_GOOGLE_KEY = "agent:google_key";
280
284
  var KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary";
285
+ var KV_GLOBAL_KILL_SWITCH = "global:kill_switch";
281
286
  var KV_HEALTH_CHECK = "health_check";
282
287
  var KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check";
283
288
  var QUEUE_MODE_FAILOVER = "queue_failover";
@@ -307,6 +312,7 @@ var KVKeys = {
307
312
  KV_AGENT_ANTHROPIC_KEY,
308
313
  KV_AGENT_GOOGLE_KEY,
309
314
  KV_DASHBOARD_AI_HEALTH_SUMMARY,
315
+ KV_GLOBAL_KILL_SWITCH,
310
316
  KV_HEALTH_CHECK,
311
317
  KV_HOUSEKEEPING_LAST_CHECK,
312
318
  QUEUE_MODE_FAILOVER,
@@ -1786,6 +1792,7 @@ var TradeQueueMessageSchema = z2.object({
1786
1792
  price: z2.number().positive().finite().optional(),
1787
1793
  leverage: z2.number().int().positive().max(125).optional(),
1788
1794
  test: z2.boolean().optional(),
1795
+ idempotencyKey: z2.string().min(1).max(512).optional(),
1789
1796
  queuedAt: z2.string().min(1).max(64)
1790
1797
  }).strict();
1791
1798
  var TradeSignalSchema = z2.object({
@@ -1818,6 +1825,51 @@ var BalanceSchema = z2.object({
1818
1825
  timestamp: z2.number().int().positive()
1819
1826
  }).strict();
1820
1827
 
1828
+ // src/kill-switch.ts
1829
+ var KILL_SWITCH_ACTIVE_PREFIX = "KILL_SWITCH_ACTIVE";
1830
+ var KILL_SWITCH_KEYS = [
1831
+ KV_TRADE_KILL_SWITCH,
1832
+ KV_GLOBAL_KILL_SWITCH
1833
+ ];
1834
+ function isTruthyKillSwitchFlag(value) {
1835
+ if (value == null)
1836
+ return false;
1837
+ const v = value.trim().toLowerCase();
1838
+ return v === "true" || v === "1" || v === "yes" || v === "on";
1839
+ }
1840
+ async function checkKillSwitch(kv, options) {
1841
+ const onMissingKv = options?.onMissingKv ?? "open";
1842
+ const onReadError = options?.onReadError ?? "closed";
1843
+ if (!kv) {
1844
+ if (onMissingKv === "closed") {
1845
+ return { enabled: true, source: "missing_kv" };
1846
+ }
1847
+ return { enabled: false };
1848
+ }
1849
+ try {
1850
+ const values = await Promise.all(KILL_SWITCH_KEYS.map(async (key) => ({
1851
+ key,
1852
+ value: await kv.get(key)
1853
+ })));
1854
+ for (const { key, value } of values) {
1855
+ if (isTruthyKillSwitchFlag(value)) {
1856
+ return { enabled: true, source: key };
1857
+ }
1858
+ }
1859
+ return { enabled: false };
1860
+ } catch (error) {
1861
+ const errorStr = String(error);
1862
+ if (onReadError === "closed") {
1863
+ return { enabled: true, source: "read_error", error: errorStr };
1864
+ }
1865
+ return { enabled: false, error: errorStr };
1866
+ }
1867
+ }
1868
+ async function isTradingPaused(kv, options) {
1869
+ const result = await checkKillSwitch(kv, options);
1870
+ return result.enabled;
1871
+ }
1872
+
1821
1873
  // src/kvUtils.ts
1822
1874
  async function logKvTimestamp(env, prefix = "timestamp") {
1823
1875
  const timestamp = new Date().toISOString();
@@ -2184,7 +2236,13 @@ function createMockEnv(overrides) {
2184
2236
  }
2185
2237
 
2186
2238
  // src/path-utils.ts
2187
- import { existsSync as existsSync3 } from "fs";
2239
+ import {
2240
+ existsSync as existsSync3,
2241
+ mkdirSync as mkdirSync2,
2242
+ readFileSync as readFileSync3,
2243
+ writeFileSync as writeFileSync2,
2244
+ chmodSync as chmodSync2
2245
+ } from "fs";
2188
2246
  import { homedir as homedir2 } from "os";
2189
2247
  import { dirname, join as join3, resolve } from "path";
2190
2248
  function createHooxPath(path) {
@@ -2210,7 +2268,55 @@ function isHooxSetupRoot(dir) {
2210
2268
  return false;
2211
2269
  try {
2212
2270
  const root = resolve(dir);
2213
- return existsSync3(join3(root, "wrangler.jsonc")) && existsSync3(join3(root, "packages", "cli", "package.json"));
2271
+ if (!existsSync3(join3(root, "packages", "cli", "package.json"))) {
2272
+ return false;
2273
+ }
2274
+ return existsSync3(join3(root, "wrangler.jsonc")) || existsSync3(join3(root, "wrangler.jsonc.example")) || existsSync3(join3(root, "workers")) || existsSync3(join3(root, ".gitmodules"));
2275
+ } catch {
2276
+ return false;
2277
+ }
2278
+ }
2279
+ function getRememberedMonorepoPath() {
2280
+ return resolveHooxPath("config/monorepo.json");
2281
+ }
2282
+ function getRememberedMonorepoRoot() {
2283
+ try {
2284
+ const path = getRememberedMonorepoPath();
2285
+ if (!existsSync3(path))
2286
+ return null;
2287
+ const raw = readFileSync3(path, "utf-8");
2288
+ const data = JSON.parse(raw);
2289
+ if (!data.root || typeof data.root !== "string")
2290
+ return null;
2291
+ const resolved = resolve(data.root);
2292
+ return isHooxSetupRoot(resolved) ? resolved : null;
2293
+ } catch {
2294
+ return null;
2295
+ }
2296
+ }
2297
+ function rememberMonorepoRoot(root) {
2298
+ try {
2299
+ const resolved = resolve(root);
2300
+ if (!isHooxSetupRoot(resolved))
2301
+ return false;
2302
+ const configDir = getHooxConfigDir();
2303
+ mkdirSync2(configDir, { recursive: true, mode: 448 });
2304
+ try {
2305
+ chmodSync2(configDir, 448);
2306
+ } catch {}
2307
+ const payload = {
2308
+ root: resolved,
2309
+ updatedAt: new Date().toISOString()
2310
+ };
2311
+ const path = getRememberedMonorepoPath();
2312
+ writeFileSync2(path, JSON.stringify(payload, null, 2) + `
2313
+ `, {
2314
+ mode: 384
2315
+ });
2316
+ try {
2317
+ chmodSync2(path, 384);
2318
+ } catch {}
2319
+ return true;
2214
2320
  } catch {
2215
2321
  return false;
2216
2322
  }
@@ -2230,6 +2336,7 @@ function resolveHooxRuntimeRoot(options) {
2230
2336
  const env = options?.env ?? process.env;
2231
2337
  const cwd = resolve(options?.cwd ?? process.cwd());
2232
2338
  const globalRepo = getHooxRepoPath();
2339
+ const remembered = options?.skipRemembered ? null : getRememberedMonorepoRoot();
2233
2340
  const envRepo = env.HOOX_REPO?.trim();
2234
2341
  if (envRepo) {
2235
2342
  const resolved = resolve(envRepo);
@@ -2240,6 +2347,7 @@ function resolveHooxRuntimeRoot(options) {
2240
2347
  checked: {
2241
2348
  env: resolved,
2242
2349
  cwd: findHooxSetupRoot(cwd),
2350
+ remembered,
2243
2351
  global: globalRepo
2244
2352
  }
2245
2353
  };
@@ -2250,6 +2358,7 @@ function resolveHooxRuntimeRoot(options) {
2250
2358
  checked: {
2251
2359
  env: resolved,
2252
2360
  cwd: findHooxSetupRoot(cwd),
2361
+ remembered,
2253
2362
  global: globalRepo
2254
2363
  }
2255
2364
  };
@@ -2259,20 +2368,27 @@ function resolveHooxRuntimeRoot(options) {
2259
2368
  return {
2260
2369
  root: local,
2261
2370
  source: "cwd",
2262
- checked: { cwd: local, global: globalRepo }
2371
+ checked: { cwd: local, remembered, global: globalRepo }
2372
+ };
2373
+ }
2374
+ if (remembered) {
2375
+ return {
2376
+ root: remembered,
2377
+ source: "remembered",
2378
+ checked: { cwd: null, remembered, global: globalRepo }
2263
2379
  };
2264
2380
  }
2265
2381
  if (isHooxSetupRoot(globalRepo)) {
2266
2382
  return {
2267
2383
  root: globalRepo,
2268
2384
  source: "global",
2269
- checked: { cwd: null, global: globalRepo }
2385
+ checked: { cwd: null, remembered: null, global: globalRepo }
2270
2386
  };
2271
2387
  }
2272
2388
  return {
2273
2389
  root: null,
2274
2390
  source: "none",
2275
- checked: { cwd: null, global: globalRepo }
2391
+ checked: { cwd: null, remembered: null, global: globalRepo }
2276
2392
  };
2277
2393
  }
2278
2394
  function getTuiEntryCandidates(runtimeRoot) {
@@ -3625,7 +3741,8 @@ var initialState = {
3625
3741
  sidebarExpanded: true,
3626
3742
  modal: null,
3627
3743
  commandPaletteOpen: false,
3628
- previousView: null
3744
+ previousView: null,
3745
+ statusErrorExpanded: false
3629
3746
  };
3630
3747
  var useUIStore = create()(immer((set) => ({
3631
3748
  ...initialState,
@@ -3656,6 +3773,12 @@ var useUIStore = create()(immer((set) => ({
3656
3773
  state.activeView = state.previousView;
3657
3774
  state.previousView = null;
3658
3775
  }
3776
+ }),
3777
+ toggleStatusErrorExpanded: () => set((state) => {
3778
+ state.statusErrorExpanded = !state.statusErrorExpanded;
3779
+ }),
3780
+ setStatusErrorExpanded: (expanded) => set((state) => {
3781
+ state.statusErrorExpanded = expanded;
3659
3782
  })
3660
3783
  })));
3661
3784
 
@@ -3678,6 +3801,23 @@ function ringPush(arr, item, max) {
3678
3801
  var tradeStreamAbort = null;
3679
3802
  var logStreamAbort = null;
3680
3803
  var fetchWorkersGeneration = 0;
3804
+ var reconnectTimer = null;
3805
+ function clearReconnectTimer() {
3806
+ if (reconnectTimer !== null) {
3807
+ clearTimeout(reconnectTimer);
3808
+ reconnectTimer = null;
3809
+ }
3810
+ }
3811
+ function scheduleReconnect(delayMs) {
3812
+ clearReconnectTimer();
3813
+ if (delayMs < 0)
3814
+ return;
3815
+ reconnectTimer = setTimeout(() => {
3816
+ reconnectTimer = null;
3817
+ scheduledReconnectTick();
3818
+ }, delayMs);
3819
+ }
3820
+ var scheduledReconnectTick = async () => {};
3681
3821
  var MAX_TRADES = 500;
3682
3822
  var MAX_ALERTS = 100;
3683
3823
  var MAX_LOGS = 1000;
@@ -3712,6 +3852,7 @@ var useServiceStore = create2()(immer2((set, get) => ({
3712
3852
  const data = await hooxFetch2("/v1/workers");
3713
3853
  if (gen !== fetchWorkersGeneration)
3714
3854
  return;
3855
+ clearReconnectTimer();
3715
3856
  set((state) => {
3716
3857
  state.workers = data;
3717
3858
  state.lastUpdated = Date.now();
@@ -3737,6 +3878,7 @@ var useServiceStore = create2()(immer2((set, get) => ({
3737
3878
  timestamp: Date.now(),
3738
3879
  acknowledged: false
3739
3880
  });
3881
+ let nextDelay = 0;
3740
3882
  set((state) => {
3741
3883
  state.lastError = msg;
3742
3884
  state.disconnectedAt = state.disconnectedAt ?? Date.now();
@@ -3745,21 +3887,26 @@ var useServiceStore = create2()(immer2((set, get) => ({
3745
3887
  state.retryCount = state.retryCount + 1;
3746
3888
  if (state.retryCount >= MAX_RETRIES2) {
3747
3889
  state.connectionStatus = "offline";
3748
- state.lastError = `Connection lost after ${MAX_RETRIES2} retries`;
3890
+ state.lastError = `${msg} (gave up after ${MAX_RETRIES2} retries)`;
3891
+ state.reconnectDelay = 0;
3749
3892
  } else {
3750
3893
  state.reconnectDelay = getBackoffDelay(state.retryCount);
3894
+ nextDelay = state.reconnectDelay;
3751
3895
  }
3752
3896
  } else if (state.connectionStatus === "reconnecting") {
3753
3897
  state.retryCount = state.retryCount + 1;
3754
3898
  if (state.retryCount >= MAX_RETRIES2) {
3755
3899
  state.connectionStatus = "offline";
3756
- state.lastError = `Connection lost after ${MAX_RETRIES2} retries`;
3900
+ state.lastError = `${msg} (gave up after ${MAX_RETRIES2} retries)`;
3757
3901
  state.reconnectDelay = 0;
3758
3902
  } else {
3759
3903
  state.reconnectDelay = getBackoffDelay(state.retryCount);
3904
+ nextDelay = state.reconnectDelay;
3760
3905
  }
3761
3906
  }
3762
3907
  });
3908
+ if (nextDelay > 0)
3909
+ scheduleReconnect(nextDelay);
3763
3910
  }
3764
3911
  },
3765
3912
  streamTrades: async () => {
@@ -3821,6 +3968,17 @@ var useServiceStore = create2()(immer2((set, get) => ({
3821
3968
  const merged = [...state.alerts, ...alerts];
3822
3969
  state.alerts = merged.length > MAX_ALERTS ? merged.slice(merged.length - MAX_ALERTS) : merged;
3823
3970
  }),
3971
+ acknowledgeAlert: (id) => set((state) => {
3972
+ const hit = state.alerts.find((a) => a.id === id);
3973
+ if (hit)
3974
+ hit.acknowledged = true;
3975
+ }),
3976
+ dismissAlert: (id) => set((state) => {
3977
+ state.alerts = state.alerts.filter((a) => a.id !== id);
3978
+ }),
3979
+ clearLogs: () => set((state) => {
3980
+ state.logs = [];
3981
+ }),
3824
3982
  setConnectionStatus: (status) => set((state) => {
3825
3983
  if (status === "connected") {
3826
3984
  state.retryCount = 0;
@@ -3851,49 +4009,69 @@ var useServiceStore = create2()(immer2((set, get) => ({
3851
4009
  state.metrics = metrics;
3852
4010
  state.lastUpdated = metrics.lastUpdated;
3853
4011
  }),
3854
- handleConnectionSuccess: () => set((state) => {
3855
- state.lastSuccessfulFetch = Date.now();
3856
- state.retryCount = 0;
3857
- state.lastError = null;
3858
- state.lastErrorDetails = null;
3859
- state.reconnectDelay = 0;
3860
- state.disconnectedAt = null;
3861
- state.connectionStatus = "connected";
3862
- }),
3863
- handleConnectionFailure: (errorMessage) => set((state) => {
3864
- state.lastError = errorMessage;
3865
- state.disconnectedAt = state.disconnectedAt ?? Date.now();
3866
- if (state.connectionStatus === "connected" || state.connectionStatus === "polling") {
3867
- state.connectionStatus = "reconnecting";
3868
- state.retryCount = 1;
3869
- state.reconnectDelay = getBackoffDelay(1);
3870
- } else if (state.connectionStatus === "reconnecting") {
3871
- state.retryCount = state.retryCount + 1;
3872
- if (state.retryCount >= MAX_RETRIES2) {
3873
- state.connectionStatus = "offline";
3874
- state.lastError = `Connection lost after ${MAX_RETRIES2} retries`;
3875
- state.reconnectDelay = 0;
3876
- } else {
3877
- state.reconnectDelay = getBackoffDelay(state.retryCount);
4012
+ handleConnectionSuccess: () => {
4013
+ clearReconnectTimer();
4014
+ set((state) => {
4015
+ state.lastSuccessfulFetch = Date.now();
4016
+ state.retryCount = 0;
4017
+ state.lastError = null;
4018
+ state.lastErrorDetails = null;
4019
+ state.reconnectDelay = 0;
4020
+ state.disconnectedAt = null;
4021
+ state.connectionStatus = "connected";
4022
+ });
4023
+ },
4024
+ handleConnectionFailure: (errorMessage) => {
4025
+ let nextDelay = 0;
4026
+ set((state) => {
4027
+ state.lastError = errorMessage;
4028
+ state.disconnectedAt = state.disconnectedAt ?? Date.now();
4029
+ if (state.connectionStatus === "connected" || state.connectionStatus === "polling") {
4030
+ state.connectionStatus = "reconnecting";
4031
+ state.retryCount = 1;
4032
+ state.reconnectDelay = getBackoffDelay(1);
4033
+ nextDelay = state.reconnectDelay;
4034
+ } else if (state.connectionStatus === "reconnecting") {
4035
+ state.retryCount = state.retryCount + 1;
4036
+ if (state.retryCount >= MAX_RETRIES2) {
4037
+ state.connectionStatus = "offline";
4038
+ state.lastError = `${errorMessage} (gave up after ${MAX_RETRIES2} retries)`;
4039
+ state.reconnectDelay = 0;
4040
+ } else {
4041
+ state.reconnectDelay = getBackoffDelay(state.retryCount);
4042
+ nextDelay = state.reconnectDelay;
4043
+ }
3878
4044
  }
3879
- }
3880
- }),
3881
- resetRetries: () => set((state) => {
3882
- state.retryCount = 0;
3883
- state.lastError = null;
3884
- state.lastErrorDetails = null;
3885
- state.reconnectDelay = 0;
3886
- state.disconnectedAt = null;
3887
- }),
3888
- forceRetry: () => set((state) => {
3889
- if (state.connectionStatus === "offline") {
3890
- state.connectionStatus = "polling";
4045
+ });
4046
+ if (nextDelay > 0)
4047
+ scheduleReconnect(nextDelay);
4048
+ },
4049
+ resetRetries: () => {
4050
+ clearReconnectTimer();
4051
+ set((state) => {
3891
4052
  state.retryCount = 0;
3892
4053
  state.lastError = null;
3893
4054
  state.lastErrorDetails = null;
3894
4055
  state.reconnectDelay = 0;
4056
+ state.disconnectedAt = null;
4057
+ });
4058
+ },
4059
+ forceRetry: () => {
4060
+ clearReconnectTimer();
4061
+ const wasOffline = get().connectionStatus === "offline";
4062
+ set((state) => {
4063
+ if (state.connectionStatus === "offline") {
4064
+ state.connectionStatus = "polling";
4065
+ state.retryCount = 0;
4066
+ state.lastError = null;
4067
+ state.lastErrorDetails = null;
4068
+ state.reconnectDelay = 0;
4069
+ }
4070
+ });
4071
+ if (wasOffline) {
4072
+ scheduleReconnect(0);
3895
4073
  }
3896
- }),
4074
+ },
3897
4075
  setLastErrorDetails: (details) => set((state) => {
3898
4076
  state.lastErrorDetails = details;
3899
4077
  state.lastError = details === null ? null : summarizeCliError(details);
@@ -3916,38 +4094,73 @@ var useServiceStore = create2()(immer2((set, get) => ({
3916
4094
  }, MAX_ALERTS);
3917
4095
  })
3918
4096
  })));
4097
+ scheduledReconnectTick = async () => {
4098
+ const status = useServiceStore.getState().connectionStatus;
4099
+ if (status === "reconnecting" || status === "polling") {
4100
+ await useServiceStore.getState().fetchWorkers();
4101
+ }
4102
+ };
3919
4103
 
3920
4104
  // src/stores/config-store.ts
3921
4105
  import { create as create3 } from "zustand";
3922
4106
  import { immer as immer3 } from "zustand/middleware/immer";
3923
4107
  import { persist, createJSONStorage } from "zustand/middleware";
3924
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
3925
- import { homedir as homedir3 } from "os";
4108
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync3, existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
3926
4109
  import { join as join4 } from "path";
4110
+ function getTuiPreferencesPath() {
4111
+ return join4(getHooxHome(), ".tui-state", "preferences.json");
4112
+ }
4113
+ function getLegacyConfigJsonPath() {
4114
+ return join4(getHooxHome(), "config.json");
4115
+ }
4116
+ function extractZustandPrefsPayload(raw) {
4117
+ try {
4118
+ const parsed = JSON.parse(raw);
4119
+ if (parsed && typeof parsed === "object" && parsed.state && typeof parsed.state === "object" && !Array.isArray(parsed.state) && (("theme" in parsed.state) || ("refreshIntervalMs" in parsed.state)) && !("apiToken" in parsed)) {
4120
+ return raw;
4121
+ }
4122
+ } catch {}
4123
+ return null;
4124
+ }
3927
4125
  var bunConfigStorage = {
3928
4126
  getItem: async (_name) => {
3929
4127
  try {
3930
- const file = Bun.file(join4(homedir3(), ".hoox", "config.json"));
3931
- const exists = await file.exists();
3932
- if (!exists)
3933
- return null;
3934
- return await file.text();
4128
+ const prefsPath = getTuiPreferencesPath();
4129
+ const prefsFile = Bun.file(prefsPath);
4130
+ if (await prefsFile.exists()) {
4131
+ return await prefsFile.text();
4132
+ }
4133
+ const legacyPath = getLegacyConfigJsonPath();
4134
+ if (existsSync4(legacyPath)) {
4135
+ const legacyRaw = readFileSync4(legacyPath, "utf-8");
4136
+ const envelope = extractZustandPrefsPayload(legacyRaw);
4137
+ if (envelope) {
4138
+ await bunConfigStorage.setItem(_name, envelope);
4139
+ return envelope;
4140
+ }
4141
+ }
4142
+ return null;
3935
4143
  } catch {
3936
4144
  return null;
3937
4145
  }
3938
4146
  },
3939
4147
  setItem: async (_name, value) => {
3940
- const dir = join4(homedir3(), ".hoox");
3941
- if (!existsSync4(dir)) {
3942
- mkdirSync2(dir, { recursive: true, mode: HOOX_DIR_MODE });
4148
+ const home = getHooxHome();
4149
+ const stateDir = join4(home, ".tui-state");
4150
+ if (!existsSync4(home)) {
4151
+ mkdirSync3(home, { recursive: true, mode: HOOX_DIR_MODE });
4152
+ }
4153
+ if (!existsSync4(stateDir)) {
4154
+ mkdirSync3(stateDir, { recursive: true, mode: HOOX_DIR_MODE });
3943
4155
  }
3944
4156
  try {
3945
- chmodSync2(dir, HOOX_DIR_MODE);
4157
+ chmodSync3(home, HOOX_DIR_MODE);
4158
+ chmodSync3(stateDir, HOOX_DIR_MODE);
3946
4159
  } catch {}
3947
- const filePath = join4(dir, "config.json");
4160
+ const filePath = getTuiPreferencesPath();
3948
4161
  await Bun.write(filePath, value);
3949
4162
  try {
3950
- chmodSync2(filePath, HOOX_CONFIG_FILE_MODE);
4163
+ chmodSync3(filePath, HOOX_CONFIG_FILE_MODE);
3951
4164
  } catch {}
3952
4165
  },
3953
4166
  removeItem: async (_name) => {}
@@ -4019,7 +4232,7 @@ var useConfigStore = create3()(persist(immer3((set) => ({
4019
4232
  state.notifications[channel] = !state.notifications[channel];
4020
4233
  })
4021
4234
  })), {
4022
- name: "hoox-config",
4235
+ name: "hoox-tui-prefs",
4023
4236
  storage: createJSONStorage(() => bunConfigStorage),
4024
4237
  partialize: (state) => ({
4025
4238
  theme: state.theme,
@@ -4068,6 +4281,7 @@ export {
4068
4281
  resolveHooxRuntimeRoot,
4069
4282
  resolveHooxPath,
4070
4283
  resolveDependencies,
4284
+ rememberMonorepoRoot,
4071
4285
  readConfigSync,
4072
4286
  readConfig,
4073
4287
  parseDashboardManifest,
@@ -4079,6 +4293,8 @@ export {
4079
4293
  kvManifestFromDashboardManifests,
4080
4294
  isWithinHooxHome,
4081
4295
  isUnixModeGroupOrWorldAccessible,
4296
+ isTruthyKillSwitchFlag,
4297
+ isTradingPaused,
4082
4298
  isHooxSetupRoot,
4083
4299
  isDashboardSectionFlatKv,
4084
4300
  isDashboardSectionEditable,
@@ -4090,6 +4306,8 @@ export {
4090
4306
  headersToObject,
4091
4307
  hasOperatorClientCredentials,
4092
4308
  getTuiEntryCandidates,
4309
+ getRememberedMonorepoRoot,
4310
+ getRememberedMonorepoPath,
4093
4311
  getRelativeHooxPath,
4094
4312
  getHooxWranglerPath,
4095
4313
  getHooxStatePath,
@@ -4137,6 +4355,7 @@ export {
4137
4355
  createJsonResponse,
4138
4356
  createErrorResponse,
4139
4357
  createCronHandler,
4358
+ checkKillSwitch,
4140
4359
  buildOperatorAuthHeaders,
4141
4360
  buildDashboardKvKey,
4142
4361
  authenticatedServiceFetch,
@@ -4163,6 +4382,8 @@ export {
4163
4382
  PRESETS,
4164
4383
  LogLevelColor,
4165
4384
  KVKeys,
4385
+ KILL_SWITCH_KEYS,
4386
+ KILL_SWITCH_ACTIVE_PREFIX,
4166
4387
  InternalAuthKeyFields,
4167
4388
  INTEGRATIONS,
4168
4389
  HOOX_DIR_MODE,