@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.
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Copyright (c) 2026 HOOX · HOOX · jango-blockchained (hoox-sh)
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ /** Prefix for trade-worker kill-switch error messages (message.startsWith checks). */
6
+ export declare const KILL_SWITCH_ACTIVE_PREFIX = "KILL_SWITCH_ACTIVE";
7
+ export declare const KILL_SWITCH_KEYS: readonly ["trade:kill_switch", "global:kill_switch"];
8
+ /**
9
+ * Truthy kill-switch flag values (case-insensitive, trimmed):
10
+ * true, 1, yes, on
11
+ */
12
+ export declare function isTruthyKillSwitchFlag(value: string | null | undefined): boolean;
13
+ export type KillSwitchFailMode = "open" | "closed";
14
+ export interface KillSwitchResult {
15
+ enabled: boolean;
16
+ source?: string;
17
+ error?: string;
18
+ }
19
+ export interface CheckKillSwitchOptions {
20
+ /**
21
+ * When CONFIG_KV is missing.
22
+ * Default "open" (gateway/dev). Trade-worker should pass "closed".
23
+ */
24
+ onMissingKv?: KillSwitchFailMode;
25
+ /**
26
+ * When KV get throws.
27
+ * Default "closed" for safety (stricter than the gateway's historical fail-open).
28
+ */
29
+ onReadError?: KillSwitchFailMode;
30
+ }
31
+ /** Minimal KV surface used by kill-switch checks (avoids workers-types dependency). */
32
+ export type KillSwitchKv = {
33
+ get(key: string): Promise<string | null>;
34
+ };
35
+ /**
36
+ * Read both kill-switch keys in parallel. If any value is truthy, trading is paused.
37
+ *
38
+ * Fail modes:
39
+ * - Missing kv → enabled iff onMissingKv === "closed" (source: "missing_kv")
40
+ * - Read error → enabled iff onReadError === "closed"
41
+ */
42
+ export declare function checkKillSwitch(kv: KillSwitchKv | undefined | null, options?: CheckKillSwitchOptions): Promise<KillSwitchResult>;
43
+ /**
44
+ * Convenience boolean wrapper around {@link checkKillSwitch}.
45
+ */
46
+ export declare function isTradingPaused(kv: KillSwitchKv | undefined | null, options?: CheckKillSwitchOptions): Promise<boolean>;
47
+ //# sourceMappingURL=kill-switch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kill-switch.d.ts","sourceRoot":"","sources":["../src/kill-switch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,sFAAsF;AACtF,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAE9D,eAAO,MAAM,gBAAgB,sDAGnB,CAAC;AAEX;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,OAAO,CAIT;AAED,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;OAGG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED,uFAAuF;AACvF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,EACnC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAiC3B;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,EACnC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,OAAO,CAAC,CAGlB"}
@@ -0,0 +1,130 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
+
18
+ // src/kvKeys.ts
19
+ var KV_TRADE_DEFAULT_LEVERAGE = "trade:default_leverage";
20
+ var KV_TRADE_MAX_POSITION_SIZE = "trade:max_position_size";
21
+ var KV_TRADE_MAX_DAILY_DRAWDOWN_PERCENT = "trade:max_daily_drawdown_percent";
22
+ var KV_TRADE_TRAILING_STOP_PERCENT = "trade:trailing_stop_percent";
23
+ var KV_TRADE_KILL_SWITCH = "trade:kill_switch";
24
+ var KV_TRADE_ROUTING = "trade:routing";
25
+ var KV_BOT_ENABLED = "bot:enabled";
26
+ var KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id";
27
+ var KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution";
28
+ var KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error";
29
+ var KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled";
30
+ var KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips";
31
+ var KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode";
32
+ var KV_EMAIL_SCAN_SUBJECT = "email:scan_subject";
33
+ var KV_EMAIL_USE_IMAP = "email:use_imap";
34
+ var KV_EMAIL_COIN_PATTERN = "email:coin_pattern";
35
+ var KV_EMAIL_ACTION_PATTERN = "email:action_pattern";
36
+ var KV_EMAIL_QUANTITY_MULTIPLIER = "email:quantity_multiplier";
37
+ var KV_AGENT_CONFIG = "agent:config";
38
+ var KV_AGENT_OPENAI_KEY = "agent:openai_key";
39
+ var KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key";
40
+ var KV_AGENT_GOOGLE_KEY = "agent:google_key";
41
+ var KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary";
42
+ var KV_GLOBAL_KILL_SWITCH = "global:kill_switch";
43
+ var KV_HEALTH_CHECK = "health_check";
44
+ var KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check";
45
+ var QUEUE_MODE_FAILOVER = "queue_failover";
46
+ var QUEUE_MODE_EVERYWHERE = "queue_everywhere";
47
+ var QUEUE_MODE_DISABLED = "queue_disabled";
48
+ var KVKeys = {
49
+ KV_TRADE_DEFAULT_LEVERAGE,
50
+ KV_TRADE_MAX_POSITION_SIZE,
51
+ KV_TRADE_MAX_DAILY_DRAWDOWN_PERCENT,
52
+ KV_TRADE_TRAILING_STOP_PERCENT,
53
+ KV_TRADE_KILL_SWITCH,
54
+ KV_TRADE_ROUTING,
55
+ KV_BOT_ENABLED,
56
+ KV_BOT_DEFAULT_CHAT_ID,
57
+ KV_BOT_NOTIFY_ON_EXECUTION,
58
+ KV_BOT_NOTIFY_ON_ERROR,
59
+ KV_WEBHOOK_IP_CHECK_ENABLED,
60
+ KV_WEBHOOK_ALLOWED_IPS,
61
+ KV_WEBHOOK_QUEUE_MODE,
62
+ KV_EMAIL_SCAN_SUBJECT,
63
+ KV_EMAIL_USE_IMAP,
64
+ KV_EMAIL_COIN_PATTERN,
65
+ KV_EMAIL_ACTION_PATTERN,
66
+ KV_EMAIL_QUANTITY_MULTIPLIER,
67
+ KV_AGENT_CONFIG,
68
+ KV_AGENT_OPENAI_KEY,
69
+ KV_AGENT_ANTHROPIC_KEY,
70
+ KV_AGENT_GOOGLE_KEY,
71
+ KV_DASHBOARD_AI_HEALTH_SUMMARY,
72
+ KV_GLOBAL_KILL_SWITCH,
73
+ KV_HEALTH_CHECK,
74
+ KV_HOUSEKEEPING_LAST_CHECK,
75
+ QUEUE_MODE_FAILOVER,
76
+ QUEUE_MODE_EVERYWHERE,
77
+ QUEUE_MODE_DISABLED
78
+ };
79
+
80
+ // src/kill-switch.ts
81
+ var KILL_SWITCH_ACTIVE_PREFIX = "KILL_SWITCH_ACTIVE";
82
+ var KILL_SWITCH_KEYS = [
83
+ KV_TRADE_KILL_SWITCH,
84
+ KV_GLOBAL_KILL_SWITCH
85
+ ];
86
+ function isTruthyKillSwitchFlag(value) {
87
+ if (value == null)
88
+ return false;
89
+ const v = value.trim().toLowerCase();
90
+ return v === "true" || v === "1" || v === "yes" || v === "on";
91
+ }
92
+ async function checkKillSwitch(kv, options) {
93
+ const onMissingKv = options?.onMissingKv ?? "open";
94
+ const onReadError = options?.onReadError ?? "closed";
95
+ if (!kv) {
96
+ if (onMissingKv === "closed") {
97
+ return { enabled: true, source: "missing_kv" };
98
+ }
99
+ return { enabled: false };
100
+ }
101
+ try {
102
+ const values = await Promise.all(KILL_SWITCH_KEYS.map(async (key) => ({
103
+ key,
104
+ value: await kv.get(key)
105
+ })));
106
+ for (const { key, value } of values) {
107
+ if (isTruthyKillSwitchFlag(value)) {
108
+ return { enabled: true, source: key };
109
+ }
110
+ }
111
+ return { enabled: false };
112
+ } catch (error) {
113
+ const errorStr = String(error);
114
+ if (onReadError === "closed") {
115
+ return { enabled: true, source: "read_error", error: errorStr };
116
+ }
117
+ return { enabled: false, error: errorStr };
118
+ }
119
+ }
120
+ async function isTradingPaused(kv, options) {
121
+ const result = await checkKillSwitch(kv, options);
122
+ return result.enabled;
123
+ }
124
+ export {
125
+ isTruthyKillSwitchFlag,
126
+ isTradingPaused,
127
+ checkKillSwitch,
128
+ KILL_SWITCH_KEYS,
129
+ KILL_SWITCH_ACTIVE_PREFIX
130
+ };
package/dist/kvKeys.d.ts CHANGED
@@ -38,6 +38,7 @@ export declare const KV_AGENT_OPENAI_KEY = "agent:openai_key";
38
38
  export declare const KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key";
