@jango-blockchained/hoox-cli 0.9.4 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +29 -30
  2. package/dist/index.js +1585 -1563
  3. package/package.json +4 -1
package/dist/index.js CHANGED
@@ -24114,798 +24114,1186 @@ var init_config2 = __esm(() => {
24114
24114
  init_config_service();
24115
24115
  });
24116
24116
 
24117
- // src/services/kv/kv-sync-service.ts
24118
- var exports_kv_sync_service = {};
24119
- __export(exports_kv_sync_service, {
24120
- KvSyncService: () => KvSyncService
24121
- });
24117
+ // src/services/cloudflare/cloudflare-service.ts
24118
+ import path3 from "path";
24122
24119
 
24123
- class KvSyncService {
24124
- async resolveNamespaceId(namespaceId) {
24125
- if (namespaceId)
24126
- return namespaceId;
24120
+ class CloudflareService {
24121
+ cwd;
24122
+ homeDir;
24123
+ configService;
24124
+ constructor(cwd, homeDir, configService) {
24125
+ this.cwd = cwd ?? process.cwd();
24126
+ this.homeDir = homeDir;
24127
+ this.configService = configService ?? (this.homeDir ? new ConfigService(undefined, this.homeDir) : undefined);
24128
+ }
24129
+ resolveWorkerPath(workerPath) {
24130
+ if (this.configService) {
24131
+ const workerName = path3.basename(workerPath);
24132
+ return this.configService.getWorkerPath(workerName);
24133
+ }
24134
+ if (this.homeDir) {
24135
+ const workerName = path3.basename(workerPath);
24136
+ return path3.join(this.homeDir, ".hoox", "workers", workerName);
24137
+ }
24138
+ return path3.resolve(this.cwd, workerPath);
24139
+ }
24140
+ async runWrangler(args, cwd) {
24127
24141
  try {
24128
- const proc = Bun.spawn(["wrangler", "kv", "namespace", "list"], {
24142
+ const proc = Bun.spawn(["wrangler", ...args], {
24143
+ cwd: cwd ?? this.cwd,
24129
24144
  stdout: "pipe",
24130
24145
  stderr: "pipe"
24131
24146
  });
24132
24147
  const stdout2 = await new Response(proc.stdout).text();
24148
+ const stderr = await new Response(proc.stderr).text();
24133
24149
  const exitCode = await proc.exited;
24134
24150
  if (exitCode === 0) {
24135
- try {
24136
- const namespaces = JSON.parse(stdout2);
24137
- const configKv = namespaces.find((n3) => n3.title === "CONFIG_KV");
24138
- if (configKv)
24139
- return configKv.id;
24140
- } catch {}
24151
+ return { ok: true, value: stdout2.trim() };
24141
24152
  }
24142
- } catch {}
24143
- throw new Error("Could not resolve CONFIG_KV namespace ID. Provide --namespace-id flag.");
24153
+ return {
24154
+ ok: false,
24155
+ error: stderr.trim() || `wrangler exited with code ${exitCode}`
24156
+ };
24157
+ } catch (err) {
24158
+ const message = err instanceof Error ? err.message : String(err);
24159
+ const hint = /ENOENT|not found/i.test(message) ? "Install wrangler with `bun add -g wrangler` (or `npm i -g wrangler`), then run `wrangler login`." : undefined;
24160
+ return {
24161
+ ok: false,
24162
+ error: hint ? `Failed to spawn wrangler: ${message}
24163
+ \u21B3 hint: ${hint}` : `Failed to spawn wrangler: ${message}`
24164
+ };
24165
+ }
24144
24166
  }
24145
- async list(namespaceId) {
24146
- const proc = Bun.spawn(["wrangler", "kv", "key", "list", "--namespace-id", namespaceId], { stdout: "pipe", stderr: "pipe" });
24147
- const stdout2 = await new Response(proc.stdout).text();
24148
- const exitCode = await proc.exited;
24149
- if (exitCode !== 0) {
24150
- throw new Error(`Failed to list KV keys: ${stdout2.trim() || `exit ${exitCode}`}`);
24167
+ async whoami() {
24168
+ return this.runWrangler(["whoami"]);
24169
+ }
24170
+ async deploy(workerPath, env) {
24171
+ const resolvedPath = this.resolveWorkerPath(workerPath);
24172
+ const args = ["deploy"];
24173
+ if (env) {
24174
+ args.push("--env", env);
24151
24175
  }
24152
- try {
24153
- const parsed = JSON.parse(stdout2);
24154
- return parsed;
24155
- } catch {
24156
- return stdout2.split(`
24157
- `).filter(Boolean).map((name) => ({ name: name.trim() }));
24176
+ const result = await this.runWrangler(args, resolvedPath);
24177
+ if (!result.ok) {
24178
+ return result;
24179
+ }
24180
+ const url2 = this.extractUrl(result.value);
24181
+ const output = result.value;
24182
+ const deployResult = { url: url2, rawOutput: output };
24183
+ const pathParts = workerPath.split("/");
24184
+ deployResult.name = pathParts[pathParts.length - 1];
24185
+ const sizeMatch = output.match(/Total Upload:\s*([\d.]+)\s*([KMGT]?i?B)/i);
24186
+ if (sizeMatch) {
24187
+ deployResult.size = `${sizeMatch[1]} ${sizeMatch[2]}`;
24188
+ }
24189
+ const startupMatch = output.match(/Worker Startup Time:\s*(\d+)\s*ms/i);
24190
+ if (startupMatch) {
24191
+ deployResult.startupTime = `${startupMatch[1]} ms`;
24192
+ }
24193
+ const versionMatch = output.match(/Current Version ID:\s*([a-f0-9-]{36,})/i);
24194
+ if (versionMatch) {
24195
+ deployResult.versionId = versionMatch[1];
24158
24196
  }
24197
+ return { ok: true, value: deployResult };
24159
24198
  }
24160
- async get(namespaceId, key) {
24161
- const proc = Bun.spawn(["wrangler", "kv", "key", "get", "--namespace-id", namespaceId, key], { stdout: "pipe", stderr: "pipe" });
24162
- const stdout2 = await new Response(proc.stdout).text();
24163
- const stderr = await new Response(proc.stderr).text();
24164
- const exitCode = await proc.exited;
24165
- if (exitCode !== 0) {
24166
- if (stderr.includes("not found"))
24167
- return null;
24168
- throw new Error(`Failed to get key "${key}": ${stderr.trim() || `exit ${exitCode}`}`);
24199
+ async versionsList(workerName) {
24200
+ const result = await this.runWrangler([
24201
+ "versions",
24202
+ "list",
24203
+ "--name",
24204
+ workerName,
24205
+ "--json"
24206
+ ]);
24207
+ if (!result.ok) {
24208
+ return result;
24209
+ }
24210
+ try {
24211
+ const parsed = JSON.parse(result.value);
24212
+ if (!Array.isArray(parsed)) {
24213
+ return {
24214
+ ok: false,
24215
+ error: `Expected array from wrangler versions list, got ${typeof parsed}`
24216
+ };
24217
+ }
24218
+ const versions2 = parsed.map((v) => ({
24219
+ id: String(v.id ?? ""),
24220
+ number: typeof v.number === "number" ? v.number : undefined,
24221
+ created_on: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.created_on ?? "") : undefined,
24222
+ author: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.author ?? "") : undefined,
24223
+ message: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.message ?? "") : undefined,
24224
+ source: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.source ?? "") : undefined
24225
+ }));
24226
+ return { ok: true, value: versions2 };
24227
+ } catch (err) {
24228
+ const message = err instanceof Error ? err.message : String(err);
24229
+ return {
24230
+ ok: false,
24231
+ error: `Failed to parse versions list: ${message}`
24232
+ };
24169
24233
  }
24170
- return stdout2.trim() || null;
24171
24234
  }
24172
- async set(namespaceId, key, value) {
24173
- const proc = Bun.spawn(["wrangler", "kv", "key", "put", "--namespace-id", namespaceId, key], { stdout: "pipe", stderr: "pipe", stdin: "pipe" });
24174
- proc.stdin.write(value + `
24175
- `);
24176
- proc.stdin.end();
24177
- const [, stderr] = await Promise.all([
24178
- new Response(proc.stdout).text(),
24179
- new Response(proc.stderr).text()
24235
+ async versionsRollback(workerName, versionId) {
24236
+ return this.runWrangler([
24237
+ "versions",
24238
+ "rollback",
24239
+ "--name",
24240
+ workerName,
24241
+ "--version-id",
24242
+ versionId
24180
24243
  ]);
24181
- const exitCode = await proc.exited;
24182
- if (exitCode !== 0) {
24183
- throw new Error(`Failed to set key "${key}": ${stderr.trim() || `exit ${exitCode}`}`);
24244
+ }
24245
+ async dev(workerPath, port) {
24246
+ const devPort = port ?? 8787;
24247
+ const resolvedPath = this.resolveWorkerPath(workerPath);
24248
+ try {
24249
+ Bun.spawn(["wrangler", "dev", "--port", String(devPort)], {
24250
+ cwd: resolvedPath,
24251
+ stdout: "pipe",
24252
+ stderr: "pipe"
24253
+ });
24254
+ return { ok: true, value: { port: devPort } };
24255
+ } catch (err) {
24256
+ const message = err instanceof Error ? err.message : String(err);
24257
+ return { ok: false, error: `Failed to start dev server: ${message}` };
24184
24258
  }
24185
24259
  }
24186
- async delete(namespaceId, key) {
24187
- const proc = Bun.spawn(["wrangler", "kv", "key", "delete", "--namespace-id", namespaceId, key], { stdout: "pipe", stderr: "pipe" });
24188
- const exitCode = await proc.exited;
24189
- const stderr = await new Response(proc.stderr).text();
24190
- if (exitCode !== 0) {
24191
- throw new Error(`Failed to delete key "${key}": ${stderr.trim() || `exit ${exitCode}`}`);
24260
+ async tail(workerName) {
24261
+ return this.runWrangler(["tail", workerName]);
24262
+ }
24263
+ async d1List() {
24264
+ return this.runWrangler(["d1", "list", "--json"]);
24265
+ }
24266
+ async d1Create(name) {
24267
+ return this.runWrangler(["d1", "create", name]);
24268
+ }
24269
+ async d1Delete(name) {
24270
+ return this.runWrangler(["d1", "delete", name]);
24271
+ }
24272
+ async d1Execute(name, sql, remote = true) {
24273
+ const args = ["d1", "execute", name, "--command", sql];
24274
+ if (remote)
24275
+ args.push("--remote");
24276
+ const result = await this.runWrangler(args);
24277
+ if (!result.ok)
24278
+ return result;
24279
+ const extracted = extractJsonArray(result.value);
24280
+ if (extracted === null) {
24281
+ return {
24282
+ ok: false,
24283
+ error: `wrangler d1 execute returned non-JSON output: ${result.value.slice(0, 200)}`
24284
+ };
24192
24285
  }
24286
+ return { ok: true, value: extracted };
24193
24287
  }
24194
- static getManifest() {
24195
- return {
24196
- namespace: "CONFIG_KV",
24197
- keys: [
24198
- {
24199
- key: "webhook:tradingview:ip_check_enabled",
24200
- type: "boolean",
24201
- default: "false",
24202
- description: "Enable TradingView IP allowlist check"
24203
- },
24204
- {
24205
- key: "webhook:allowed_ips",
24206
- type: "string",
24207
- default: "",
24208
- description: "Comma-separated allowed IPs for webhook"
24209
- },
24210
- {
24211
- key: "routing:dynamic:enabled",
24212
- type: "boolean",
24213
- default: "false",
24214
- description: "Enable dynamic routing"
24215
- },
24216
- {
24217
- key: "trade:max_daily_drawdown_percent",
24218
- type: "number",
24219
- default: "10",
24220
- description: "Max daily loss percentage before halt"
24221
- },
24222
- {
24223
- key: "trade:kill_switch",
24224
- type: "boolean",
24225
- default: "false",
24226
- description: "Emergency stop all trading"
24227
- },
24228
- {
24229
- key: "trade:watermark:{exchange}:{symbol}:{side}",
24230
- type: "number",
24231
- default: "",
24232
- description: "Per-market watermark (template key)",
24233
- secret: true
24234
- },
24235
- {
24236
- key: "agent:openai_key",
24237
- type: "string",
24238
- default: "",
24239
- description: "OpenAI API key for AI agent",
24240
- secret: true
24241
- },
24242
- {
24243
- key: "agent:anthropic_key",
24244
- type: "string",
24245
- default: "",
24246
- description: "Anthropic API key for AI agent",
24247
- secret: true
24248
- },
24249
- {
24250
- key: "agent:google_key",
24251
- type: "string",
24252
- default: "",
24253
- description: "Google AI API key for agent",
24254
- secret: true
24255
- },
24256
- {
24257
- key: "agent:azure_api_key",
24258
- type: "string",
24259
- default: "",
24260
- description: "Azure OpenAI API key",
24261
- secret: true
24262
- },
24263
- {
24264
- key: "agent:azure_endpoint",
24265
- type: "string",
24266
- default: "",
24267
- description: "Azure OpenAI endpoint",
24268
- secret: true
24269
- },
24270
- {
24271
- key: "email:scan_subject",
24272
- type: "string",
24273
- default: "",
24274
- description: "Email subject filter for signal scanning"
24275
- },
24276
- {
24277
- key: "email:coin_pattern",
24278
- type: "string",
24279
- default: "",
24280
- description: "Regex pattern to extract coin from email"
24281
- },
24282
- {
24283
- key: "email:action_pattern",
24284
- type: "string",
24285
- default: "",
24286
- description: "Regex pattern to extract action from email"
24287
- },
24288
- {
24289
- key: "email:quantity_multiplier",
24290
- type: "number",
24291
- default: "1",
24292
- description: "Multiplier for email signal quantity"
24293
- },
24294
- {
24295
- key: "email:use_imap",
24296
- type: "boolean",
24297
- default: "false",
24298
- description: "Use IMAP for email scanning"
24299
- }
24300
- ]
24301
- };
24288
+ async kvList() {
24289
+ return this.runWrangler(["kv", "namespace", "list"]);
24302
24290
  }
24303
- static getManifestKeys() {
24304
- return KvSyncService.getManifest().keys;
24291
+ async kvCreate(name) {
24292
+ return this.runWrangler(["kv", "namespace", "create", name]);
24305
24293
  }
24306
- }
24307
-
24308
- // src/services/schema/schema-service.ts
24309
- var exports_schema_service = {};
24310
- __export(exports_schema_service, {
24311
- SchemaService: () => SchemaService
24312
- });
24313
- import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
24314
- import { resolve as resolve4 } from "path";
24315
-
24316
- class SchemaService {
24317
- projectRoot;
24318
- constructor(projectRoot = process.cwd()) {
24319
- this.projectRoot = projectRoot;
24294
+ async kvDelete(id) {
24295
+ return this.runWrangler([
24296
+ "kv",
24297
+ "namespace",
24298
+ "delete",
24299
+ "--namespace-id",
24300
+ id
24301
+ ]);
24320
24302
  }
24321
- getWorkerNames() {
24322
- return WORKER_NAMES;
24303
+ async r2List() {
24304
+ return this.runWrangler(["r2", "bucket", "list"]);
24323
24305
  }
24324
- getManifest(name) {
24325
- return WORKER_MANIFESTS[name];
24306
+ async r2Create(name) {
24307
+ return this.runWrangler(["r2", "bucket", "create", name]);
24326
24308
  }
24327
- validateWorker(name) {
24328
- const manifest = WORKER_MANIFESTS[name];
24329
- if (!manifest) {
24309
+ async r2Delete(name) {
24310
+ return this.runWrangler(["r2", "bucket", "delete", name]);
24311
+ }
24312
+ async queueList() {
24313
+ return this.runWrangler(["queues", "list"]);
24314
+ }
24315
+ async queueCreate(name) {
24316
+ return this.runWrangler(["queues", "create", name]);
24317
+ }
24318
+ async queueDelete(name) {
24319
+ return this.runWrangler(["queues", "delete", name]);
24320
+ }
24321
+ async vectorizeList() {
24322
+ return this.runWrangler(["vectorize", "list", "--json"]);
24323
+ }
24324
+ async vectorizeCreate(name, dimensions = 768, metric = "cosine") {
24325
+ return this.runWrangler([
24326
+ "vectorize",
24327
+ "create",
24328
+ name,
24329
+ "--dimensions",
24330
+ String(dimensions),
24331
+ "--metric",
24332
+ metric
24333
+ ]);
24334
+ }
24335
+ async vectorizeDelete(name) {
24336
+ return this.runWrangler(["vectorize", "delete", name]);
24337
+ }
24338
+ async analyticsList() {
24339
+ return this.runWrangler(["analytics", "dataset", "list"]);
24340
+ }
24341
+ async analyticsCreate(_name) {
24342
+ return {
24343
+ ok: false,
24344
+ error: `Analytics datasets cannot be created via wrangler. ` + `Please use the Cloudflare Dashboard: ` + `https://dash.cloudflare.com/?to=/:account/analytics`
24345
+ };
24346
+ }
24347
+ async secretList(workerName) {
24348
+ const result = await this.runWrangler([
24349
+ "secret",
24350
+ "list",
24351
+ "--name",
24352
+ workerName
24353
+ ]);
24354
+ if (!result.ok)
24355
+ return result;
24356
+ const extracted = extractJsonArray(result.value);
24357
+ if (extracted === null) {
24330
24358
  return {
24331
- worker: name,
24332
- passed: false,
24333
- errors: [
24334
- {
24335
- worker: name,
24336
- severity: "error",
24337
- message: `Unknown worker "${name}"`
24338
- }
24339
- ]
24359
+ ok: false,
24360
+ error: `wrangler secret list returned non-JSON output: ${result.value.slice(0, 200)}`
24340
24361
  };
24341
24362
  }
24342
- const workersDir = resolve4(this.projectRoot, "workers");
24343
- const rootWranglerPath = resolve4(this.projectRoot, "wrangler.jsonc");
24344
- const workerWranglerPath = resolve4(workersDir, name, "wrangler.jsonc");
24345
- const devVarsPath = resolve4(workersDir, name, ".dev.vars");
24346
- const errors4 = [];
24347
- const isHooxProject = existsSync6(resolve4(this.projectRoot, "wrangler.jsonc")) || existsSync6(resolve4(this.projectRoot, "workers"));
24363
+ return { ok: true, value: extracted };
24364
+ }
24365
+ async secretPut(workerName, secretName, value) {
24348
24366
  try {
24349
- const wranglerContent = readFileSync4(workerWranglerPath, "utf-8");
24350
- errors4.push(...validateWranglerJsonc(name, manifest, wranglerContent));
24351
- } catch (e) {
24352
- const isErrnoException = e instanceof Error && "code" in e;
24353
- const isEnoent = isErrnoException && e.code === "ENOENT";
24354
- const errMessage = e instanceof Error ? e.message : String(e);
24355
- const message = isEnoent && !isHooxProject ? `Cannot read ${workerWranglerPath}: File not found. Are you in the Hoox project root directory?` : `Cannot read ${workerWranglerPath}: ${errMessage}`;
24356
- errors4.push({
24357
- worker: name,
24358
- severity: "error",
24359
- message
24367
+ const proc = Bun.spawn(["wrangler", "secret", "put", secretName, "--name", workerName], {
24368
+ cwd: this.cwd,
24369
+ stdout: "pipe",
24370
+ stderr: "pipe",
24371
+ stdin: "pipe"
24360
24372
  });
24373
+ proc.stdin.write(value + `
24374
+ `);
24375
+ proc.stdin.end();
24376
+ const stdout2 = await new Response(proc.stdout).text();
24377
+ const stderr = await new Response(proc.stderr).text();
24378
+ const exitCode = await proc.exited;
24379
+ if (exitCode === 0) {
24380
+ return { ok: true, value: stdout2.trim() };
24381
+ }
24382
+ return {
24383
+ ok: false,
24384
+ error: stderr.trim() || `wrangler exited with code ${exitCode}`
24385
+ };
24386
+ } catch (err) {
24387
+ const message = err instanceof Error ? err.message : String(err);
24388
+ return { ok: false, error: `Failed to set secret: ${message}` };
24361
24389
  }
24362
- try {
24363
- const rootContent = readFileSync4(rootWranglerPath, "utf-8");
24364
- errors4.push(...validateRootSecrets(name, manifest, rootContent));
24365
- } catch (e) {
24366
- const errMessage = e instanceof Error ? e.message : String(e);
24367
- errors4.push({
24368
- worker: name,
24369
- severity: "warning",
24370
- message: `Cannot read root wrangler.jsonc: ${errMessage}`
24371
- });
24390
+ }
24391
+ async secretDelete(workerName, secretName) {
24392
+ return this.runWrangler([
24393
+ "secret",
24394
+ "delete",
24395
+ secretName,
24396
+ "--name",
24397
+ workerName
24398
+ ]);
24399
+ }
24400
+ async zonesList() {
24401
+ const token = process.env.CLOUDFLARE_API_TOKEN;
24402
+ if (!token) {
24403
+ return {
24404
+ ok: false,
24405
+ error: "CLOUDFLARE_API_TOKEN environment variable is not set. Set it or run `wrangler login`."
24406
+ };
24372
24407
  }
24373
24408
  try {
24374
- const devVarsContent = readFileSync4(devVarsPath, "utf-8");
24375
- errors4.push(...validateDevVars(name, manifest, devVarsContent));
24376
- } catch (e) {
24377
- const errMessage = e instanceof Error ? e.message : String(e);
24378
- errors4.push({
24379
- worker: name,
24380
- severity: "warning",
24381
- message: `Cannot read ${devVarsPath}: ${errMessage}`
24409
+ const response = await fetch("https://api.cloudflare.com/client/v4/zones?per_page=50", {
24410
+ headers: {
24411
+ Authorization: `Bearer ${token}`,
24412
+ "Content-Type": "application/json"
24413
+ }
24382
24414
  });
24415
+ const json2 = await response.json();
24416
+ if (!response.ok || !json2.success) {
24417
+ const errorMsg = json2.errors?.map((e) => e.message).join("; ") || `HTTP ${response.status}`;
24418
+ return { ok: false, error: `Failed to list zones: ${errorMsg}` };
24419
+ }
24420
+ const lines = json2.result.map((z2) => `${z2.name} (${z2.id})`);
24421
+ return { ok: true, value: lines.join(`
24422
+ `) };
24423
+ } catch (err) {
24424
+ const message = err instanceof Error ? err.message : String(err);
24425
+ return { ok: false, error: `Cloudflare API request failed: ${message}` };
24383
24426
  }
24384
- return {
24385
- worker: name,
24386
- passed: errors4.filter((e) => e.severity === "error").length === 0,
24387
- errors: errors4
24388
- };
24389
24427
  }
24390
- validateAll() {
24391
- return WORKER_NAMES.map((name) => this.validateWorker(name));
24392
- }
24393
- }
24394
- var init_schema_service = __esm(() => {
24395
- init_src();
24396
- });
24397
-
24398
- // src/commands/trace/trace-service.ts
24399
- var exports_trace_service = {};
24400
- __export(exports_trace_service, {
24401
- TraceService: () => TraceService
24402
- });
24403
- function getCredentials2() {
24404
- const token = process.env.CLOUDFLARE_API_TOKEN;
24405
- const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
24406
- if (!token) {
24407
- throw new CLIError("CLOUDFLARE_API_TOKEN environment variable is not set. Set it or run `wrangler login`.", 1 /* ERROR */);
24408
- }
24409
- if (!accountId) {
24410
- throw new CLIError("CLOUDFLARE_ACCOUNT_ID environment variable is not set.", 1 /* ERROR */);
24428
+ extractUrl(stdout2) {
24429
+ for (const line of stdout2.split(`
24430
+ `)) {
24431
+ const trimmed = line.trim();
24432
+ const match = trimmed.match(/(https?:\/\/[^\s]+(?:workers\.dev|cloudflareworkers\.com)[^\s]*)/);
24433
+ if (match)
24434
+ return match[1];
24435
+ }
24436
+ return;
24411
24437
  }
24412
- return { token, accountId };
24413
24438
  }
24414
- async function cfApi2(method, path6, body, query) {
24415
- const { token } = getCredentials2();
24416
- let url2 = `${CF_API_BASE2}${path6}`;
24417
- if (query) {
24418
- const params = new URLSearchParams;
24419
- for (const [k, v] of Object.entries(query)) {
24420
- if (v !== undefined)
24421
- params.set(k, String(v));
24439
+ function extractJsonArray(raw) {
24440
+ const first = raw.indexOf("[");
24441
+ if (first === -1)
24442
+ return null;
24443
+ let depth = 0;
24444
+ let inString = false;
24445
+ let escape = false;
24446
+ for (let i2 = first;i2 < raw.length; i2++) {
24447
+ const ch = raw[i2];
24448
+ if (escape) {
24449
+ escape = false;
24450
+ continue;
24422
24451
  }
24423
- const qs = params.toString();
24424
- if (qs)
24425
- url2 += `?${qs}`;
24426
- }
24427
- try {
24428
- const response = await fetch(url2, {
24429
- method,
24430
- headers: {
24431
- Authorization: `Bearer ${token}`,
24432
- "Content-Type": "application/json"
24433
- },
24434
- body: body !== undefined ? JSON.stringify(body) : undefined
24435
- });
24436
- const json2 = await response.json();
24437
- if (!response.ok || !json2.success) {
24438
- const errorMsg = json2.errors?.map((e) => e.message).join("; ") || `HTTP ${response.status}`;
24439
- throw new CLIError(`Cloudflare API error: ${errorMsg}`, 1 /* ERROR */);
24452
+ if (inString) {
24453
+ if (ch === "\\")
24454
+ escape = true;
24455
+ else if (ch === '"')
24456
+ inString = false;
24457
+ continue;
24458
+ }
24459
+ if (ch === '"') {
24460
+ inString = true;
24461
+ continue;
24462
+ }
24463
+ if (ch === "[")
24464
+ depth++;
24465
+ else if (ch === "]") {
24466
+ depth--;
24467
+ if (depth === 0)
24468
+ return raw.slice(first, i2 + 1);
24440
24469
  }
24441
- return json2.result;
24442
- } catch (err) {
24443
- if (err instanceof CLIError)
24444
- throw err;
24445
- const message = err instanceof Error ? err.message : String(err);
24446
- throw new CLIError(`Cloudflare API request failed: ${message}`, 1 /* ERROR */);
24447
24470
  }
24471
+ return null;
24448
24472
  }
24473
+ var init_cloudflare_service = __esm(() => {
24474
+ init_config2();
24475
+ });
24449
24476
 
24450
- class TraceService {
24451
- accountId;
24452
- constructor() {
24453
- const { accountId } = getCredentials2();
24454
- this.accountId = accountId;
24477
+ // src/services/kv/kv-sync-service.ts
24478
+ var exports_kv_sync_service = {};
24479
+ __export(exports_kv_sync_service, {
24480
+ stripWranglerStdoutNoise: () => stripWranglerStdoutNoise,
24481
+ KvSyncService: () => KvSyncService
24482
+ });
24483
+ function stripWranglerStdoutNoise(raw) {
24484
+ const lines = raw.split(`
24485
+ `);
24486
+ const cleaned = lines.filter((line) => {
24487
+ const t2 = line.trim();
24488
+ if (!t2)
24489
+ return false;
24490
+ if (t2.startsWith("There is a newer version of Wrangler"))
24491
+ return false;
24492
+ if (t2.includes("update available"))
24493
+ return false;
24494
+ if (t2.startsWith("\u26C5"))
24495
+ return false;
24496
+ if (/^[\u2500\-\u2550]{3,}$/.test(t2))
24497
+ return false;
24498
+ if (t2.startsWith("\u25B2 [WARNING]") || t2.startsWith("\u2718 [ERROR]"))
24499
+ return false;
24500
+ return true;
24501
+ });
24502
+ return cleaned.join(`
24503
+ `).trim();
24504
+ }
24505
+
24506
+ class KvSyncService {
24507
+ async resolveNamespaceId(namespaceId) {
24508
+ if (namespaceId)
24509
+ return namespaceId;
24510
+ try {
24511
+ const proc = Bun.spawn(["wrangler", "kv", "namespace", "list"], {
24512
+ stdout: "pipe",
24513
+ stderr: "pipe"
24514
+ });
24515
+ const stdout2 = await new Response(proc.stdout).text();
24516
+ const exitCode = await proc.exited;
24517
+ if (exitCode === 0) {
24518
+ try {
24519
+ const jsonText = extractJsonArray(stdout2) ?? stripWranglerStdoutNoise(stdout2);
24520
+ const namespaces = JSON.parse(jsonText);
24521
+ const configKv = namespaces.find((n3) => n3.title === "CONFIG_KV");
24522
+ if (configKv)
24523
+ return configKv.id;
24524
+ } catch {}
24525
+ }
24526
+ } catch {}
24527
+ throw new Error("Could not resolve CONFIG_KV namespace ID. Provide --namespace-id flag.");
24455
24528
  }
24456
- async query(request) {
24457
- const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/query`;
24458
- const result = await cfApi2("POST", path6, request);
24459
- if (request.view === "events") {
24460
- const events = result.events?.events ?? [];
24461
- return { success: true, events };
24529
+ async list(namespaceId) {
24530
+ const proc = Bun.spawn(["wrangler", "kv", "key", "list", "--namespace-id", namespaceId], { stdout: "pipe", stderr: "pipe" });
24531
+ const stdout2 = await new Response(proc.stdout).text();
24532
+ const exitCode = await proc.exited;
24533
+ if (exitCode !== 0) {
24534
+ throw new Error(`Failed to list KV keys: ${stdout2.trim() || `exit ${exitCode}`}`);
24462
24535
  }
24463
- if (request.view === "calculations") {
24464
- const metrics = (result.calculations ?? []).map((c3) => ({
24465
- calculations: (c3.aggregates ?? []).map((a3) => ({
24466
- alias: c3.calculation,
24467
- value: typeof a3.value === "number" ? a3.value : Number(a3.value ?? 0)
24468
- })),
24469
- groupBy: c3.groupBy
24470
- }));
24471
- return { success: true, metrics };
24536
+ try {
24537
+ const parsed = JSON.parse(stdout2);
24538
+ return parsed;
24539
+ } catch {
24540
+ return stdout2.split(`
24541
+ `).filter(Boolean).map((name) => ({ name: name.trim() }));
24472
24542
  }
24473
- return { success: true };
24474
24543
  }
24475
- async queryEvents(options) {
24476
- const filters = [];
24477
- if (options.service) {
24478
- filters.push({
24479
- key: "$metadata.service",
24480
- operation: "eq",
24481
- type: "string",
24482
- value: options.service
24483
- });
24484
- }
24485
- if (options.trigger) {
24486
- filters.push({
24487
- key: "$metadata.trigger",
24488
- operation: "includes",
24489
- type: "string",
24490
- value: options.trigger
24491
- });
24492
- }
24493
- if (options.level) {
24494
- filters.push({
24495
- key: "$metadata.level",
24496
- operation: "eq",
24497
- type: "string",
24498
- value: options.level
24499
- });
24544
+ async get(namespaceId, key) {
24545
+ const proc = Bun.spawn(["wrangler", "kv", "key", "get", "--namespace-id", namespaceId, key], { stdout: "pipe", stderr: "pipe" });
24546
+ const stdout2 = await new Response(proc.stdout).text();
24547
+ const stderr = await new Response(proc.stderr).text();
24548
+ const exitCode = await proc.exited;
24549
+ if (exitCode !== 0) {
24550
+ if (stderr.includes("not found"))
24551
+ return null;
24552
+ throw new Error(`Failed to get key "${key}": ${stderr.trim() || `exit ${exitCode}`}`);
24500
24553
  }
24501
- const now = Date.now();
24502
- const oneHourAgo = now - 60 * 60 * 1000;
24503
- const request = {
24504
- view: "events",
24505
- queryId: "trace-events",
24506
- limit: options.limit ?? 50,
24507
- parameters: {
24508
- filters
24509
- },
24510
- timeframe: {
24511
- from: options.from ?? oneHourAgo,
24512
- to: options.to ?? now
24513
- }
24514
- };
24515
- return this.query(request);
24554
+ const cleaned = stripWranglerStdoutNoise(stdout2);
24555
+ return cleaned.length > 0 ? cleaned : null;
24516
24556
  }
24517
- async queryMetrics(options) {
24518
- const filters = [];
24519
- if (options.service) {
24520
- filters.push({
24521
- key: "$metadata.service",
24522
- operation: "eq",
24523
- type: "string",
24524
- value: options.service
24525
- });
24557
+ async set(namespaceId, key, value) {
24558
+ const proc = Bun.spawn(["wrangler", "kv", "key", "put", "--namespace-id", namespaceId, key], { stdout: "pipe", stderr: "pipe", stdin: "pipe" });
24559
+ proc.stdin.write(value + `
24560
+ `);
24561
+ proc.stdin.end();
24562
+ const [, stderr] = await Promise.all([
24563
+ new Response(proc.stdout).text(),
24564
+ new Response(proc.stderr).text()
24565
+ ]);
24566
+ const exitCode = await proc.exited;
24567
+ if (exitCode !== 0) {
24568
+ throw new Error(`Failed to set key "${key}": ${stderr.trim() || `exit ${exitCode}`}`);
24526
24569
  }
24527
- const calculations = (options.calculations ?? [{ operator: "count" }]).map((c3) => ({
24528
- operator: c3.operator,
24529
- key: c3.key,
24530
- keyType: c3.key ? "number" : undefined,
24531
- alias: c3.alias ?? c3.operator
24532
- }));
24533
- const groupBys = options.groupBy ? [{ type: "string", value: options.groupBy }] : [];
24534
- const now = Date.now();
24535
- const oneHourAgo = now - 60 * 60 * 1000;
24536
- const request = {
24537
- view: "calculations",
24538
- queryId: "trace-metrics",
24539
- parameters: {
24540
- filters,
24541
- calculations,
24542
- groupBys
24543
- },
24544
- timeframe: {
24545
- from: options.from ?? oneHourAgo,
24546
- to: options.to ?? now
24547
- }
24548
- };
24549
- return this.query(request);
24550
24570
  }
24551
- async listKeys(options) {
24552
- const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/keys`;
24553
- const body = {
24554
- needle: options?.needle ? { value: options.needle, isRegex: false, matchCase: false } : undefined,
24555
- limit: options?.limit ?? 100
24556
- };
24557
- const raw = await cfApi2("POST", path6, body);
24558
- return { keys: raw };
24559
- }
24560
- async listValues(options) {
24561
- const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/values`;
24562
- const now = Date.now();
24563
- const oneHourAgo = now - 60 * 60 * 1000;
24564
- const body = {
24565
- key: options.key,
24566
- type: options.type ?? "string",
24567
- datasets: [],
24568
- limit: options.limit ?? 50,
24569
- timeframe: {
24570
- from: options.from ?? oneHourAgo,
24571
- to: options.to ?? now
24572
- }
24573
- };
24574
- const raw = await cfApi2("POST", path6, body);
24575
- return { values: raw.map((v) => v.value) };
24576
- }
24577
- async listDestinations() {
24578
- const path6 = `/accounts/${this.accountId}/workers/observability/destinations`;
24579
- return cfApi2("GET", path6);
24580
- }
24581
- async createDestination(input) {
24582
- const path6 = `/accounts/${this.accountId}/workers/observability/destinations`;
24583
- return cfApi2("POST", path6, input);
24584
- }
24585
- async deleteDestination(slug) {
24586
- const path6 = `/accounts/${this.accountId}/workers/observability/destinations/${slug}`;
24587
- await cfApi2("DELETE", path6);
24588
- }
24589
- async getUsage(options) {
24590
- const path6 = `/accounts/${this.accountId}/workers/observability/usage`;
24591
- const now = Date.now();
24592
- const sevenDaysAgo = now - 7 * 24 * 60 * 60 * 1000;
24593
- const raw = await cfApi2("GET", path6, undefined, {
24594
- from: options?.from ?? sevenDaysAgo,
24595
- to: options?.to ?? now
24596
- });
24597
- const byWorker = {};
24598
- for (const row of raw.breakdown ?? []) {
24599
- byWorker[row.service] = (byWorker[row.service] ?? 0) + row.count;
24571
+ async delete(namespaceId, key) {
24572
+ const proc = Bun.spawn(["wrangler", "kv", "key", "delete", "--namespace-id", namespaceId, key], { stdout: "pipe", stderr: "pipe" });
24573
+ const exitCode = await proc.exited;
24574
+ const stderr = await new Response(proc.stderr).text();
24575
+ if (exitCode !== 0) {
24576
+ throw new Error(`Failed to delete key "${key}": ${stderr.trim() || `exit ${exitCode}`}`);
24600
24577
  }
24601
- return {
24602
- eventCount: raw.events,
24603
- from: new Date(options?.from ?? sevenDaysAgo).toISOString(),
24604
- to: new Date(options?.to ?? now).toISOString(),
24605
- byWorker
24606
- };
24607
24578
  }
24608
- async prepareLiveTail(options) {
24609
- const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/live-tail`;
24610
- const body = {
24611
- filters: options?.service ? [
24579
+ static getManifest() {
24580
+ return {
24581
+ namespace: "CONFIG_KV",
24582
+ keys: [
24612
24583
  {
24613
- key: "$metadata.service",
24614
- operation: "eq",
24584
+ key: "webhook:tradingview:ip_check_enabled",
24585
+ type: "boolean",
24586
+ default: "false",
24587
+ description: "Enable TradingView IP allowlist check"
24588
+ },
24589
+ {
24590
+ key: "webhook:allowed_ips",
24615
24591
  type: "string",
24616
- value: options.service
24592
+ default: "",
24593
+ description: "Comma-separated allowed IPs for webhook"
24594
+ },
24595
+ {
24596
+ key: "routing:dynamic:enabled",
24597
+ type: "boolean",
24598
+ default: "false",
24599
+ description: "Enable dynamic routing"
24600
+ },
24601
+ {
24602
+ key: "trade:max_daily_drawdown_percent",
24603
+ type: "number",
24604
+ default: "10",
24605
+ description: "Max daily loss percentage before halt"
24606
+ },
24607
+ {
24608
+ key: "trade:kill_switch",
24609
+ type: "boolean",
24610
+ default: "false",
24611
+ description: "Emergency stop all trading"
24612
+ },
24613
+ {
24614
+ key: "trade:watermark:{exchange}:{symbol}:{side}",
24615
+ type: "number",
24616
+ default: "",
24617
+ description: "Per-market watermark (template key)",
24618
+ secret: true
24619
+ },
24620
+ {
24621
+ key: "agent:openai_key",
24622
+ type: "string",
24623
+ default: "",
24624
+ description: "OpenAI API key for AI agent",
24625
+ secret: true
24626
+ },
24627
+ {
24628
+ key: "agent:anthropic_key",
24629
+ type: "string",
24630
+ default: "",
24631
+ description: "Anthropic API key for AI agent",
24632
+ secret: true
24633
+ },
24634
+ {
24635
+ key: "agent:google_key",
24636
+ type: "string",
24637
+ default: "",
24638
+ description: "Google AI API key for agent",
24639
+ secret: true
24640
+ },
24641
+ {
24642
+ key: "agent:azure_api_key",
24643
+ type: "string",
24644
+ default: "",
24645
+ description: "Azure OpenAI API key",
24646
+ secret: true
24647
+ },
24648
+ {
24649
+ key: "agent:azure_endpoint",
24650
+ type: "string",
24651
+ default: "",
24652
+ description: "Azure OpenAI endpoint",
24653
+ secret: true
24654
+ },
24655
+ {
24656
+ key: "email:scan_subject",
24657
+ type: "string",
24658
+ default: "",
24659
+ description: "Email subject filter for signal scanning"
24660
+ },
24661
+ {
24662
+ key: "email:coin_pattern",
24663
+ type: "string",
24664
+ default: "",
24665
+ description: "Regex pattern to extract coin from email"
24666
+ },
24667
+ {
24668
+ key: "email:action_pattern",
24669
+ type: "string",
24670
+ default: "",
24671
+ description: "Regex pattern to extract action from email"
24672
+ },
24673
+ {
24674
+ key: "email:quantity_multiplier",
24675
+ type: "number",
24676
+ default: "1",
24677
+ description: "Multiplier for email signal quantity"
24678
+ },
24679
+ {
24680
+ key: "email:use_imap",
24681
+ type: "boolean",
24682
+ default: "false",
24683
+ description: "Use IMAP for email scanning"
24617
24684
  }
24618
- ] : []
24685
+ ]
24619
24686
  };
24620
- return cfApi2("POST", path6, body);
24621
24687
  }
24622
- async liveTailHeartbeat(sessionId) {
24623
- const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/live-tail/heartbeat`;
24624
- await cfApi2("POST", path6, { sessionId });
24688
+ static getManifestKeys() {
24689
+ return KvSyncService.getManifest().keys;
24625
24690
  }
24626
24691
  }
24627
- var CF_API_BASE2 = "https://api.cloudflare.com/client/v4";
24628
- var init_trace_service = __esm(() => {
24629
- init_errors4();
24692
+ var init_kv_sync_service = __esm(() => {
24693
+ init_cloudflare_service();
24630
24694
  });
24631
24695
 
24632
- // src/index.ts
24633
- import { readFileSync as readFileSync8 } from "fs";
24634
-
24635
- // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/error.js
24636
- class CommanderError extends Error {
24637
- constructor(exitCode, code, message) {
24638
- super(message);
24639
- Error.captureStackTrace(this, this.constructor);
24640
- this.name = this.constructor.name;
24641
- this.code = code;
24642
- this.exitCode = exitCode;
24643
- this.nestedError = undefined;
24644
- }
24645
- }
24646
-
24647
- class InvalidArgumentError extends CommanderError {
24648
- constructor(message) {
24649
- super(1, "commander.invalidArgument", message);
24650
- Error.captureStackTrace(this, this.constructor);
24651
- this.name = this.constructor.name;
24652
- }
24653
- }
24696
+ // src/services/schema/schema-service.ts
24697
+ var exports_schema_service = {};
24698
+ __export(exports_schema_service, {
24699
+ SchemaService: () => SchemaService
24700
+ });
24701
+ import { readFileSync as readFileSync4, existsSync as existsSync7 } from "fs";
24702
+ import { resolve as resolve4 } from "path";
24654
24703
 
24655
- // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/argument.js
24656
- class Argument {
24657
- constructor(name, description) {
24658
- this.description = description || "";
24659
- this.variadic = false;
24660
- this.parseArg = undefined;
24661
- this.defaultValue = undefined;
24662
- this.defaultValueDescription = undefined;
24663
- this.argChoices = undefined;
24664
- switch (name[0]) {
24665
- case "<":
24666
- this.required = true;
24667
- this._name = name.slice(1, -1);
24668
- break;
24669
- case "[":
24670
- this.required = false;
24671
- this._name = name.slice(1, -1);
24672
- break;
24673
- default:
24674
- this.required = true;
24675
- this._name = name;
24676
- break;
24677
- }
24678
- if (this._name.endsWith("...")) {
24679
- this.variadic = true;
24680
- this._name = this._name.slice(0, -3);
24681
- }
24682
- }
24683
- name() {
24684
- return this._name;
24704
+ class SchemaService {
24705
+ projectRoot;
24706
+ constructor(projectRoot = process.cwd()) {
24707
+ this.projectRoot = projectRoot;
24685
24708
  }
24686
- _collectValue(value, previous) {
24687
- if (previous === this.defaultValue || !Array.isArray(previous)) {
24688
- return [value];
24689
- }
24690
- previous.push(value);
24691
- return previous;
24709
+ getWorkerNames() {
24710
+ return WORKER_NAMES;
24692
24711
  }
24693
- default(value, description) {
24694
- this.defaultValue = value;
24695
- this.defaultValueDescription = description;
24696
- return this;
24712
+ getManifest(name) {
24713
+ return WORKER_MANIFESTS[name];
24697
24714
  }
24698
- argParser(fn) {
24699
- this.parseArg = fn;
24700
- return this;
24701
- }
24702
- choices(values) {
24703
- this.argChoices = values.slice();
24704
- this.parseArg = (arg, previous) => {
24705
- if (!this.argChoices.includes(arg)) {
24706
- throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
24707
- }
24708
- if (this.variadic) {
24709
- return this._collectValue(arg, previous);
24710
- }
24711
- return arg;
24715
+ validateWorker(name) {
24716
+ const manifest = WORKER_MANIFESTS[name];
24717
+ if (!manifest) {
24718
+ return {
24719
+ worker: name,
24720
+ passed: false,
24721
+ errors: [
24722
+ {
24723
+ worker: name,
24724
+ severity: "error",
24725
+ message: `Unknown worker "${name}"`
24726
+ }
24727
+ ]
24728
+ };
24729
+ }
24730
+ const workersDir = resolve4(this.projectRoot, "workers");
24731
+ const rootWranglerPath = resolve4(this.projectRoot, "wrangler.jsonc");
24732
+ const workerWranglerPath = resolve4(workersDir, name, "wrangler.jsonc");
24733
+ const devVarsPath = resolve4(workersDir, name, ".dev.vars");
24734
+ const errors4 = [];
24735
+ const isHooxProject = existsSync7(resolve4(this.projectRoot, "wrangler.jsonc")) || existsSync7(resolve4(this.projectRoot, "workers"));
24736
+ try {
24737
+ const wranglerContent = readFileSync4(workerWranglerPath, "utf-8");
24738
+ errors4.push(...validateWranglerJsonc(name, manifest, wranglerContent));
24739
+ } catch (e) {
24740
+ const isErrnoException = e instanceof Error && "code" in e;
24741
+ const isEnoent = isErrnoException && e.code === "ENOENT";
24742
+ const errMessage = e instanceof Error ? e.message : String(e);
24743
+ const message = isEnoent && !isHooxProject ? `Cannot read ${workerWranglerPath}: File not found. Are you in the Hoox project root directory?` : `Cannot read ${workerWranglerPath}: ${errMessage}`;
24744
+ errors4.push({
24745
+ worker: name,
24746
+ severity: "error",
24747
+ message
24748
+ });
24749
+ }
24750
+ try {
24751
+ const rootContent = readFileSync4(rootWranglerPath, "utf-8");
24752
+ errors4.push(...validateRootSecrets(name, manifest, rootContent));
24753
+ } catch (e) {
24754
+ const errMessage = e instanceof Error ? e.message : String(e);
24755
+ errors4.push({
24756
+ worker: name,
24757
+ severity: "warning",
24758
+ message: `Cannot read root wrangler.jsonc: ${errMessage}`
24759
+ });
24760
+ }
24761
+ try {
24762
+ const devVarsContent = readFileSync4(devVarsPath, "utf-8");
24763
+ errors4.push(...validateDevVars(name, manifest, devVarsContent));
24764
+ } catch (e) {
24765
+ const errMessage = e instanceof Error ? e.message : String(e);
24766
+ errors4.push({
24767
+ worker: name,
24768
+ severity: "warning",
24769
+ message: `Cannot read ${devVarsPath}: ${errMessage}`
24770
+ });
24771
+ }
24772
+ return {
24773
+ worker: name,
24774
+ passed: errors4.filter((e) => e.severity === "error").length === 0,
24775
+ errors: errors4
24712
24776
  };
24713
- return this;
24714
24777
  }
24715
- argRequired() {
24716
- this.required = true;
24717
- return this;
24718
- }
24719
- argOptional() {
24720
- this.required = false;
24721
- return this;
24778
+ validateAll() {
24779
+ return WORKER_NAMES.map((name) => this.validateWorker(name));
24722
24780
  }
24723
24781
  }
24724
- function humanReadableArgName(arg) {
24725
- const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
24726
- return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
24727
- }
24728
-
24729
- // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/command.js
24730
- import { EventEmitter } from "events";
24731
- import childProcess from "child_process";
24732
- import path from "path";
24733
- import fs from "fs";
24734
- import process2 from "process";
24735
- import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
24736
-
24737
- // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/help.js
24738
- import { stripVTControlCharacters } from "util";
24782
+ var init_schema_service = __esm(() => {
24783
+ init_src();
24784
+ });
24739
24785
 
24740
- class Help {
24741
- constructor() {
24742
- this.helpWidth = undefined;
24743
- this.minWidthToWrap = 40;
24744
- this.sortSubcommands = false;
24745
- this.sortOptions = false;
24746
- this.showGlobalOptions = false;
24786
+ // src/commands/trace/trace-service.ts
24787
+ var exports_trace_service = {};
24788
+ __export(exports_trace_service, {
24789
+ TraceService: () => TraceService
24790
+ });
24791
+ function getCredentials2() {
24792
+ const token = process.env.CLOUDFLARE_API_TOKEN;
24793
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
24794
+ if (!token) {
24795
+ throw new CLIError("CLOUDFLARE_API_TOKEN environment variable is not set. Set it or run `wrangler login`.", 1 /* ERROR */);
24747
24796
  }
24748
- prepareContext(contextOptions) {
24749
- this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
24797
+ if (!accountId) {
24798
+ throw new CLIError("CLOUDFLARE_ACCOUNT_ID environment variable is not set.", 1 /* ERROR */);
24750
24799
  }
24751
- visibleCommands(cmd) {
24752
- const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
24753
- const helpCommand = cmd._getHelpCommand();
24754
- if (helpCommand && !helpCommand._hidden) {
24755
- visibleCommands.push(helpCommand);
24800
+ return { token, accountId };
24801
+ }
24802
+ async function cfApi2(method, path6, body, query) {
24803
+ const { token } = getCredentials2();
24804
+ let url2 = `${CF_API_BASE2}${path6}`;
24805
+ if (query) {
24806
+ const params = new URLSearchParams;
24807
+ for (const [k, v] of Object.entries(query)) {
24808
+ if (v !== undefined)
24809
+ params.set(k, String(v));
24756
24810
  }
24757
- if (this.sortSubcommands) {
24758
- visibleCommands.sort((a, b) => {
24759
- return a.name().localeCompare(b.name());
24760
- });
24811
+ const qs = params.toString();
24812
+ if (qs)
24813
+ url2 += `?${qs}`;
24814
+ }
24815
+ try {
24816
+ const response = await fetch(url2, {
24817
+ method,
24818
+ headers: {
24819
+ Authorization: `Bearer ${token}`,
24820
+ "Content-Type": "application/json"
24821
+ },
24822
+ body: body !== undefined ? JSON.stringify(body) : undefined
24823
+ });
24824
+ const json2 = await response.json();
24825
+ if (!response.ok || !json2.success) {
24826
+ const errorMsg = json2.errors?.map((e) => e.message).join("; ") || `HTTP ${response.status}`;
24827
+ throw new CLIError(`Cloudflare API error: ${errorMsg}`, 1 /* ERROR */);
24761
24828
  }
24762
- return visibleCommands;
24829
+ return json2.result;
24830
+ } catch (err) {
24831
+ if (err instanceof CLIError)
24832
+ throw err;
24833
+ const message = err instanceof Error ? err.message : String(err);
24834
+ throw new CLIError(`Cloudflare API request failed: ${message}`, 1 /* ERROR */);
24763
24835
  }
24764
- compareOptions(a, b) {
24765
- const getSortKey = (option) => {
24766
- return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
24767
- };
24768
- return getSortKey(a).localeCompare(getSortKey(b));
24836
+ }
24837
+
24838
+ class TraceService {
24839
+ accountId;
24840
+ constructor() {
24841
+ const { accountId } = getCredentials2();
24842
+ this.accountId = accountId;
24769
24843
  }
24770
- visibleOptions(cmd) {
24771
- const visibleOptions = cmd.options.filter((option) => !option.hidden);
24772
- const helpOption = cmd._getHelpOption();
24773
- if (helpOption && !helpOption.hidden) {
24774
- const removeShort = helpOption.short && cmd._findOption(helpOption.short);
24775
- const removeLong = helpOption.long && cmd._findOption(helpOption.long);
24776
- if (!removeShort && !removeLong) {
24777
- visibleOptions.push(helpOption);
24778
- } else if (helpOption.long && !removeLong) {
24779
- visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description));
24780
- } else if (helpOption.short && !removeShort) {
24781
- visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description));
24782
- }
24844
+ async query(request) {
24845
+ const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/query`;
24846
+ const result = await cfApi2("POST", path6, request);
24847
+ if (request.view === "events") {
24848
+ const events = result.events?.events ?? [];
24849
+ return { success: true, events };
24783
24850
  }
24784
- if (this.sortOptions) {
24785
- visibleOptions.sort(this.compareOptions);
24851
+ if (request.view === "calculations") {
24852
+ const metrics = (result.calculations ?? []).map((c3) => ({
24853
+ calculations: (c3.aggregates ?? []).map((a3) => ({
24854
+ alias: c3.calculation,
24855
+ value: typeof a3.value === "number" ? a3.value : Number(a3.value ?? 0)
24856
+ })),
24857
+ groupBy: c3.groupBy
24858
+ }));
24859
+ return { success: true, metrics };
24786
24860
  }
24787
- return visibleOptions;
24861
+ return { success: true };
24788
24862
  }
24789
- visibleGlobalOptions(cmd) {
24790
- if (!this.showGlobalOptions)
24791
- return [];
24792
- const globalOptions = [];
24793
- for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
24794
- const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden);
24795
- globalOptions.push(...visibleOptions);
24796
- }
24797
- if (this.sortOptions) {
24798
- globalOptions.sort(this.compareOptions);
24863
+ async queryEvents(options) {
24864
+ const filters = [];
24865
+ if (options.service) {
24866
+ filters.push({
24867
+ key: "$metadata.service",
24868
+ operation: "eq",
24869
+ type: "string",
24870
+ value: options.service
24871
+ });
24799
24872
  }
24800
- return globalOptions;
24801
- }
24802
- visibleArguments(cmd) {
24803
- if (cmd._argsDescription) {
24804
- cmd.registeredArguments.forEach((argument) => {
24805
- argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
24873
+ if (options.trigger) {
24874
+ filters.push({
24875
+ key: "$metadata.trigger",
24876
+ operation: "includes",
24877
+ type: "string",
24878
+ value: options.trigger
24806
24879
  });
24807
24880
  }
24808
- if (cmd.registeredArguments.find((argument) => argument.description)) {
24809
- return cmd.registeredArguments;
24881
+ if (options.level) {
24882
+ filters.push({
24883
+ key: "$metadata.level",
24884
+ operation: "eq",
24885
+ type: "string",
24886
+ value: options.level
24887
+ });
24810
24888
  }
24811
- return [];
24812
- }
24813
- subcommandTerm(cmd) {
24814
- const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
24815
- return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + (args ? " " + args : "");
24816
- }
24817
- optionTerm(option) {
24818
- return option.flags;
24819
- }
24820
- argumentTerm(argument) {
24821
- return argument.name();
24889
+ const now = Date.now();
24890
+ const oneHourAgo = now - 60 * 60 * 1000;
24891
+ const request = {
24892
+ view: "events",
24893
+ queryId: "trace-events",
24894
+ limit: options.limit ?? 50,
24895
+ parameters: {
24896
+ filters
24897
+ },
24898
+ timeframe: {
24899
+ from: options.from ?? oneHourAgo,
24900
+ to: options.to ?? now
24901
+ }
24902
+ };
24903
+ return this.query(request);
24822
24904
  }
24823
- longestSubcommandTermLength(cmd, helper) {
24824
- return helper.visibleCommands(cmd).reduce((max, command) => {
24825
- return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command))));
24826
- }, 0);
24905
+ async queryMetrics(options) {
24906
+ const filters = [];
24907
+ if (options.service) {
24908
+ filters.push({
24909
+ key: "$metadata.service",
24910
+ operation: "eq",
24911
+ type: "string",
24912
+ value: options.service
24913
+ });
24914
+ }
24915
+ const calculations = (options.calculations ?? [{ operator: "count" }]).map((c3) => ({
24916
+ operator: c3.operator,
24917
+ key: c3.key,
24918
+ keyType: c3.key ? "number" : undefined,
24919
+ alias: c3.alias ?? c3.operator
24920
+ }));
24921
+ const groupBys = options.groupBy ? [{ type: "string", value: options.groupBy }] : [];
24922
+ const now = Date.now();
24923
+ const oneHourAgo = now - 60 * 60 * 1000;
24924
+ const request = {
24925
+ view: "calculations",
24926
+ queryId: "trace-metrics",
24927
+ parameters: {
24928
+ filters,
24929
+ calculations,
24930
+ groupBys
24931
+ },
24932
+ timeframe: {
24933
+ from: options.from ?? oneHourAgo,
24934
+ to: options.to ?? now
24935
+ }
24936
+ };
24937
+ return this.query(request);
24827
24938
  }
24828
- longestOptionTermLength(cmd, helper) {
24829
- return helper.visibleOptions(cmd).reduce((max, option) => {
24830
- return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
24831
- }, 0);
24939
+ async listKeys(options) {
24940
+ const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/keys`;
24941
+ const body = {
24942
+ needle: options?.needle ? { value: options.needle, isRegex: false, matchCase: false } : undefined,
24943
+ limit: options?.limit ?? 100
24944
+ };
24945
+ const raw = await cfApi2("POST", path6, body);
24946
+ return { keys: raw };
24832
24947
  }
24833
- longestGlobalOptionTermLength(cmd, helper) {
24834
- return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
24835
- return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
24836
- }, 0);
24948
+ async listValues(options) {
24949
+ const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/values`;
24950
+ const now = Date.now();
24951
+ const oneHourAgo = now - 60 * 60 * 1000;
24952
+ const body = {
24953
+ key: options.key,
24954
+ type: options.type ?? "string",
24955
+ datasets: [],
24956
+ limit: options.limit ?? 50,
24957
+ timeframe: {
24958
+ from: options.from ?? oneHourAgo,
24959
+ to: options.to ?? now
24960
+ }
24961
+ };
24962
+ const raw = await cfApi2("POST", path6, body);
24963
+ return { values: raw.map((v) => v.value) };
24837
24964
  }
24838
- longestArgumentTermLength(cmd, helper) {
24839
- return helper.visibleArguments(cmd).reduce((max, argument) => {
24840
- return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument))));
24841
- }, 0);
24965
+ async listDestinations() {
24966
+ const path6 = `/accounts/${this.accountId}/workers/observability/destinations`;
24967
+ return cfApi2("GET", path6);
24842
24968
  }
24843
- commandUsage(cmd) {
24844
- let cmdName = cmd._name;
24845
- if (cmd._aliases[0]) {
24846
- cmdName = cmdName + "|" + cmd._aliases[0];
24847
- }
24848
- let ancestorCmdNames = "";
24849
- for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
24850
- ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
24969
+ async createDestination(input) {
24970
+ const path6 = `/accounts/${this.accountId}/workers/observability/destinations`;
24971
+ return cfApi2("POST", path6, input);
24972
+ }
24973
+ async deleteDestination(slug) {
24974
+ const path6 = `/accounts/${this.accountId}/workers/observability/destinations/${slug}`;
24975
+ await cfApi2("DELETE", path6);
24976
+ }
24977
+ async getUsage(options) {
24978
+ const path6 = `/accounts/${this.accountId}/workers/observability/usage`;
24979
+ const now = Date.now();
24980
+ const sevenDaysAgo = now - 7 * 24 * 60 * 60 * 1000;
24981
+ const raw = await cfApi2("GET", path6, undefined, {
24982
+ from: options?.from ?? sevenDaysAgo,
24983
+ to: options?.to ?? now
24984
+ });
24985
+ const byWorker = {};
24986
+ for (const row of raw.breakdown ?? []) {
24987
+ byWorker[row.service] = (byWorker[row.service] ?? 0) + row.count;
24851
24988
  }
24852
- return ancestorCmdNames + cmdName + " " + cmd.usage();
24989
+ return {
24990
+ eventCount: raw.events,
24991
+ from: new Date(options?.from ?? sevenDaysAgo).toISOString(),
24992
+ to: new Date(options?.to ?? now).toISOString(),
24993
+ byWorker
24994
+ };
24853
24995
  }
24854
- commandDescription(cmd) {
24855
- return cmd.description();
24996
+ async prepareLiveTail(options) {
24997
+ const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/live-tail`;
24998
+ const body = {
24999
+ filters: options?.service ? [
25000
+ {
25001
+ key: "$metadata.service",
25002
+ operation: "eq",
25003
+ type: "string",
25004
+ value: options.service
25005
+ }
25006
+ ] : []
25007
+ };
25008
+ return cfApi2("POST", path6, body);
24856
25009
  }
24857
- subcommandDescription(cmd) {
24858
- return cmd.summary() || cmd.description();
25010
+ async liveTailHeartbeat(sessionId) {
25011
+ const path6 = `/accounts/${this.accountId}/workers/observability/telemetry/live-tail/heartbeat`;
25012
+ await cfApi2("POST", path6, { sessionId });
24859
25013
  }
24860
- optionDescription(option) {
24861
- const extraInfo = [];
24862
- if (option.argChoices) {
24863
- extraInfo.push(`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
24864
- }
24865
- if (option.defaultValue !== undefined) {
24866
- const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
24867
- if (showDefault) {
24868
- extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
24869
- }
24870
- }
24871
- if (option.presetArg !== undefined && option.optional) {
24872
- extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
24873
- }
24874
- if (option.envVar !== undefined) {
24875
- extraInfo.push(`env: ${option.envVar}`);
24876
- }
24877
- if (extraInfo.length > 0) {
24878
- const extraDescription = `(${extraInfo.join(", ")})`;
24879
- if (option.description) {
24880
- return `${option.description} ${extraDescription}`;
24881
- }
24882
- return extraDescription;
24883
- }
24884
- return option.description;
25014
+ }
25015
+ var CF_API_BASE2 = "https://api.cloudflare.com/client/v4";
25016
+ var init_trace_service = __esm(() => {
25017
+ init_errors4();
25018
+ });
25019
+
25020
+ // src/index.ts
25021
+ import { readFileSync as readFileSync8 } from "fs";
25022
+
25023
+ // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/error.js
25024
+ class CommanderError extends Error {
25025
+ constructor(exitCode, code, message) {
25026
+ super(message);
25027
+ Error.captureStackTrace(this, this.constructor);
25028
+ this.name = this.constructor.name;
25029
+ this.code = code;
25030
+ this.exitCode = exitCode;
25031
+ this.nestedError = undefined;
24885
25032
  }
24886
- argumentDescription(argument) {
24887
- const extraInfo = [];
24888
- if (argument.argChoices) {
24889
- extraInfo.push(`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
25033
+ }
25034
+
25035
+ class InvalidArgumentError extends CommanderError {
25036
+ constructor(message) {
25037
+ super(1, "commander.invalidArgument", message);
25038
+ Error.captureStackTrace(this, this.constructor);
25039
+ this.name = this.constructor.name;
25040
+ }
25041
+ }
25042
+
25043
+ // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/argument.js
25044
+ class Argument {
25045
+ constructor(name, description) {
25046
+ this.description = description || "";
25047
+ this.variadic = false;
25048
+ this.parseArg = undefined;
25049
+ this.defaultValue = undefined;
25050
+ this.defaultValueDescription = undefined;
25051
+ this.argChoices = undefined;
25052
+ switch (name[0]) {
25053
+ case "<":
25054
+ this.required = true;
25055
+ this._name = name.slice(1, -1);
25056
+ break;
25057
+ case "[":
25058
+ this.required = false;
25059
+ this._name = name.slice(1, -1);
25060
+ break;
25061
+ default:
25062
+ this.required = true;
25063
+ this._name = name;
25064
+ break;
24890
25065
  }
24891
- if (argument.defaultValue !== undefined) {
24892
- extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
25066
+ if (this._name.endsWith("...")) {
25067
+ this.variadic = true;
25068
+ this._name = this._name.slice(0, -3);
24893
25069
  }
24894
- if (extraInfo.length > 0) {
24895
- const extraDescription = `(${extraInfo.join(", ")})`;
24896
- if (argument.description) {
24897
- return `${argument.description} ${extraDescription}`;
24898
- }
24899
- return extraDescription;
25070
+ }
25071
+ name() {
25072
+ return this._name;
25073
+ }
25074
+ _collectValue(value, previous) {
25075
+ if (previous === this.defaultValue || !Array.isArray(previous)) {
25076
+ return [value];
24900
25077
  }
24901
- return argument.description;
25078
+ previous.push(value);
25079
+ return previous;
24902
25080
  }
24903
- formatItemList(heading, items, helper) {
24904
- if (items.length === 0)
24905
- return [];
24906
- return [helper.styleTitle(heading), ...items, ""];
25081
+ default(value, description) {
25082
+ this.defaultValue = value;
25083
+ this.defaultValueDescription = description;
25084
+ return this;
24907
25085
  }
24908
- groupItems(unsortedItems, visibleItems, getGroup) {
25086
+ argParser(fn) {
25087
+ this.parseArg = fn;
25088
+ return this;
25089
+ }
25090
+ choices(values) {
25091
+ this.argChoices = values.slice();
25092
+ this.parseArg = (arg, previous) => {
25093
+ if (!this.argChoices.includes(arg)) {
25094
+ throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
25095
+ }
25096
+ if (this.variadic) {
25097
+ return this._collectValue(arg, previous);
25098
+ }
25099
+ return arg;
25100
+ };
25101
+ return this;
25102
+ }
25103
+ argRequired() {
25104
+ this.required = true;
25105
+ return this;
25106
+ }
25107
+ argOptional() {
25108
+ this.required = false;
25109
+ return this;
25110
+ }
25111
+ }
25112
+ function humanReadableArgName(arg) {
25113
+ const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
25114
+ return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
25115
+ }
25116
+
25117
+ // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/command.js
25118
+ import { EventEmitter } from "events";
25119
+ import childProcess from "child_process";
25120
+ import path from "path";
25121
+ import fs from "fs";
25122
+ import process2 from "process";
25123
+ import { stripVTControlCharacters as stripVTControlCharacters2 } from "util";
25124
+
25125
+ // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/help.js
25126
+ import { stripVTControlCharacters } from "util";
25127
+
25128
+ class Help {
25129
+ constructor() {
25130
+ this.helpWidth = undefined;
25131
+ this.minWidthToWrap = 40;
25132
+ this.sortSubcommands = false;
25133
+ this.sortOptions = false;
25134
+ this.showGlobalOptions = false;
25135
+ }
25136
+ prepareContext(contextOptions) {
25137
+ this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
25138
+ }
25139
+ visibleCommands(cmd) {
25140
+ const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
25141
+ const helpCommand = cmd._getHelpCommand();
25142
+ if (helpCommand && !helpCommand._hidden) {
25143
+ visibleCommands.push(helpCommand);
25144
+ }
25145
+ if (this.sortSubcommands) {
25146
+ visibleCommands.sort((a, b) => {
25147
+ return a.name().localeCompare(b.name());
25148
+ });
25149
+ }
25150
+ return visibleCommands;
25151
+ }
25152
+ compareOptions(a, b) {
25153
+ const getSortKey = (option) => {
25154
+ return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
25155
+ };
25156
+ return getSortKey(a).localeCompare(getSortKey(b));
25157
+ }
25158
+ visibleOptions(cmd) {
25159
+ const visibleOptions = cmd.options.filter((option) => !option.hidden);
25160
+ const helpOption = cmd._getHelpOption();
25161
+ if (helpOption && !helpOption.hidden) {
25162
+ const removeShort = helpOption.short && cmd._findOption(helpOption.short);
25163
+ const removeLong = helpOption.long && cmd._findOption(helpOption.long);
25164
+ if (!removeShort && !removeLong) {
25165
+ visibleOptions.push(helpOption);
25166
+ } else if (helpOption.long && !removeLong) {
25167
+ visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description));
25168
+ } else if (helpOption.short && !removeShort) {
25169
+ visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description));
25170
+ }
25171
+ }
25172
+ if (this.sortOptions) {
25173
+ visibleOptions.sort(this.compareOptions);
25174
+ }
25175
+ return visibleOptions;
25176
+ }
25177
+ visibleGlobalOptions(cmd) {
25178
+ if (!this.showGlobalOptions)
25179
+ return [];
25180
+ const globalOptions = [];
25181
+ for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
25182
+ const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden);
25183
+ globalOptions.push(...visibleOptions);
25184
+ }
25185
+ if (this.sortOptions) {
25186
+ globalOptions.sort(this.compareOptions);
25187
+ }
25188
+ return globalOptions;
25189
+ }
25190
+ visibleArguments(cmd) {
25191
+ if (cmd._argsDescription) {
25192
+ cmd.registeredArguments.forEach((argument) => {
25193
+ argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
25194
+ });
25195
+ }
25196
+ if (cmd.registeredArguments.find((argument) => argument.description)) {
25197
+ return cmd.registeredArguments;
25198
+ }
25199
+ return [];
25200
+ }
25201
+ subcommandTerm(cmd) {
25202
+ const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
25203
+ return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + (args ? " " + args : "");
25204
+ }
25205
+ optionTerm(option) {
25206
+ return option.flags;
25207
+ }
25208
+ argumentTerm(argument) {
25209
+ return argument.name();
25210
+ }
25211
+ longestSubcommandTermLength(cmd, helper) {
25212
+ return helper.visibleCommands(cmd).reduce((max, command) => {
25213
+ return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command))));
25214
+ }, 0);
25215
+ }
25216
+ longestOptionTermLength(cmd, helper) {
25217
+ return helper.visibleOptions(cmd).reduce((max, option) => {
25218
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
25219
+ }, 0);
25220
+ }
25221
+ longestGlobalOptionTermLength(cmd, helper) {
25222
+ return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
25223
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
25224
+ }, 0);
25225
+ }
25226
+ longestArgumentTermLength(cmd, helper) {
25227
+ return helper.visibleArguments(cmd).reduce((max, argument) => {
25228
+ return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument))));
25229
+ }, 0);
25230
+ }
25231
+ commandUsage(cmd) {
25232
+ let cmdName = cmd._name;
25233
+ if (cmd._aliases[0]) {
25234
+ cmdName = cmdName + "|" + cmd._aliases[0];
25235
+ }
25236
+ let ancestorCmdNames = "";
25237
+ for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
25238
+ ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
25239
+ }
25240
+ return ancestorCmdNames + cmdName + " " + cmd.usage();
25241
+ }
25242
+ commandDescription(cmd) {
25243
+ return cmd.description();
25244
+ }
25245
+ subcommandDescription(cmd) {
25246
+ return cmd.summary() || cmd.description();
25247
+ }
25248
+ optionDescription(option) {
25249
+ const extraInfo = [];
25250
+ if (option.argChoices) {
25251
+ extraInfo.push(`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
25252
+ }
25253
+ if (option.defaultValue !== undefined) {
25254
+ const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
25255
+ if (showDefault) {
25256
+ extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
25257
+ }
25258
+ }
25259
+ if (option.presetArg !== undefined && option.optional) {
25260
+ extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
25261
+ }
25262
+ if (option.envVar !== undefined) {
25263
+ extraInfo.push(`env: ${option.envVar}`);
25264
+ }
25265
+ if (extraInfo.length > 0) {
25266
+ const extraDescription = `(${extraInfo.join(", ")})`;
25267
+ if (option.description) {
25268
+ return `${option.description} ${extraDescription}`;
25269
+ }
25270
+ return extraDescription;
25271
+ }
25272
+ return option.description;
25273
+ }
25274
+ argumentDescription(argument) {
25275
+ const extraInfo = [];
25276
+ if (argument.argChoices) {
25277
+ extraInfo.push(`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
25278
+ }
25279
+ if (argument.defaultValue !== undefined) {
25280
+ extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
25281
+ }
25282
+ if (extraInfo.length > 0) {
25283
+ const extraDescription = `(${extraInfo.join(", ")})`;
25284
+ if (argument.description) {
25285
+ return `${argument.description} ${extraDescription}`;
25286
+ }
25287
+ return extraDescription;
25288
+ }
25289
+ return argument.description;
25290
+ }
25291
+ formatItemList(heading, items, helper) {
25292
+ if (items.length === 0)
25293
+ return [];
25294
+ return [helper.styleTitle(heading), ...items, ""];
25295
+ }
25296
+ groupItems(unsortedItems, visibleItems, getGroup) {
24909
25297
  const result = new Map;
24910
25298
  unsortedItems.forEach((item) => {
24911
25299
  const group = getGroup(item);
@@ -26983,608 +27371,254 @@ function colorizeCell(value, colorizeStatus) {
26983
27371
  ].includes(lower)) {
26984
27372
  return `${theme.success(icons.success)} ${theme.text(v)}`;
26985
27373
  }
26986
- if (["warn", "warning", "degraded", "partial", "pending"].includes(lower)) {
26987
- return `${theme.warning(icons.warning)} ${theme.text(v)}`;
26988
- }
26989
- if ([
26990
- "err",
26991
- "error",
26992
- "fail",
26993
- "failed",
26994
- "down",
26995
- "unreachable",
26996
- "disabled"
26997
- ].includes(lower)) {
26998
- return `${theme.error(icons.error)} ${theme.text(v)}`;
26999
- }
27000
- return value;
27001
- }
27002
- function formatJson(data, opts) {
27003
- const json2 = opts?.quiet ? JSON.stringify(data) : JSON.stringify(data, null, 2);
27004
- process.stdout.write(`${json2}
27005
- `);
27006
- }
27007
- function formatKeyValue(pairs, opts = {}) {
27008
- if (opts.quiet)
27009
- return;
27010
- if (opts.json) {
27011
- process.stdout.write(JSON.stringify(pairs, null, 2) + `
27012
- `);
27013
- return;
27014
- }
27015
- const maxKeyLen = Math.max(...Object.keys(pairs).map((k) => stripAnsi(k).length), 0);
27016
- for (const [key, value] of Object.entries(pairs)) {
27017
- const paddedKey = key.padEnd(maxKeyLen);
27018
- process.stdout.write(` ${theme.key(paddedKey)} ${theme.textMuted(":")} ${value}
27019
- `);
27020
- }
27021
- }
27022
- function getFormatOptions(cmd) {
27023
- const opts = cmd.optsWithGlobals();
27024
- return {
27025
- json: Boolean(opts.json),
27026
- quiet: Boolean(opts.quiet),
27027
- noColor: Boolean(opts.color === false)
27028
- };
27029
- }
27030
- function formatCompletion(message, opts = {}) {
27031
- if (opts.json || opts.quiet)
27032
- return;
27033
- if (process.exitCode && process.exitCode !== 0)
27034
- return;
27035
- if (!isRichMode(opts))
27036
- return;
27037
- const parts = [theme.success(icons.success), theme.text(message)];
27038
- if (opts.durationMs !== undefined) {
27039
- parts.push(theme.textMuted(formatDuration3(opts.durationMs)));
27040
- }
27041
- process.stdout.write(`${parts.join(" ")}
27042
- `);
27043
- if (opts.suggestion) {
27044
- const reason = opts.suggestion.reason ? ` ${theme.textMuted(`(${opts.suggestion.reason})`)}` : "";
27045
- process.stdout.write(` ${theme.textMuted("\u2192")} ${theme.textMuted("next:")} ${theme.accent(opts.suggestion.command)}${reason}
27046
- `);
27047
- }
27048
- }
27049
-
27050
- // src/utils/error-handler.ts
27051
- init_errors4();
27052
-
27053
- // src/utils/string.ts
27054
- function levenshtein(a2, b) {
27055
- if (a2 === b)
27056
- return 0;
27057
- if (a2.length === 0)
27058
- return b.length;
27059
- if (b.length === 0)
27060
- return a2.length;
27061
- const [s, t] = a2.length <= b.length ? [a2, b] : [b, a2];
27062
- const m = s.length;
27063
- const n = t.length;
27064
- let prev = new Array(m + 1);
27065
- for (let i = 0;i <= m; i++)
27066
- prev[i] = i;
27067
- let curr = new Array(m + 1);
27068
- for (let j = 1;j <= n; j++) {
27069
- curr[0] = j;
27070
- for (let i = 1;i <= m; i++) {
27071
- const cost = s.charCodeAt(i - 1) === t.charCodeAt(j - 1) ? 0 : 1;
27072
- curr[i] = Math.min(curr[i - 1] + 1, prev[i] + 1, prev[i - 1] + cost);
27073
- }
27074
- [prev, curr] = [curr, prev];
27075
- }
27076
- return prev[m];
27077
- }
27078
-
27079
- // src/utils/error-handler.ts
27080
- var SUGGESTION_THRESHOLD = 2;
27081
- function collectCommandNames(cmd, acc = new Set) {
27082
- for (const sub of cmd.commands) {
27083
- if (sub.name() && !sub.hidden) {
27084
- acc.add(sub.name());
27085
- collectCommandNames(sub, acc);
27086
- }
27087
- }
27088
- return acc;
27089
- }
27090
- function suggestForCommand(program2, unknown2) {
27091
- if (unknown2.length < 2)
27092
- return;
27093
- const normalized = unknown2.replace(/s$/, "");
27094
- const candidates = collectCommandNames(program2);
27095
- let best;
27096
- for (const candidate of candidates) {
27097
- const d = Math.min(levenshtein(unknown2, candidate), levenshtein(normalized, candidate));
27098
- if (d > SUGGESTION_THRESHOLD)
27099
- continue;
27100
- if (!best || d < best.dist) {
27101
- best = { name: candidate, dist: d };
27102
- }
27103
- }
27104
- return best?.name;
27105
- }
27106
- function withErrorHandling(handler, options) {
27107
- return async (...args) => {
27108
- try {
27109
- await handler(...args);
27110
- } catch (error51) {
27111
- const service = options?.service ?? "cli";
27112
- if (error51 instanceof CLIError) {
27113
- formatError2(error51, options?.opts);
27114
- process.exitCode = error51.code;
27115
- return;
27116
- } else if (error51 instanceof Error) {
27117
- formatError2(`[${service}] ${error51.message}`, options?.opts);
27118
- process.exitCode = 1 /* ERROR */;
27119
- return;
27120
- } else {
27121
- formatError2(`[${service}] Unknown error: ${String(error51)}`, options?.opts);
27122
- process.exitCode = 4 /* CommandFailed */;
27123
- return;
27124
- }
27125
- }
27126
- };
27127
- }
27128
-
27129
- // src/utils/help-formatter.ts
27130
- function renderHelp(cmd, helper) {
27131
- const subcommands = cmd.commands.filter((c) => !c._hidden).map((c) => ({ name: c.name(), desc: c.description() ?? "" }));
27132
- const blocks = [];
27133
- const argNames = cmd.registeredArguments.map((a2) => a2.name()).join(" ");
27134
- const titleName = argNames ? `${cmd.name()} ${argNames}` : cmd.name();
27135
- blocks.push(theme.heading(` ${titleName}`));
27136
- if (cmd.description()) {
27137
- blocks.push(` ${theme.textMuted(cmd.description())}`);
27138
- }
27139
- blocks.push(theme.textFaint("\u2500".repeat(60)));
27140
- const usageLine = buildUsage(cmd);
27141
- blocks.push(headerLine("Usage"));
27142
- blocks.push(` ${theme.accent(usageLine)}`);
27143
- const options = cmd.options.filter((o) => !o.hidden);
27144
- if (options.length > 0) {
27145
- blocks.push("");
27146
- blocks.push(headerLine("Options"));
27147
- const flagWidth = Math.max(...options.map((o) => o.flags.length));
27148
- for (const o of options) {
27149
- const padded = o.flags.padEnd(flagWidth);
27150
- const desc = o.description ? theme.textMuted(o.description) : "";
27151
- blocks.push(` ${theme.text(padded)} ${desc}`);
27152
- }
27153
- }
27154
- if (subcommands.length > 0) {
27155
- blocks.push("");
27156
- blocks.push(headerLine("Commands"));
27157
- const nameWidth = Math.max(...subcommands.map((s) => s.name.length));
27158
- for (const s of subcommands) {
27159
- const padded = s.name.padEnd(nameWidth);
27160
- blocks.push(` ${theme.text(padded)} ${theme.textMuted(s.desc)}`);
27161
- }
27162
- }
27163
- const afterText = captureHelpEvent(cmd, "afterHelp");
27164
- if (afterText.trim()) {
27165
- blocks.push("");
27166
- blocks.push(headerLine("Examples"));
27167
- blocks.push(` ${theme.textMuted(afterText.trim())}`);
27168
- }
27169
- const out = blocks.join(`
27170
- `) + `
27171
- `;
27172
- return isRichMode() ? out : stripAnsi(out);
27173
- }
27174
- function headerLine(text) {
27175
- return ` ${theme.textSubtle(text)}`;
27176
- }
27177
- function buildUsage(cmd) {
27178
- const parts = [];
27179
- let c = cmd;
27180
- while (c && c.name()) {
27181
- parts.unshift(c.name());
27182
- c = c.parent;
27183
- }
27184
- for (const arg of cmd.registeredArguments) {
27185
- parts.push(arg.name());
27186
- }
27187
- return `${parts.join(" ")} [options]`;
27188
- }
27189
- function captureHelpEvent(cmd, eventName) {
27190
- const parts = [];
27191
- const context = {
27192
- error: false,
27193
- command: cmd,
27194
- write: (str) => {
27195
- parts.push(str);
27196
- }
27197
- };
27198
- const emitter = cmd;
27199
- emitter.emit(eventName, context);
27200
- return parts.join("");
27201
- }
27202
-
27203
- // src/utils/completion.ts
27204
- var SUGGEST_NEXT = {
27205
- init: { command: "hoox setup", reason: "provision infrastructure" },
27206
- setup: { command: "hoox deploy all", reason: "ship to Cloudflare" },
27207
- "deploy all": { command: "hoox check health", reason: "verify the deploy" },
27208
- "check health": { command: "hoox monitor status", reason: "keep watching" },
27209
- "monitor kill-switch off": {
27210
- command: "hoox check health",
27211
- reason: "re-enable trading"
27212
- }
27213
- };
27214
- function suggestNextCommand(commandPath) {
27215
- return SUGGEST_NEXT[commandPath];
27216
- }
27217
- function getCmdPath(cmd) {
27218
- const parts = [];
27219
- let current2 = cmd;
27220
- while (current2 && current2.name() && current2.parent) {
27221
- parts.unshift(current2.name());
27222
- current2 = current2.parent;
27223
- }
27224
- return parts.join(" ");
27225
- }
27226
-
27227
- // src/commands/init/init-command.ts
27228
- init_dist4();
27229
- init_src();
27230
-
27231
- // src/services/cloudflare/cloudflare-service.ts
27232
- init_config2();
27233
- import path3 from "path";
27234
-
27235
- class CloudflareService {
27236
- cwd;
27237
- homeDir;
27238
- configService;
27239
- constructor(cwd, homeDir, configService) {
27240
- this.cwd = cwd ?? process.cwd();
27241
- this.homeDir = homeDir;
27242
- this.configService = configService ?? (this.homeDir ? new ConfigService(undefined, this.homeDir) : undefined);
27243
- }
27244
- resolveWorkerPath(workerPath) {
27245
- if (this.configService) {
27246
- const workerName = path3.basename(workerPath);
27247
- return this.configService.getWorkerPath(workerName);
27248
- }
27249
- if (this.homeDir) {
27250
- const workerName = path3.basename(workerPath);
27251
- return path3.join(this.homeDir, ".hoox", "workers", workerName);
27252
- }
27253
- return path3.resolve(this.cwd, workerPath);
27254
- }
27255
- async runWrangler(args, cwd) {
27256
- try {
27257
- const proc = Bun.spawn(["wrangler", ...args], {
27258
- cwd: cwd ?? this.cwd,
27259
- stdout: "pipe",
27260
- stderr: "pipe"
27261
- });
27262
- const stdout2 = await new Response(proc.stdout).text();
27263
- const stderr = await new Response(proc.stderr).text();
27264
- const exitCode = await proc.exited;
27265
- if (exitCode === 0) {
27266
- return { ok: true, value: stdout2.trim() };
27267
- }
27268
- return {
27269
- ok: false,
27270
- error: stderr.trim() || `wrangler exited with code ${exitCode}`
27271
- };
27272
- } catch (err) {
27273
- const message = err instanceof Error ? err.message : String(err);
27274
- const hint = /ENOENT|not found/i.test(message) ? "Install wrangler with `bun add -g wrangler` (or `npm i -g wrangler`), then run `wrangler login`." : undefined;
27275
- return {
27276
- ok: false,
27277
- error: hint ? `Failed to spawn wrangler: ${message}
27278
- \u21B3 hint: ${hint}` : `Failed to spawn wrangler: ${message}`
27279
- };
27280
- }
27281
- }
27282
- async whoami() {
27283
- return this.runWrangler(["whoami"]);
27284
- }
27285
- async deploy(workerPath, env) {
27286
- const resolvedPath = this.resolveWorkerPath(workerPath);
27287
- const args = ["deploy"];
27288
- if (env) {
27289
- args.push("--env", env);
27290
- }
27291
- const result = await this.runWrangler(args, resolvedPath);
27292
- if (!result.ok) {
27293
- return result;
27294
- }
27295
- const url2 = this.extractUrl(result.value);
27296
- const output = result.value;
27297
- const deployResult = { url: url2, rawOutput: output };
27298
- const pathParts = workerPath.split("/");
27299
- deployResult.name = pathParts[pathParts.length - 1];
27300
- const sizeMatch = output.match(/Total Upload:\s*([\d.]+)\s*([KMGT]?i?B)/i);
27301
- if (sizeMatch) {
27302
- deployResult.size = `${sizeMatch[1]} ${sizeMatch[2]}`;
27303
- }
27304
- const startupMatch = output.match(/Worker Startup Time:\s*(\d+)\s*ms/i);
27305
- if (startupMatch) {
27306
- deployResult.startupTime = `${startupMatch[1]} ms`;
27307
- }
27308
- const versionMatch = output.match(/Current Version ID:\s*([a-f0-9-]{36,})/i);
27309
- if (versionMatch) {
27310
- deployResult.versionId = versionMatch[1];
27311
- }
27312
- return { ok: true, value: deployResult };
27313
- }
27314
- async versionsList(workerName) {
27315
- const result = await this.runWrangler([
27316
- "versions",
27317
- "list",
27318
- "--name",
27319
- workerName,
27320
- "--json"
27321
- ]);
27322
- if (!result.ok) {
27323
- return result;
27324
- }
27325
- try {
27326
- const parsed = JSON.parse(result.value);
27327
- if (!Array.isArray(parsed)) {
27328
- return {
27329
- ok: false,
27330
- error: `Expected array from wrangler versions list, got ${typeof parsed}`
27331
- };
27332
- }
27333
- const versions2 = parsed.map((v) => ({
27334
- id: String(v.id ?? ""),
27335
- number: typeof v.number === "number" ? v.number : undefined,
27336
- created_on: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.created_on ?? "") : undefined,
27337
- author: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.author ?? "") : undefined,
27338
- message: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.message ?? "") : undefined,
27339
- source: typeof v.metadata === "object" && v.metadata !== null ? String(v.metadata.source ?? "") : undefined
27340
- }));
27341
- return { ok: true, value: versions2 };
27342
- } catch (err) {
27343
- const message = err instanceof Error ? err.message : String(err);
27344
- return {
27345
- ok: false,
27346
- error: `Failed to parse versions list: ${message}`
27347
- };
27348
- }
27349
- }
27350
- async versionsRollback(workerName, versionId) {
27351
- return this.runWrangler([
27352
- "versions",
27353
- "rollback",
27354
- "--name",
27355
- workerName,
27356
- "--version-id",
27357
- versionId
27358
- ]);
27359
- }
27360
- async dev(workerPath, port) {
27361
- const devPort = port ?? 8787;
27362
- const resolvedPath = this.resolveWorkerPath(workerPath);
27363
- try {
27364
- Bun.spawn(["wrangler", "dev", "--port", String(devPort)], {
27365
- cwd: resolvedPath,
27366
- stdout: "pipe",
27367
- stderr: "pipe"
27368
- });
27369
- return { ok: true, value: { port: devPort } };
27370
- } catch (err) {
27371
- const message = err instanceof Error ? err.message : String(err);
27372
- return { ok: false, error: `Failed to start dev server: ${message}` };
27373
- }
27374
- }
27375
- async tail(workerName) {
27376
- return this.runWrangler(["tail", workerName]);
27377
- }
27378
- async d1List() {
27379
- return this.runWrangler(["d1", "list", "--json"]);
27380
- }
27381
- async d1Create(name) {
27382
- return this.runWrangler(["d1", "create", name]);
27383
- }
27384
- async d1Delete(name) {
27385
- return this.runWrangler(["d1", "delete", name]);
27386
- }
27387
- async d1Execute(name, sql, remote = true) {
27388
- const args = ["d1", "execute", name, "--command", sql];
27389
- if (remote)
27390
- args.push("--remote");
27391
- const result = await this.runWrangler(args);
27392
- if (!result.ok)
27393
- return result;
27394
- const extracted = extractJsonArray(result.value);
27395
- if (extracted === null) {
27396
- return {
27397
- ok: false,
27398
- error: `wrangler d1 execute returned non-JSON output: ${result.value.slice(0, 200)}`
27399
- };
27400
- }
27401
- return { ok: true, value: extracted };
27402
- }
27403
- async kvList() {
27404
- return this.runWrangler(["kv", "namespace", "list"]);
27405
- }
27406
- async kvCreate(name) {
27407
- return this.runWrangler(["kv", "namespace", "create", name]);
27408
- }
27409
- async kvDelete(id) {
27410
- return this.runWrangler([
27411
- "kv",
27412
- "namespace",
27413
- "delete",
27414
- "--namespace-id",
27415
- id
27416
- ]);
27417
- }
27418
- async r2List() {
27419
- return this.runWrangler(["r2", "bucket", "list"]);
27420
- }
27421
- async r2Create(name) {
27422
- return this.runWrangler(["r2", "bucket", "create", name]);
27423
- }
27424
- async r2Delete(name) {
27425
- return this.runWrangler(["r2", "bucket", "delete", name]);
27426
- }
27427
- async queueList() {
27428
- return this.runWrangler(["queues", "list"]);
27374
+ if (["warn", "warning", "degraded", "partial", "pending"].includes(lower)) {
27375
+ return `${theme.warning(icons.warning)} ${theme.text(v)}`;
27429
27376
  }
27430
- async queueCreate(name) {
27431
- return this.runWrangler(["queues", "create", name]);
27377
+ if ([
27378
+ "err",
27379
+ "error",
27380
+ "fail",
27381
+ "failed",
27382
+ "down",
27383
+ "unreachable",
27384
+ "disabled"
27385
+ ].includes(lower)) {
27386
+ return `${theme.error(icons.error)} ${theme.text(v)}`;
27432
27387
  }
27433
- async queueDelete(name) {
27434
- return this.runWrangler(["queues", "delete", name]);
27388
+ return value;
27389
+ }
27390
+ function formatJson(data, opts) {
27391
+ const json2 = opts?.quiet ? JSON.stringify(data) : JSON.stringify(data, null, 2);
27392
+ process.stdout.write(`${json2}
27393
+ `);
27394
+ }
27395
+ function formatKeyValue(pairs, opts = {}) {
27396
+ if (opts.quiet)
27397
+ return;
27398
+ if (opts.json) {
27399
+ process.stdout.write(JSON.stringify(pairs, null, 2) + `
27400
+ `);
27401
+ return;
27435
27402
  }
27436
- async vectorizeList() {
27437
- return this.runWrangler(["vectorize", "list", "--json"]);
27403
+ const maxKeyLen = Math.max(...Object.keys(pairs).map((k) => stripAnsi(k).length), 0);
27404
+ for (const [key, value] of Object.entries(pairs)) {
27405
+ const paddedKey = key.padEnd(maxKeyLen);
27406
+ process.stdout.write(` ${theme.key(paddedKey)} ${theme.textMuted(":")} ${value}
27407
+ `);
27438
27408
  }
27439
- async vectorizeCreate(name, dimensions = 768, metric = "cosine") {
27440
- return this.runWrangler([
27441
- "vectorize",
27442
- "create",
27443
- name,
27444
- "--dimensions",
27445
- String(dimensions),
27446
- "--metric",
27447
- metric
27448
- ]);
27409
+ }
27410
+ function getFormatOptions(cmd) {
27411
+ const opts = cmd.optsWithGlobals();
27412
+ return {
27413
+ json: Boolean(opts.json),
27414
+ quiet: Boolean(opts.quiet),
27415
+ noColor: Boolean(opts.color === false)
27416
+ };
27417
+ }
27418
+ function formatCompletion(message, opts = {}) {
27419
+ if (opts.json || opts.quiet)
27420
+ return;
27421
+ if (process.exitCode && process.exitCode !== 0)
27422
+ return;
27423
+ if (!isRichMode(opts))
27424
+ return;
27425
+ const parts = [theme.success(icons.success), theme.text(message)];
27426
+ if (opts.durationMs !== undefined) {
27427
+ parts.push(theme.textMuted(formatDuration3(opts.durationMs)));
27449
27428
  }
27450
- async vectorizeDelete(name) {
27451
- return this.runWrangler(["vectorize", "delete", name]);
27429
+ process.stdout.write(`${parts.join(" ")}
27430
+ `);
27431
+ if (opts.suggestion) {
27432
+ const reason = opts.suggestion.reason ? ` ${theme.textMuted(`(${opts.suggestion.reason})`)}` : "";
27433
+ process.stdout.write(` ${theme.textMuted("\u2192")} ${theme.textMuted("next:")} ${theme.accent(opts.suggestion.command)}${reason}
27434
+ `);
27452
27435
  }
27453
- async analyticsList() {
27454
- return this.runWrangler(["analytics", "dataset", "list"]);
27436
+ }
27437
+
27438
+ // src/utils/error-handler.ts
27439
+ init_errors4();
27440
+
27441
+ // src/utils/string.ts
27442
+ function levenshtein(a2, b) {
27443
+ if (a2 === b)
27444
+ return 0;
27445
+ if (a2.length === 0)
27446
+ return b.length;
27447
+ if (b.length === 0)
27448
+ return a2.length;
27449
+ const [s, t] = a2.length <= b.length ? [a2, b] : [b, a2];
27450
+ const m = s.length;
27451
+ const n = t.length;
27452
+ let prev = new Array(m + 1);
27453
+ for (let i = 0;i <= m; i++)
27454
+ prev[i] = i;
27455
+ let curr = new Array(m + 1);
27456
+ for (let j = 1;j <= n; j++) {
27457
+ curr[0] = j;
27458
+ for (let i = 1;i <= m; i++) {
27459
+ const cost = s.charCodeAt(i - 1) === t.charCodeAt(j - 1) ? 0 : 1;
27460
+ curr[i] = Math.min(curr[i - 1] + 1, prev[i] + 1, prev[i - 1] + cost);
27461
+ }
27462
+ [prev, curr] = [curr, prev];
27455
27463
  }
27456
- async analyticsCreate(_name) {
27457
- return {
27458
- ok: false,
27459
- error: `Analytics datasets cannot be created via wrangler. ` + `Please use the Cloudflare Dashboard: ` + `https://dash.cloudflare.com/?to=/:account/analytics`
27460
- };
27464
+ return prev[m];
27465
+ }
27466
+
27467
+ // src/utils/error-handler.ts
27468
+ var SUGGESTION_THRESHOLD = 2;
27469
+ function collectCommandNames(cmd, acc = new Set) {
27470
+ for (const sub of cmd.commands) {
27471
+ if (sub.name() && !sub.hidden) {
27472
+ acc.add(sub.name());
27473
+ collectCommandNames(sub, acc);
27474
+ }
27461
27475
  }
27462
- async secretList(workerName) {
27463
- const result = await this.runWrangler([
27464
- "secret",
27465
- "list",
27466
- "--name",
27467
- workerName
27468
- ]);
27469
- if (!result.ok)
27470
- return result;
27471
- const extracted = extractJsonArray(result.value);
27472
- if (extracted === null) {
27473
- return {
27474
- ok: false,
27475
- error: `wrangler secret list returned non-JSON output: ${result.value.slice(0, 200)}`
27476
- };
27476
+ return acc;
27477
+ }
27478
+ function suggestForCommand(program2, unknown2) {
27479
+ if (unknown2.length < 2)
27480
+ return;
27481
+ const normalized = unknown2.replace(/s$/, "");
27482
+ const candidates = collectCommandNames(program2);
27483
+ let best;
27484
+ for (const candidate of candidates) {
27485
+ const d = Math.min(levenshtein(unknown2, candidate), levenshtein(normalized, candidate));
27486
+ if (d > SUGGESTION_THRESHOLD)
27487
+ continue;
27488
+ if (!best || d < best.dist) {
27489
+ best = { name: candidate, dist: d };
27477
27490
  }
27478
- return { ok: true, value: extracted };
27479
27491
  }
27480
- async secretPut(workerName, secretName, value) {
27492
+ return best?.name;
27493
+ }
27494
+ function withErrorHandling(handler, options) {
27495
+ return async (...args) => {
27481
27496
  try {
27482
- const proc = Bun.spawn(["wrangler", "secret", "put", secretName, "--name", workerName], {
27483
- cwd: this.cwd,
27484
- stdout: "pipe",
27485
- stderr: "pipe",
27486
- stdin: "pipe"
27487
- });
27488
- proc.stdin.write(value + `
27489
- `);
27490
- proc.stdin.end();
27491
- const stdout2 = await new Response(proc.stdout).text();
27492
- const stderr = await new Response(proc.stderr).text();
27493
- const exitCode = await proc.exited;
27494
- if (exitCode === 0) {
27495
- return { ok: true, value: stdout2.trim() };
27497
+ await handler(...args);
27498
+ } catch (error51) {
27499
+ const service = options?.service ?? "cli";
27500
+ if (error51 instanceof CLIError) {
27501
+ formatError2(error51, options?.opts);
27502
+ process.exitCode = error51.code;
27503
+ return;
27504
+ } else if (error51 instanceof Error) {
27505
+ formatError2(`[${service}] ${error51.message}`, options?.opts);
27506
+ process.exitCode = 1 /* ERROR */;
27507
+ return;
27508
+ } else {
27509
+ formatError2(`[${service}] Unknown error: ${String(error51)}`, options?.opts);
27510
+ process.exitCode = 4 /* CommandFailed */;
27511
+ return;
27496
27512
  }
27497
- return {
27498
- ok: false,
27499
- error: stderr.trim() || `wrangler exited with code ${exitCode}`
27500
- };
27501
- } catch (err) {
27502
- const message = err instanceof Error ? err.message : String(err);
27503
- return { ok: false, error: `Failed to set secret: ${message}` };
27504
27513
  }
27514
+ };
27515
+ }
27516
+
27517
+ // src/utils/help-formatter.ts
27518
+ function renderHelp(cmd, helper) {
27519
+ const subcommands = cmd.commands.filter((c) => !c._hidden).map((c) => ({ name: c.name(), desc: c.description() ?? "" }));
27520
+ const blocks = [];
27521
+ const argNames = cmd.registeredArguments.map((a2) => a2.name()).join(" ");
27522
+ const titleName = argNames ? `${cmd.name()} ${argNames}` : cmd.name();
27523
+ blocks.push(theme.heading(` ${titleName}`));
27524
+ if (cmd.description()) {
27525
+ blocks.push(` ${theme.textMuted(cmd.description())}`);
27505
27526
  }
27506
- async secretDelete(workerName, secretName) {
27507
- return this.runWrangler([
27508
- "secret",
27509
- "delete",
27510
- secretName,
27511
- "--name",
27512
- workerName
27513
- ]);
27514
- }
27515
- async zonesList() {
27516
- const token = process.env.CLOUDFLARE_API_TOKEN;
27517
- if (!token) {
27518
- return {
27519
- ok: false,
27520
- error: "CLOUDFLARE_API_TOKEN environment variable is not set. Set it or run `wrangler login`."
27521
- };
27527
+ blocks.push(theme.textFaint("\u2500".repeat(60)));
27528
+ const usageLine = buildUsage(cmd);
27529
+ blocks.push(headerLine("Usage"));
27530
+ blocks.push(` ${theme.accent(usageLine)}`);
27531
+ const options = cmd.options.filter((o) => !o.hidden);
27532
+ if (options.length > 0) {
27533
+ blocks.push("");
27534
+ blocks.push(headerLine("Options"));
27535
+ const flagWidth = Math.max(...options.map((o) => o.flags.length));
27536
+ for (const o of options) {
27537
+ const padded = o.flags.padEnd(flagWidth);
27538
+ const desc = o.description ? theme.textMuted(o.description) : "";
27539
+ blocks.push(` ${theme.text(padded)} ${desc}`);
27522
27540
  }
27523
- try {
27524
- const response = await fetch("https://api.cloudflare.com/client/v4/zones?per_page=50", {
27525
- headers: {
27526
- Authorization: `Bearer ${token}`,
27527
- "Content-Type": "application/json"
27528
- }
27529
- });
27530
- const json2 = await response.json();
27531
- if (!response.ok || !json2.success) {
27532
- const errorMsg = json2.errors?.map((e) => e.message).join("; ") || `HTTP ${response.status}`;
27533
- return { ok: false, error: `Failed to list zones: ${errorMsg}` };
27534
- }
27535
- const lines = json2.result.map((z2) => `${z2.name} (${z2.id})`);
27536
- return { ok: true, value: lines.join(`
27537
- `) };
27538
- } catch (err) {
27539
- const message = err instanceof Error ? err.message : String(err);
27540
- return { ok: false, error: `Cloudflare API request failed: ${message}` };
27541
+ }
27542
+ if (subcommands.length > 0) {
27543
+ blocks.push("");
27544
+ blocks.push(headerLine("Commands"));
27545
+ const nameWidth = Math.max(...subcommands.map((s) => s.name.length));
27546
+ for (const s of subcommands) {
27547
+ const padded = s.name.padEnd(nameWidth);
27548
+ blocks.push(` ${theme.text(padded)} ${theme.textMuted(s.desc)}`);
27541
27549
  }
27542
27550
  }
27543
- extractUrl(stdout2) {
27544
- for (const line of stdout2.split(`
27545
- `)) {
27546
- const trimmed = line.trim();
27547
- const match = trimmed.match(/(https?:\/\/[^\s]+(?:workers\.dev|cloudflareworkers\.com)[^\s]*)/);
27548
- if (match)
27549
- return match[1];
27550
- }
27551
- return;
27551
+ const afterText = captureHelpEvent(cmd, "afterHelp");
27552
+ if (afterText.trim()) {
27553
+ blocks.push("");
27554
+ blocks.push(headerLine("Examples"));
27555
+ blocks.push(` ${theme.textMuted(afterText.trim())}`);
27552
27556
  }
27557
+ const out = blocks.join(`
27558
+ `) + `
27559
+ `;
27560
+ return isRichMode() ? out : stripAnsi(out);
27553
27561
  }
27554
- function extractJsonArray(raw) {
27555
- const first = raw.indexOf("[");
27556
- if (first === -1)
27557
- return null;
27558
- let depth = 0;
27559
- let inString = false;
27560
- let escape = false;
27561
- for (let i2 = first;i2 < raw.length; i2++) {
27562
- const ch = raw[i2];
27563
- if (escape) {
27564
- escape = false;
27565
- continue;
27566
- }
27567
- if (inString) {
27568
- if (ch === "\\")
27569
- escape = true;
27570
- else if (ch === '"')
27571
- inString = false;
27572
- continue;
27573
- }
27574
- if (ch === '"') {
27575
- inString = true;
27576
- continue;
27577
- }
27578
- if (ch === "[")
27579
- depth++;
27580
- else if (ch === "]") {
27581
- depth--;
27582
- if (depth === 0)
27583
- return raw.slice(first, i2 + 1);
27562
+ function headerLine(text) {
27563
+ return ` ${theme.textSubtle(text)}`;
27564
+ }
27565
+ function buildUsage(cmd) {
27566
+ const parts = [];
27567
+ let c = cmd;
27568
+ while (c && c.name()) {
27569
+ parts.unshift(c.name());
27570
+ c = c.parent;
27571
+ }
27572
+ for (const arg of cmd.registeredArguments) {
27573
+ parts.push(arg.name());
27574
+ }
27575
+ return `${parts.join(" ")} [options]`;
27576
+ }
27577
+ function captureHelpEvent(cmd, eventName) {
27578
+ const parts = [];
27579
+ const context = {
27580
+ error: false,
27581
+ command: cmd,
27582
+ write: (str) => {
27583
+ parts.push(str);
27584
27584
  }
27585
+ };
27586
+ const emitter = cmd;
27587
+ emitter.emit(eventName, context);
27588
+ return parts.join("");
27589
+ }
27590
+
27591
+ // src/utils/completion.ts
27592
+ var SUGGEST_NEXT = {
27593
+ init: { command: "hoox setup", reason: "provision infrastructure" },
27594
+ setup: { command: "hoox deploy all", reason: "ship to Cloudflare" },
27595
+ "deploy all": { command: "hoox check health", reason: "verify the deploy" },
27596
+ "check health": { command: "hoox monitor status", reason: "keep watching" },
27597
+ "monitor kill-switch off": {
27598
+ command: "hoox check health",
27599
+ reason: "re-enable trading"
27585
27600
  }
27586
- return null;
27601
+ };
27602
+ function suggestNextCommand(commandPath) {
27603
+ return SUGGEST_NEXT[commandPath];
27604
+ }
27605
+ function getCmdPath(cmd) {
27606
+ const parts = [];
27607
+ let current2 = cmd;
27608
+ while (current2 && current2.name() && current2.parent) {
27609
+ parts.unshift(current2.name());
27610
+ current2 = current2.parent;
27611
+ }
27612
+ return parts.join(" ");
27587
27613
  }
27614
+
27615
+ // src/commands/init/init-command.ts
27616
+ init_dist4();
27617
+ init_src();
27618
+
27619
+ // src/services/cloudflare/index.ts
27620
+ init_cloudflare_service();
27621
+
27588
27622
  // src/commands/init/init-command.ts
27589
27623
  init_errors4();
27590
27624
 
@@ -30832,7 +30866,7 @@ async function doUpdateInternalUrls(fmt) {
30832
30866
  }
30833
30867
  async function doKvConfig(fmt) {
30834
30868
  try {
30835
- const { KvSyncService: KvSyncService2 } = await Promise.resolve().then(() => exports_kv_sync_service);
30869
+ const { KvSyncService: KvSyncService2 } = await Promise.resolve().then(() => (init_kv_sync_service(), exports_kv_sync_service));
30836
30870
  const kvSync = new KvSyncService2;
30837
30871
  process.stdout.write(`${theme.info("Resolving CONFIG_KV namespace...")}
30838
30872
  `);
@@ -32054,6 +32088,10 @@ EXAMPLES:
32054
32088
  await handleGenerateDevVars(opts);
32055
32089
  }, { service: "env" }));
32056
32090
  }
32091
+
32092
+ // src/services/kv/index.ts
32093
+ init_kv_sync_service();
32094
+
32057
32095
  // src/commands/config/kv-command.ts
32058
32096
  init_errors4();
32059
32097
  async function resolveNs(cmd) {
@@ -33419,12 +33457,75 @@ async function handleSetup(opts) {
33419
33457
  process.exitCode = 1 /* ERROR */;
33420
33458
  }
33421
33459
  }
33460
+ var HEALTH_PROBE_TIMEOUT_MS = 8000;
33461
+ function resolveWorkerBaseUrl(workerName, global) {
33462
+ if (workerName === "hoox") {
33463
+ const envUrl = process.env.HOOX_GATEWAY_URL;
33464
+ if (envUrl && envUrl.length > 0) {
33465
+ return envUrl.replace(/\/+$/, "");
33466
+ }
33467
+ }
33468
+ const prefix = global.subdomain_prefix;
33469
+ if (prefix && prefix.length > 0) {
33470
+ return `https://${workerName}.${prefix}.workers.dev`;
33471
+ }
33472
+ const accountId = global.cloudflare_account_id || process.env.CLOUDFLARE_ACCOUNT_ID;
33473
+ if (accountId && accountId.length > 0) {
33474
+ return `https://${workerName}.${accountId}.workers.dev`;
33475
+ }
33476
+ throw new Error(`Cannot resolve URL for worker "${workerName}". Set global.subdomain_prefix or cloudflare_account_id in wrangler.jsonc (or HOOX_GATEWAY_URL for the gateway).`);
33477
+ }
33478
+ async function probeWorkerHealth(workerName, baseUrl, timeoutMs = HEALTH_PROBE_TIMEOUT_MS) {
33479
+ const url2 = `${baseUrl.replace(/\/+$/, "")}/health`;
33480
+ const started = Date.now();
33481
+ const controller = new AbortController;
33482
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
33483
+ try {
33484
+ const res = await fetch(url2, {
33485
+ method: "GET",
33486
+ signal: controller.signal,
33487
+ headers: { Accept: "application/json" }
33488
+ });
33489
+ const responseTime = Date.now() - started;
33490
+ if (res.ok) {
33491
+ return {
33492
+ worker: workerName,
33493
+ status: "healthy",
33494
+ connectivity: true,
33495
+ responseTime,
33496
+ url: url2
33497
+ };
33498
+ }
33499
+ return {
33500
+ worker: workerName,
33501
+ status: res.status >= 500 ? "down" : "degraded",
33502
+ connectivity: true,
33503
+ responseTime,
33504
+ url: url2,
33505
+ error: `HTTP ${res.status}`
33506
+ };
33507
+ } catch (err) {
33508
+ const responseTime = Date.now() - started;
33509
+ const aborted2 = err instanceof Error && err.name === "AbortError" || typeof err === "object" && err !== null && "name" in err && err.name === "AbortError";
33510
+ const message = aborted2 ? `Timeout after ${timeoutMs}ms` : err instanceof Error ? err.message : String(err);
33511
+ return {
33512
+ worker: workerName,
33513
+ status: "down",
33514
+ connectivity: false,
33515
+ responseTime,
33516
+ url: url2,
33517
+ error: message
33518
+ };
33519
+ } finally {
33520
+ clearTimeout(timer);
33521
+ }
33522
+ }
33422
33523
  async function handleHealth(opts, autoFix) {
33423
33524
  const results = [];
33424
33525
  try {
33425
33526
  const configService = new ConfigService;
33426
33527
  await configService.load();
33427
- const cf = new CloudflareService;
33528
+ const global = configService.getGlobal();
33428
33529
  const enabledWorkers = configService.listEnabledWorkers();
33429
33530
  if (enabledWorkers.length === 0) {
33430
33531
  formatSuccess("No enabled workers to check", opts);
@@ -33434,14 +33535,8 @@ async function handleHealth(opts, autoFix) {
33434
33535
  title: `Probe ${workerName}`,
33435
33536
  run: async () => {
33436
33537
  try {
33437
- const tailResult = await cf.tail(workerName);
33438
- const healthy = tailResult.ok;
33439
- return {
33440
- worker: workerName,
33441
- status: healthy ? "healthy" : "degraded",
33442
- connectivity: healthy,
33443
- error: tailResult.ok ? undefined : tailResult.error ?? "Unknown error"
33444
- };
33538
+ const baseUrl = resolveWorkerBaseUrl(workerName, global);
33539
+ return await probeWorkerHealth(workerName, baseUrl);
33445
33540
  } catch (err) {
33446
33541
  const message = err instanceof Error ? err.message : String(err);
33447
33542
  return {
@@ -33468,6 +33563,7 @@ async function handleHealth(opts, autoFix) {
33468
33563
  const rows = results.map((r2) => ({
33469
33564
  Worker: r2.worker,
33470
33565
  Status: r2.status,
33566
+ Latency: r2.responseTime != null ? `${r2.responseTime}ms` : "-",
33471
33567
  Connectivity: r2.connectivity ? "connected" : "failed",
33472
33568
  Error: r2.error ?? "-"
33473
33569
  }));
@@ -33796,10 +33892,11 @@ EXAMPLES:
33796
33892
  }, { service: "check" }));
33797
33893
  checkCmd.command("health").summary("Check worker connectivity and responsiveness").description(`Run health checks on all enabled workers to verify they are running and responsive.
33798
33894
 
33799
- Each worker is probed to verify:
33800
- - Worker is deployed to Cloudflare
33801
- - Worker is responding to requests
33802
- - No critical errors in recent logs
33895
+ Each worker is probed with a short HTTP GET to /health (default timeout 8s):
33896
+ - Worker URL from global.subdomain_prefix (or account id)
33897
+ - healthy \u2192 HTTP 2xx from /health
33898
+ - degraded \u2192 reachable but non-2xx (e.g. 4xx)
33899
+ - down \u2192 timeout, DNS, or network error
33803
33900
 
33804
33901
  OPTIONS:
33805
33902
  --fix Attempt automatic repair for detected issues (informational)
@@ -34285,6 +34382,7 @@ function registerTestCommand(program2) {
34285
34382
  }, { service: "test" }));
34286
34383
  }
34287
34384
  // src/commands/waf/waf-command.ts
34385
+ init_cloudflare_service();
34288
34386
  init_errors4();
34289
34387
  var CF_API_BASE = "https://api.cloudflare.com/client/v4";
34290
34388
  function getCredentials() {
@@ -34818,14 +34916,22 @@ init_dist4();
34818
34916
 
34819
34917
  // src/services/db/db-service.ts
34820
34918
  init_config2();
34919
+ init_cloudflare_service();
34920
+ import { existsSync as existsSync6 } from "fs";
34821
34921
  import { join as join7 } from "path";
34922
+ var D1_WRANGLER_CONFIG_CANDIDATES = [
34923
+ "workers/d1-worker/wrangler.jsonc",
34924
+ "workers/trade-worker/wrangler.jsonc"
34925
+ ];
34822
34926
 
34823
34927
  class DbService {
34824
34928
  configService;
34825
34929
  homeDir;
34826
- constructor(configService, homeDir) {
34930
+ wranglerConfigPath;
34931
+ constructor(configService, homeDir, wranglerConfigPath) {
34827
34932
  this.configService = configService ?? new ConfigService;
34828
34933
  this.homeDir = homeDir;
34934
+ this.wranglerConfigPath = wranglerConfigPath ?? process.env.HOOX_WRANGLER_CONFIG;
34829
34935
  }
34830
34936
  resolveDefaultSchemaPath() {
34831
34937
  if (this.homeDir) {
@@ -34897,7 +35003,8 @@ class DbService {
34897
35003
  }
34898
35004
  static parseTableNames(output) {
34899
35005
  try {
34900
- const parsed = JSON.parse(output);
35006
+ const jsonText = extractJsonArray(output) ?? output;
35007
+ const parsed = JSON.parse(jsonText);
34901
35008
  if (Array.isArray(parsed) && parsed.length > 0) {
34902
35009
  const first = parsed[0];
34903
35010
  if (first.results && Array.isArray(first.results)) {
@@ -34908,8 +35015,19 @@ class DbService {
34908
35015
  return output.split(`
34909
35016
  `).map((l2) => l2.trim()).filter(Boolean);
34910
35017
  }
35018
+ resolveWranglerConfigPath() {
35019
+ if (this.wranglerConfigPath)
35020
+ return this.wranglerConfigPath;
35021
+ for (const candidate of D1_WRANGLER_CONFIG_CANDIDATES) {
35022
+ if (existsSync6(candidate))
35023
+ return candidate;
35024
+ }
35025
+ return;
35026
+ }
34911
35027
  async runWrangler(args) {
34912
- const proc = Bun.spawn(["wrangler", ...args], {
35028
+ const configPath = this.resolveWranglerConfigPath();
35029
+ const fullArgs = configPath && !args.includes("-c") && !args.includes("--config") ? [...args, "-c", configPath] : args;
35030
+ const proc = Bun.spawn(["wrangler", ...fullArgs], {
34913
35031
  stdout: "pipe",
34914
35032
  stderr: "pipe"
34915
35033
  });
@@ -34917,7 +35035,8 @@ class DbService {
34917
35035
  const stderr = await new Response(proc.stderr).text();
34918
35036
  const exitCode = await proc.exited;
34919
35037
  if (exitCode !== 0) {
34920
- throw new Error(stderr.trim() || `wrangler exited with code ${exitCode}`);
35038
+ const detail = stderr.trim() || stdout2.trim() || `wrangler exited with code ${exitCode}`;
35039
+ throw new Error(detail);
34921
35040
  }
34922
35041
  return stdout2.trim();
34923
35042
  }
@@ -35151,6 +35270,7 @@ EXAMPLES:
35151
35270
  }, { service: "db" }));
35152
35271
  }
35153
35272
  // src/commands/monitor/monitor-command.ts
35273
+ init_kv_sync_service();
35154
35274
  init_errors4();
35155
35275
  function assertSafeInteger(value, name, max) {
35156
35276
  if (!Number.isInteger(value) || value < 0 || value > max || !Number.isSafeInteger(value)) {
@@ -35219,7 +35339,11 @@ function parseWranglerQueuesJson(raw) {
35219
35339
  const cleaned = raw.trim();
35220
35340
  if (!cleaned)
35221
35341
  return [];
35222
- const parsed = JSON.parse(cleaned);
35342
+ const firstBracket = cleaned.indexOf("[");
35343
+ const firstBrace = cleaned.indexOf("{");
35344
+ const start = firstBracket === -1 ? firstBrace : firstBrace === -1 ? firstBracket : Math.min(firstBracket, firstBrace);
35345
+ const payload = start >= 0 ? cleaned.slice(start) : cleaned;
35346
+ const parsed = JSON.parse(payload);
35223
35347
  if (Array.isArray(parsed)) {
35224
35348
  return parsed;
35225
35349
  }
@@ -35228,9 +35352,37 @@ function parseWranglerQueuesJson(raw) {
35228
35352
  }
35229
35353
  return [];
35230
35354
  }
35355
+ function parseWranglerQueuesTable(raw) {
35356
+ const queues = [];
35357
+ for (const line of raw.split(`
35358
+ `)) {
35359
+ if (!line.includes("\u2502"))
35360
+ continue;
35361
+ if (/[\u250C\u2514\u251C\u2500\u252C\u2534\u253C]/.test(line))
35362
+ continue;
35363
+ const cells = line.split("\u2502").map((c3) => c3.trim()).filter((c3) => c3.length > 0);
35364
+ if (cells.length < 2)
35365
+ continue;
35366
+ if (cells[0] === "id" || cells[0] === "name")
35367
+ continue;
35368
+ if (!/^[0-9a-f-]{16,}$/i.test(cells[0]))
35369
+ continue;
35370
+ const producers = cells[4] !== undefined && cells[4] !== "" ? Number(cells[4]) : undefined;
35371
+ const consumers = cells[5] !== undefined && cells[5] !== "" ? Number(cells[5]) : undefined;
35372
+ queues.push({
35373
+ queue_id: cells[0],
35374
+ queue_name: cells[1],
35375
+ created_on: cells[2],
35376
+ modified_on: cells[3],
35377
+ producers_total_count: Number.isFinite(producers) ? producers : undefined,
35378
+ consumers_total_count: Number.isFinite(consumers) ? consumers : undefined
35379
+ });
35380
+ }
35381
+ return queues;
35382
+ }
35231
35383
  async function doMonitorQueueDepth(fmt) {
35232
35384
  try {
35233
- const proc = Bun.spawn(["wrangler", "queues", "list", "--json"], {
35385
+ const proc = Bun.spawn(["wrangler", "queues", "list"], {
35234
35386
  stdout: "pipe",
35235
35387
  stderr: "pipe"
35236
35388
  });
@@ -35241,22 +35393,20 @@ async function doMonitorQueueDepth(fmt) {
35241
35393
  throw new Error(stderr.trim() || `wrangler exited with code ${exitCode}`);
35242
35394
  }
35243
35395
  if (fmt.json) {
35244
- const queues = parseWranglerQueuesJson(stdout2);
35396
+ let queues;
35397
+ try {
35398
+ queues = parseWranglerQueuesJson(stdout2);
35399
+ if (queues.length === 0) {
35400
+ queues = parseWranglerQueuesTable(stdout2);
35401
+ }
35402
+ } catch {
35403
+ queues = parseWranglerQueuesTable(stdout2);
35404
+ }
35245
35405
  process.stdout.write(JSON.stringify({ queues }, null, 2) + `
35246
35406
  `);
35247
35407
  return;
35248
35408
  }
35249
- const procHuman = Bun.spawn(["wrangler", "queues", "list"], {
35250
- stdout: "pipe",
35251
- stderr: "pipe"
35252
- });
35253
- const stdoutHuman = await new Response(procHuman.stdout).text();
35254
- const stderrHuman = await new Response(procHuman.stderr).text();
35255
- const exitHuman = await procHuman.exited;
35256
- if (exitHuman !== 0) {
35257
- throw new Error(stderrHuman.trim() || `wrangler exited with code ${exitHuman}`);
35258
- }
35259
- process.stdout.write(stdoutHuman + `
35409
+ process.stdout.write(stdout2 + `
35260
35410
  `);
35261
35411
  } catch (err) {
35262
35412
  formatError2(err instanceof Error ? err.message : String(err), fmt);
@@ -35640,7 +35790,9 @@ class RepairService {
35640
35790
  }
35641
35791
  }
35642
35792
  }
35793
+
35643
35794
  // src/commands/repair/repair-command.ts
35795
+ init_kv_sync_service();
35644
35796
  init_errors4();
35645
35797
  async function handleCheck(fmt, options = {}) {
35646
35798
  try {
@@ -35649,10 +35801,23 @@ async function handleCheck(fmt, options = {}) {
35649
35801
  installDeps: Boolean(options.installDeps),
35650
35802
  typecheck: options.typecheck !== false
35651
35803
  });
35652
- if (result.allPassed) {
35653
- formatSuccess("All checks passed", fmt);
35804
+ if (fmt.json) {
35805
+ process.stdout.write(JSON.stringify(result, null, 2) + `
35806
+ `);
35654
35807
  } else {
35655
- formatError2(new CLIError(`${result.failedCount} check(s) failed`, 1 /* ERROR */), fmt);
35808
+ const rows = result.steps.map((s) => ({
35809
+ Step: s.step,
35810
+ Status: s.success ? "ok" : "fail",
35811
+ Detail: s.message ?? s.error ?? "-"
35812
+ }));
35813
+ formatTable(rows, fmt);
35814
+ if (result.allPassed) {
35815
+ formatSuccess(`All ${result.passedCount} check(s) passed`, fmt);
35816
+ } else {
35817
+ formatError2(new CLIError(`${result.failedCount} of ${result.steps.length} check(s) failed`, 1 /* ERROR */), fmt);
35818
+ }
35819
+ }
35820
+ if (!result.allPassed) {
35656
35821
  process.exitCode = 1 /* ERROR */;
35657
35822
  }
35658
35823
  } catch (err) {
@@ -35930,22 +36095,56 @@ function registerSchemaCommand(program2) {
35930
36095
  }
35931
36096
  // src/commands/tui/tui-command.ts
35932
36097
  import { spawn } from "child_process";
35933
- import { resolve as resolve6, dirname as dirname2 } from "path";
36098
+ import { createRequire } from "module";
36099
+ import { resolve as resolve6, dirname as dirname2, join as join8 } from "path";
35934
36100
  import { fileURLToPath } from "url";
35935
- import { existsSync as existsSync7 } from "fs";
36101
+ import { existsSync as existsSync8 } from "fs";
35936
36102
  init_errors4();
35937
36103
  var __dirname2 = dirname2(fileURLToPath(import.meta.url));
35938
- function resolveTUIEntry() {
36104
+ var require2 = createRequire(import.meta.url);
36105
+ var TUI_PKG = "@jango-blockchained/hoox-tui";
36106
+ function collectTuiCandidates() {
35939
36107
  const candidates = [
35940
36108
  resolve6(__dirname2, "../../../../tui/src/main.tsx"),
36109
+ resolve6(__dirname2, "../../../../tui/dist/main.js"),
36110
+ resolve6(__dirname2, "../../../tui/src/main.tsx"),
36111
+ resolve6(__dirname2, "../../../tui/dist/main.js"),
35941
36112
  resolve6(process.cwd(), "packages/tui/src/main.tsx"),
35942
- resolve6(process.cwd(), "../tui/src/main.tsx")
36113
+ resolve6(process.cwd(), "packages/tui/dist/main.js"),
36114
+ resolve6(process.cwd(), "../tui/src/main.tsx"),
36115
+ resolve6(process.cwd(), "../tui/dist/main.js")
35943
36116
  ];
36117
+ pushPackageEntries(candidates, require2);
36118
+ try {
36119
+ const cwdRequire = createRequire(join8(process.cwd(), "package.json"));
36120
+ pushPackageEntries(candidates, cwdRequire);
36121
+ } catch {}
36122
+ return candidates;
36123
+ }
36124
+ function pushPackageEntries(candidates, req) {
36125
+ try {
36126
+ const pkgJsonPath = req.resolve(`${TUI_PKG}/package.json`);
36127
+ const root = dirname2(pkgJsonPath);
36128
+ candidates.push(join8(root, "src/main.tsx"), join8(root, "dist/main.js"), join8(root, "src/main.ts"));
36129
+ } catch {}
36130
+ }
36131
+ function resolveTUIEntry() {
36132
+ const candidates = collectTuiCandidates();
35944
36133
  for (const path6 of candidates) {
35945
- if (existsSync7(path6))
36134
+ if (existsSync8(path6))
35946
36135
  return path6;
35947
36136
  }
35948
- throw new CLIError("Could not find TUI entry point. Ensure packages/tui/src/main.tsx exists.", 1 /* ERROR */);
36137
+ throw new CLIError([
36138
+ "Could not find the Hoox TUI entry point.",
36139
+ "",
36140
+ "Fix options:",
36141
+ " \u2022 From the monorepo: ensure packages/tui/src/main.tsx exists",
36142
+ ` \u2022 Or install the package: bun add -g ${TUI_PKG}`,
36143
+ " \u2022 Or from a project: bun add -d " + TUI_PKG,
36144
+ "",
36145
+ "Then re-run: hoox tui"
36146
+ ].join(`
36147
+ `), 1 /* ERROR */);
35949
36148
  }
35950
36149
  function registerTUICommand(program2) {
35951
36150
  program2.command("tui").description("Launch the OpenTUI terminal operations center").option("--fps <number>", "Target frames per second", "30").option("--no-mouse", "Disable mouse support").action(withErrorHandling(async (options) => {
@@ -36812,7 +37011,20 @@ EXAMPLES:
36812
37011
  to: options.to
36813
37012
  }, fmt);
36814
37013
  }, { service: "trace" }));
36815
- const destinationsCmd = traceCmd.command("destinations").summary("Manage OTLP export destinations");
37014
+ const destinationsCmd = traceCmd.command("destinations").summary("Manage OTLP export destinations").description(`List and manage OTLP export destinations.
37015
+
37016
+ SUBCOMMANDS:
37017
+ list List destinations (default when no subcommand given)
37018
+ add <name> <url> Add a destination
37019
+ remove <slug> Remove a destination
37020
+
37021
+ EXAMPLES:
37022
+ hoox trace destinations List (default)
37023
+ hoox trace destinations list
37024
+ hoox trace destinations add honeycomb https://api.honeycomb.io/1/traces`).action(withErrorHandling(async (_options, cmd) => {
37025
+ const fmt = getFormatOptions(cmd);
37026
+ await handleDestinationsList(fmt);
37027
+ }, { service: "trace" }));
36816
37028
  destinationsCmd.command("list").summary("List OTLP export destinations").description(`List all configured OTLP export destinations.
36817
37029
 
36818
37030
  Destinations allow exporting traces (and logs) to third-party observability
@@ -37534,137 +37746,24 @@ function registerCompletionCommand(program2) {
37534
37746
  }
37535
37747
  }));
37536
37748
  }
37537
- // src/commands/pine/pine-command.ts
37538
- import { resolve as resolve7 } from "path";
37539
- var PINE_WORKER_DIR = resolve7(process.cwd(), "workers/pine-worker");
37540
- async function spawnPineScript(script, args = []) {
37541
- const proc = Bun.spawn(["bun", "run", script, ...args], {
37542
- cwd: PINE_WORKER_DIR,
37543
- stdio: ["inherit", "inherit", "inherit"]
37544
- });
37545
- return await proc.exited;
37546
- }
37547
- function registerPineCommand(program2) {
37548
- const pineCmd = program2.command("pine").summary("Pine Script strategy tooling (backtest, data, export)").description(`Manage Pine Script strategies, data, and chart exports.
37549
-
37550
- SUBCOMMANDS:
37551
- download Download OHLCV historical data from Binance
37552
- backtest <file> Run a Pine Script against local historical data
37553
- export <file> Export per-bar chart data as CSV or JSON
37554
- bundle Bundle built-in Pine libraries for deployment
37555
-
37556
- Data is stored under workers/pine-worker/data/ and consumed by the
37557
- pine-worker at runtime.
37558
-
37559
- EXAMPLES:
37560
- hoox pine download Default: BTCUSDT 1d 365d
37561
- hoox pine download --all All default symbols
37562
- hoox pine download -s ETHUSDT --tf 1h -d 30 Custom download
37563
- hoox pine backtest ../grid.pine -s BTCUSDT Run a strategy
37564
- hoox pine export ../grid.pine --csv Export chart data as CSV
37565
- hoox pine bundle Bundle libraries for deploy`);
37566
- pineCmd.command("download").summary("Download OHLCV historical data from Binance").description(`Fetch historical klines from Binance and store as compressed JSON Lines
37567
- under workers/pine-worker/data/{SYMBOL}/{TIMEFRAME}/{YYYY}.jsonl.gz.
37568
-
37569
- OPTIONS:
37570
- -s, --symbol Symbol to download (default: BTCUSDT)
37571
- --tf Timeframe: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h,
37572
- 8h, 12h, 1d, 3d, 1w, 1M (default: 1d)
37573
- -d, --days Days of history to fetch (default: 365)
37574
- -a, --all Download all default symbols (BTC, ETH, SOL, BNB,
37575
- XRP, ADA, DOGE, AVAX)
37576
-
37577
- EXAMPLES:
37578
- hoox pine download
37579
- hoox pine download --all
37580
- hoox pine download -s ETHUSDT --tf 1h -d 30`).option("-s, --symbol <symbol>", "Symbol to download", "BTCUSDT").option("--tf <timeframe>", "Timeframe interval", "1d").option("-d, --days <days>", "Days of history to fetch", "365").option("-a, --all", "Download all default symbols").action(withErrorHandling(async (opts) => {
37581
- const args = [];
37582
- if (opts.all) {
37583
- args.push("--all");
37584
- } else {
37585
- args.push("--symbol", opts.symbol);
37586
- args.push("--tf", opts.tf);
37587
- if (opts.days !== "365")
37588
- args.push("--days", opts.days);
37589
- }
37590
- process.exitCode = await spawnPineScript("scripts/download-data.ts", args);
37591
- }, { service: "pine" }));
37592
- pineCmd.command("backtest <script-path>").summary("Run a Pine Script against local historical data").description(`Execute a Pine Script strategy against historical OHLCV data and
37593
- print trade events (entries, exits, orders) to stdout.
37594
-
37595
- ARGUMENTS:
37596
- script-path Path to the .pine script file
37597
-
37598
- OPTIONS:
37599
- -s, --symbol Trading symbol (default: BTCUSDT)
37600
- --tf Timeframe (default: 5m)
37601
- -b, --bars Number of bars to evaluate (default: 864)
37602
-
37603
- EXAMPLES:
37604
- hoox pine backtest ../grid.pine
37605
- hoox pine backtest ../grid.pine -s ETHUSDT --tf 15m -b 500`).option("-s, --symbol <symbol>", "Trading symbol", "BTCUSDT").option("--tf <timeframe>", "Timeframe", "5m").option("-b, --bars <bars>", "Number of bars to evaluate", "864").action(withErrorHandling(async (scriptPath, opts) => {
37606
- process.exitCode = await spawnPineScript("scripts/run-backtest.ts", [
37607
- scriptPath,
37608
- opts.symbol,
37609
- opts.tf,
37610
- opts.bars
37611
- ]);
37612
- }, { service: "pine" }));
37613
- pineCmd.command("export <script-path>").summary("Export per-bar chart data (TradingView-style)").description(`Run a Pine Script and export per-bar OHLCV + plot values as
37614
- CSV or JSON \u2014 matching TradingView's "Export chart data" layout.
37615
-
37616
- ARGUMENTS:
37617
- script-path Path to the .pine script file
37618
-
37619
- OPTIONS:
37620
- -s, --symbol Trading symbol (default: BTCUSDT)
37621
- --tf Timeframe (default: 1d)
37622
- -b, --bars Number of bars to evaluate (default: 500)
37623
- --csv Export as CSV (default: JSON)
37624
-
37625
- Output files are written to the current directory:
37626
- {SYMBOL}_{TIMEFRAME}_chart.csv or {SYMBOL}_{TIMEFRAME}_chart.json
37627
-
37628
- EXAMPLES:
37629
- hoox pine export ../grid.pine
37630
- hoox pine export ../grid.pine -s ETHUSDT --csv
37631
- hoox pine export ../grid.pine --tf 1h -b 200`).option("-s, --symbol <symbol>", "Trading symbol", "BTCUSDT").option("--tf <timeframe>", "Timeframe", "1d").option("-b, --bars <bars>", "Number of bars to evaluate", "500").option("--csv", "Export as CSV (default: JSON)").action(withErrorHandling(async (scriptPath, opts) => {
37632
- const args = [scriptPath, opts.symbol, opts.tf, opts.bars];
37633
- if (opts.csv)
37634
- args.push("--csv");
37635
- process.exitCode = await spawnPineScript("scripts/export-chart.ts", args);
37636
- }, { service: "pine" }));
37637
- pineCmd.command("bundle").summary("Bundle built-in Pine libraries for deployment").description(`Embed libraries/*.pine files into src/module/bundled-libraries.ts
37638
- so library imports work in the Cloudflare Worker runtime.
37639
-
37640
- This runs automatically as a prebuild step before deploy, but can
37641
- also be run manually after updating library files.
37642
-
37643
- EXAMPLES:
37644
- hoox pine bundle`).action(withErrorHandling(async () => {
37645
- process.exitCode = await spawnPineScript("scripts/bundle-libraries.ts");
37646
- }, { service: "pine" }));
37647
- pineCmd.action(() => {
37648
- pineCmd.help();
37649
- });
37650
- }
37651
37749
  // src/ui/banner.ts
37652
- import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
37750
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
37653
37751
  import { fileURLToPath as fileURLToPath2 } from "url";
37654
- import { dirname as dirname3, join as join8 } from "path";
37655
- var TAGLINE = "Cloudflare Workers Platform";
37752
+ import { dirname as dirname3, join as join9 } from "path";
37656
37753
  var ORANGE = ansis_default.hex("#ff7f2a");
37657
37754
  var AMBER = ansis_default.hex("#ffb722");
37658
37755
  var INDIGO = ansis_default.hex("#818cf8");
37659
37756
  var INDIGO_SOFT = ansis_default.hex("#a5b4fc");
37660
37757
  var ZINC = ansis_default.hex("#a1a1aa");
37661
37758
  var ZINC_FAINT = ansis_default.hex("#52525b");
37759
+ var ZINC_SOFT = ansis_default.hex("#71717a");
37760
+ var TAGLINE = "Cloudflare Workers Platform";
37662
37761
  function findCliVersion() {
37663
37762
  const PKG_NAME = "@jango-blockchained/hoox-cli";
37664
37763
  let dir = dirname3(fileURLToPath2(import.meta.url));
37665
37764
  for (let i2 = 0;i2 < 5; i2++) {
37666
- const pkgPath = join8(dir, "package.json");
37667
- if (existsSync8(pkgPath)) {
37765
+ const pkgPath = join9(dir, "package.json");
37766
+ if (existsSync9(pkgPath)) {
37668
37767
  try {
37669
37768
  const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
37670
37769
  if (pkg.name === PKG_NAME)
@@ -37680,107 +37779,35 @@ function findCliVersion() {
37680
37779
  }
37681
37780
  var VERSION = findCliVersion();
37682
37781
  var DISCLAIMER2 = "DISCLAIMER: Trading cryptocurrencies involves substantial risk of loss. Use at your own risk.";
37683
- var LOGO_GRID = [
37684
- " /\\ ",
37685
- " /##\\ ",
37686
- " /####\\ ",
37687
- " // ## \\\\ ",
37688
- " // #### \\\\ ",
37689
- " // \\\\ ",
37690
- " //- #### -\\\\ ",
37691
- " \\\\- #### -// ",
37692
- " \\\\ // ",
37693
- " \\\\ #### // ",
37694
- " \\\\ ## // ",
37695
- " \\####/ ",
37696
- " \\##/ ",
37697
- " \\/ "
37698
- ];
37699
- var LOGO_W = LOGO_GRID[0].length;
37700
- function cellRole(ch) {
37701
- if (ch === "#" || ch === "\u2588")
37702
- return "solid";
37703
- if (ch === " " || ch === "")
37704
- return "empty";
37705
- return "outline";
37706
- }
37707
- function displayChar(ch) {
37708
- if (ch === "#")
37709
- return "\u2588";
37710
- if (ch === "/")
37711
- return "\u2571";
37712
- if (ch === "\\")
37713
- return "\u2572";
37714
- if (ch === "-" || ch === "_")
37715
- return "\u2500";
37716
- return ch;
37717
- }
37718
- function colorLogoLine(raw, row, phase, mode) {
37719
- let out = "";
37720
- for (let col = 0;col < raw.length; col++) {
37721
- const enc = raw[col];
37722
- const role = cellRole(enc);
37723
- if (role === "empty") {
37724
- out += " ";
37725
- continue;
37726
- }
37727
- const ch = displayChar(enc);
37728
- if (mode === "assemble") {
37729
- const solidReady = phase >= 0.15;
37730
- const outlineReady = phase >= 0.5;
37731
- if (role === "solid" && !solidReady) {
37732
- out += ZINC_FAINT("\xB7");
37733
- continue;
37734
- }
37735
- if (role === "outline" && !outlineReady) {
37736
- out += " ";
37737
- continue;
37738
- }
37739
- if (role === "solid" && phase < 0.45) {
37740
- out += ZINC(ch);
37741
- continue;
37742
- }
37743
- if (role === "outline" && phase < 0.75) {
37744
- out += ZINC_FAINT(ch);
37745
- continue;
37746
- }
37747
- }
37748
- if (mode === "shimmer") {
37749
- const t2 = (phase * 1.5 + (col + row) * 0.07) % 1;
37750
- if (t2 < 0.12) {
37751
- out += (role === "solid" ? AMBER : INDIGO_SOFT)(ch);
37752
- } else if (t2 < 0.3) {
37753
- out += (role === "solid" ? ORANGE : INDIGO)(ch);
37754
- } else {
37755
- out += role === "solid" ? ansis_default.hex("#e4e4e7")(ch) : INDIGO.dim(ch);
37756
- }
37757
- continue;
37758
- }
37759
- out += role === "solid" ? ansis_default.hex("#fafafa")(ch) : ansis_default.hex("#a1a1aa")(ch);
37760
- }
37761
- return out;
37762
- }
37763
- function renderLogoBlock(phase, mode) {
37764
- return LOGO_GRID.map((line, row) => colorLogoLine(line, row, phase, mode));
37765
- }
37766
37782
  var WORDMARK = [
37767
- "\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557",
37768
- "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D",
37769
- "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2554\u255D ",
37770
- "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 ",
37771
- "\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2554\u255D \u2588\u2588\u2557",
37772
- "\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D"
37783
+ " _ _ ___ _____ _ ",
37784
+ "| | | |/ _ \\ / _ \\ \\/ / ",
37785
+ "| |_| | (_) | (_) > < ",
37786
+ " \\___/ \\___/ \\___/_/\\_\\ "
37773
37787
  ];
37788
+ var WORD_W = WORDMARK[0].length;
37774
37789
  function colorWordmark(phase, mode) {
37775
37790
  return WORDMARK.map((line, row) => {
37776
- if (mode === "assemble" && phase < 0.7) {
37777
- const reveal = Math.max(0, (phase - 0.5) / 0.35);
37778
- if (reveal <= 0)
37779
- return ZINC_FAINT(line.replace(/[^\s]/g, "\xB7"));
37780
- if (reveal < 1)
37781
- return ZINC(line);
37782
- }
37783
- if (mode === "shimmer") {
37791
+ if (mode === "assemble") {
37792
+ const local = Math.max(0, Math.min(1, phase));
37793
+ const cut = Math.floor(local * line.length);
37794
+ let out = "";
37795
+ for (let col = 0;col < line.length; col++) {
37796
+ const ch = line[col];
37797
+ if (ch === " ") {
37798
+ out += " ";
37799
+ continue;
37800
+ }
37801
+ if (col > cut)
37802
+ out += ZINC_FAINT("\xB7");
37803
+ else if (local < 0.85)
37804
+ out += ZINC(ch);
37805
+ else
37806
+ out += theme.heading(ch);
37807
+ }
37808
+ return out;
37809
+ }
37810
+ if (mode === "pulse") {
37784
37811
  let out = "";
37785
37812
  for (let col = 0;col < line.length; col++) {
37786
37813
  const ch = line[col];
@@ -37788,36 +37815,32 @@ function colorWordmark(phase, mode) {
37788
37815
  out += " ";
37789
37816
  continue;
37790
37817
  }
37791
- const t2 = (phase * 1.2 + col * 0.04 + row * 0.05) % 1;
37792
- out += t2 < 0.2 ? INDIGO_SOFT(ch) : INDIGO.bold(ch);
37818
+ const t2 = (phase * 1.5 + col * 0.05 + row * 0.06) % 1;
37819
+ if (t2 < 0.12)
37820
+ out += AMBER(ch);
37821
+ else if (t2 < 0.25)
37822
+ out += ORANGE(ch);
37823
+ else if (t2 < 0.4)
37824
+ out += INDIGO_SOFT(ch);
37825
+ else
37826
+ out += INDIGO.bold(ch);
37793
37827
  }
37794
37828
  return out;
37795
37829
  }
37796
37830
  return theme.heading(line);
37797
37831
  });
37798
37832
  }
37799
- var BANNER_PAD = " ";
37833
+ var PAD = " ";
37800
37834
  function composeFrame(phase, mode) {
37801
- const logo = renderLogoBlock(phase, mode);
37802
37835
  const word = colorWordmark(phase, mode);
37803
- const gap = " ";
37804
- const wordH = word.length;
37805
- const logoH = logo.length;
37806
- const topPad = Math.floor((logoH - wordH) / 2);
37807
- const contentW = LOGO_W + gap.length + (WORDMARK[0]?.length ?? 0);
37808
- const lines = [];
37809
- for (let i2 = 0;i2 < logoH; i2++) {
37810
- const left = logo[i2];
37811
- const wi = i2 - topPad;
37812
- const right = wi >= 0 && wi < wordH ? word[wi] : " ".repeat(WORDMARK[0].length);
37813
- lines.push(BANNER_PAD + left + gap + right);
37814
- }
37815
- const rule = ZINC_FAINT("\u2500".repeat(contentW + 2));
37816
- const meta3 = BANNER_PAD + ZINC(TAGLINE) + " " + ZINC_FAINT("\xB7") + " " + INDIGO_SOFT(`v${VERSION}`);
37817
- const metaVis = stripAnsi(meta3).length;
37818
- const metaPad = Math.max(0, Math.floor((contentW + 2 - metaVis) / 2));
37819
- const metaLine = " ".repeat(metaPad) + meta3.trimStart();
37820
- return [BANNER_PAD + rule, ...lines, BANNER_PAD + rule, metaLine].join(`
37836
+ const contentW = WORD_W;
37837
+ const body = word.map((line) => PAD + line);
37838
+ const rule = PAD + ZINC_FAINT("\u2500".repeat(contentW));
37839
+ const metaInner = ZINC_SOFT(TAGLINE) + " " + ZINC_FAINT("\xB7") + " " + INDIGO_SOFT(`v${VERSION}`);
37840
+ const metaVis = stripAnsi(metaInner).length;
37841
+ const metaPad = Math.max(0, Math.floor((contentW - metaVis) / 2));
37842
+ const meta3 = PAD + " ".repeat(metaPad) + metaInner;
37843
+ return [rule, ...body, rule, meta3].join(`
37821
37844
  `);
37822
37845
  }
37823
37846
  function canAnimate() {
@@ -37844,12 +37867,12 @@ async function animateBanner(options) {
37844
37867
  `);
37845
37868
  return lineCount;
37846
37869
  }
37847
- const durationMs = options?.durationMs ?? 900;
37870
+ const durationMs = options?.durationMs ?? 800;
37848
37871
  const assembleMs = Math.floor(durationMs * 0.55);
37849
- const shimmerMs = durationMs - assembleMs;
37850
- const fps = 24;
37872
+ const pulseMs = durationMs - assembleMs;
37873
+ const fps = 28;
37851
37874
  const assembleFrames = Math.max(6, Math.round(assembleMs / 1000 * fps));
37852
- const shimmerFrames = Math.max(4, Math.round(shimmerMs / 1000 * fps));
37875
+ const pulseFrames = Math.max(4, Math.round(pulseMs / 1000 * fps));
37853
37876
  let wroteLines = 0;
37854
37877
  const writeFrame = (frame) => {
37855
37878
  const lines = frame.split(`
@@ -37873,14 +37896,14 @@ async function animateBanner(options) {
37873
37896
  process.stdout.write("\x1B[?25l");
37874
37897
  try {
37875
37898
  for (let i2 = 0;i2 < assembleFrames; i2++) {
37876
- const phase = i2 / (assembleFrames - 1);
37899
+ const phase = i2 / Math.max(1, assembleFrames - 1);
37877
37900
  writeFrame(composeFrame(phase, "assemble"));
37878
37901
  await sleep2(assembleMs / assembleFrames);
37879
37902
  }
37880
- for (let i2 = 0;i2 < shimmerFrames; i2++) {
37881
- const phase = i2 / Math.max(1, shimmerFrames - 1);
37882
- writeFrame(composeFrame(phase, "shimmer"));
37883
- await sleep2(shimmerMs / shimmerFrames);
37903
+ for (let i2 = 0;i2 < pulseFrames; i2++) {
37904
+ const phase = i2 / Math.max(1, pulseFrames - 1);
37905
+ writeFrame(composeFrame(phase, "pulse"));
37906
+ await sleep2(pulseMs / pulseFrames);
37884
37907
  }
37885
37908
  writeFrame(finalFrame);
37886
37909
  } finally {
@@ -38358,7 +38381,6 @@ registerSetupCommand(program2);
38358
38381
  registerTraceCommand(program2);
38359
38382
  registerPerfCommand(program2);
38360
38383
  registerCompletionCommand(program2);
38361
- registerPineCommand(program2);
38362
38384
  async function main() {
38363
38385
  try {
38364
38386
  const hasArgs = process.argv.slice(2).length > 0;