@hoox-sh/hoox-cli 0.11.9 → 0.13.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.
- package/README.md +2 -2
- package/dist/index.js +586 -176
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -14691,7 +14691,7 @@ var init_zod = __esm(() => {
|
|
|
14691
14691
|
});
|
|
14692
14692
|
|
|
14693
14693
|
// ../shared/src/types.ts
|
|
14694
|
-
var TradeActionSchema, WebhookPayloadSchema, TradeQueueMessageSchema, TradeSignalSchema, PositionSchema, BalanceSchema;
|
|
14694
|
+
var TradeActionSchema, MAX_WEBHOOK_LEVERAGE = 125, MAX_WEBHOOK_QUANTITY = 1e6, WebhookPayloadSchema, TradeQueueMessageSchema, TradeSignalSchema, PositionSchema, BalanceSchema;
|
|
14695
14695
|
var init_types = __esm(() => {
|
|
14696
14696
|
init_zod();
|
|
14697
14697
|
TradeActionSchema = exports_external.enum([
|
|
@@ -14704,10 +14704,10 @@ var init_types = __esm(() => {
|
|
|
14704
14704
|
exchange: exports_external.string().min(1),
|
|
14705
14705
|
action: TradeActionSchema,
|
|
14706
14706
|
symbol: exports_external.string().min(1).max(20),
|
|
14707
|
-
quantity: exports_external.number().positive().finite(),
|
|
14707
|
+
quantity: exports_external.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
|
|
14708
14708
|
price: exports_external.number().positive().finite().optional(),
|
|
14709
14709
|
orderType: exports_external.string().optional(),
|
|
14710
|
-
leverage: exports_external.number().int().positive().optional(),
|
|
14710
|
+
leverage: exports_external.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
|
|
14711
14711
|
test: exports_external.boolean().optional()
|
|
14712
14712
|
}).strict();
|
|
14713
14713
|
TradeQueueMessageSchema = exports_external.object({
|
|
@@ -14715,9 +14715,9 @@ var init_types = __esm(() => {
|
|
|
14715
14715
|
exchange: exports_external.string().min(1).max(64),
|
|
14716
14716
|
action: TradeActionSchema,
|
|
14717
14717
|
symbol: exports_external.string().min(1).max(32),
|
|
14718
|
-
quantity: exports_external.number().positive().finite(),
|
|
14718
|
+
quantity: exports_external.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
|
|
14719
14719
|
price: exports_external.number().positive().finite().optional(),
|
|
14720
|
-
leverage: exports_external.number().int().positive().max(
|
|
14720
|
+
leverage: exports_external.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
|
|
14721
14721
|
test: exports_external.boolean().optional(),
|
|
14722
14722
|
idempotencyKey: exports_external.string().min(1).max(512).optional(),
|
|
14723
14723
|
queuedAt: exports_external.string().min(1).max(64)
|
|
@@ -14754,7 +14754,7 @@ var init_types = __esm(() => {
|
|
|
14754
14754
|
});
|
|
14755
14755
|
|
|
14756
14756
|
// ../shared/src/kvKeys.ts
|
|
14757
|
-
var KV_TRADE_DEFAULT_LEVERAGE = "trade:default_leverage", KV_TRADE_MAX_POSITION_SIZE = "trade:max_position_size", KV_TRADE_MAX_DAILY_DRAWDOWN_PERCENT = "trade:max_daily_drawdown_percent", KV_TRADE_TRAILING_STOP_PERCENT = "trade:trailing_stop_percent", KV_TRADE_KILL_SWITCH = "trade:kill_switch", KV_TRADE_ROUTING = "trade:routing", KV_BOT_ENABLED = "bot:enabled", KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id", KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution", KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error", KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled", KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips", KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode", KV_EMAIL_SCAN_SUBJECT = "email:scan_subject", KV_EMAIL_USE_IMAP = "email:use_imap", KV_EMAIL_COIN_PATTERN = "email:coin_pattern", KV_EMAIL_ACTION_PATTERN = "email:action_pattern", KV_EMAIL_QUANTITY_MULTIPLIER = "email:quantity_multiplier", KV_AGENT_CONFIG = "agent:config", KV_AGENT_OPENAI_KEY = "agent:openai_key", KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key", KV_AGENT_GOOGLE_KEY = "agent:google_key", KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary", KV_GLOBAL_KILL_SWITCH = "global:kill_switch", KV_HEALTH_CHECK = "health_check", KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check", QUEUE_MODE_FAILOVER = "queue_failover", QUEUE_MODE_EVERYWHERE = "queue_everywhere", QUEUE_MODE_DISABLED = "queue_disabled", KVKeys;
|
|
14757
|
+
var KV_TRADE_DEFAULT_LEVERAGE = "trade:default_leverage", KV_TRADE_MAX_POSITION_SIZE = "trade:max_position_size", KV_TRADE_MAX_DAILY_DRAWDOWN_PERCENT = "trade:max_daily_drawdown_percent", KV_TRADE_TRAILING_STOP_PERCENT = "trade:trailing_stop_percent", KV_TRADE_KILL_SWITCH = "trade:kill_switch", KV_TRADE_ROUTING = "trade:routing", KV_BOT_ENABLED = "bot:enabled", KV_BOT_DEFAULT_CHAT_ID = "bot:default_chat_id", KV_BOT_NOTIFY_ON_EXECUTION = "bot:notify_on_execution", KV_BOT_NOTIFY_ON_ERROR = "bot:notify_on_error", KV_TELEGRAM_ALLOWED_CHAT_IDS = "telegram:allowed_chat_ids", KV_WEBHOOK_IP_CHECK_ENABLED = "webhook:tradingview:ip_check_enabled", KV_WEBHOOK_ALLOWED_IPS = "webhook:tradingview:allowed_ips", KV_WEBHOOK_QUEUE_MODE = "webhook:queue_mode", KV_EMAIL_SCAN_SUBJECT = "email:scan_subject", KV_EMAIL_USE_IMAP = "email:use_imap", KV_EMAIL_COIN_PATTERN = "email:coin_pattern", KV_EMAIL_ACTION_PATTERN = "email:action_pattern", KV_EMAIL_QUANTITY_MULTIPLIER = "email:quantity_multiplier", KV_AGENT_CONFIG = "agent:config", KV_AGENT_OPENAI_KEY = "agent:openai_key", KV_AGENT_ANTHROPIC_KEY = "agent:anthropic_key", KV_AGENT_GOOGLE_KEY = "agent:google_key", KV_DASHBOARD_AI_HEALTH_SUMMARY = "dashboard:ai_health_summary", KV_GLOBAL_KILL_SWITCH = "global:kill_switch", KV_HEALTH_CHECK = "health_check", KV_HOUSEKEEPING_LAST_CHECK = "housekeeping:last_check", QUEUE_MODE_FAILOVER = "queue_failover", QUEUE_MODE_EVERYWHERE = "queue_everywhere", QUEUE_MODE_DISABLED = "queue_disabled", KVKeys;
|
|
14758
14758
|
var init_kvKeys = __esm(() => {
|
|
14759
14759
|
KVKeys = {
|
|
14760
14760
|
KV_TRADE_DEFAULT_LEVERAGE,
|
|
@@ -14767,6 +14767,7 @@ var init_kvKeys = __esm(() => {
|
|
|
14767
14767
|
KV_BOT_DEFAULT_CHAT_ID,
|
|
14768
14768
|
KV_BOT_NOTIFY_ON_EXECUTION,
|
|
14769
14769
|
KV_BOT_NOTIFY_ON_ERROR,
|
|
14770
|
+
KV_TELEGRAM_ALLOWED_CHAT_IDS,
|
|
14770
14771
|
KV_WEBHOOK_IP_CHECK_ENABLED,
|
|
14771
14772
|
KV_WEBHOOK_ALLOWED_IPS,
|
|
14772
14773
|
KV_WEBHOOK_QUEUE_MODE,
|
|
@@ -14843,8 +14844,10 @@ function toError(err, fallback = "Unknown error") {
|
|
|
14843
14844
|
return err.message;
|
|
14844
14845
|
if (typeof err === "string")
|
|
14845
14846
|
return err;
|
|
14846
|
-
if (err && typeof err === "object" && "message" in err
|
|
14847
|
-
|
|
14847
|
+
if (err && typeof err === "object" && "message" in err) {
|
|
14848
|
+
const message = err.message;
|
|
14849
|
+
if (typeof message === "string")
|
|
14850
|
+
return message;
|
|
14848
14851
|
}
|
|
14849
14852
|
if (err === null || err === undefined)
|
|
14850
14853
|
return fallback;
|
|
@@ -15105,6 +15108,52 @@ async function logKvTimestamp(env, prefix = "timestamp") {
|
|
|
15105
15108
|
console.error(`Failed to log timestamp to KV: ${toError(error51, "Unknown error")}`);
|
|
15106
15109
|
}
|
|
15107
15110
|
}
|
|
15111
|
+
async function tryBulkGetChunk(kv, chunk) {
|
|
15112
|
+
try {
|
|
15113
|
+
const result = await kv.get([...chunk]);
|
|
15114
|
+
if (!(result instanceof Map)) {
|
|
15115
|
+
return null;
|
|
15116
|
+
}
|
|
15117
|
+
return chunk.map((key) => result.get(key) ?? null);
|
|
15118
|
+
} catch {
|
|
15119
|
+
return null;
|
|
15120
|
+
}
|
|
15121
|
+
}
|
|
15122
|
+
async function kvGetMany(kv, keys) {
|
|
15123
|
+
if (keys.length === 0)
|
|
15124
|
+
return [];
|
|
15125
|
+
const out = new Array(keys.length);
|
|
15126
|
+
let offset = 0;
|
|
15127
|
+
while (offset < keys.length) {
|
|
15128
|
+
const chunk = keys.slice(offset, offset + KV_BULK_GET_MAX_KEYS);
|
|
15129
|
+
const bulk = await tryBulkGetChunk(kv, chunk);
|
|
15130
|
+
if (bulk === null) {
|
|
15131
|
+
const rest = await Promise.all(keys.slice(offset).map((key) => kv.get(key)));
|
|
15132
|
+
for (let i = 0;i < rest.length; i++) {
|
|
15133
|
+
out[offset + i] = rest[i] ?? null;
|
|
15134
|
+
}
|
|
15135
|
+
return out;
|
|
15136
|
+
}
|
|
15137
|
+
for (let i = 0;i < bulk.length; i++) {
|
|
15138
|
+
out[offset + i] = bulk[i] ?? null;
|
|
15139
|
+
}
|
|
15140
|
+
offset += chunk.length;
|
|
15141
|
+
}
|
|
15142
|
+
return out;
|
|
15143
|
+
}
|
|
15144
|
+
async function kvGetManyAsRecord(kv, keys) {
|
|
15145
|
+
const values = await kvGetMany(kv, keys);
|
|
15146
|
+
const out = {};
|
|
15147
|
+
for (let i = 0;i < keys.length; i++) {
|
|
15148
|
+
out[keys[i]] = values[i] ?? null;
|
|
15149
|
+
}
|
|
15150
|
+
return out;
|
|
15151
|
+
}
|
|
15152
|
+
async function kvPutMany(kv, entries) {
|
|
15153
|
+
if (entries.length === 0)
|
|
15154
|
+
return;
|
|
15155
|
+
await Promise.all(entries.map((entry) => kv.put(entry.key, entry.value, entry.options)));
|
|
15156
|
+
}
|
|
15108
15157
|
function headersToObject(headers) {
|
|
15109
15158
|
const result = {};
|
|
15110
15159
|
if (!headers)
|
|
@@ -15118,6 +15167,7 @@ function headersToObject(headers) {
|
|
|
15118
15167
|
}
|
|
15119
15168
|
return result;
|
|
15120
15169
|
}
|
|
15170
|
+
var KV_BULK_GET_MAX_KEYS = 100;
|
|
15121
15171
|
var init_kvUtils = __esm(() => {
|
|
15122
15172
|
init_errors3();
|
|
15123
15173
|
});
|
|
@@ -15167,29 +15217,60 @@ var init_health = __esm(() => {
|
|
|
15167
15217
|
});
|
|
15168
15218
|
|
|
15169
15219
|
// ../shared/src/queue-handler.ts
|
|
15220
|
+
async function mapPool(items, concurrency, fn) {
|
|
15221
|
+
if (items.length === 0)
|
|
15222
|
+
return;
|
|
15223
|
+
const limit = Math.min(Math.max(1, concurrency), items.length);
|
|
15224
|
+
if (limit === 1) {
|
|
15225
|
+
for (const item of items) {
|
|
15226
|
+
await fn(item);
|
|
15227
|
+
}
|
|
15228
|
+
return;
|
|
15229
|
+
}
|
|
15230
|
+
let nextIndex = 0;
|
|
15231
|
+
async function worker() {
|
|
15232
|
+
while (true) {
|
|
15233
|
+
const i = nextIndex++;
|
|
15234
|
+
if (i >= items.length)
|
|
15235
|
+
return;
|
|
15236
|
+
await fn(items[i]);
|
|
15237
|
+
}
|
|
15238
|
+
}
|
|
15239
|
+
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
15240
|
+
}
|
|
15170
15241
|
function createQueueHandler(options) {
|
|
15171
|
-
const {
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15242
|
+
const {
|
|
15243
|
+
maxRetries,
|
|
15244
|
+
backoffDelays,
|
|
15245
|
+
onMessage,
|
|
15246
|
+
onRetry,
|
|
15247
|
+
onDLQ,
|
|
15248
|
+
logger,
|
|
15249
|
+
concurrency: concurrencyOpt
|
|
15250
|
+
} = options;
|
|
15251
|
+
const concurrency = typeof concurrencyOpt === "number" && Number.isFinite(concurrencyOpt) && concurrencyOpt >= 1 ? Math.floor(concurrencyOpt) : 1;
|
|
15252
|
+
async function processMessage(msg) {
|
|
15253
|
+
const attemptNumber = msg.attempts || 0;
|
|
15254
|
+
const logId = `[${msg.id}]`;
|
|
15255
|
+
try {
|
|
15256
|
+
logger?.info(`${logId} Processing message (attempt ${attemptNumber + 1})`);
|
|
15257
|
+
await onMessage(msg.body, attemptNumber);
|
|
15258
|
+
logger?.info(`${logId} Message processed successfully`);
|
|
15259
|
+
} catch (error51) {
|
|
15260
|
+
const errorMsg = error51 instanceof Error ? error51.message : String(error51);
|
|
15261
|
+
if (attemptNumber < maxRetries) {
|
|
15262
|
+
const delaySeconds = backoffDelays[attemptNumber] ?? backoffDelays[backoffDelays.length - 1] ?? 0;
|
|
15263
|
+
logger?.info(`${logId} Retrying in ${delaySeconds}s (attempt ${attemptNumber + 2}/${maxRetries + 1})`);
|
|
15264
|
+
await onRetry?.(msg.body, attemptNumber, errorMsg, delaySeconds);
|
|
15265
|
+
msg.retry({ delaySeconds });
|
|
15266
|
+
} else {
|
|
15267
|
+
logger?.error(`${logId} Max retries exceeded (${maxRetries + 1} attempts), moving to DLQ`);
|
|
15268
|
+
await onDLQ?.(msg.body, attemptNumber, errorMsg);
|
|
15191
15269
|
}
|
|
15192
15270
|
}
|
|
15271
|
+
}
|
|
15272
|
+
return async (batch) => {
|
|
15273
|
+
await mapPool(batch.messages, concurrency, processMessage);
|
|
15193
15274
|
};
|
|
15194
15275
|
}
|
|
15195
15276
|
|
|
@@ -17078,7 +17159,7 @@ var init_presets = __esm(() => {
|
|
|
17078
17159
|
"analytics-worker",
|
|
17079
17160
|
"telegram-worker"
|
|
17080
17161
|
],
|
|
17081
|
-
integrations: ["
|
|
17162
|
+
integrations: ["exchange", "telegram"]
|
|
17082
17163
|
},
|
|
17083
17164
|
{
|
|
17084
17165
|
name: "full",
|
|
@@ -17095,15 +17176,7 @@ var init_presets = __esm(() => {
|
|
|
17095
17176
|
"web3-wallet-worker",
|
|
17096
17177
|
"pyne-worker"
|
|
17097
17178
|
],
|
|
17098
|
-
integrations: [
|
|
17099
|
-
"binance",
|
|
17100
|
-
"bybit",
|
|
17101
|
-
"mexc",
|
|
17102
|
-
"telegram",
|
|
17103
|
-
"openai",
|
|
17104
|
-
"wallet",
|
|
17105
|
-
"pyne"
|
|
17106
|
-
]
|
|
17179
|
+
integrations: ["exchange", "telegram", "openai", "wallet", "pyne"]
|
|
17107
17180
|
}
|
|
17108
17181
|
];
|
|
17109
17182
|
WORKER_DEPENDENCIES = {
|
|
@@ -17116,30 +17189,12 @@ var init_presets = __esm(() => {
|
|
|
17116
17189
|
};
|
|
17117
17190
|
INTEGRATIONS = [
|
|
17118
17191
|
{
|
|
17119
|
-
key: "
|
|
17120
|
-
label: "Binance
|
|
17121
|
-
workerName: "trade-worker",
|
|
17122
|
-
secrets: {
|
|
17123
|
-
BINANCE_KEY_BINDING: "Binance API Key",
|
|
17124
|
-
BINANCE_SECRET_BINDING: "Binance API Secret"
|
|
17125
|
-
}
|
|
17126
|
-
},
|
|
17127
|
-
{
|
|
17128
|
-
key: "mexc",
|
|
17129
|
-
label: "MEXC Exchange",
|
|
17130
|
-
workerName: "trade-worker",
|
|
17131
|
-
secrets: {
|
|
17132
|
-
MEXC_KEY_BINDING: "MEXC API Key",
|
|
17133
|
-
MEXC_SECRET_BINDING: "MEXC API Secret"
|
|
17134
|
-
}
|
|
17135
|
-
},
|
|
17136
|
-
{
|
|
17137
|
-
key: "bybit",
|
|
17138
|
-
label: "Bybit Exchange",
|
|
17192
|
+
key: "exchange",
|
|
17193
|
+
label: "Exchange API (Binance / Bybit / MEXC)",
|
|
17139
17194
|
workerName: "trade-worker",
|
|
17140
17195
|
secrets: {
|
|
17141
|
-
|
|
17142
|
-
|
|
17196
|
+
EXCHANGE_KEY_BINDING: "Exchange API Key",
|
|
17197
|
+
EXCHANGE_SECRET_BINDING: "Exchange API Secret"
|
|
17143
17198
|
}
|
|
17144
17199
|
},
|
|
17145
17200
|
{
|
|
@@ -17311,7 +17366,11 @@ class WizardEngine {
|
|
|
17311
17366
|
return { ...this.state };
|
|
17312
17367
|
}
|
|
17313
17368
|
getCurrentStep() {
|
|
17314
|
-
|
|
17369
|
+
const step = STEPS.find((s) => s.id === this.state.step) ?? STEPS[0];
|
|
17370
|
+
if (!step) {
|
|
17371
|
+
throw new Error("Wizard has no steps defined");
|
|
17372
|
+
}
|
|
17373
|
+
return step;
|
|
17315
17374
|
}
|
|
17316
17375
|
getCompletedSteps() {
|
|
17317
17376
|
return [...this.state.completedSteps];
|
|
@@ -17334,8 +17393,11 @@ class WizardEngine {
|
|
|
17334
17393
|
this.state.completedSteps.push(this.state.step);
|
|
17335
17394
|
}
|
|
17336
17395
|
const currentIdx = STEP_ORDER.indexOf(this.state.step);
|
|
17337
|
-
if (currentIdx < STEP_ORDER.length - 1) {
|
|
17338
|
-
|
|
17396
|
+
if (currentIdx >= 0 && currentIdx < STEP_ORDER.length - 1) {
|
|
17397
|
+
const nextStep = STEP_ORDER[currentIdx + 1];
|
|
17398
|
+
if (nextStep !== undefined) {
|
|
17399
|
+
this.state.step = nextStep;
|
|
17400
|
+
}
|
|
17339
17401
|
}
|
|
17340
17402
|
this.state.updatedAt = Date.now();
|
|
17341
17403
|
return [];
|
|
@@ -17346,6 +17408,8 @@ class WizardEngine {
|
|
|
17346
17408
|
const currentIdx = STEP_ORDER.indexOf(this.state.step);
|
|
17347
17409
|
if (currentIdx > 0) {
|
|
17348
17410
|
const previousStep = STEP_ORDER[currentIdx - 1];
|
|
17411
|
+
if (previousStep === undefined)
|
|
17412
|
+
return;
|
|
17349
17413
|
this.state.step = previousStep;
|
|
17350
17414
|
this.state.completedSteps = this.state.completedSteps.filter((s) => s !== this.state.step || STEP_ORDER.indexOf(s) <= STEP_ORDER.indexOf(previousStep));
|
|
17351
17415
|
}
|
|
@@ -17573,9 +17637,12 @@ function deriveCalledBy(manifests) {
|
|
|
17573
17637
|
if (!calledBy[workerName])
|
|
17574
17638
|
calledBy[workerName] = new Set;
|
|
17575
17639
|
for (const svc of manifest.services) {
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
17640
|
+
let callers = calledBy[svc.service];
|
|
17641
|
+
if (!callers) {
|
|
17642
|
+
callers = new Set;
|
|
17643
|
+
calledBy[svc.service] = callers;
|
|
17644
|
+
}
|
|
17645
|
+
callers.add(workerName);
|
|
17579
17646
|
}
|
|
17580
17647
|
}
|
|
17581
17648
|
const result = {};
|
|
@@ -17584,12 +17651,16 @@ function deriveCalledBy(manifests) {
|
|
|
17584
17651
|
}
|
|
17585
17652
|
return result;
|
|
17586
17653
|
}
|
|
17587
|
-
|
|
17654
|
+
function getWorkerDefaultEnabled(name) {
|
|
17655
|
+
return manifests[name]?.defaultEnabled;
|
|
17656
|
+
}
|
|
17657
|
+
var manifests, CALLED_BY, WORKER_MANIFESTS, WORKER_NAMES, WORKER_CATALOG;
|
|
17588
17658
|
var init_registry = __esm(() => {
|
|
17589
17659
|
manifests = {
|
|
17590
17660
|
hoox: {
|
|
17591
17661
|
name: "hoox",
|
|
17592
17662
|
path: "workers/hoox-worker",
|
|
17663
|
+
defaultEnabled: true,
|
|
17593
17664
|
vars: {
|
|
17594
17665
|
WEBHOOK_API_KEY_BINDING: {
|
|
17595
17666
|
type: "secret",
|
|
@@ -17599,7 +17670,11 @@ var init_registry = __esm(() => {
|
|
|
17599
17670
|
type: "secret",
|
|
17600
17671
|
description: "Inter-worker auth key"
|
|
17601
17672
|
},
|
|
17602
|
-
HA_TOKEN_BINDING: { type: "secret", description: "Home Assistant token" }
|
|
17673
|
+
HA_TOKEN_BINDING: { type: "secret", description: "Home Assistant token" },
|
|
17674
|
+
TELEGRAM_ALLOWED_CHAT_IDS: {
|
|
17675
|
+
type: "secret",
|
|
17676
|
+
description: "Comma-separated chat IDs for webhook notify (fail-closed when unset); alias AUTHORIZED_CHAT_IDS"
|
|
17677
|
+
}
|
|
17603
17678
|
},
|
|
17604
17679
|
services: [
|
|
17605
17680
|
{
|
|
@@ -17625,7 +17700,8 @@ var init_registry = __esm(() => {
|
|
|
17625
17700
|
ai: true,
|
|
17626
17701
|
queues: { producer: ["trade-execution"] },
|
|
17627
17702
|
durableObjects: [
|
|
17628
|
-
{ name: "IDEMPOTENCY_STORE", className: "IdempotencyStore" }
|
|
17703
|
+
{ name: "IDEMPOTENCY_STORE", className: "IdempotencyStore" },
|
|
17704
|
+
{ name: "RATE_LIMITER", className: "RateLimiterStore" }
|
|
17629
17705
|
]
|
|
17630
17706
|
},
|
|
17631
17707
|
middleware: [
|
|
@@ -17640,6 +17716,7 @@ var init_registry = __esm(() => {
|
|
|
17640
17716
|
"trade-worker": {
|
|
17641
17717
|
name: "trade-worker",
|
|
17642
17718
|
path: "workers/trade-worker",
|
|
17719
|
+
defaultEnabled: true,
|
|
17643
17720
|
vars: {
|
|
17644
17721
|
INTERNAL_KEY_BINDING: {
|
|
17645
17722
|
type: "secret",
|
|
@@ -17649,15 +17726,22 @@ var init_registry = __esm(() => {
|
|
|
17649
17726
|
type: "secret",
|
|
17650
17727
|
description: "Telegram outbound auth"
|
|
17651
17728
|
},
|
|
17652
|
-
|
|
17653
|
-
BINANCE_SECRET_BINDING: {
|
|
17729
|
+
EXCHANGE_KEY_BINDING: {
|
|
17654
17730
|
type: "secret",
|
|
17655
|
-
description: "
|
|
17731
|
+
description: "Unified exchange API key (Binance / Bybit / MEXC)"
|
|
17656
17732
|
},
|
|
17657
|
-
|
|
17658
|
-
|
|
17659
|
-
|
|
17660
|
-
|
|
17733
|
+
EXCHANGE_SECRET_BINDING: {
|
|
17734
|
+
type: "secret",
|
|
17735
|
+
description: "Unified exchange API secret"
|
|
17736
|
+
},
|
|
17737
|
+
EXCHANGE_TESTNET_KEY_BINDING: {
|
|
17738
|
+
type: "secret",
|
|
17739
|
+
description: "Optional unified testnet API key"
|
|
17740
|
+
},
|
|
17741
|
+
EXCHANGE_TESTNET_SECRET_BINDING: {
|
|
17742
|
+
type: "secret",
|
|
17743
|
+
description: "Optional unified testnet API secret"
|
|
17744
|
+
}
|
|
17661
17745
|
},
|
|
17662
17746
|
services: [
|
|
17663
17747
|
{
|
|
@@ -17699,6 +17783,7 @@ var init_registry = __esm(() => {
|
|
|
17699
17783
|
"telegram-worker": {
|
|
17700
17784
|
name: "telegram-worker",
|
|
17701
17785
|
path: "workers/telegram-worker",
|
|
17786
|
+
defaultEnabled: true,
|
|
17702
17787
|
vars: {
|
|
17703
17788
|
INTERNAL_KEY_BINDING: {
|
|
17704
17789
|
type: "secret",
|
|
@@ -17712,6 +17797,10 @@ var init_registry = __esm(() => {
|
|
|
17712
17797
|
TELEGRAM_SECRET_TOKEN: {
|
|
17713
17798
|
type: "secret",
|
|
17714
17799
|
description: "Webhook verification token"
|
|
17800
|
+
},
|
|
17801
|
+
AUTHORIZED_CHAT_IDS: {
|
|
17802
|
+
type: "secret",
|
|
17803
|
+
description: "Comma-separated chat IDs; inbound webhook fail-closed when unset; outbound /alert allowlist"
|
|
17715
17804
|
}
|
|
17716
17805
|
},
|
|
17717
17806
|
services: [],
|
|
@@ -17732,6 +17821,7 @@ var init_registry = __esm(() => {
|
|
|
17732
17821
|
"d1-worker": {
|
|
17733
17822
|
name: "d1-worker",
|
|
17734
17823
|
path: "workers/d1-worker",
|
|
17824
|
+
defaultEnabled: true,
|
|
17735
17825
|
vars: {
|
|
17736
17826
|
INTERNAL_KEY_BINDING: {
|
|
17737
17827
|
type: "secret",
|
|
@@ -17754,6 +17844,7 @@ var init_registry = __esm(() => {
|
|
|
17754
17844
|
"web3-wallet-worker": {
|
|
17755
17845
|
name: "web3-wallet-worker",
|
|
17756
17846
|
path: "workers/web3-wallet-worker",
|
|
17847
|
+
defaultEnabled: false,
|
|
17757
17848
|
vars: {
|
|
17758
17849
|
WALLET_PK_SECRET: { type: "secret", description: "Wallet private key" },
|
|
17759
17850
|
WALLET_MNEMONIC_SECRET: {
|
|
@@ -17774,6 +17865,7 @@ var init_registry = __esm(() => {
|
|
|
17774
17865
|
"agent-worker": {
|
|
17775
17866
|
name: "agent-worker",
|
|
17776
17867
|
path: "workers/agent-worker",
|
|
17868
|
+
defaultEnabled: true,
|
|
17777
17869
|
vars: {
|
|
17778
17870
|
AGENT_INTERNAL_KEY: { type: "secret", description: "Agent worker auth" },
|
|
17779
17871
|
INTERNAL_KEY_BINDING: {
|
|
@@ -17810,6 +17902,7 @@ var init_registry = __esm(() => {
|
|
|
17810
17902
|
"email-worker": {
|
|
17811
17903
|
name: "email-worker",
|
|
17812
17904
|
path: "workers/email-worker",
|
|
17905
|
+
defaultEnabled: false,
|
|
17813
17906
|
vars: {
|
|
17814
17907
|
INTERNAL_KEY_BINDING: {
|
|
17815
17908
|
type: "secret",
|
|
@@ -17847,6 +17940,7 @@ var init_registry = __esm(() => {
|
|
|
17847
17940
|
"analytics-worker": {
|
|
17848
17941
|
name: "analytics-worker",
|
|
17849
17942
|
path: "workers/analytics-worker",
|
|
17943
|
+
defaultEnabled: true,
|
|
17850
17944
|
vars: {
|
|
17851
17945
|
CLOUDFLARE_API_TOKEN: {
|
|
17852
17946
|
type: "secret",
|
|
@@ -17866,6 +17960,7 @@ var init_registry = __esm(() => {
|
|
|
17866
17960
|
"report-worker": {
|
|
17867
17961
|
name: "report-worker",
|
|
17868
17962
|
path: "workers/report-worker",
|
|
17963
|
+
defaultEnabled: false,
|
|
17869
17964
|
vars: {
|
|
17870
17965
|
CF_API_TOKEN_BINDING: {
|
|
17871
17966
|
type: "secret",
|
|
@@ -17900,6 +17995,7 @@ var init_registry = __esm(() => {
|
|
|
17900
17995
|
"pyne-worker": {
|
|
17901
17996
|
name: "pyne-worker",
|
|
17902
17997
|
path: "workers/pyne-worker",
|
|
17998
|
+
defaultEnabled: true,
|
|
17903
17999
|
vars: {
|
|
17904
18000
|
API_KEY: {
|
|
17905
18001
|
type: "secret",
|
|
@@ -17937,6 +18033,7 @@ var init_registry = __esm(() => {
|
|
|
17937
18033
|
dashboard: {
|
|
17938
18034
|
name: "dashboard",
|
|
17939
18035
|
path: "workers/dashboard",
|
|
18036
|
+
defaultEnabled: true,
|
|
17940
18037
|
vars: {
|
|
17941
18038
|
DASHBOARD_USER: {
|
|
17942
18039
|
type: "secret",
|
|
@@ -17979,6 +18076,14 @@ var init_registry = __esm(() => {
|
|
|
17979
18076
|
CALLED_BY = deriveCalledBy(manifests);
|
|
17980
18077
|
WORKER_MANIFESTS = manifests;
|
|
17981
18078
|
WORKER_NAMES = Object.keys(manifests).sort();
|
|
18079
|
+
WORKER_CATALOG = WORKER_NAMES.map((name) => {
|
|
18080
|
+
const m = manifests[name];
|
|
18081
|
+
return {
|
|
18082
|
+
name: m.name,
|
|
18083
|
+
path: m.path,
|
|
18084
|
+
defaultEnabled: m.defaultEnabled
|
|
18085
|
+
};
|
|
18086
|
+
});
|
|
17982
18087
|
});
|
|
17983
18088
|
|
|
17984
18089
|
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
@@ -19618,7 +19723,7 @@ function validateWranglerJsonc(workerName, manifest, jsoncContent) {
|
|
|
19618
19723
|
}
|
|
19619
19724
|
}
|
|
19620
19725
|
for (const [name, def] of Object.entries(manifest.vars)) {
|
|
19621
|
-
if (def.type === "secret" && !name.endsWith("_BINDING") && !name.endsWith("_SECRET") && !name.startsWith("CLOUDFLARE_") && name !== "TELEGRAM_SECRET_TOKEN" && name !== "MAILGUN_API_KEY" && name !== "EMAIL_SCAN_SUBJECT" && name !== "DASHBOARD_USER" && name !== "DASHBOARD_PASS" && name !== "SESSION_SECRET" && name !== "AGENT_INTERNAL_KEY") {
|
|
19726
|
+
if (def.type === "secret" && !name.endsWith("_BINDING") && !name.endsWith("_SECRET") && !name.startsWith("CLOUDFLARE_") && name !== "TELEGRAM_SECRET_TOKEN" && name !== "TELEGRAM_ALLOWED_CHAT_IDS" && name !== "AUTHORIZED_CHAT_IDS" && name !== "MAILGUN_API_KEY" && name !== "EMAIL_SCAN_SUBJECT" && name !== "DASHBOARD_USER" && name !== "DASHBOARD_PASS" && name !== "SESSION_SECRET" && name !== "AGENT_INTERNAL_KEY") {
|
|
19622
19727
|
errors3.push({
|
|
19623
19728
|
worker: workerName,
|
|
19624
19729
|
severity: "warning",
|
|
@@ -19735,6 +19840,8 @@ function generateWranglerJsonc(manifest) {
|
|
|
19735
19840
|
parts.push(` "vars": {`);
|
|
19736
19841
|
for (const [i, name] of varKeys.entries()) {
|
|
19737
19842
|
const def = manifest.vars[name];
|
|
19843
|
+
if (!def)
|
|
19844
|
+
continue;
|
|
19738
19845
|
const comma = i < varKeys.length - 1 ? "," : "";
|
|
19739
19846
|
const val = def.type === "secret" ? "__SECRET__" : JSON.stringify(def.default ?? "");
|
|
19740
19847
|
parts.push(` "${name}": ${val}${comma}`);
|
|
@@ -21561,7 +21668,7 @@ function getBackoffDelay(retryCount) {
|
|
|
21561
21668
|
if (retryCount <= 0)
|
|
21562
21669
|
return 0;
|
|
21563
21670
|
const index = Math.min(retryCount - 1, BACKOFF_SEQUENCE.length - 1);
|
|
21564
|
-
return BACKOFF_SEQUENCE[index];
|
|
21671
|
+
return BACKOFF_SEQUENCE[index] ?? 0;
|
|
21565
21672
|
}
|
|
21566
21673
|
var BACKOFF_SEQUENCE, MAX_RETRIES2 = 5, tradeStreamAbort = null, logStreamAbort = null, fetchWorkersGeneration = 0, reconnectTimer = null, scheduledReconnectTick = async () => {}, MAX_TRADES = 500, MAX_ALERTS = 100, MAX_LOGS = 1000, initialState2, useServiceStore;
|
|
21567
21674
|
var init_service_store = __esm(() => {
|
|
@@ -22218,7 +22325,10 @@ __export(exports_src, {
|
|
|
22218
22325
|
logKvTimestamp: () => logKvTimestamp,
|
|
22219
22326
|
loadDashboardManifestsFromRoot: () => loadDashboardManifestsFromRoot,
|
|
22220
22327
|
loadDashboardKvManifestFromRoot: () => loadDashboardKvManifestFromRoot,
|
|
22328
|
+
kvPutMany: () => kvPutMany,
|
|
22221
22329
|
kvManifestFromDashboardManifests: () => kvManifestFromDashboardManifests,
|
|
22330
|
+
kvGetManyAsRecord: () => kvGetManyAsRecord,
|
|
22331
|
+
kvGetMany: () => kvGetMany,
|
|
22222
22332
|
isWithinHooxHome: () => isWithinHooxHome,
|
|
22223
22333
|
isUnixModeGroupOrWorldAccessible: () => isUnixModeGroupOrWorldAccessible,
|
|
22224
22334
|
isTruthyKillSwitchFlag: () => isTruthyKillSwitchFlag,
|
|
@@ -22233,6 +22343,7 @@ __export(exports_src, {
|
|
|
22233
22343
|
healthCheck: () => healthCheck,
|
|
22234
22344
|
headersToObject: () => headersToObject,
|
|
22235
22345
|
hasOperatorClientCredentials: () => hasOperatorClientCredentials,
|
|
22346
|
+
getWorkerDefaultEnabled: () => getWorkerDefaultEnabled,
|
|
22236
22347
|
getTuiEntryCandidates: () => getTuiEntryCandidates,
|
|
22237
22348
|
getRememberedMonorepoRoot: () => getRememberedMonorepoRoot,
|
|
22238
22349
|
getRememberedMonorepoPath: () => getRememberedMonorepoPath,
|
|
@@ -22295,6 +22406,7 @@ __export(exports_src, {
|
|
|
22295
22406
|
WORKER_NAMES: () => WORKER_NAMES,
|
|
22296
22407
|
WORKER_MANIFESTS: () => WORKER_MANIFESTS,
|
|
22297
22408
|
WORKER_DEPENDENCIES: () => WORKER_DEPENDENCIES,
|
|
22409
|
+
WORKER_CATALOG: () => WORKER_CATALOG,
|
|
22298
22410
|
WIZARD_STATE_PATH: () => WIZARD_STATE_PATH,
|
|
22299
22411
|
WALLET_EXECUTE_AUTH_KEY_FIELDS: () => WALLET_EXECUTE_AUTH_KEY_FIELDS,
|
|
22300
22412
|
TradeSignalSchema: () => TradeSignalSchema,
|
|
@@ -22309,6 +22421,7 @@ __export(exports_src, {
|
|
|
22309
22421
|
PositionSchema: () => PositionSchema,
|
|
22310
22422
|
PRESETS: () => PRESETS,
|
|
22311
22423
|
LogLevelColor: () => LogLevelColor,
|
|
22424
|
+
KV_BULK_GET_MAX_KEYS: () => KV_BULK_GET_MAX_KEYS,
|
|
22312
22425
|
KVKeys: () => KVKeys,
|
|
22313
22426
|
KILL_SWITCH_KEYS: () => KILL_SWITCH_KEYS,
|
|
22314
22427
|
KILL_SWITCH_ACTIVE_PREFIX: () => KILL_SWITCH_ACTIVE_PREFIX,
|
|
@@ -25257,6 +25370,76 @@ ${e.errors.map((m3) => ` - ${m3}`).join(`
|
|
|
25257
25370
|
const config2 = this.ensureLoaded();
|
|
25258
25371
|
return Object.entries(config2.workers).filter(([, w]) => w.enabled).map(([name]) => name);
|
|
25259
25372
|
}
|
|
25373
|
+
listWorkerStatuses() {
|
|
25374
|
+
const config2 = this.ensureLoaded();
|
|
25375
|
+
const names = new Set([
|
|
25376
|
+
...WORKER_CATALOG.map((w) => w.name),
|
|
25377
|
+
...Object.keys(config2.workers ?? {})
|
|
25378
|
+
]);
|
|
25379
|
+
return [...names].sort().map((name) => {
|
|
25380
|
+
const catalog = WORKER_MANIFESTS[name];
|
|
25381
|
+
const cfg = config2.workers?.[name];
|
|
25382
|
+
return {
|
|
25383
|
+
name,
|
|
25384
|
+
path: cfg?.path ?? catalog?.path ?? `workers/${name}`,
|
|
25385
|
+
enabled: cfg?.enabled ?? catalog?.defaultEnabled ?? false,
|
|
25386
|
+
defaultEnabled: catalog?.defaultEnabled,
|
|
25387
|
+
inConfig: Boolean(cfg),
|
|
25388
|
+
inCatalog: Boolean(catalog)
|
|
25389
|
+
};
|
|
25390
|
+
});
|
|
25391
|
+
}
|
|
25392
|
+
async setWorkersEnabled(names, enabled) {
|
|
25393
|
+
this.ensureLoaded();
|
|
25394
|
+
const filePath = this.configPath;
|
|
25395
|
+
const file2 = Bun.file(filePath);
|
|
25396
|
+
if (!await file2.exists()) {
|
|
25397
|
+
throw new Error(`Config file not found: ${filePath}`);
|
|
25398
|
+
}
|
|
25399
|
+
let raw = await file2.text();
|
|
25400
|
+
const results = [];
|
|
25401
|
+
const unique = [...new Set(names.map((n3) => n3.trim()).filter(Boolean))];
|
|
25402
|
+
for (const name of unique) {
|
|
25403
|
+
const existing = this.config.workers?.[name];
|
|
25404
|
+
const catalog = WORKER_MANIFESTS[name];
|
|
25405
|
+
if (!existing && !catalog) {
|
|
25406
|
+
throw new Error(`Unknown worker "${name}". Known workers: ${WORKER_CATALOG.map((w) => w.name).join(", ")}`);
|
|
25407
|
+
}
|
|
25408
|
+
let seeded = false;
|
|
25409
|
+
if (!existing) {
|
|
25410
|
+
const entry = {
|
|
25411
|
+
enabled,
|
|
25412
|
+
path: catalog.path,
|
|
25413
|
+
vars: {},
|
|
25414
|
+
secrets: []
|
|
25415
|
+
};
|
|
25416
|
+
const seedEdits = modify(raw, ["workers", name], entry, {
|
|
25417
|
+
formattingOptions: JSONC_FORMAT,
|
|
25418
|
+
isArrayInsertion: false
|
|
25419
|
+
});
|
|
25420
|
+
raw = applyEdits(raw, seedEdits);
|
|
25421
|
+
seeded = true;
|
|
25422
|
+
} else {
|
|
25423
|
+
const edits = modify(raw, ["workers", name, "enabled"], enabled, {
|
|
25424
|
+
formattingOptions: JSONC_FORMAT
|
|
25425
|
+
});
|
|
25426
|
+
raw = applyEdits(raw, edits);
|
|
25427
|
+
}
|
|
25428
|
+
results.push({ name, enabled, seeded });
|
|
25429
|
+
}
|
|
25430
|
+
await Bun.write(filePath, raw);
|
|
25431
|
+
await this.load(filePath);
|
|
25432
|
+
return results;
|
|
25433
|
+
}
|
|
25434
|
+
async enableWorker(name) {
|
|
25435
|
+
await this.setWorkersEnabled([name], true);
|
|
25436
|
+
}
|
|
25437
|
+
async disableWorker(name) {
|
|
25438
|
+
await this.setWorkersEnabled([name], false);
|
|
25439
|
+
}
|
|
25440
|
+
getWorkerDefaultEnabled(name) {
|
|
25441
|
+
return getWorkerDefaultEnabled(name);
|
|
25442
|
+
}
|
|
25260
25443
|
validate() {
|
|
25261
25444
|
const errors4 = [];
|
|
25262
25445
|
if (!this.config) {
|
|
@@ -25309,9 +25492,16 @@ ${e.errors.map((m3) => ` - ${m3}`).join(`
|
|
|
25309
25492
|
return this.config;
|
|
25310
25493
|
}
|
|
25311
25494
|
}
|
|
25495
|
+
var JSONC_FORMAT;
|
|
25312
25496
|
var init_config_service = __esm(() => {
|
|
25313
25497
|
init_main();
|
|
25314
25498
|
init_src();
|
|
25499
|
+
JSONC_FORMAT = {
|
|
25500
|
+
tabSize: 2,
|
|
25501
|
+
insertSpaces: true,
|
|
25502
|
+
eol: `
|
|
25503
|
+
`
|
|
25504
|
+
};
|
|
25315
25505
|
});
|
|
25316
25506
|
|
|
25317
25507
|
// src/services/config/index.ts
|
|
@@ -25758,6 +25948,9 @@ class PrerequisitesService {
|
|
|
25758
25948
|
return { outdated: false };
|
|
25759
25949
|
}
|
|
25760
25950
|
const current2 = match[1];
|
|
25951
|
+
if (!current2) {
|
|
25952
|
+
return { outdated: false };
|
|
25953
|
+
}
|
|
25761
25954
|
const meetsMin = this.satisfies(current2, this.MINIMUM_WRANGLER);
|
|
25762
25955
|
return {
|
|
25763
25956
|
outdated: !meetsMin,
|
|
@@ -25814,7 +26007,7 @@ class PrerequisitesService {
|
|
|
25814
26007
|
});
|
|
25815
26008
|
const stdout2 = await new Response(proc.stdout).text();
|
|
25816
26009
|
const match = stdout2.match(/(\d+\.\d+)/);
|
|
25817
|
-
const version2 = match
|
|
26010
|
+
const version2 = match?.[1] ?? "unknown";
|
|
25818
26011
|
const [major, minor] = version2.split(".").map(Number);
|
|
25819
26012
|
const passed = (major ?? 0) >= 2 && (minor ?? 0) >= 40;
|
|
25820
26013
|
return {
|
|
@@ -26334,7 +26527,7 @@ var exports_schema_service = {};
|
|
|
26334
26527
|
__export(exports_schema_service, {
|
|
26335
26528
|
SchemaService: () => SchemaService
|
|
26336
26529
|
});
|
|
26337
|
-
import { readFileSync as
|
|
26530
|
+
import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
|
|
26338
26531
|
import { resolve as resolve4 } from "path";
|
|
26339
26532
|
|
|
26340
26533
|
class SchemaService {
|
|
@@ -26370,7 +26563,7 @@ class SchemaService {
|
|
|
26370
26563
|
const errors4 = [];
|
|
26371
26564
|
const isHooxProject = existsSync11(resolve4(this.projectRoot, "wrangler.jsonc")) || existsSync11(resolve4(this.projectRoot, "workers"));
|
|
26372
26565
|
try {
|
|
26373
|
-
const wranglerContent =
|
|
26566
|
+
const wranglerContent = readFileSync8(workerWranglerPath, "utf-8");
|
|
26374
26567
|
errors4.push(...validateWranglerJsonc(name, manifest, wranglerContent));
|
|
26375
26568
|
} catch (e) {
|
|
26376
26569
|
const isErrnoException = e instanceof Error && "code" in e;
|
|
@@ -26384,7 +26577,7 @@ class SchemaService {
|
|
|
26384
26577
|
});
|
|
26385
26578
|
}
|
|
26386
26579
|
try {
|
|
26387
|
-
const rootContent =
|
|
26580
|
+
const rootContent = readFileSync8(rootWranglerPath, "utf-8");
|
|
26388
26581
|
errors4.push(...validateRootSecrets(name, manifest, rootContent));
|
|
26389
26582
|
} catch (e) {
|
|
26390
26583
|
const errMessage = e instanceof Error ? e.message : String(e);
|
|
@@ -26395,7 +26588,7 @@ class SchemaService {
|
|
|
26395
26588
|
});
|
|
26396
26589
|
}
|
|
26397
26590
|
try {
|
|
26398
|
-
const devVarsContent =
|
|
26591
|
+
const devVarsContent = readFileSync8(devVarsPath, "utf-8");
|
|
26399
26592
|
errors4.push(...validateDevVars(name, manifest, devVarsContent));
|
|
26400
26593
|
} catch (e) {
|
|
26401
26594
|
const errMessage = e instanceof Error ? e.message : String(e);
|
|
@@ -26654,7 +26847,7 @@ var init_trace_service = __esm(() => {
|
|
|
26654
26847
|
});
|
|
26655
26848
|
|
|
26656
26849
|
// src/index.ts
|
|
26657
|
-
import { readFileSync as
|
|
26850
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
26658
26851
|
|
|
26659
26852
|
// ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/error.js
|
|
26660
26853
|
class CommanderError extends Error {
|
|
@@ -28857,7 +29050,13 @@ function formatTable(rows, opts = {}) {
|
|
|
28857
29050
|
const alignNumbers = opts.alignNumbers !== false;
|
|
28858
29051
|
const colorizeStatus = opts.colorizeStatus !== false;
|
|
28859
29052
|
const compact = opts.compact === true;
|
|
28860
|
-
const
|
|
29053
|
+
const firstRow = rows[0];
|
|
29054
|
+
if (!firstRow) {
|
|
29055
|
+
process.stdout.write(`${theme.dim("(empty)")}
|
|
29056
|
+
`);
|
|
29057
|
+
return;
|
|
29058
|
+
}
|
|
29059
|
+
const keys = Object.keys(firstRow);
|
|
28861
29060
|
const processed = rows.map((row) => {
|
|
28862
29061
|
const out = {};
|
|
28863
29062
|
for (const k of keys) {
|
|
@@ -28894,17 +29093,18 @@ function formatTable(rows, opts = {}) {
|
|
|
28894
29093
|
widths[key] = Math.max(widths[key], stripped);
|
|
28895
29094
|
}
|
|
28896
29095
|
}
|
|
28897
|
-
const topParts = keys.map((k) => "\u2500".repeat(widths[k] + 2));
|
|
29096
|
+
const topParts = keys.map((k) => "\u2500".repeat((widths[k] ?? 0) + 2));
|
|
28898
29097
|
const topBorder = `\u250C${topParts.join("\u252C")}\u2510`;
|
|
28899
29098
|
const sepBorder = `\u251C${topParts.join("\u253C")}\u2524`;
|
|
28900
29099
|
const botBorder = `\u2514${topParts.join("\u2534")}\u2518`;
|
|
28901
|
-
const headerCells = keys.map((k) => theme.bold(k.padEnd(widths[k])).toString());
|
|
29100
|
+
const headerCells = keys.map((k) => theme.bold(k.padEnd(widths[k] ?? 0)).toString());
|
|
28902
29101
|
const headerRow = `\u2502 ${headerCells.join(" \u2502 ")} \u2502`;
|
|
28903
29102
|
const dataRows = processed.map((row, rowIdx) => {
|
|
28904
29103
|
const isAlt = zebra && rowIdx % 2 === 0;
|
|
28905
29104
|
const cells = keys.map((k) => {
|
|
28906
29105
|
const value = row[k] ?? "";
|
|
28907
|
-
const
|
|
29106
|
+
const width = widths[k] ?? 0;
|
|
29107
|
+
const padded = numericColumns.has(k) ? value.padStart(width) : value.padEnd(width);
|
|
28908
29108
|
if (isAlt && !value.includes("\x1B")) {
|
|
28909
29109
|
return theme.textMuted(padded);
|
|
28910
29110
|
}
|
|
@@ -29027,11 +29227,11 @@ function levenshtein(a2, b) {
|
|
|
29027
29227
|
curr[0] = j;
|
|
29028
29228
|
for (let i = 1;i <= m; i++) {
|
|
29029
29229
|
const cost = s.charCodeAt(i - 1) === t.charCodeAt(j - 1) ? 0 : 1;
|
|
29030
|
-
curr[i] = Math.min(curr[i - 1] + 1, prev[i] + 1, prev[i - 1] + cost);
|
|
29230
|
+
curr[i] = Math.min((curr[i - 1] ?? 0) + 1, (prev[i] ?? 0) + 1, (prev[i - 1] ?? 0) + cost);
|
|
29031
29231
|
}
|
|
29032
29232
|
[prev, curr] = [curr, prev];
|
|
29033
29233
|
}
|
|
29034
|
-
return prev[m];
|
|
29234
|
+
return prev[m] ?? 0;
|
|
29035
29235
|
}
|
|
29036
29236
|
|
|
29037
29237
|
// src/utils/error-handler.ts
|
|
@@ -30480,6 +30680,8 @@ class SetupService {
|
|
|
30480
30680
|
if (!varsMatch)
|
|
30481
30681
|
continue;
|
|
30482
30682
|
const varsBlock = varsMatch[1];
|
|
30683
|
+
if (varsBlock === undefined)
|
|
30684
|
+
continue;
|
|
30483
30685
|
const nullEntries = varsBlock.match(/"\w+"\s*:\s*null/g);
|
|
30484
30686
|
if (!nullEntries)
|
|
30485
30687
|
continue;
|
|
@@ -31614,46 +31816,32 @@ class EnvService {
|
|
|
31614
31816
|
hint: "Telegram webhook secret token"
|
|
31615
31817
|
},
|
|
31616
31818
|
{
|
|
31617
|
-
name: "
|
|
31618
|
-
required: false,
|
|
31619
|
-
secret: true,
|
|
31620
|
-
section: "Exchanges",
|
|
31621
|
-
hint: "Binance API key"
|
|
31622
|
-
},
|
|
31623
|
-
{
|
|
31624
|
-
name: "BINANCE_SECRET_BINDING",
|
|
31625
|
-
required: false,
|
|
31626
|
-
secret: true,
|
|
31627
|
-
section: "Exchanges",
|
|
31628
|
-
hint: "Binance API secret"
|
|
31629
|
-
},
|
|
31630
|
-
{
|
|
31631
|
-
name: "MEXC_KEY_BINDING",
|
|
31819
|
+
name: "EXCHANGE_KEY_BINDING",
|
|
31632
31820
|
required: false,
|
|
31633
31821
|
secret: true,
|
|
31634
31822
|
section: "Exchanges",
|
|
31635
|
-
hint: "
|
|
31823
|
+
hint: "Unified exchange API key (Binance / Bybit / MEXC \u2014 venue via routing)"
|
|
31636
31824
|
},
|
|
31637
31825
|
{
|
|
31638
|
-
name: "
|
|
31826
|
+
name: "EXCHANGE_SECRET_BINDING",
|
|
31639
31827
|
required: false,
|
|
31640
31828
|
secret: true,
|
|
31641
31829
|
section: "Exchanges",
|
|
31642
|
-
hint: "
|
|
31830
|
+
hint: "Unified exchange API secret"
|
|
31643
31831
|
},
|
|
31644
31832
|
{
|
|
31645
|
-
name: "
|
|
31833
|
+
name: "EXCHANGE_TESTNET_KEY_BINDING",
|
|
31646
31834
|
required: false,
|
|
31647
31835
|
secret: true,
|
|
31648
31836
|
section: "Exchanges",
|
|
31649
|
-
hint: "
|
|
31837
|
+
hint: "Optional testnet API key (when signals use test: true)"
|
|
31650
31838
|
},
|
|
31651
31839
|
{
|
|
31652
|
-
name: "
|
|
31840
|
+
name: "EXCHANGE_TESTNET_SECRET_BINDING",
|
|
31653
31841
|
required: false,
|
|
31654
31842
|
secret: true,
|
|
31655
31843
|
section: "Exchanges",
|
|
31656
|
-
hint: "
|
|
31844
|
+
hint: "Optional testnet API secret"
|
|
31657
31845
|
},
|
|
31658
31846
|
{
|
|
31659
31847
|
name: "EMAIL_HOST_BINDING",
|
|
@@ -31824,12 +32012,8 @@ class EnvService {
|
|
|
31824
32012
|
"workers/trade-worker": [
|
|
31825
32013
|
"API_SERVICE_KEY_BINDING",
|
|
31826
32014
|
"INTERNAL_KEY_BINDING",
|
|
31827
|
-
"
|
|
31828
|
-
"
|
|
31829
|
-
"MEXC_KEY_BINDING",
|
|
31830
|
-
"MEXC_SECRET_BINDING",
|
|
31831
|
-
"BYBIT_KEY_BINDING",
|
|
31832
|
-
"BYBIT_SECRET_BINDING"
|
|
32015
|
+
"EXCHANGE_KEY_BINDING",
|
|
32016
|
+
"EXCHANGE_SECRET_BINDING"
|
|
31833
32017
|
],
|
|
31834
32018
|
"workers/agent-worker": ["AGENT_INTERNAL_KEY"],
|
|
31835
32019
|
"workers/d1-worker": ["INTERNAL_KEY_BINDING"],
|
|
@@ -33724,6 +33908,27 @@ var SYSTEM_SECRET_NAMES = [
|
|
|
33724
33908
|
"API_SERVICE_KEY_BINDING"
|
|
33725
33909
|
];
|
|
33726
33910
|
var SYSTEM_SECRET_SET = new Set(SYSTEM_SECRET_NAMES);
|
|
33911
|
+
var WORKER_SYSTEM_SECRETS = {
|
|
33912
|
+
"d1-worker": ["INTERNAL_KEY_BINDING"],
|
|
33913
|
+
"analytics-worker": ["INTERNAL_KEY_BINDING"],
|
|
33914
|
+
"trade-worker": [
|
|
33915
|
+
"INTERNAL_KEY_BINDING",
|
|
33916
|
+
"TELEGRAM_INTERNAL_KEY_BINDING",
|
|
33917
|
+
"API_SERVICE_KEY_BINDING"
|
|
33918
|
+
],
|
|
33919
|
+
"report-worker": ["INTERNAL_KEY_BINDING"],
|
|
33920
|
+
"email-worker": ["INTERNAL_KEY_BINDING"],
|
|
33921
|
+
"agent-worker": ["INTERNAL_KEY_BINDING", "AGENT_INTERNAL_KEY"],
|
|
33922
|
+
hoox: ["INTERNAL_KEY_BINDING", "WEBHOOK_API_KEY_BINDING"],
|
|
33923
|
+
"web3-wallet-worker": ["INTERNAL_KEY_BINDING"],
|
|
33924
|
+
"telegram-worker": ["INTERNAL_KEY_BINDING"],
|
|
33925
|
+
dashboard: [
|
|
33926
|
+
"AGENT_INTERNAL_KEY",
|
|
33927
|
+
"SESSION_SECRET",
|
|
33928
|
+
"TRADE_INTERNAL_KEY",
|
|
33929
|
+
"API_SERVICE_KEY_BINDING"
|
|
33930
|
+
]
|
|
33931
|
+
};
|
|
33727
33932
|
function isSystemSecret(name) {
|
|
33728
33933
|
return SYSTEM_SECRET_SET.has(name);
|
|
33729
33934
|
}
|
|
@@ -33844,11 +34049,19 @@ class SecretsService {
|
|
|
33844
34049
|
const content = await devVarsFile.text();
|
|
33845
34050
|
existingValues = this.parseDotEnv(content);
|
|
33846
34051
|
}
|
|
34052
|
+
let keysFallback = new Map;
|
|
34053
|
+
if (options.systemOnly) {
|
|
34054
|
+
const keysFile = Bun.file(".keys/setup.env");
|
|
34055
|
+
if (await keysFile.exists()) {
|
|
34056
|
+
keysFallback = this.parseDotEnv(await keysFile.text());
|
|
34057
|
+
}
|
|
34058
|
+
}
|
|
33847
34059
|
let secrets;
|
|
33848
34060
|
if (options.systemOnly) {
|
|
33849
34061
|
const fromDeclared = declared.filter((s) => isSystemSecret(s));
|
|
33850
34062
|
const fromDevVars = [...SYSTEM_SECRET_NAMES].filter((s) => existingValues.has(s));
|
|
33851
|
-
|
|
34063
|
+
const fromMap = [...WORKER_SYSTEM_SECRETS[workerName] ?? []];
|
|
34064
|
+
secrets = [...new Set([...fromDeclared, ...fromDevVars, ...fromMap])];
|
|
33852
34065
|
} else {
|
|
33853
34066
|
secrets = declared;
|
|
33854
34067
|
}
|
|
@@ -33858,7 +34071,7 @@ class SecretsService {
|
|
|
33858
34071
|
const items = [];
|
|
33859
34072
|
for (const secret of secrets) {
|
|
33860
34073
|
try {
|
|
33861
|
-
const value = existingValues.get(secret);
|
|
34074
|
+
const value = existingValues.get(secret) ?? keysFallback.get(secret);
|
|
33862
34075
|
if (value !== undefined && !this.isPlaceholder(value)) {
|
|
33863
34076
|
await this.execWranglerSecretPut(worker.path, secret, value, workerName);
|
|
33864
34077
|
synced.push(secret);
|
|
@@ -34138,8 +34351,8 @@ The command will prompt for the secret value (hidden input).
|
|
|
34138
34351
|
It writes to the worker's .dev.vars file and syncs to Cloudflare.
|
|
34139
34352
|
|
|
34140
34353
|
EXAMPLES:
|
|
34141
|
-
hoox secrets set trade-worker
|
|
34142
|
-
hoox config secrets set trade-worker
|
|
34354
|
+
hoox secrets set trade-worker EXCHANGE_KEY_BINDING
|
|
34355
|
+
hoox config secrets set trade-worker EXCHANGE_KEY_BINDING`).action(withErrorHandling(async (workerName, secretName, _2, cmd) => {
|
|
34143
34356
|
const opts = getFormatOptions(cmd);
|
|
34144
34357
|
const svc = await SecretsService.create();
|
|
34145
34358
|
const declared = svc.listSecrets(workerName);
|
|
@@ -34184,8 +34397,8 @@ ARGUMENTS:
|
|
|
34184
34397
|
This removes the secret from Cloudflare and from the worker's .dev.vars file.
|
|
34185
34398
|
|
|
34186
34399
|
EXAMPLES:
|
|
34187
|
-
hoox secrets delete trade-worker
|
|
34188
|
-
hoox config secrets delete trade-worker
|
|
34400
|
+
hoox secrets delete trade-worker EXCHANGE_KEY_BINDING
|
|
34401
|
+
hoox config secrets delete trade-worker EXCHANGE_KEY_BINDING`).action(withErrorHandling(async (workerName, secretName, _2, cmd) => {
|
|
34189
34402
|
const opts = getFormatOptions(cmd);
|
|
34190
34403
|
const svc = await SecretsService.create();
|
|
34191
34404
|
const declared = svc.listSecrets(workerName);
|
|
@@ -34327,7 +34540,7 @@ EXAMPLES:
|
|
|
34327
34540
|
}
|
|
34328
34541
|
|
|
34329
34542
|
// src/commands/config/keys-subcommands.ts
|
|
34330
|
-
import { existsSync as existsSync9 } from "fs";
|
|
34543
|
+
import { chmodSync as chmodSync6, existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
34331
34544
|
init_fs_secure();
|
|
34332
34545
|
init_theme();
|
|
34333
34546
|
function generateKey(bytes = 32) {
|
|
@@ -34335,6 +34548,82 @@ function generateKey(bytes = 32) {
|
|
|
34335
34548
|
crypto.getRandomValues(buf);
|
|
34336
34549
|
return Array.from(buf, (b3) => b3.toString(16).padStart(2, "0")).join("");
|
|
34337
34550
|
}
|
|
34551
|
+
var DEV_VARS_WORKER_KEYS2 = {
|
|
34552
|
+
"d1-worker": ["INTERNAL_KEY_BINDING"],
|
|
34553
|
+
"analytics-worker": ["INTERNAL_KEY_BINDING"],
|
|
34554
|
+
"trade-worker": [
|
|
34555
|
+
"INTERNAL_KEY_BINDING",
|
|
34556
|
+
"TELEGRAM_INTERNAL_KEY_BINDING",
|
|
34557
|
+
"API_SERVICE_KEY_BINDING"
|
|
34558
|
+
],
|
|
34559
|
+
"report-worker": ["INTERNAL_KEY_BINDING"],
|
|
34560
|
+
"email-worker": ["INTERNAL_KEY_BINDING"],
|
|
34561
|
+
"agent-worker": ["INTERNAL_KEY_BINDING", "AGENT_INTERNAL_KEY"],
|
|
34562
|
+
hoox: ["INTERNAL_KEY_BINDING", "WEBHOOK_API_KEY_BINDING"],
|
|
34563
|
+
"web3-wallet-worker": ["INTERNAL_KEY_BINDING"],
|
|
34564
|
+
"telegram-worker": ["INTERNAL_KEY_BINDING"],
|
|
34565
|
+
dashboard: [
|
|
34566
|
+
"AGENT_INTERNAL_KEY",
|
|
34567
|
+
"SESSION_SECRET",
|
|
34568
|
+
"TRADE_INTERNAL_KEY",
|
|
34569
|
+
"API_SERVICE_KEY_BINDING"
|
|
34570
|
+
]
|
|
34571
|
+
};
|
|
34572
|
+
var WORKER_FS_DIR2 = {
|
|
34573
|
+
hoox: "hoox-worker"
|
|
34574
|
+
};
|
|
34575
|
+
function workerFsDir2(worker) {
|
|
34576
|
+
return WORKER_FS_DIR2[worker] ?? worker;
|
|
34577
|
+
}
|
|
34578
|
+
function parseEnvFile2(text2) {
|
|
34579
|
+
const map2 = new Map;
|
|
34580
|
+
for (const line of text2.split(`
|
|
34581
|
+
`)) {
|
|
34582
|
+
const trimmed = line.trim();
|
|
34583
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
34584
|
+
continue;
|
|
34585
|
+
const eq = trimmed.indexOf("=");
|
|
34586
|
+
if (eq <= 0)
|
|
34587
|
+
continue;
|
|
34588
|
+
map2.set(trimmed.slice(0, eq), trimmed.slice(eq + 1));
|
|
34589
|
+
}
|
|
34590
|
+
return map2;
|
|
34591
|
+
}
|
|
34592
|
+
async function writeDevVarsFromKeys(keys) {
|
|
34593
|
+
let count = 0;
|
|
34594
|
+
for (const [worker, secretNames] of Object.entries(DEV_VARS_WORKER_KEYS2)) {
|
|
34595
|
+
const path5 = `workers/${workerFsDir2(worker)}/.dev.vars`;
|
|
34596
|
+
const meshSet = new Set(secretNames);
|
|
34597
|
+
const existing = existsSync9(path5) ? parseEnvFile2(readFileSync7(path5, "utf-8")) : new Map;
|
|
34598
|
+
for (const secretName of secretNames) {
|
|
34599
|
+
const value = keys[secretName];
|
|
34600
|
+
if (value)
|
|
34601
|
+
existing.set(secretName, value);
|
|
34602
|
+
}
|
|
34603
|
+
let content = `# .dev.vars \u2014 local secrets for ${worker}
|
|
34604
|
+
`;
|
|
34605
|
+
content += `# Generated by \`hoox keys generate\`. NEVER commit this file.
|
|
34606
|
+
|
|
34607
|
+
`;
|
|
34608
|
+
for (const secretName of secretNames) {
|
|
34609
|
+
const value = existing.get(secretName);
|
|
34610
|
+
if (value !== undefined)
|
|
34611
|
+
content += `${secretName}=${value}
|
|
34612
|
+
`;
|
|
34613
|
+
}
|
|
34614
|
+
for (const [k, v] of existing) {
|
|
34615
|
+
if (!meshSet.has(k))
|
|
34616
|
+
content += `${k}=${v}
|
|
34617
|
+
`;
|
|
34618
|
+
}
|
|
34619
|
+
await Bun.write(path5, content);
|
|
34620
|
+
try {
|
|
34621
|
+
chmodSync6(path5, 384);
|
|
34622
|
+
} catch {}
|
|
34623
|
+
count++;
|
|
34624
|
+
}
|
|
34625
|
+
return count;
|
|
34626
|
+
}
|
|
34338
34627
|
function registerKeysSubcommands(keysCmd, service = "config") {
|
|
34339
34628
|
keysCmd.command("generate").summary("Generate new internal auth keys").description(`Generate new internal auth keys and save to .keys/ directory.
|
|
34340
34629
|
|
|
@@ -34376,9 +34665,12 @@ EXAMPLES:
|
|
|
34376
34665
|
`) + `
|
|
34377
34666
|
`);
|
|
34378
34667
|
secureSecretFile(`${keysDir}/setup.env`);
|
|
34379
|
-
|
|
34668
|
+
const devVarsCount = await writeDevVarsFromKeys(keys);
|
|
34669
|
+
formatSuccess(`Generated ${Object.keys(keys).length} keys in ${keysDir}/ + ${devVarsCount} .dev.vars`, opts);
|
|
34380
34670
|
if (!opts.quiet && !opts.json) {
|
|
34381
34671
|
process.stdout.write(`${theme.warning("!")} Keep these keys secret. Add ${keysDir}/ to .gitignore.
|
|
34672
|
+
`);
|
|
34673
|
+
process.stdout.write(`${theme.dim("\u2192")} Next: hoox secrets sync --system
|
|
34382
34674
|
`);
|
|
34383
34675
|
formatKeyValue(keys, opts);
|
|
34384
34676
|
}
|
|
@@ -34476,7 +34768,7 @@ EXAMPLES:
|
|
|
34476
34768
|
hoox config show Display current configuration
|
|
34477
34769
|
hoox config set workers.agent-worker.enabled false
|
|
34478
34770
|
hoox config secrets list List secrets for a worker
|
|
34479
|
-
hoox config secrets set trade-worker
|
|
34771
|
+
hoox config secrets set trade-worker EXCHANGE_KEY_BINDING
|
|
34480
34772
|
hoox config keys generate Generate new internal keys`);
|
|
34481
34773
|
configCmd.command("show").summary("Display current wrangler.jsonc configuration").description(`Display the current wrangler.jsonc configuration in a formatted table.
|
|
34482
34774
|
|
|
@@ -34671,7 +34963,7 @@ COMMANDS:
|
|
|
34671
34963
|
|
|
34672
34964
|
EXAMPLES:
|
|
34673
34965
|
hoox secrets list trade-worker
|
|
34674
|
-
hoox secrets set trade-worker
|
|
34966
|
+
hoox secrets set trade-worker EXCHANGE_KEY_BINDING
|
|
34675
34967
|
hoox secrets sync --system
|
|
34676
34968
|
hoox secrets sync`);
|
|
34677
34969
|
registerSecretsSubcommands(cmd, "secrets");
|
|
@@ -36223,11 +36515,19 @@ async function resolveZone(cf) {
|
|
|
36223
36515
|
if (lines.length === 0) {
|
|
36224
36516
|
throw new CLIError("No zones found. Set CLOUDFLARE_ZONE_ID environment variable.", 1 /* ERROR */);
|
|
36225
36517
|
}
|
|
36226
|
-
const
|
|
36518
|
+
const firstLine = lines[0];
|
|
36519
|
+
if (!firstLine) {
|
|
36520
|
+
throw new CLIError("No zones found. Set CLOUDFLARE_ZONE_ID environment variable.", 1 /* ERROR */);
|
|
36521
|
+
}
|
|
36522
|
+
const match = firstLine.match(/^(.+?)\s+\((.+?)\)\s*$/);
|
|
36227
36523
|
if (match) {
|
|
36228
|
-
|
|
36524
|
+
const name = match[1];
|
|
36525
|
+
const id = match[2];
|
|
36526
|
+
if (name && id) {
|
|
36527
|
+
return { name, id };
|
|
36528
|
+
}
|
|
36229
36529
|
}
|
|
36230
|
-
return { name:
|
|
36530
|
+
return { name: firstLine, id: firstLine };
|
|
36231
36531
|
}
|
|
36232
36532
|
async function handleStatus(opts) {
|
|
36233
36533
|
const cf = new CloudflareService;
|
|
@@ -36545,6 +36845,8 @@ EXAMPLES:
|
|
|
36545
36845
|
const results = [];
|
|
36546
36846
|
for (let i2 = 0;i2 < workers.length; i2++) {
|
|
36547
36847
|
const name2 = workers[i2];
|
|
36848
|
+
if (!name2)
|
|
36849
|
+
continue;
|
|
36548
36850
|
const workerConfig = configService.getWorker(name2);
|
|
36549
36851
|
if (!workerConfig)
|
|
36550
36852
|
continue;
|
|
@@ -36822,7 +37124,11 @@ class DbService {
|
|
|
36822
37124
|
if (!match) {
|
|
36823
37125
|
throw new Error(`Migration script "${path6}" was found but no \`d1 execute \u2026 --command="\u2026"\` line could be extracted. ` + `Refusing to fall back to a no-op migration \u2014 please check the script format.`);
|
|
36824
37126
|
}
|
|
36825
|
-
|
|
37127
|
+
const command = match[1];
|
|
37128
|
+
if (!command) {
|
|
37129
|
+
throw new Error(`Migration script "${path6}" was found but no \`d1 execute \u2026 --command="\u2026"\` line could be extracted. ` + `Refusing to fall back to a no-op migration \u2014 please check the script format.`);
|
|
37130
|
+
}
|
|
37131
|
+
return command;
|
|
36826
37132
|
}
|
|
36827
37133
|
}
|
|
36828
37134
|
// src/commands/db/db-command.ts
|
|
@@ -37129,15 +37435,19 @@ function parseWranglerQueuesTable(raw) {
|
|
|
37129
37435
|
const cells = line.split("\u2502").map((c3) => c3.trim()).filter((c3) => c3.length > 0);
|
|
37130
37436
|
if (cells.length < 2)
|
|
37131
37437
|
continue;
|
|
37132
|
-
|
|
37438
|
+
const queueId = cells[0];
|
|
37439
|
+
const queueName = cells[1];
|
|
37440
|
+
if (!queueId || !queueName)
|
|
37133
37441
|
continue;
|
|
37134
|
-
if (
|
|
37442
|
+
if (queueId === "id" || queueId === "name")
|
|
37443
|
+
continue;
|
|
37444
|
+
if (!/^[0-9a-f-]{16,}$/i.test(queueId))
|
|
37135
37445
|
continue;
|
|
37136
37446
|
const producers = cells[4] !== undefined && cells[4] !== "" ? Number(cells[4]) : undefined;
|
|
37137
37447
|
const consumers = cells[5] !== undefined && cells[5] !== "" ? Number(cells[5]) : undefined;
|
|
37138
37448
|
queues.push({
|
|
37139
|
-
queue_id:
|
|
37140
|
-
queue_name:
|
|
37449
|
+
queue_id: queueId,
|
|
37450
|
+
queue_name: queueName,
|
|
37141
37451
|
created_on: cells[2],
|
|
37142
37452
|
modified_on: cells[3],
|
|
37143
37453
|
producers_total_count: Number.isFinite(producers) ? producers : undefined,
|
|
@@ -37322,57 +37632,151 @@ SUBCOMMANDS:
|
|
|
37322
37632
|
}, { service: "monitor" }));
|
|
37323
37633
|
}
|
|
37324
37634
|
// src/commands/workers/workers-command.ts
|
|
37635
|
+
init_src();
|
|
37325
37636
|
init_config2();
|
|
37637
|
+
init_errors4();
|
|
37326
37638
|
async function doListWorkers(fmt) {
|
|
37327
37639
|
const configService = new ConfigService;
|
|
37328
37640
|
await configService.load();
|
|
37329
|
-
const
|
|
37330
|
-
const rows =
|
|
37331
|
-
|
|
37332
|
-
|
|
37333
|
-
|
|
37334
|
-
|
|
37335
|
-
|
|
37336
|
-
|
|
37337
|
-
|
|
37338
|
-
|
|
37641
|
+
const statuses = configService.listWorkerStatuses();
|
|
37642
|
+
const rows = statuses.map((w) => ({
|
|
37643
|
+
Worker: w.name,
|
|
37644
|
+
Status: w.enabled ? "enabled" : "disabled",
|
|
37645
|
+
Default: w.defaultEnabled === undefined ? "-" : w.defaultEnabled ? "enabled" : "disabled",
|
|
37646
|
+
Path: w.path,
|
|
37647
|
+
Config: w.inConfig ? "yes" : "no",
|
|
37648
|
+
Catalog: w.inCatalog ? "yes" : "no"
|
|
37649
|
+
}));
|
|
37650
|
+
if (fmt.json) {
|
|
37651
|
+
formatJson(statuses.map((w) => ({
|
|
37652
|
+
name: w.name,
|
|
37653
|
+
enabled: w.enabled,
|
|
37654
|
+
defaultEnabled: w.defaultEnabled ?? null,
|
|
37655
|
+
path: w.path,
|
|
37656
|
+
inConfig: w.inConfig,
|
|
37657
|
+
inCatalog: w.inCatalog
|
|
37658
|
+
})), fmt);
|
|
37659
|
+
return;
|
|
37660
|
+
}
|
|
37661
|
+
formatTable(rows, fmt);
|
|
37662
|
+
}
|
|
37663
|
+
function doCatalog(fmt) {
|
|
37664
|
+
const rows = WORKER_CATALOG.map((w) => ({
|
|
37665
|
+
Worker: w.name,
|
|
37666
|
+
Default: w.defaultEnabled ? "enabled" : "disabled",
|
|
37667
|
+
Path: w.path
|
|
37668
|
+
}));
|
|
37339
37669
|
if (fmt.json) {
|
|
37340
|
-
formatJson(
|
|
37670
|
+
formatJson(WORKER_CATALOG.map((w) => ({
|
|
37671
|
+
name: w.name,
|
|
37672
|
+
defaultEnabled: w.defaultEnabled,
|
|
37673
|
+
path: w.path
|
|
37674
|
+
})), fmt);
|
|
37341
37675
|
return;
|
|
37342
37676
|
}
|
|
37343
37677
|
formatTable(rows, fmt);
|
|
37344
37678
|
}
|
|
37679
|
+
async function doSetEnabled(names, enabled, fmt) {
|
|
37680
|
+
if (names.length === 0) {
|
|
37681
|
+
throw new CLIError(`Specify at least one worker name (e.g. hoox workers ${enabled ? "enable" : "disable"} trade-worker)`, 2 /* INVALID_USAGE */, undefined, true, `Run \`hoox workers catalog\` to see known workers.`);
|
|
37682
|
+
}
|
|
37683
|
+
const configService = new ConfigService;
|
|
37684
|
+
await configService.load();
|
|
37685
|
+
let results;
|
|
37686
|
+
try {
|
|
37687
|
+
results = await configService.setWorkersEnabled(names, enabled);
|
|
37688
|
+
} catch (e) {
|
|
37689
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
37690
|
+
throw new CLIError(msg, 2 /* INVALID_USAGE */, undefined, true);
|
|
37691
|
+
}
|
|
37692
|
+
if (fmt.json) {
|
|
37693
|
+
formatJson({ action: enabled ? "enable" : "disable", results }, fmt);
|
|
37694
|
+
return;
|
|
37695
|
+
}
|
|
37696
|
+
for (const r2 of results) {
|
|
37697
|
+
const seedNote = r2.seeded ? " (seeded from catalog)" : "";
|
|
37698
|
+
formatSuccess(`${r2.name} \u2192 ${r2.enabled ? "enabled" : "disabled"}${seedNote}`, fmt);
|
|
37699
|
+
}
|
|
37700
|
+
}
|
|
37345
37701
|
function registerWorkersCommand(program2) {
|
|
37346
|
-
const workersCmd = program2.command("workers").summary("Manage Cloudflare Workers (list, dev, logs)").description(`Manage your Hoox Cloudflare Workers.
|
|
37702
|
+
const workersCmd = program2.command("workers").summary("Manage Cloudflare Workers (list, enable, disable, dev, logs)").description(`Manage your Hoox Cloudflare Workers.
|
|
37347
37703
|
|
|
37348
37704
|
SUBCOMMANDS:
|
|
37349
|
-
list List all workers
|
|
37705
|
+
list List all workers (catalog + config) with status
|
|
37706
|
+
catalog Show the canonical worker catalog and defaults
|
|
37707
|
+
enable <name...> Enable workers in wrangler.jsonc
|
|
37708
|
+
disable <name...> Disable workers in wrangler.jsonc
|
|
37350
37709
|
dev <name> Start a worker for local development (delegates to dev worker)
|
|
37351
37710
|
logs <name> Tail logs for a specific worker (delegates to logs worker)
|
|
37352
37711
|
|
|
37712
|
+
The worker catalog (shared package) is the source of all known workers and
|
|
37713
|
+
their default enabled flags. Enable/disable updates workers.<name>.enabled
|
|
37714
|
+
in the root wrangler.jsonc. Missing catalog workers are seeded on enable.
|
|
37715
|
+
|
|
37353
37716
|
For health checks, use 'hoox check health'.
|
|
37354
37717
|
For deployments, use 'hoox deploy workers' or 'hoox deploy worker <name>'.
|
|
37355
37718
|
|
|
37356
37719
|
EXAMPLES:
|
|
37357
|
-
hoox workers list
|
|
37358
|
-
hoox workers
|
|
37359
|
-
hoox workers
|
|
37360
|
-
hoox workers
|
|
37361
|
-
|
|
37362
|
-
|
|
37363
|
-
|
|
37364
|
-
|
|
37365
|
-
|
|
37366
|
-
-
|
|
37367
|
-
-
|
|
37720
|
+
hoox workers list
|
|
37721
|
+
hoox workers catalog
|
|
37722
|
+
hoox workers enable trade-worker agent-worker
|
|
37723
|
+
hoox workers disable web3-wallet-worker email-worker
|
|
37724
|
+
hoox workers dev trade-worker
|
|
37725
|
+
hoox workers logs hoox`);
|
|
37726
|
+
workersCmd.command("list").summary("List workers with enabled status (catalog + config)").description(`List all workers from the shared catalog merged with wrangler.jsonc.
|
|
37727
|
+
|
|
37728
|
+
Columns:
|
|
37729
|
+
- Worker name
|
|
37730
|
+
- Status (effective enabled/disabled)
|
|
37731
|
+
- Default (catalog default)
|
|
37732
|
+
- Path
|
|
37733
|
+
- Config / Catalog membership
|
|
37368
37734
|
|
|
37369
37735
|
EXAMPLES:
|
|
37370
|
-
hoox workers list
|
|
37371
|
-
hoox workers list --json
|
|
37372
|
-
hoox workers list --quiet Minimal output`).action(withErrorHandling(async (_opts, cmd) => {
|
|
37736
|
+
hoox workers list
|
|
37737
|
+
hoox workers list --json`).action(withErrorHandling(async (_opts, cmd) => {
|
|
37373
37738
|
const fmt = getFormatOptions(cmd);
|
|
37374
37739
|
await doListWorkers(fmt);
|
|
37375
37740
|
}, { service: "workers" }));
|
|
37741
|
+
workersCmd.command("catalog").summary("Show the canonical worker catalog with defaults").description(`Print the shared worker catalog \u2014 every known worker and its default
|
|
37742
|
+
enabled flag. This is the source of truth used when seeding missing workers
|
|
37743
|
+
on enable.
|
|
37744
|
+
|
|
37745
|
+
EXAMPLES:
|
|
37746
|
+
hoox workers catalog
|
|
37747
|
+
hoox workers catalog --json`).action(withErrorHandling(async (_opts, cmd) => {
|
|
37748
|
+
const fmt = getFormatOptions(cmd);
|
|
37749
|
+
doCatalog(fmt);
|
|
37750
|
+
}, { service: "workers" }));
|
|
37751
|
+
workersCmd.command("enable").argument("<names...>", "Worker name(s) to enable").summary("Enable one or more workers in wrangler.jsonc").description(`Set workers.<name>.enabled = true in the root wrangler.jsonc.
|
|
37752
|
+
|
|
37753
|
+
If a worker exists in the catalog but not in config, it is seeded with
|
|
37754
|
+
path/secrets from the catalog and enabled.
|
|
37755
|
+
|
|
37756
|
+
ARGUMENTS:
|
|
37757
|
+
names One or more worker names (e.g. trade-worker email-worker)
|
|
37758
|
+
|
|
37759
|
+
EXAMPLES:
|
|
37760
|
+
hoox workers enable trade-worker
|
|
37761
|
+
hoox workers enable report-worker web3-wallet-worker
|
|
37762
|
+
hoox workers enable dashboard --json`).action(withErrorHandling(async (names, _opts, cmd) => {
|
|
37763
|
+
const fmt = getFormatOptions(cmd);
|
|
37764
|
+
await doSetEnabled(names, true, fmt);
|
|
37765
|
+
}, { service: "workers" }));
|
|
37766
|
+
workersCmd.command("disable").argument("<names...>", "Worker name(s) to disable").summary("Disable one or more workers in wrangler.jsonc").description(`Set workers.<name>.enabled = false in the root wrangler.jsonc.
|
|
37767
|
+
|
|
37768
|
+
Disabled workers are skipped by deploy/logs/all flows that use
|
|
37769
|
+
ConfigService.listEnabledWorkers().
|
|
37770
|
+
|
|
37771
|
+
ARGUMENTS:
|
|
37772
|
+
names One or more worker names
|
|
37773
|
+
|
|
37774
|
+
EXAMPLES:
|
|
37775
|
+
hoox workers disable email-worker
|
|
37776
|
+
hoox workers disable web3-wallet-worker report-worker`).action(withErrorHandling(async (names, _opts, cmd) => {
|
|
37777
|
+
const fmt = getFormatOptions(cmd);
|
|
37778
|
+
await doSetEnabled(names, false, fmt);
|
|
37779
|
+
}, { service: "workers" }));
|
|
37376
37780
|
workersCmd.command("dev <name>").summary("Start a single worker for local development").description(`Start a specific worker for local development by running \`hoox dev worker <name>\` in-process.
|
|
37377
37781
|
|
|
37378
37782
|
ARGUMENTS:
|
|
@@ -37918,10 +38322,10 @@ import { existsSync as existsSync12, realpathSync } from "fs";
|
|
|
37918
38322
|
import { homedir as homedir4 } from "os";
|
|
37919
38323
|
|
|
37920
38324
|
// src/services/perf/endpoint-resolver.ts
|
|
37921
|
-
import { readFileSync as
|
|
38325
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
37922
38326
|
function readSubdomainPrefix() {
|
|
37923
38327
|
try {
|
|
37924
|
-
const raw =
|
|
38328
|
+
const raw = readFileSync9("wrangler.jsonc", "utf8");
|
|
37925
38329
|
const stripped = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
37926
38330
|
const parsed = JSON.parse(stripped);
|
|
37927
38331
|
const prefix = parsed.global?.subdomain_prefix;
|
|
@@ -38965,7 +39369,7 @@ function registerDisclaimerCommand(program2) {
|
|
|
38965
39369
|
}));
|
|
38966
39370
|
}
|
|
38967
39371
|
// src/commands/agent/agent-command.ts
|
|
38968
|
-
import { readFileSync as
|
|
39372
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
38969
39373
|
init_errors4();
|
|
38970
39374
|
var PROVIDERS = [
|
|
38971
39375
|
{
|
|
@@ -38999,7 +39403,7 @@ function checkDevVars() {
|
|
|
38999
39403
|
const candidates = ["workers/agent-worker/.dev.vars", ".dev.vars"];
|
|
39000
39404
|
for (const filePath of candidates) {
|
|
39001
39405
|
try {
|
|
39002
|
-
const content =
|
|
39406
|
+
const content = readFileSync10(filePath, "utf-8");
|
|
39003
39407
|
for (const line of content.split(`
|
|
39004
39408
|
`)) {
|
|
39005
39409
|
const trimmed = line.trim();
|
|
@@ -39530,7 +39934,7 @@ EXAMPLES:
|
|
|
39530
39934
|
}
|
|
39531
39935
|
// src/commands/pyne/pyne-command.ts
|
|
39532
39936
|
init_config2();
|
|
39533
|
-
import { existsSync as existsSync14, readFileSync as
|
|
39937
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
39534
39938
|
import { resolve as resolve8 } from "path";
|
|
39535
39939
|
init_errors4();
|
|
39536
39940
|
var DEFAULT_TIMEOUT_MS = 30000;
|
|
@@ -39556,7 +39960,7 @@ function loadDevVars(workerDir) {
|
|
|
39556
39960
|
try {
|
|
39557
39961
|
if (!existsSync14(filePath))
|
|
39558
39962
|
continue;
|
|
39559
|
-
const content =
|
|
39963
|
+
const content = readFileSync11(filePath, "utf-8");
|
|
39560
39964
|
for (const line of content.split(`
|
|
39561
39965
|
`)) {
|
|
39562
39966
|
const trimmed = line.trim();
|
|
@@ -39775,7 +40179,7 @@ EXAMPLES:
|
|
|
39775
40179
|
if (!existsSync14(abs)) {
|
|
39776
40180
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39777
40181
|
}
|
|
39778
|
-
body.script =
|
|
40182
|
+
body.script = readFileSync11(abs, "utf-8");
|
|
39779
40183
|
}
|
|
39780
40184
|
const res = await pyneFetch(baseUrl, "/run", {
|
|
39781
40185
|
method: "POST",
|
|
@@ -39826,7 +40230,7 @@ EXAMPLES:
|
|
|
39826
40230
|
if (!existsSync14(abs)) {
|
|
39827
40231
|
throw new CLIError(`Script not found: ${abs}`, 1 /* ERROR */);
|
|
39828
40232
|
}
|
|
39829
|
-
const script =
|
|
40233
|
+
const script = readFileSync11(abs, "utf-8");
|
|
39830
40234
|
const baseName = abs.split(/[/\\]/).pop() ?? "script.pine";
|
|
39831
40235
|
const scriptId = opts.id ?? baseName.replace(/\.pine$/i, "").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
39832
40236
|
const res = await pyneFetch(baseUrl, "/scripts", {
|
|
@@ -40189,15 +40593,21 @@ function parseTime(input) {
|
|
|
40189
40593
|
return;
|
|
40190
40594
|
const relativeMatch = input.match(/^(\d+)([smhd])$/);
|
|
40191
40595
|
if (relativeMatch) {
|
|
40192
|
-
const
|
|
40596
|
+
const rawValue = relativeMatch[1];
|
|
40193
40597
|
const unit = relativeMatch[2];
|
|
40598
|
+
if (!rawValue || !unit)
|
|
40599
|
+
return;
|
|
40600
|
+
const value = parseInt(rawValue, 10);
|
|
40194
40601
|
const multipliers = {
|
|
40195
40602
|
s: 1000,
|
|
40196
40603
|
m: 60 * 1000,
|
|
40197
40604
|
h: 60 * 60 * 1000,
|
|
40198
40605
|
d: 24 * 60 * 60 * 1000
|
|
40199
40606
|
};
|
|
40200
|
-
|
|
40607
|
+
const mult = multipliers[unit];
|
|
40608
|
+
if (mult === undefined)
|
|
40609
|
+
return;
|
|
40610
|
+
return Date.now() - value * mult;
|
|
40201
40611
|
}
|
|
40202
40612
|
const ms = new Date(input).getTime();
|
|
40203
40613
|
return Number.isFinite(ms) ? ms : undefined;
|
|
@@ -41489,7 +41899,7 @@ function registerCompletionCommand(program2) {
|
|
|
41489
41899
|
// src/ui/banner.ts
|
|
41490
41900
|
init_ansis();
|
|
41491
41901
|
init_theme();
|
|
41492
|
-
import { existsSync as existsSync15, readFileSync as
|
|
41902
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
|
|
41493
41903
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
41494
41904
|
import { dirname as dirname4, join as join13 } from "path";
|
|
41495
41905
|
var ORANGE = ansis_default.hex("#ff7f2a");
|
|
@@ -41507,7 +41917,7 @@ function findCliVersion() {
|
|
|
41507
41917
|
const pkgPath = join13(dir, "package.json");
|
|
41508
41918
|
if (existsSync15(pkgPath)) {
|
|
41509
41919
|
try {
|
|
41510
|
-
const pkg = JSON.parse(
|
|
41920
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
41511
41921
|
if (pkg.name === PKG_NAME)
|
|
41512
41922
|
return pkg.version;
|
|
41513
41923
|
} catch {}
|
|
@@ -42142,7 +42552,7 @@ if (typeof Bun === "undefined") {
|
|
|
42142
42552
|
`);
|
|
42143
42553
|
process.exit(1);
|
|
42144
42554
|
}
|
|
42145
|
-
var pkgVersion = JSON.parse(
|
|
42555
|
+
var pkgVersion = JSON.parse(readFileSync13(new URL("../package.json", import.meta.url), "utf-8")).version;
|
|
42146
42556
|
var program2 = new Command;
|
|
42147
42557
|
program2.name("hoox").description("Hoox CLI \u2014 manage Cloudflare Workers, infrastructure, secrets, and deployments").version(`${pkgVersion}
|
|
42148
42558
|
|