39
39
  export declare const KV_AGENT_GOOGLE_KEY = "agent:google_key";
40
40
  export declare const KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary";
41
+ export declare const KV_GLOBAL_KILL_SWITCH = "global:kill_switch";
41
42
  export declare const KV_HEALTH_CHECK = "health_check";
42
43
  export declare const KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check";
43
44
  export declare const QUEUE_MODE_FAILOVER = "queue_failover";
@@ -67,6 +68,7 @@ export declare const KVKeys: {
67
68
  KV_AGENT_ANTHROPIC_KEY: string;
68
69
  KV_AGENT_GOOGLE_KEY: string;
69
70
  KV_DASHBOARD_AI_HEALTH_SUMMARY: string;
71
+ KV_GLOBAL_KILL_SWITCH: string;
70
72
  KV_HEALTH_CHECK: string;
71
73
  KV_HOUSEKEEPING_LAST_CHECK: string;
72
74
  QUEUE_MODE_FAILOVER: string;
@@ -1 +1 @@
1
- {"version":3,"file":"kvKeys.d.ts","sourceRoot":"","sources":["../src/kvKeys.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAGH,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAClE,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,mCAAmC,qCACZ,CAAC;AACrC,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAC5E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AACxD,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAGhD,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAC5C,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAG5D,eAAO,MAAM,2BAA2B,yCACA,CAAC;AACzC,eAAO,MAAM,sBAAsB,oCAAoC,CAAC;AACxE,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAG1D,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAClD,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAC9D,eAAO,MAAM,4BAA4B,8BAA8B,CAAC;AAGxE,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAC9C,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AACtD,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAGtD,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAG5E,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAC9C,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AAGpE,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAKpD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BlB,CAAC"}
1
+ {"version":3,"file":"kvKeys.d.ts","sourceRoot":"","sources":["../src/kvKeys.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAGH,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAClE,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,mCAAmC,qCACZ,CAAC;AACrC,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAC5E,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AACxD,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAGhD,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAC5C,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AACpE,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAG5D,eAAO,MAAM,2BAA2B,yCACA,CAAC;AACzC,eAAO,MAAM,sBAAsB,oCAAoC,CAAC;AACxE,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAG1D,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAClD,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAC9D,eAAO,MAAM,4BAA4B,8BAA8B,CAAC;AAGxE,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAC9C,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AACtD,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAC5D,eAAO,MAAM,mBAAmB,qBAAqB,CAAC;AAGtD,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAG5E,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAC1D,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAC9C,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AAGpE,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAKpD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BlB,CAAC"}
package/dist/kvKeys.js CHANGED
@@ -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,
@@ -89,6 +91,7 @@ export {
89
91
  KV_TRADE_DEFAULT_LEVERAGE,
90
92
  KV_HOUSEKEEPING_LAST_CHECK,
91
93
  KV_HEALTH_CHECK,
94
+ KV_GLOBAL_KILL_SWITCH,
92
95
  KV_EMAIL_USE_IMAP,
93
96
  KV_EMAIL_SCAN_SUBJECT,
94
97
  KV_EMAIL_QUANTITY_MULTIPLIER,
@@ -1 +1 @@
1
- {"version":3,"file":"operator-transport.d.ts","sourceRoot":"","sources":["../src/operator-transport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC;AAwBD,MAAM,WAAW,+BAA+B;IAC9C;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,GAAE,oBAA0D,EAC/D,OAAO,GAAE,+BAAoC,GAC5C,wBAAwB,CAyB1B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuBxB;AAED,qEAAqE;AACrE,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAGT;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,MAAM,GACX,MAAM,CAIR"}
1
+ {"version":3,"file":"operator-transport.d.ts","sourceRoot":"","sources":["../src/operator-transport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC;AA6BD,MAAM,WAAW,+BAA+B;IAC9C;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,GAAE,oBAA0D,EAC/D,OAAO,GAAE,+BAAoC,GAC5C,wBAAwB,CAyB1B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAuBxB;AAED,qEAAqE;AACrE,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAGT;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,MAAM,GACX,MAAM,CAIR"}
@@ -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
  }
@@ -10,7 +10,7 @@ export type HooxPath = string & {
10
10
  readonly __brand: "HooxPath";
11
11
  };
12
12
  /** Where resolveHooxRuntimeRoot found (or failed to find) a setup monorepo. */
13
- export type RuntimeRootSource = "env" | "cwd" | "global" | "none";
13
+ export type RuntimeRootSource = "env" | "cwd" | "remembered" | "global" | "none";
14
14
  /** Result of resolveHooxRuntimeRoot(). */
15
15
  export interface RuntimeRootResult {
16
16
  /** Absolute monorepo root, or null if none found. */
@@ -21,9 +21,17 @@ export interface RuntimeRootResult {
21
21
  checked: {
22
22
  env?: string;
23
23
  cwd: string | null;
24
+ remembered?: string | null;
24
25
  global: string;
25
26
  };
26
27
  }
28
+ /** Persisted monorepo pointer written when the CLI discovers a checkout. */
29
+ export interface RememberedMonorepo {
30
+ /** Absolute path to monorepo root. */
31
+ root: string;
32
+ /** ISO timestamp of last successful remember. */
33
+ updatedAt: string;
34
+ }
27
35
  /**
28
36
  * Gets the Hoox home directory location: $HOME/.hoox
29
37
  *
@@ -48,9 +56,29 @@ export declare function getHooxHome(): HooxPath;
48
56
  /**
49
57
  * True when `dir` looks like a hoox monorepo root.
50
58
  *
51
- * Markers match CLI verifyRepoRoot: root wrangler.jsonc + packages/cli package.
59
+ * Aligns with CLI `verifyRepoRoot`:
60
+ * - Required: `packages/cli/package.json`
61
+ * - Plus one of: `wrangler.jsonc`, `wrangler.jsonc.example`, `workers/`, `.gitmodules`
62
+ *
63
+ * (`wrangler.jsonc` is gitignored and created by init — fresh clones only
64
+ * ship `wrangler.jsonc.example`.)
52
65
  */
53
66
  export declare function isHooxSetupRoot(dir: string): boolean;
67
+ /**
68
+ * Path to the remembered monorepo pointer file.
69
+ * `$HOOX_HOME/config/monorepo.json` (default `~/.hoox/config/monorepo.json`).
70
+ */
71
+ export declare function getRememberedMonorepoPath(): HooxPath;
72
+ /**
73
+ * Read the last monorepo path the CLI discovered (if still valid).
74
+ * Returns null when missing, unreadable, or no longer a setup root.
75
+ */
76
+ export declare function getRememberedMonorepoRoot(): string | null;
77
+ /**
78
+ * Persist a monorepo root for future CLI invocations from any cwd.
79
+ * No-op when path is not a valid setup root.
80
+ */
81
+ export declare function rememberMonorepoRoot(root: string): boolean;
54
82
  /**
55
83
  * Walk up from `startDir` looking for a hoox monorepo root.
56
84
  *
@@ -63,14 +91,17 @@ export declare function findHooxSetupRoot(startDir?: string): string | null;
63
91
  * Order:
64
92
  * 1. HOOX_REPO — must pass isHooxSetupRoot or result is source "env" with root null
65
93
  * 2. Walk up from cwd
66
- * 3. getHooxRepoPath() ($HOME/.hoox/repo or $HOOX_HOME/repo)
94
+ * 3. Remembered monorepo (~/.hoox/config/monorepo.json) — last discovered checkout
95
+ * 4. getHooxRepoPath() ($HOME/.hoox/repo or $HOOX_HOME/repo)
67
96
  *
68
97
  * Project cwd and tool root are intentionally separate: a random project
69
- * directory can still use the global runtime for TUI / templates.
98
+ * directory can still use a remembered or global monorepo for CLI ops.
70
99
  */
71
100
  export declare function resolveHooxRuntimeRoot(options?: {
72
101
  cwd?: string;
73
102
  env?: NodeJS.ProcessEnv;
103
+ /** Skip reading remembered path (tests). Default false. */
104
+ skipRemembered?: boolean;
74
105
  }): RuntimeRootResult;
75
106
  /**
76
107
  * Candidate TUI entry files under a monorepo root (source first, then dist).
@@ -1 +1 @@
1
- {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../src/path-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0BH;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AAEjE,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAElE,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,iDAAiD;IACjD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,qDAAqD;IACrD,OAAO,EAAE;QACP,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAUD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAgBtC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWpD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,GAAE,MAAsB,GAC/B,MAAM,GAAG,IAAI,CAQf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,iBAAiB,CAoDpB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAOnE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ,CAiC9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAStD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,IAAI,QAAQ,CAE1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,QAAQ,CAE3C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,IAAI,QAAQ,CAEzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,QAAQ,CAE9C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,QAAQ,CAE3C"}
1
+ {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../src/path-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkCH;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AAEjE,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,KAAK,GACL,YAAY,GACZ,QAAQ,GACR,MAAM,CAAC;AAEX,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,iDAAiD;IACjD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,qDAAqD;IACrD,OAAO,EAAE;QACP,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IACjC,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAgBtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAgBpD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,QAAQ,CAEpD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,GAAG,IAAI,CAYzD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA4B1D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,GAAE,MAAsB,GAC/B,MAAM,GAAG,IAAI,CAQf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,iBAAiB,CAiEpB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAOnE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ,CAiC9D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAStD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,IAAI,QAAQ,CAE1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,QAAQ,CAE3C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,IAAI,QAAQ,CAEzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,QAAQ,CAE9C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,QAAQ,CAE3C"}
@@ -16,7 +16,13 @@ var __export = (target, all) => {
16
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
18
  // src/path-utils.ts
19
- import { existsSync } from "fs";
19
+ import {
20
+ existsSync,
21
+ mkdirSync,
22
+ readFileSync,
23
+ writeFileSync,
24
+ chmodSync
25
+ } from "fs";
20
26
  import { homedir } from "os";
21
27
  import { dirname, join, resolve } from "path";
22
28
  function createHooxPath(path) {
@@ -42,7 +48,55 @@ function isHooxSetupRoot(dir) {
42
48
  return false;
43
49
  try {
44
50
  const root = resolve(dir);
45
- return existsSync(join(root, "wrangler.jsonc")) && existsSync(join(root, "packages", "cli", "package.json"));
51
+ if (!existsSync(join(root, "packages", "cli", "package.json"))) {
52
+ return false;
53
+ }
54
+ return existsSync(join(root, "wrangler.jsonc")) || existsSync(join(root, "wrangler.jsonc.example")) || existsSync(join(root, "workers")) || existsSync(join(root, ".gitmodules"));
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+ function getRememberedMonorepoPath() {
60
+ return resolveHooxPath("config/monorepo.json");
61
+ }
62
+ function getRememberedMonorepoRoot() {
63
+ try {
64
+ const path = getRememberedMonorepoPath();
65
+ if (!existsSync(path))
66
+ return null;
67
+ const raw = readFileSync(path, "utf-8");
68
+ const data = JSON.parse(raw);
69
+ if (!data.root || typeof data.root !== "string")
70
+ return null;
71
+ const resolved = resolve(data.root);
72
+ return isHooxSetupRoot(resolved) ? resolved : null;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function rememberMonorepoRoot(root) {
78
+ try {
79
+ const resolved = resolve(root);
80
+ if (!isHooxSetupRoot(resolved))
81
+ return false;
82
+ const configDir = getHooxConfigDir();
83
+ mkdirSync(configDir, { recursive: true, mode: 448 });
84
+ try {
85
+ chmodSync(configDir, 448);
86
+ } catch {}
87
+ const payload = {
88
+ root: resolved,
89
+ updatedAt: new Date().toISOString()
90
+ };
91
+ const path = getRememberedMonorepoPath();
92
+ writeFileSync(path, JSON.stringify(payload, null, 2) + `
93
+ `, {
94
+ mode: 384
95
+ });
96
+ try {
97
+ chmodSync(path, 384);
98
+ } catch {}
99
+ return true;
46
100
  } catch {
47
101
  return false;
48
102
  }
@@ -62,6 +116,7 @@ function resolveHooxRuntimeRoot(options) {
62
116
  const env = options?.env ?? process.env;
63
117
  const cwd = resolve(options?.cwd ?? process.cwd());
64
118
  const globalRepo = getHooxRepoPath();
119
+ const remembered = options?.skipRemembered ? null : getRememberedMonorepoRoot();
65
120
  const envRepo = env.HOOX_REPO?.trim();
66
121
  if (envRepo) {
67
122
  const resolved = resolve(envRepo);
@@ -72,6 +127,7 @@ function resolveHooxRuntimeRoot(options) {
72
127
  checked: {
73
128
  env: resolved,
74
129
  cwd: findHooxSetupRoot(cwd),
130
+ remembered,
75
131
  global: globalRepo
76
132
  }
77
133
  };
@@ -82,6 +138,7 @@ function resolveHooxRuntimeRoot(options) {
82
138
  checked: {
83
139
  env: resolved,
84
140
  cwd: findHooxSetupRoot(cwd),
141
+ remembered,
85
142
  global: globalRepo
86
143
  }
87
144
  };
@@ -91,20 +148,27 @@ function resolveHooxRuntimeRoot(options) {
91
148
  return {
92
149
  root: local,
93
150
  source: "cwd",
94
- checked: { cwd: local, global: globalRepo }
151
+ checked: { cwd: local, remembered, global: globalRepo }
152
+ };
153
+ }
154
+ if (remembered) {
155
+ return {
156
+ root: remembered,
157
+ source: "remembered",
158
+ checked: { cwd: null, remembered, global: globalRepo }
95
159
  };
96
160
  }
97
161
  if (isHooxSetupRoot(globalRepo)) {
98
162
  return {
99
163
  root: globalRepo,
100
164
  source: "global",
101
- checked: { cwd: null, global: globalRepo }
165
+ checked: { cwd: null, remembered: null, global: globalRepo }
102
166
  };
103
167
  }
104
168
  return {
105
169
  root: null,
106
170
  source: "none",
107
- checked: { cwd: null, global: globalRepo }
171
+ checked: { cwd: null, remembered: null, global: globalRepo }
108
172
  };
109
173
  }
110
174
  function getTuiEntryCandidates(runtimeRoot) {
@@ -174,9 +238,12 @@ function getHooxStatePath() {
174
238
  export {
175
239
  resolveHooxRuntimeRoot,
176
240
  resolveHooxPath,
241
+ rememberMonorepoRoot,
177
242
  isWithinHooxHome,
178
243
  isHooxSetupRoot,
179
244
  getTuiEntryCandidates,
245
+ getRememberedMonorepoRoot,
246
+ getRememberedMonorepoPath,
180
247
  getRelativeHooxPath,
181
248
  getHooxWranglerPath,
182
249
  getHooxStatePath,
@@ -27,7 +27,7 @@ export declare const D1_READ_AUTH_KEY_FIELDS: readonly ["D1_READ_KEY_BINDING", "
27
27
  export declare const D1_WRITE_AUTH_KEY_FIELDS: readonly ["D1_WRITE_KEY_BINDING", "INTERNAL_KEY_BINDING"];
28
28
  /** trade-worker execute routes (/webhook, /process, POST /api/signals). */
29
29
  export declare const TRADE_EXECUTE_AUTH_KEY_FIELDS: readonly ["TRADE_EXECUTE_KEY_BINDING", "INTERNAL_KEY_BINDING", "AGENT_INTERNAL_KEY"];
30
- /** trade-worker read routes (GET /api/signals, GET /report). */
30
+ /** trade-worker read routes (GET /api/signals, GET /api/system-logs, GET /report). */
31
31
  export declare const TRADE_READ_AUTH_KEY_FIELDS: readonly ["TRADE_READ_KEY_BINDING", "INTERNAL_KEY_BINDING"];
32
32
  /** telegram-worker /alert notification endpoint. */
33
33
  export declare const TELEGRAM_ALERT_AUTH_KEY_FIELDS: readonly ["TELEGRAM_INTERNAL_KEY_BINDING", "INTERNAL_KEY_BINDING"];
@@ -1 +1 @@
1
- {"version":3,"file":"service-bindings.d.ts","sourceRoot":"","sources":["../src/service-bindings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAmB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzE;AAED,uDAAuD;AACvD,eAAO,MAAM,qBAAqB;;;;;;;;;IAShC,sDAAsD;;;;CAI9C,CAAC;AAEX,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,0DAG1B,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,2DAG3B,CAAC;AAEX,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,sFAIhC,CAAC;AAEX,gEAAgE;AAChE,eAAO,MAAM,0BAA0B,6DAG7B,CAAC;AAEX,oDAAoD;AACpD,eAAO,MAAM,8BAA8B,oEAGjC,CAAC;AAEX,4CAA4C;AAC5C,eAAO,MAAM,8BAA8B,iEAGjC,CAAC;AAEX,wEAAwE;AACxE,eAAO,MAAM,iCAAiC,6EAIpC,CAAC;AAEX,8CAA8C;AAC9C,eAAO,MAAM,uCAAuC,sFAI1C,CAAC;AAEX,gDAAgD;AAChD,eAAO,MAAM,wCAAwC,6FAI3C,CAAC;AAEX,0DAA0D;AAC1D,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,mBAAmB,GAC7B,MAAM,GAAG,SAAS,CAEpB;AAED,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,uBAAuB,EACzE,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;CACzC,GACA,OAAO,CAAC,QAAQ,CAAC,CAsBnB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,QAAQ,CAAC,CAWnB"}
1
+ {"version":3,"file":"service-bindings.d.ts","sourceRoot":"","sources":["../src/service-bindings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAmB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzE;AAED,uDAAuD;AACvD,eAAO,MAAM,qBAAqB;;;;;;;;;IAShC,sDAAsD;;;;CAI9C,CAAC;AAEX,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,0DAG1B,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,2DAG3B,CAAC;AAEX,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,sFAIhC,CAAC;AAEX,sFAAsF;AACtF,eAAO,MAAM,0BAA0B,6DAG7B,CAAC;AAEX,oDAAoD;AACpD,eAAO,MAAM,8BAA8B,oEAGjC,CAAC;AAEX,4CAA4C;AAC5C,eAAO,MAAM,8BAA8B,iEAGjC,CAAC;AAEX,wEAAwE;AACxE,eAAO,MAAM,iCAAiC,6EAIpC,CAAC;AAEX,8CAA8C;AAC9C,eAAO,MAAM,uCAAuC,sFAI1C,CAAC;AAEX,gDAAgD;AAChD,eAAO,MAAM,wCAAwC,6FAI3C,CAAC;AAEX,0DAA0D;AAC1D,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,mBAAmB,GAC7B,MAAM,GAAG,SAAS,CAEpB;AAED,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,uBAAuB,EACzE,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;CACzC,GACA,OAAO,CAAC,QAAQ,CAAC,CAsBnB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,QAAQ,CAAC,CAWnB"}
package/dist/session.js CHANGED
@@ -16,7 +16,13 @@ var __export = (target, all) => {
16
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
18
  // src/path-utils.ts
19
- import { existsSync } from "fs";
19
+ import {
20
+ existsSync,
21
+ mkdirSync,
22
+ readFileSync,
23
+ writeFileSync,
24
+ chmodSync
25
+ } from "fs";
20
26
  import { homedir } from "os";
21
27
  import { dirname, join, resolve } from "path";
22
28
  function createHooxPath(path) {
@@ -42,7 +48,55 @@ function isHooxSetupRoot(dir) {
42
48
  return false;
43
49
  try {
44
50
  const root = resolve(dir);
45
- return existsSync(join(root, "wrangler.jsonc")) && existsSync(join(root, "packages", "cli", "package.json"));
51
+ if (!existsSync(join(root, "packages", "cli", "package.json"))) {
52
+ return false;
53
+ }
54
+ return existsSync(join(root, "wrangler.jsonc")) || existsSync(join(root, "wrangler.jsonc.example")) || existsSync(join(root, "workers")) || existsSync(join(root, ".gitmodules"));
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+ function getRememberedMonorepoPath() {
60
+ return resolveHooxPath("config/monorepo.json");
61
+ }
62
+ function getRememberedMonorepoRoot() {
63
+ try {
64
+ const path = getRememberedMonorepoPath();
65
+ if (!existsSync(path))
66
+ return null;
67
+ const raw = readFileSync(path, "utf-8");
68
+ const data = JSON.parse(raw);
69
+ if (!data.root || typeof data.root !== "string")
70
+ return null;
71
+ const resolved = resolve(data.root);
72
+ return isHooxSetupRoot(resolved) ? resolved : null;
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function rememberMonorepoRoot(root) {
78
+ try {
79
+ const resolved = resolve(root);
80
+ if (!isHooxSetupRoot(resolved))
81
+ return false;
82
+ const configDir = getHooxConfigDir();
83
+ mkdirSync(configDir, { recursive: true, mode: 448 });
84
+ try {
85
+ chmodSync(configDir, 448);
86
+ } catch {}
87
+ const payload = {
88
+ root: resolved,
89
+ updatedAt: new Date().toISOString()
90
+ };
91
+ const path = getRememberedMonorepoPath();
92
+ writeFileSync(path, JSON.stringify(payload, null, 2) + `
93
+ `, {
94
+ mode: 384
95
+ });
96
+ try {
97
+ chmodSync(path, 384);
98
+ } catch {}
99
+ return true;
46
100
  } catch {
47
101
  return false;
48
102
  }
@@ -62,6 +116,7 @@ function resolveHooxRuntimeRoot(options) {
62
116
  const env = options?.env ?? process.env;
63
117
  const cwd = resolve(options?.cwd ?? process.cwd());
64
118
  const globalRepo = getHooxRepoPath();
119
+ const remembered = options?.skipRemembered ? null : getRememberedMonorepoRoot();
65
120
  const envRepo = env.HOOX_REPO?.trim();
66
121
  if (envRepo) {
67
122
  const resolved = resolve(envRepo);
@@ -72,6 +127,7 @@ function resolveHooxRuntimeRoot(options) {
72
127
  checked: {
73
128
  env: resolved,
74
129
  cwd: findHooxSetupRoot(cwd),
130
+ remembered,
75
131
  global: globalRepo
76
132
  }
77
133
  };
@@ -82,6 +138,7 @@ function resolveHooxRuntimeRoot(options) {
82
138
  checked: {
83
139
  env: resolved,
84
140
  cwd: findHooxSetupRoot(cwd),
141
+ remembered,
85
142
  global: globalRepo
86
143
  }
87
144
  };
@@ -91,20 +148,27 @@ function resolveHooxRuntimeRoot(options) {
91
148
  return {
92
149
  root: local,
93
150
  source: "cwd",
94
- checked: { cwd: local, global: globalRepo }
151
+ checked: { cwd: local, remembered, global: globalRepo }
152
+ };
153
+ }
154
+ if (remembered) {
155
+ return {
156
+ root: remembered,
157
+ source: "remembered",
158
+ checked: { cwd: null, remembered, global: globalRepo }
95
159
  };
96
160
  }
97
161
  if (isHooxSetupRoot(globalRepo)) {
98
162
  return {
99
163
  root: globalRepo,
100
164
  source: "global",
101
- checked: { cwd: null, global: globalRepo }
165
+ checked: { cwd: null, remembered: null, global: globalRepo }
102
166
  };
103
167
  }
104
168
  return {
105
169
  root: null,
106
170
  source: "none",
107
- checked: { cwd: null, global: globalRepo }
171
+ checked: { cwd: null, remembered: null, global: globalRepo }
108
172
  };
109
173
  }
110
174
  function getTuiEntryCandidates(runtimeRoot) {
package/dist/sse.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
  }
@@ -3,6 +3,8 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import type { ViewId, LogFilter, NotificationPreferences } from "../types";
6
+ /** TUI prefs file — isolated from operator config.json (which may hold apiToken). */
7
+ export declare function getTuiPreferencesPath(): string;
6
8
  export interface ConfigState {
7
9
  theme: "dark" | "light";
8
10
  refreshIntervalMs: number;