@okx_ai/okx-trade-cli 1.3.6-beta.2 → 1.3.6-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -34,22 +34,16 @@ import os from "os";
34
34
  import { writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2 } from "fs";
35
35
  import { join as join4, resolve, basename, sep } from "path";
36
36
  import { randomUUID } from "crypto";
37
- import { createHash } from "crypto";
38
- import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
39
- import { join as join5 } from "path";
40
- import { createHash as createHash2, createPublicKey, verify as cryptoVerify } from "crypto";
41
- import { readFileSync as readFileSync3 } from "fs";
42
- import { join as join6, resolve as resolve2, sep as sep2 } from "path";
43
37
  import yauzl from "yauzl";
44
38
  import { createWriteStream, mkdirSync as mkdirSync3 } from "fs";
45
- import { resolve as resolve3, dirname as dirname2 } from "path";
46
- import { readFileSync as readFileSync4, existsSync } from "fs";
47
- import { join as join7 } from "path";
48
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync2 } from "fs";
49
- import { join as join8, dirname as dirname3 } from "path";
39
+ import { resolve as resolve2, dirname as dirname2 } from "path";
40
+ import { readFileSync as readFileSync2, existsSync } from "fs";
41
+ import { join as join5 } from "path";
42
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync2 } from "fs";
43
+ import { join as join6, dirname as dirname3 } from "path";
50
44
  import { homedir as homedir4 } from "os";
51
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
52
- import { join as join9, dirname as dirname4 } from "path";
45
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
46
+ import { join as join7, dirname as dirname4 } from "path";
53
47
  import { homedir as homedir5 } from "os";
54
48
 
55
49
  // ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
@@ -127,7 +121,7 @@ function skipVoid(str, ptr, banNewLines, banComments) {
127
121
  ptr++;
128
122
  return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines);
129
123
  }
130
- function skipUntil(str, ptr, sep3, end, banNewLines = false) {
124
+ function skipUntil(str, ptr, sep2, end, banNewLines = false) {
131
125
  if (!end) {
132
126
  ptr = indexOfNewline(str, ptr);
133
127
  return ptr < 0 ? str.length : ptr;
@@ -136,7 +130,7 @@ function skipUntil(str, ptr, sep3, end, banNewLines = false) {
136
130
  let c = str[i];
137
131
  if (c === "#") {
138
132
  i = indexOfNewline(str, i);
139
- } else if (c === sep3) {
133
+ } else if (c === sep2) {
140
134
  return i + 1;
141
135
  } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
142
136
  return i;
@@ -879,8 +873,8 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
879
873
  }
880
874
 
881
875
  // ../core/dist/index.js
882
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
883
- import { join as join10 } from "path";
876
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
877
+ import { join as join8 } from "path";
884
878
  import { homedir as homedir6 } from "os";
885
879
  import fs2 from "fs";
886
880
  import path2 from "path";
@@ -897,37 +891,25 @@ import {
897
891
  renameSync as renameSync4
898
892
  } from "fs";
899
893
  import { homedir as homedir9, platform as platform2 } from "os";
900
- import { join as join13, dirname as dirname7 } from "path";
894
+ import { join as join11, dirname as dirname7 } from "path";
901
895
  import { createWriteStream as createWriteStream2, unlinkSync as unlinkSync3 } from "fs";
902
896
  import { get as httpsGet } from "https";
903
897
  import { get as httpGet } from "http";
904
898
  import {
905
- readFileSync as readFileSync9,
899
+ readFileSync as readFileSync7,
906
900
  mkdirSync as mkdirSync8,
907
901
  chmodSync,
908
902
  existsSync as existsSync6,
909
903
  unlinkSync as unlinkSync4,
910
904
  renameSync as renameSync3
911
905
  } from "fs";
912
- import { createHash as createHash3 } from "crypto";
906
+ import { createHash } from "crypto";
913
907
  import { homedir as homedir8, platform, arch } from "os";
914
- import { join as join12, dirname as dirname6 } from "path";
915
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as unlinkSync6, existsSync as existsSync8 } from "fs";
916
- import { join as join14 } from "path";
908
+ import { join as join10, dirname as dirname6 } from "path";
909
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, unlinkSync as unlinkSync6, existsSync as existsSync8 } from "fs";
910
+ import { join as join12 } from "path";
917
911
  import { homedir as homedir10 } from "os";
918
- function hasProxyEnv(env = process.env) {
919
- return Boolean(
920
- env.HTTPS_PROXY || env.https_proxy || env.HTTP_PROXY || env.http_proxy
921
- );
922
- }
923
- function installEnvProxyDispatcher(deps = {}) {
924
- const env = deps.env ?? process.env;
925
- if (!hasProxyEnv(env)) return false;
926
- const register = deps.register ?? (() => setGlobalDispatcher(new EnvHttpProxyAgent()));
927
- register();
928
- return true;
929
- }
930
- installEnvProxyDispatcher();
912
+ setGlobalDispatcher(new EnvHttpProxyAgent());
931
913
  var EXEC_TIMEOUT_MS = 3e4;
932
914
  var ALLOWED_DOMAIN_RE = /^[\w.-]+\.okx\.com$/;
933
915
  var PILOT_BIN_DIR = join(homedir(), ".okx", "bin");
@@ -950,25 +932,25 @@ function execPilotBinary(domain, exclude = [], userAgent) {
950
932
  if (userAgent) {
951
933
  args.push("--user-agent", userAgent);
952
934
  }
953
- return new Promise((resolve4) => {
935
+ return new Promise((resolve3) => {
954
936
  execFile(
955
937
  binPath,
956
938
  args,
957
939
  { timeout: EXEC_TIMEOUT_MS, encoding: "utf-8" },
958
940
  (error, stdout) => {
959
941
  if (error) {
960
- resolve4(null);
942
+ resolve3(null);
961
943
  return;
962
944
  }
963
945
  try {
964
946
  const result = JSON.parse(stdout);
965
947
  if (result.code === 0 && result.data) {
966
- resolve4(result.data);
948
+ resolve3(result.data);
967
949
  } else {
968
- resolve4(null);
950
+ resolve3(null);
969
951
  }
970
952
  } catch {
971
- resolve4(null);
953
+ resolve3(null);
972
954
  }
973
955
  }
974
956
  );
@@ -1302,7 +1284,7 @@ var EXIT_CODES = {
1302
1284
  NOT_LOGGED_IN: 2,
1303
1285
  REFRESH_FAILED: 3
1304
1286
  };
1305
- function finalizeToken(code, token, resolve4, reject) {
1287
+ function finalizeToken(code, token, resolve3, reject) {
1306
1288
  if (code === EXIT_CODES.SUCCESS) {
1307
1289
  if (!token) {
1308
1290
  reject(new AuthenticationError(
@@ -1311,7 +1293,7 @@ function finalizeToken(code, token, resolve4, reject) {
1311
1293
  ));
1312
1294
  return;
1313
1295
  }
1314
- resolve4(token);
1296
+ resolve3(token);
1315
1297
  return;
1316
1298
  }
1317
1299
  if (code === EXIT_CODES.NOT_LOGGED_IN) {
@@ -1348,7 +1330,7 @@ function defaultWindowsPipeName() {
1348
1330
  return WIN_PIPE_PREFIX + randomBytes(32).toString("hex");
1349
1331
  }
1350
1332
  function execAuthTokenWindows(binPath, makePipeName = defaultWindowsPipeName) {
1351
- return new Promise((resolve4, reject) => {
1333
+ return new Promise((resolve3, reject) => {
1352
1334
  const pipeName = makePipeName();
1353
1335
  const server = createServer();
1354
1336
  const chunks = [];
@@ -1368,7 +1350,7 @@ function execAuthTokenWindows(binPath, makePipeName = defaultWindowsPipeName) {
1368
1350
  const tryFinalize = () => {
1369
1351
  if (!pipeClosed || exitCode === void 0) return;
1370
1352
  const token = Buffer.concat(chunks).toString("utf-8").trim();
1371
- settle(() => finalizeToken(exitCode, token, resolve4, reject));
1353
+ settle(() => finalizeToken(exitCode, token, resolve3, reject));
1372
1354
  };
1373
1355
  server.on("connection", (socket) => {
1374
1356
  connectionMade = true;
@@ -1415,7 +1397,7 @@ function execAuthToken() {
1415
1397
  return process.platform === "win32" ? execAuthTokenWindows(binPath) : execAuthTokenUnix(binPath);
1416
1398
  }
1417
1399
  function execAuthTokenUnix(binPath) {
1418
- return new Promise((resolve4, reject) => {
1400
+ return new Promise((resolve3, reject) => {
1419
1401
  const child = spawn2(binPath, ["token"], {
1420
1402
  stdio: ["ignore", "ignore", "inherit", "pipe"]
1421
1403
  // stdin stdout stderr fd3 (pipe)
@@ -1428,35 +1410,35 @@ function execAuthTokenUnix(binPath) {
1428
1410
  });
1429
1411
  child.on("close", (code) => {
1430
1412
  const token = Buffer.concat(chunks).toString("utf-8").trim();
1431
- finalizeToken(code, token, resolve4, reject);
1413
+ finalizeToken(code, token, resolve3, reject);
1432
1414
  });
1433
1415
  });
1434
1416
  }
1435
1417
  function execAuthStatus() {
1436
1418
  const binPath = getAuthBinaryPath();
1437
- return new Promise((resolve4) => {
1419
+ return new Promise((resolve3) => {
1438
1420
  execFile2(
1439
1421
  binPath,
1440
1422
  ["status", "--json"],
1441
1423
  { timeout: EXEC_TIMEOUT_MS2, encoding: "utf-8" },
1442
1424
  (error, stdout) => {
1443
1425
  if (error) {
1444
- resolve4(null);
1426
+ resolve3(null);
1445
1427
  return;
1446
1428
  }
1447
1429
  try {
1448
1430
  const result = JSON.parse(stdout);
1449
- resolve4(result);
1431
+ resolve3(result);
1450
1432
  } catch {
1451
- resolve4(null);
1433
+ resolve3(null);
1452
1434
  }
1453
1435
  }
1454
1436
  );
1455
1437
  });
1456
1438
  }
1457
1439
  function sleep(ms) {
1458
- return new Promise((resolve4) => {
1459
- setTimeout(resolve4, ms);
1440
+ return new Promise((resolve3) => {
1441
+ setTimeout(resolve3, ms);
1460
1442
  });
1461
1443
  }
1462
1444
  var RateLimiter = class {
@@ -4282,223 +4264,6 @@ async function downloadSkillZip(client, name, targetDir, format = "zip") {
4282
4264
  const filePath = safeWriteFile(targetDir, fileName, result.data);
4283
4265
  return filePath;
4284
4266
  }
4285
- function listFilesRecursive(dir, base = "") {
4286
- const results = [];
4287
- for (const entry of readdirSync(dir)) {
4288
- const fullPath = join5(dir, entry);
4289
- const relPath = base ? `${base}/${entry}` : entry;
4290
- if (statSync(fullPath).isDirectory()) {
4291
- results.push(...listFilesRecursive(fullPath, relPath));
4292
- } else {
4293
- results.push(relPath);
4294
- }
4295
- }
4296
- return results;
4297
- }
4298
- function computeFileHashes(contentDir) {
4299
- const hashes = {};
4300
- for (const relPath of listFilesRecursive(contentDir)) {
4301
- if (relPath === "_meta.json") continue;
4302
- const bytes = readFileSync2(join5(contentDir, relPath));
4303
- hashes[relPath] = "sha256:" + createHash("sha256").update(bytes).digest("hex");
4304
- }
4305
- return hashes;
4306
- }
4307
- async function getPublicKey(client, keyId) {
4308
- try {
4309
- const query = {};
4310
- if (keyId !== void 0) query.keyId = keyId;
4311
- const result = await client.privateGet(
4312
- "/api/v5/skill/signing-key",
4313
- query
4314
- );
4315
- if (!result.data || result.data.status !== "active") return null;
4316
- return result.data.publicKey;
4317
- } catch (e) {
4318
- if (e instanceof ConfigError) throw e;
4319
- return null;
4320
- }
4321
- }
4322
- var ED25519_SPKI_HEADER = Buffer.from("302a300506032b6570032100", "hex");
4323
- function parseSSHPublicKey(base64) {
4324
- try {
4325
- const buf = Buffer.from(base64, "base64");
4326
- let offset = 0;
4327
- if (buf.length < 4) return null;
4328
- const algLen = buf.readUInt32BE(offset);
4329
- offset += 4;
4330
- if (offset + algLen + 4 > buf.length) return null;
4331
- if (buf.subarray(offset, offset + algLen).toString("ascii") !== "ssh-ed25519") return null;
4332
- offset += algLen;
4333
- const keyLen = buf.readUInt32BE(offset);
4334
- offset += 4;
4335
- if (keyLen !== 32 || offset + keyLen > buf.length) return null;
4336
- return buf.subarray(offset, offset + keyLen);
4337
- } catch {
4338
- return null;
4339
- }
4340
- }
4341
- async function verifySkillSignature(contentDir, signing, opts) {
4342
- if (!signing) {
4343
- const fallback = await tryServerFallback(contentDir, opts);
4344
- if (fallback?.status === "verified_by_server") return fallback;
4345
- return {
4346
- status: "failed",
4347
- error: fallback?.error ?? "Skill is not signed",
4348
- ...fallback?.mismatched?.length && { mismatched: fallback.mismatched }
4349
- };
4350
- }
4351
- const publicKeyBase64 = opts?.fetchPublicKey ? await opts.fetchPublicKey(signing.public_key_id) ?? "" : "";
4352
- if (!publicKeyBase64) {
4353
- return localFail(
4354
- contentDir,
4355
- opts,
4356
- `Unknown signing key: ${signing.public_key_id}. Please update CLI.`,
4357
- "Unknown signing key \u2014 consider updating CLI"
4358
- );
4359
- }
4360
- const rawKey = parseSSHPublicKey(publicKeyBase64);
4361
- if (!rawKey) {
4362
- return localFail(
4363
- contentDir,
4364
- opts,
4365
- `Malformed public key for key ID: ${signing.public_key_id}`,
4366
- "Malformed public key from server \u2014 consider updating CLI",
4367
- signing.public_key_id
4368
- );
4369
- }
4370
- if (!ed25519Verify(signing, rawKey)) {
4371
- return localFail(
4372
- contentDir,
4373
- opts,
4374
- "Invalid signature",
4375
- "Signature mismatch \u2014 key may be outdated or file was modified",
4376
- signing.public_key_id
4377
- );
4378
- }
4379
- const bindingError = checkNameVersionBinding(signing, opts);
4380
- if (bindingError) {
4381
- return { status: "failed", error: bindingError, publicKeyId: signing.public_key_id };
4382
- }
4383
- const integrityFailure = await checkFileIntegrity(signing, contentDir, opts);
4384
- if (integrityFailure) return integrityFailure;
4385
- const signedFiles = new Set(Object.keys(signing.files));
4386
- const extraFiles = listFilesRecursive(contentDir).filter(
4387
- (f) => f !== "_meta.json" && !signedFiles.has(f)
4388
- );
4389
- return { status: "verified", publicKeyId: signing.public_key_id, filesChecked: signedFiles.size, extraFiles };
4390
- }
4391
- async function localFail(contentDir, opts, localError, serverHint, keyId) {
4392
- const fallback = await tryServerFallback(contentDir, opts);
4393
- if (fallback?.status === "verified_by_server") {
4394
- return { ...fallback, error: serverHint };
4395
- }
4396
- return {
4397
- status: "failed",
4398
- error: localError,
4399
- ...keyId && { publicKeyId: keyId },
4400
- ...fallback?.mismatched?.length && { mismatched: fallback.mismatched }
4401
- };
4402
- }
4403
- function ed25519Verify(signing, rawKey) {
4404
- const payloadObj = { files: signing.files, public_key_id: signing.public_key_id };
4405
- if (signing.name !== void 0) payloadObj.name = signing.name;
4406
- if (signing.version !== void 0) payloadObj.version = signing.version;
4407
- const message = Buffer.from(canonicalize(payloadObj), "utf-8");
4408
- const sig = Buffer.from(signing.signature, "base64");
4409
- const spkiKey = Buffer.concat([ED25519_SPKI_HEADER, rawKey]);
4410
- const keyObj = createPublicKey({ key: spkiKey, format: "der", type: "spki" });
4411
- return cryptoVerify(null, message, keyObj, sig);
4412
- }
4413
- function checkNameVersionBinding(signing, opts) {
4414
- if (signing.name !== void 0 && opts?.skillName !== void 0 && signing.name !== opts.skillName) {
4415
- return `Skill name mismatch: signature binds "${signing.name}" but installing as "${opts.skillName}"`;
4416
- }
4417
- if (signing.version !== void 0 && opts?.skillVersion !== void 0 && signing.version !== opts.skillVersion) {
4418
- return `Skill version mismatch: signature binds "${signing.version}" but package declares "${opts.skillVersion}"`;
4419
- }
4420
- return null;
4421
- }
4422
- async function checkFileIntegrity(signing, contentDir, opts) {
4423
- const resolvedContentDir = resolve2(contentDir);
4424
- for (const [filename, expectedHash] of Object.entries(signing.files)) {
4425
- const resolvedPath = resolve2(join6(contentDir, filename));
4426
- if (!resolvedPath.startsWith(resolvedContentDir + sep2)) {
4427
- return { status: "failed", error: `Path traversal detected in signing manifest: ${filename}`, publicKeyId: signing.public_key_id };
4428
- }
4429
- let bytes;
4430
- try {
4431
- bytes = readFileSync3(resolvedPath);
4432
- } catch {
4433
- return { status: "failed", error: `File missing: ${filename}`, publicKeyId: signing.public_key_id };
4434
- }
4435
- const actual = "sha256:" + createHash2("sha256").update(bytes).digest("hex");
4436
- if (actual !== expectedHash) {
4437
- return localFail(
4438
- contentDir,
4439
- opts,
4440
- `File integrity check failed: ${filename}`,
4441
- "_meta.json may be corrupted",
4442
- signing.public_key_id
4443
- );
4444
- }
4445
- }
4446
- return null;
4447
- }
4448
- async function tryServerFallback(contentDir, opts) {
4449
- if (!opts?.serverSideVerify || !opts.skillName) return null;
4450
- const fileHashes = computeFileHashes(contentDir);
4451
- const result = await opts.serverSideVerify(
4452
- opts.skillName,
4453
- opts.skillVersion,
4454
- fileHashes
4455
- );
4456
- if (!result) return null;
4457
- if (result.verified) {
4458
- return {
4459
- status: "verified_by_server",
4460
- filesChecked: Object.keys(fileHashes).length,
4461
- serverVersion: result.version
4462
- };
4463
- }
4464
- return {
4465
- status: "failed",
4466
- filesChecked: Object.keys(fileHashes).length,
4467
- mismatched: result.mismatched,
4468
- ...result.message && { error: result.message }
4469
- };
4470
- }
4471
- function canonicalize(obj) {
4472
- return JSON.stringify(deepSortKeys(obj));
4473
- }
4474
- function compareKeys(a, b) {
4475
- if (a < b) return -1;
4476
- if (a > b) return 1;
4477
- return 0;
4478
- }
4479
- function deepSortKeys(val) {
4480
- if (val === null || typeof val !== "object") return val;
4481
- if (Array.isArray(val)) return val.map(deepSortKeys);
4482
- const sorted = {};
4483
- for (const key of Object.keys(val).sort(compareKeys)) {
4484
- sorted[key] = deepSortKeys(val[key]);
4485
- }
4486
- return sorted;
4487
- }
4488
- async function serverSideVerify(client, skillName, version, files) {
4489
- try {
4490
- const body = { skillName, files };
4491
- if (version !== void 0) body.version = version;
4492
- const result = await client.privatePost(
4493
- "/api/v5/skill/verify",
4494
- body
4495
- );
4496
- return result.data;
4497
- } catch (e) {
4498
- if (e instanceof ConfigError) throw e;
4499
- return null;
4500
- }
4501
- }
4502
4267
  var DEFAULT_MAX_TOTAL_BYTES = 100 * 1024 * 1024;
4503
4268
  var DEFAULT_MAX_FILES = 1e3;
4504
4269
  var DEFAULT_MAX_COMPRESSION_RATIO = 100;
@@ -4537,7 +4302,7 @@ async function extractSkillZip(zipPath, targetDir, limits) {
4537
4302
  const maxTotalBytes = limits?.maxTotalBytes ?? DEFAULT_MAX_TOTAL_BYTES;
4538
4303
  const maxFiles = limits?.maxFiles ?? DEFAULT_MAX_FILES;
4539
4304
  const maxCompressionRatio = limits?.maxCompressionRatio ?? DEFAULT_MAX_COMPRESSION_RATIO;
4540
- const resolvedTarget = resolve3(targetDir);
4305
+ const resolvedTarget = resolve2(targetDir);
4541
4306
  mkdirSync3(resolvedTarget, { recursive: true });
4542
4307
  return new Promise((resolvePromise, reject) => {
4543
4308
  yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
@@ -4577,11 +4342,11 @@ async function extractSkillZip(zipPath, targetDir, limits) {
4577
4342
  });
4578
4343
  }
4579
4344
  function readMetaJson(contentDir) {
4580
- const metaPath = join7(contentDir, "_meta.json");
4345
+ const metaPath = join5(contentDir, "_meta.json");
4581
4346
  if (!existsSync(metaPath)) {
4582
4347
  throw new Error(`_meta.json not found in ${contentDir}. Invalid skill package.`);
4583
4348
  }
4584
- const raw = readFileSync4(metaPath, "utf-8");
4349
+ const raw = readFileSync2(metaPath, "utf-8");
4585
4350
  let parsed;
4586
4351
  try {
4587
4352
  parsed = JSON.parse(raw);
@@ -4599,49 +4364,22 @@ function readMetaJson(contentDir) {
4599
4364
  name: String(meta.name),
4600
4365
  version: String(meta.version),
4601
4366
  title: typeof meta.title === "string" ? meta.title : "",
4602
- description: typeof meta.description === "string" ? meta.description : "",
4603
- signing: parseSigningBlock(meta.signing)
4604
- };
4605
- }
4606
- function tryReadMetaJson(contentDir) {
4607
- try {
4608
- return readMetaJson(contentDir);
4609
- } catch {
4610
- return null;
4611
- }
4612
- }
4613
- function parseSigningBlock(raw) {
4614
- if (!raw || typeof raw !== "object") return void 0;
4615
- const s = raw;
4616
- if (typeof s.signature !== "string" || typeof s.public_key_id !== "string" || !s.files) {
4617
- return void 0;
4618
- }
4619
- const rawFiles = s.files;
4620
- const files = {};
4621
- for (const [key, value] of Object.entries(rawFiles)) {
4622
- if (typeof value === "string") files[key] = value;
4623
- }
4624
- return {
4625
- signature: s.signature,
4626
- public_key_id: s.public_key_id,
4627
- files,
4628
- ...typeof s.name === "string" && { name: s.name },
4629
- ...typeof s.version === "string" && { version: s.version }
4367
+ description: typeof meta.description === "string" ? meta.description : ""
4630
4368
  };
4631
4369
  }
4632
4370
  function validateSkillMdExists(contentDir) {
4633
- const skillMdPath = join7(contentDir, "SKILL.md");
4371
+ const skillMdPath = join5(contentDir, "SKILL.md");
4634
4372
  if (!existsSync(skillMdPath)) {
4635
4373
  throw new Error(`SKILL.md not found in ${contentDir}. Invalid skill package.`);
4636
4374
  }
4637
4375
  }
4638
- var DEFAULT_REGISTRY_PATH = join8(homedir4(), ".okx", "skills", "registry.json");
4376
+ var DEFAULT_REGISTRY_PATH = join6(homedir4(), ".okx", "skills", "registry.json");
4639
4377
  function readRegistry(registryPath = DEFAULT_REGISTRY_PATH) {
4640
4378
  if (!existsSync2(registryPath)) {
4641
4379
  return { version: 1, skills: {} };
4642
4380
  }
4643
4381
  try {
4644
- const raw = readFileSync5(registryPath, "utf-8");
4382
+ const raw = readFileSync3(registryPath, "utf-8");
4645
4383
  return JSON.parse(raw);
4646
4384
  } catch {
4647
4385
  return { version: 1, skills: {} };
@@ -4651,7 +4389,7 @@ function writeRegistry(registry, registryPath = DEFAULT_REGISTRY_PATH) {
4651
4389
  mkdirSync4(dirname3(registryPath), { recursive: true });
4652
4390
  writeFileSync3(registryPath, JSON.stringify(registry, null, 2) + "\n", "utf-8");
4653
4391
  }
4654
- function upsertSkillRecord(meta, registryPath = DEFAULT_REGISTRY_PATH, verification) {
4392
+ function upsertSkillRecord(meta, registryPath = DEFAULT_REGISTRY_PATH) {
4655
4393
  const registry = readRegistry(registryPath);
4656
4394
  const now = (/* @__PURE__ */ new Date()).toISOString();
4657
4395
  const existing = registry.skills[meta.name];
@@ -4661,8 +4399,7 @@ function upsertSkillRecord(meta, registryPath = DEFAULT_REGISTRY_PATH, verificat
4661
4399
  description: meta.description,
4662
4400
  installedAt: existing?.installedAt ?? now,
4663
4401
  updatedAt: now,
4664
- source: "marketplace",
4665
- ...verification !== void 0 && { verification }
4402
+ source: "marketplace"
4666
4403
  };
4667
4404
  writeRegistry(registry, registryPath);
4668
4405
  }
@@ -12458,12 +12195,12 @@ function createToolRunner(client, config) {
12458
12195
  };
12459
12196
  }
12460
12197
  function configFilePath() {
12461
- return join9(homedir5(), ".okx", "config.toml");
12198
+ return join7(homedir5(), ".okx", "config.toml");
12462
12199
  }
12463
12200
  function readFullConfig() {
12464
12201
  const path42 = configFilePath();
12465
12202
  if (!existsSync3(path42)) return { profiles: {} };
12466
- const raw = readFileSync6(path42, "utf-8");
12203
+ const raw = readFileSync4(path42, "utf-8");
12467
12204
  try {
12468
12205
  return parse(raw);
12469
12206
  } catch (err) {
@@ -12613,7 +12350,7 @@ async function loadConfig(cli) {
12613
12350
  verbose: cli.verbose ?? false
12614
12351
  };
12615
12352
  }
12616
- var CACHE_FILE = join10(homedir6(), ".okx", "update-check.json");
12353
+ var CACHE_FILE = join8(homedir6(), ".okx", "update-check.json");
12617
12354
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
12618
12355
  var NEGATIVE_CHECK_INTERVAL_MS = 60 * 60 * 1e3;
12619
12356
  var DEFAULT_REGISTRY = "https://registry.npmjs.org/";
@@ -12621,7 +12358,7 @@ var FETCH_TIMEOUT_MS = 3e3;
12621
12358
  function readCache2() {
12622
12359
  try {
12623
12360
  if (existsSync4(CACHE_FILE)) {
12624
- return JSON.parse(readFileSync7(CACHE_FILE, "utf-8"));
12361
+ return JSON.parse(readFileSync5(CACHE_FILE, "utf-8"));
12625
12362
  }
12626
12363
  } catch {
12627
12364
  }
@@ -12629,7 +12366,7 @@ function readCache2() {
12629
12366
  }
12630
12367
  function writeCache2(cache) {
12631
12368
  try {
12632
- mkdirSync6(join10(homedir6(), ".okx"), { recursive: true });
12369
+ mkdirSync6(join8(homedir6(), ".okx"), { recursive: true });
12633
12370
  writeFileSync5(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
12634
12371
  } catch {
12635
12372
  }
@@ -12659,13 +12396,13 @@ function buildNpmrcCandidates() {
12659
12396
  let dir = process.cwd();
12660
12397
  const root = dir.startsWith("/") ? "/" : dir.slice(0, 3);
12661
12398
  while (true) {
12662
- add(join10(dir, ".npmrc"));
12399
+ add(join8(dir, ".npmrc"));
12663
12400
  if (dir === root) break;
12664
- const parent = join10(dir, "..");
12401
+ const parent = join8(dir, "..");
12665
12402
  if (parent === dir) break;
12666
12403
  dir = parent;
12667
12404
  }
12668
- add(join10(homedir6(), ".npmrc"));
12405
+ add(join8(homedir6(), ".npmrc"));
12669
12406
  if (process.platform !== "win32") {
12670
12407
  add("/etc/npmrc");
12671
12408
  }
@@ -12674,7 +12411,7 @@ function buildNpmrcCandidates() {
12674
12411
  function readNpmrcRegistry(filePath) {
12675
12412
  try {
12676
12413
  if (!existsSync4(filePath)) return null;
12677
- const lines = readFileSync7(filePath, "utf-8").split(/\r?\n/);
12414
+ const lines = readFileSync5(filePath, "utf-8").split(/\r?\n/);
12678
12415
  for (const line of lines) {
12679
12416
  const trimmed = line.trim();
12680
12417
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
@@ -13001,14 +12738,6 @@ function runSetup(options) {
13001
12738
  `);
13002
12739
  }
13003
12740
  }
13004
- var HttpStatusError = class extends Error {
13005
- statusCode;
13006
- constructor(statusCode) {
13007
- super(`HTTP ${statusCode}`);
13008
- this.name = "HttpStatusError";
13009
- this.statusCode = statusCode;
13010
- }
13011
- };
13012
12741
  function isRedirect(statusCode) {
13013
12742
  return statusCode !== void 0 && statusCode >= 300 && statusCode < 400;
13014
12743
  }
@@ -13023,7 +12752,7 @@ function validateRedirect(res, requestUrl, redirectCount, maxRedirects) {
13023
12752
  return location;
13024
12753
  }
13025
12754
  function fetchResponse(url, timeoutMs) {
13026
- return new Promise((resolve4, reject) => {
12755
+ return new Promise((resolve3, reject) => {
13027
12756
  let redirects = 0;
13028
12757
  const maxRedirects = 5;
13029
12758
  function doRequest(requestUrl) {
@@ -13041,14 +12770,10 @@ function fetchResponse(url, timeoutMs) {
13041
12770
  return;
13042
12771
  }
13043
12772
  if (res.statusCode !== 200) {
13044
- if (res.statusCode === void 0) {
13045
- reject(new Error("HTTP unknown"));
13046
- } else {
13047
- reject(new HttpStatusError(res.statusCode));
13048
- }
12773
+ reject(new Error(`HTTP ${res.statusCode ?? "unknown"}`));
13049
12774
  return;
13050
12775
  }
13051
- resolve4(res);
12776
+ resolve3(res);
13052
12777
  });
13053
12778
  req.on("error", reject);
13054
12779
  req.on("timeout", () => {
@@ -13061,10 +12786,10 @@ function fetchResponse(url, timeoutMs) {
13061
12786
  }
13062
12787
  function download(url, destPath, timeoutMs) {
13063
12788
  return fetchResponse(url, timeoutMs).then(
13064
- (res) => new Promise((resolve4, reject) => {
12789
+ (res) => new Promise((resolve3, reject) => {
13065
12790
  const file = createWriteStream2(destPath);
13066
12791
  res.pipe(file);
13067
- file.on("finish", () => file.close(() => resolve4()));
12792
+ file.on("finish", () => file.close(() => resolve3()));
13068
12793
  file.on("error", (err) => {
13069
12794
  try {
13070
12795
  unlinkSync3(destPath);
@@ -13077,10 +12802,10 @@ function download(url, destPath, timeoutMs) {
13077
12802
  }
13078
12803
  function downloadText(url, timeoutMs) {
13079
12804
  return fetchResponse(url, timeoutMs).then(
13080
- (res) => new Promise((resolve4, reject) => {
12805
+ (res) => new Promise((resolve3, reject) => {
13081
12806
  const chunks = [];
13082
12807
  res.on("data", (chunk) => chunks.push(chunk));
13083
- res.on("end", () => resolve4(Buffer.concat(chunks).toString("utf8")));
12808
+ res.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
13084
12809
  res.on("error", reject);
13085
12810
  })
13086
12811
  );
@@ -13109,10 +12834,10 @@ function getBinaryName() {
13109
12834
  return platform() === "win32" ? "okx-pilot.exe" : "okx-pilot";
13110
12835
  }
13111
12836
  function hashFile(filePath) {
13112
- const buf = readFileSync9(filePath);
12837
+ const buf = readFileSync7(filePath);
13113
12838
  return {
13114
12839
  size: buf.byteLength,
13115
- sha256: createHash3("sha256").update(buf).digest("hex")
12840
+ sha256: createHash("sha256").update(buf).digest("hex")
13116
12841
  };
13117
12842
  }
13118
12843
  function getPilotStatus(binaryPath, opts) {
@@ -13227,7 +12952,7 @@ async function installPilotBinary(destPath, sources = CDN_SOURCES, onProgress) {
13227
12952
  if (earlyResult) return earlyResult;
13228
12953
  const platformDir = getPlatformDir();
13229
12954
  const binaryName = getBinaryName();
13230
- const resolvedDest = destPath ?? join12(homedir8(), ".okx", "bin", binaryName);
12955
+ const resolvedDest = destPath ?? join10(homedir8(), ".okx", "bin", binaryName);
13231
12956
  const tmpPath = resolvedDest + ".tmp";
13232
12957
  mkdirSync8(dirname6(resolvedDest), { recursive: true });
13233
12958
  const localHash = existsSync6(resolvedDest) ? hashFile(resolvedDest) : null;
@@ -13279,41 +13004,9 @@ function removePilotBinary(binaryPath) {
13279
13004
  }
13280
13005
  }
13281
13006
  var AUTH_CDN_PATH_PREFIX = "/upgradeapp/tools/oauth";
13282
- var LINUX_ARM64_FALLBACK_DIR = "linux-x64";
13283
13007
  function getAuthBinaryName() {
13284
13008
  return platform2() === "win32" ? "okx-auth.exe" : "okx-auth";
13285
13009
  }
13286
- async function _resolveAuthPlatformFromNative(native, sources, timeoutMs) {
13287
- if (native !== "linux-arm64") {
13288
- return native;
13289
- }
13290
- const checksumPath = `${AUTH_CDN_PATH_PREFIX}/linux-arm64/checksum.json`;
13291
- let got404 = false;
13292
- for (const { host, protocol } of sources) {
13293
- const url = `${protocol}://${host}${checksumPath}`;
13294
- try {
13295
- await downloadText(url, timeoutMs);
13296
- return "linux-arm64";
13297
- } catch (err) {
13298
- if (err instanceof HttpStatusError && err.statusCode === 404) {
13299
- got404 = true;
13300
- break;
13301
- }
13302
- }
13303
- }
13304
- if (got404) {
13305
- console.warn(
13306
- "[okx-auth] Native linux-arm64 binary not yet on CDN. Falling back to linux-x64 binary \u2014 x86_64 emulation (binfmt_misc/Rosetta) required."
13307
- );
13308
- return LINUX_ARM64_FALLBACK_DIR;
13309
- }
13310
- return "linux-arm64";
13311
- }
13312
- async function resolveAuthPlatformDir(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_TIMEOUT_MS) {
13313
- const native = getPlatformDir();
13314
- if (!native) return null;
13315
- return _resolveAuthPlatformFromNative(native, sources, timeoutMs);
13316
- }
13317
13010
  function getAuthStatus(binaryPath, opts) {
13318
13011
  const resolvedPath = binaryPath ?? getAuthBinaryPath();
13319
13012
  const platformDir = getPlatformDir();
@@ -13327,7 +13020,7 @@ function getAuthStatus(binaryPath, opts) {
13327
13020
  return { binaryPath: resolvedPath, exists: true, platform: platformDir, fileSize: size, sha256 };
13328
13021
  }
13329
13022
  async function fetchAuthCdnChecksum(sources = CDN_SOURCES, timeoutMs = DOWNLOAD_TIMEOUT_MS) {
13330
- const platformDir = await resolveAuthPlatformDir(sources, timeoutMs);
13023
+ const platformDir = getPlatformDir();
13331
13024
  if (!platformDir) return null;
13332
13025
  const checksumPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/checksum.json`;
13333
13026
  for (const { host, protocol } of sources) {
@@ -13396,51 +13089,12 @@ function installPreChecks2(destPath, sources) {
13396
13089
  function isLocalUpToDate2(localHash, checksum) {
13397
13090
  return localHash !== null && localHash.size === checksum.size && localHash.sha256 === checksum.sha256;
13398
13091
  }
13399
- async function tryInstallFromOneSource(ctx) {
13400
- const { host, protocol, platformDir, checksumPath, binaryPath, tmpPath, resolvedDest, localHash, onProgress } = ctx;
13401
- try {
13402
- const checksum = await fetchAndValidateChecksum2(
13403
- host,
13404
- protocol,
13405
- checksumPath,
13406
- platformDir,
13407
- DOWNLOAD_TIMEOUT_MS,
13408
- onProgress
13409
- );
13410
- if (isLocalUpToDate2(localHash, checksum)) {
13411
- onProgress?.("Already up to date (checksum match)");
13412
- return { kind: "done", result: { status: "up-to-date", source: host } };
13413
- }
13414
- await downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, DOWNLOAD_TIMEOUT_MS, onProgress);
13415
- atomicReplace2(tmpPath, resolvedDest);
13416
- onProgress?.(`Downloaded and verified from ${host}`);
13417
- return { kind: "done", result: { status: "installed", source: host } };
13418
- } catch (err) {
13419
- try {
13420
- unlinkSync5(tmpPath);
13421
- } catch {
13422
- }
13423
- const errObj = err instanceof Error ? err : new Error(String(err));
13424
- onProgress?.(`${host} failed: ${errObj.message}`);
13425
- return { kind: "next", err: errObj };
13426
- }
13427
- }
13428
- function buildInstallFailureResult(errors) {
13429
- const formatted = errors.map(({ host, err }) => `${host}: ${err.message}`).join("\n");
13430
- const allHttpErrors = errors.length > 0 && errors.every(({ err }) => err instanceof HttpStatusError);
13431
- const prefix = allHttpErrors ? "okx-auth binary not available on CDN for this platform" : "All CDN sources failed";
13432
- return { status: "failed", error: `${prefix}:
13433
- ${formatted}` };
13434
- }
13435
13092
  async function installAuthBinary(destPath, sources = CDN_SOURCES, onProgress) {
13436
13093
  const earlyResult = installPreChecks2(destPath, sources);
13437
13094
  if (earlyResult) return earlyResult;
13438
- const platformDir = await resolveAuthPlatformDir(sources);
13439
- if (!platformDir) {
13440
- return { status: "failed", error: "Unsupported platform" };
13441
- }
13095
+ const platformDir = getPlatformDir();
13442
13096
  const binaryName = getAuthBinaryName();
13443
- const resolvedDest = destPath ?? join13(homedir9(), ".okx", "bin", binaryName);
13097
+ const resolvedDest = destPath ?? join11(homedir9(), ".okx", "bin", binaryName);
13444
13098
  const tmpPath = resolvedDest + ".tmp";
13445
13099
  mkdirSync9(dirname7(resolvedDest), { recursive: true });
13446
13100
  const localHash = existsSync7(resolvedDest) ? hashFile(resolvedDest) : null;
@@ -13448,21 +13102,35 @@ async function installAuthBinary(destPath, sources = CDN_SOURCES, onProgress) {
13448
13102
  const binaryPath = `${AUTH_CDN_PATH_PREFIX}/${platformDir}/${binaryName}`;
13449
13103
  const errors = [];
13450
13104
  for (const { host, protocol } of sources) {
13451
- const attempt = await tryInstallFromOneSource({
13452
- host,
13453
- protocol,
13454
- platformDir,
13455
- checksumPath,
13456
- binaryPath,
13457
- tmpPath,
13458
- resolvedDest,
13459
- localHash,
13460
- onProgress
13461
- });
13462
- if (attempt.kind === "done") return attempt.result;
13463
- errors.push({ host, err: attempt.err });
13105
+ try {
13106
+ const checksum = await fetchAndValidateChecksum2(
13107
+ host,
13108
+ protocol,
13109
+ checksumPath,
13110
+ platformDir,
13111
+ DOWNLOAD_TIMEOUT_MS,
13112
+ onProgress
13113
+ );
13114
+ if (isLocalUpToDate2(localHash, checksum)) {
13115
+ onProgress?.("Already up to date (checksum match)");
13116
+ return { status: "up-to-date", source: host };
13117
+ }
13118
+ await downloadAndVerify2(host, protocol, binaryPath, tmpPath, checksum, DOWNLOAD_TIMEOUT_MS, onProgress);
13119
+ atomicReplace2(tmpPath, resolvedDest);
13120
+ onProgress?.(`Downloaded and verified from ${host}`);
13121
+ return { status: "installed", source: host };
13122
+ } catch (err) {
13123
+ try {
13124
+ unlinkSync5(tmpPath);
13125
+ } catch {
13126
+ }
13127
+ const msg = err instanceof Error ? err.message : String(err);
13128
+ errors.push(`${host}: ${msg}`);
13129
+ onProgress?.(`${host} failed: ${msg}`);
13130
+ }
13464
13131
  }
13465
- return buildInstallFailureResult(errors);
13132
+ return { status: "failed", error: `All CDN sources failed:
13133
+ ${errors.join("\n")}` };
13466
13134
  }
13467
13135
  function removeAuthBinary(binaryPath) {
13468
13136
  const resolvedPath = binaryPath ?? getAuthBinaryPath();
@@ -13477,12 +13145,12 @@ function removeAuthBinary(binaryPath) {
13477
13145
  throw new Error(`Failed to remove ${resolvedPath}: ${msg}`);
13478
13146
  }
13479
13147
  }
13480
- var CACHE_PATH = join14(homedir10(), ".okx", "auth-binary-check.json");
13148
+ var CACHE_PATH = join12(homedir10(), ".okx", "auth-binary-check.json");
13481
13149
  var CHECK_INTERVAL_MS2 = 2 * 60 * 60 * 1e3;
13482
13150
  function readCache3() {
13483
13151
  try {
13484
13152
  if (!existsSync8(CACHE_PATH)) return null;
13485
- const data = JSON.parse(readFileSync10(CACHE_PATH, "utf-8"));
13153
+ const data = JSON.parse(readFileSync8(CACHE_PATH, "utf-8"));
13486
13154
  if (typeof data.cdnSha256 !== "string" || typeof data.checkedAt !== "number") return null;
13487
13155
  return { cdnSha256: data.cdnSha256, checkedAt: data.checkedAt };
13488
13156
  } catch {
@@ -13491,7 +13159,7 @@ function readCache3() {
13491
13159
  }
13492
13160
  function writeCache3(cdnSha256) {
13493
13161
  try {
13494
- mkdirSync10(join14(homedir10(), ".okx"), { recursive: true });
13162
+ mkdirSync10(join12(homedir10(), ".okx"), { recursive: true });
13495
13163
  writeFileSync7(CACHE_PATH, JSON.stringify({ cdnSha256, checkedAt: Date.now() }, null, 2), "utf-8");
13496
13164
  } catch {
13497
13165
  }
@@ -13626,7 +13294,7 @@ function markFailedIfSCodeError(data) {
13626
13294
  // src/commands/auth.ts
13627
13295
  function runOkxAuth(args) {
13628
13296
  const binPath = getAuthBinaryPath();
13629
- return new Promise((resolve4, reject) => {
13297
+ return new Promise((resolve3, reject) => {
13630
13298
  const child = spawn3(binPath, args, {
13631
13299
  stdio: "inherit"
13632
13300
  });
@@ -13634,13 +13302,13 @@ function runOkxAuth(args) {
13634
13302
  reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
13635
13303
  });
13636
13304
  child.on("close", (code) => {
13637
- resolve4(code ?? 1);
13305
+ resolve3(code ?? 1);
13638
13306
  });
13639
13307
  });
13640
13308
  }
13641
13309
  function runOkxAuthCapture(args) {
13642
13310
  const binPath = getAuthBinaryPath();
13643
- return new Promise((resolve4, reject) => {
13311
+ return new Promise((resolve3, reject) => {
13644
13312
  const child = spawn3(binPath, args, {
13645
13313
  stdio: ["inherit", "pipe", "inherit"]
13646
13314
  });
@@ -13650,7 +13318,7 @@ function runOkxAuthCapture(args) {
13650
13318
  reject(new Error(`Failed to spawn okx-auth: ${err.message}`));
13651
13319
  });
13652
13320
  child.on("close", (code) => {
13653
- resolve4({
13321
+ resolve3({
13654
13322
  code: code ?? 1,
13655
13323
  stdout: Buffer.concat(chunks).toString("utf-8")
13656
13324
  });
@@ -13855,14 +13523,14 @@ async function confirmRemoval(force, binaryPath) {
13855
13523
  return true;
13856
13524
  }
13857
13525
  function askConfirmation(prompt2) {
13858
- return new Promise((resolve4) => {
13526
+ return new Promise((resolve3) => {
13859
13527
  const rl = readline.createInterface({
13860
13528
  input: process.stdin,
13861
13529
  output: process.stdout
13862
13530
  });
13863
13531
  rl.question(prompt2, (answer) => {
13864
13532
  rl.close();
13865
- resolve4(answer.trim().toLowerCase() === "y");
13533
+ resolve3(answer.trim().toLowerCase() === "y");
13866
13534
  });
13867
13535
  });
13868
13536
  }
@@ -13894,6 +13562,110 @@ async function handleAuthCommand(action, _rest, v) {
13894
13562
  }
13895
13563
  }
13896
13564
 
13565
+ // src/commands/outcomes.ts
13566
+ import { spawn as spawn4 } from "child_process";
13567
+ import { existsSync as existsSync9 } from "fs";
13568
+ import { delimiter, join as join13 } from "path";
13569
+ var OUTCOMES_BINARY_NAME = process.platform === "win32" ? "okx-outcomes.exe" : "okx-outcomes";
13570
+ function resolveOutcomesBinaryPath() {
13571
+ const override = process.env.OKX_OUTCOMES_BIN;
13572
+ if (override) {
13573
+ if (existsSync9(override)) return override;
13574
+ errorLine(
13575
+ `Warning: OKX_OUTCOMES_BIN is set to '${override}' but no file exists there; falling back to PATH search.`
13576
+ );
13577
+ }
13578
+ const paths = (process.env.PATH ?? "").split(delimiter);
13579
+ for (const dir of paths) {
13580
+ if (!dir) continue;
13581
+ const full = join13(dir, OUTCOMES_BINARY_NAME);
13582
+ if (existsSync9(full)) return full;
13583
+ }
13584
+ return null;
13585
+ }
13586
+ function printInstallHint() {
13587
+ errorLine("Error: okx-outcomes binary not found in PATH.");
13588
+ errorLine("");
13589
+ errorLine("Install (macOS / Linux):");
13590
+ errorLine(" curl -fsSL https://raw.githubusercontent.com/okx/outcomes/master/install.sh | sh");
13591
+ errorLine("");
13592
+ errorLine("Install (Windows): download okx-outcomes.exe from");
13593
+ errorLine(" https://github.com/okx/outcomes/releases");
13594
+ errorLine("and place it on your PATH.");
13595
+ errorLine("");
13596
+ errorLine("Or set OKX_OUTCOMES_BIN env var to a custom binary path.");
13597
+ }
13598
+ function runOkxOutcomes(args) {
13599
+ const binPath = resolveOutcomesBinaryPath();
13600
+ if (!binPath) {
13601
+ printInstallHint();
13602
+ return Promise.resolve(127);
13603
+ }
13604
+ return new Promise((resolve3, reject) => {
13605
+ const child = spawn4(binPath, args, { stdio: "inherit" });
13606
+ child.on(
13607
+ "error",
13608
+ (err) => reject(new Error(`Failed to spawn okx-outcomes: ${err.message}`))
13609
+ );
13610
+ child.on("close", (code) => resolve3(code ?? 1));
13611
+ });
13612
+ }
13613
+ function printOutcomesHelp() {
13614
+ const lines = [
13615
+ "Usage: okx outcomes <command> [args...]",
13616
+ "",
13617
+ "OKX Outcomes - YES/NO event contract trading via the okx-outcomes binary.",
13618
+ "",
13619
+ "Common commands:",
13620
+ " data events List outcome events",
13621
+ " data event <eventId> Get event detail",
13622
+ " data event-markets <eventId> Event + all its markets (returns asset ids)",
13623
+ " data market <marketId> Get single market detail",
13624
+ " data trending List trending events",
13625
+ " data ticker <assetId> 24h ticker for an outcome asset",
13626
+ " data candles <assetId> OHLCV candles for an outcome asset",
13627
+ " search <keyword> Search events/markets",
13628
+ " (Note: events/event/market etc. live UNDER the `data` namespace \u2014 calling them",
13629
+ " as top-level commands prints the binary's help instead of returning JSON.)",
13630
+ "",
13631
+ " clob price/prices/midpoint(s)/spread(s)/book(s) --asset <id>",
13632
+ " CLOB read-side market data",
13633
+ " clob create-order Place limit order (EIP-712 signed)",
13634
+ " clob market-order Cross book immediately (IOC/FOK)",
13635
+ " clob cancel-oid | cancel-all | heartbeat",
13636
+ "",
13637
+ " ctf split/merge/redeem Conditional token operations",
13638
+ "",
13639
+ " account balance/order/orders/positions/closed-positions/trades",
13640
+ " HMAC-auth account queries",
13641
+ "",
13642
+ " wallet show Show derived wallet address",
13643
+ " status Health check",
13644
+ " setup Interactive .env wizard",
13645
+ "",
13646
+ "Run 'okx outcomes <command> --help' for command-specific help.",
13647
+ "",
13648
+ "Note: place flags after the subcommand, e.g. 'okx outcomes events --json'",
13649
+ " (or before the module: 'okx --json outcomes events'). Writing",
13650
+ " 'okx outcomes --json events' is not supported.",
13651
+ "",
13652
+ "Requires: curl -fsSL https://raw.githubusercontent.com/okx/outcomes/master/install.sh | sh"
13653
+ ];
13654
+ for (const line of lines) outputLine(line);
13655
+ }
13656
+ async function handleOutcomesCommand(action, rest, v) {
13657
+ if (!action || action === "--help" || action === "-h" || action === "help") {
13658
+ printOutcomesHelp();
13659
+ return;
13660
+ }
13661
+ const forwardArgs = [action, ...rest];
13662
+ if (v.json && !forwardArgs.includes("--json") && !forwardArgs.includes("-j")) {
13663
+ forwardArgs.push("--json");
13664
+ }
13665
+ const code = await runOkxOutcomes(forwardArgs);
13666
+ if (code !== 0) process.exitCode = code;
13667
+ }
13668
+
13897
13669
  // src/commands/diagnose.ts
13898
13670
  import dns from "dns/promises";
13899
13671
  import net from "net";
@@ -13919,26 +13691,26 @@ var Report = class {
13919
13691
  this.lines.push({ key, value });
13920
13692
  }
13921
13693
  print() {
13922
- const sep3 = "\u2500".repeat(52);
13694
+ const sep2 = "\u2500".repeat(52);
13923
13695
  outputLine("");
13924
- outputLine(` \u2500\u2500 Diagnostic Report (copy & share) ${sep3.slice(35)}`);
13696
+ outputLine(` \u2500\u2500 Diagnostic Report (copy & share) ${sep2.slice(35)}`);
13925
13697
  for (const { key, value } of this.lines) {
13926
13698
  outputLine(` ${key.padEnd(14)} ${value}`);
13927
13699
  }
13928
- outputLine(` ${sep3}`);
13700
+ outputLine(` ${sep2}`);
13929
13701
  outputLine("");
13930
13702
  }
13931
13703
  /** Write report to a file path, returns true on success. */
13932
13704
  writeToFile(filePath) {
13933
13705
  try {
13934
- const sep3 = "\u2500".repeat(52);
13706
+ const sep2 = "\u2500".repeat(52);
13935
13707
  const lines = [
13936
- `\u2500\u2500 Diagnostic Report (copy & share) ${sep3.slice(35)}`
13708
+ `\u2500\u2500 Diagnostic Report (copy & share) ${sep2.slice(35)}`
13937
13709
  ];
13938
13710
  for (const { key, value } of this.lines) {
13939
13711
  lines.push(`${key.padEnd(14)} ${value}`);
13940
13712
  }
13941
- lines.push(sep3, "");
13713
+ lines.push(sep2, "");
13942
13714
  fs4.writeFileSync(filePath, lines.join("\n"), "utf8");
13943
13715
  return true;
13944
13716
  } catch (_e) {
@@ -13988,7 +13760,7 @@ function sanitize2(value) {
13988
13760
  import fs5 from "fs";
13989
13761
  import path4 from "path";
13990
13762
  import os4 from "os";
13991
- import { spawnSync, spawn as spawn4 } from "child_process";
13763
+ import { spawnSync, spawn as spawn5 } from "child_process";
13992
13764
  import { createRequire as createRequire2 } from "module";
13993
13765
  import { fileURLToPath } from "url";
13994
13766
  var _require2 = createRequire2(import.meta.url);
@@ -14314,15 +14086,15 @@ async function checkStdioHandshake(entryPath, report) {
14314
14086
  clientInfo: { name: "okx-diagnose", version: "1.0" }
14315
14087
  }
14316
14088
  });
14317
- return new Promise((resolve4) => {
14089
+ return new Promise((resolve3) => {
14318
14090
  let settled = false;
14319
14091
  const settle = (passed) => {
14320
14092
  if (settled) return;
14321
14093
  settled = true;
14322
14094
  clearTimeout(timer);
14323
- resolve4(passed);
14095
+ resolve3(passed);
14324
14096
  };
14325
- const child = spawn4(process.execPath, [entryPath], {
14097
+ const child = spawn5(process.execPath, [entryPath], {
14326
14098
  stdio: ["pipe", "pipe", "pipe"],
14327
14099
  env: { ...process.env }
14328
14100
  });
@@ -14441,7 +14213,7 @@ async function cmdDiagnoseMcp(options = {}) {
14441
14213
 
14442
14214
  // src/commands/diagnose.ts
14443
14215
  var CLI_VERSION = readCliVersion();
14444
- var GIT_HASH = true ? "e5abc21f" : "dev";
14216
+ var GIT_HASH = true ? "0614700e" : "dev";
14445
14217
  function maskKey2(key) {
14446
14218
  if (!key) return "(not set)";
14447
14219
  if (key.length <= 8) return "****";
@@ -14458,7 +14230,7 @@ async function checkDns(hostname) {
14458
14230
  }
14459
14231
  async function checkSocket(createFn, successEvent, timeoutMs) {
14460
14232
  const t0 = Date.now();
14461
- return new Promise((resolve4) => {
14233
+ return new Promise((resolve3) => {
14462
14234
  const socket = createFn();
14463
14235
  const cleanup = () => {
14464
14236
  socket.removeAllListeners();
@@ -14466,15 +14238,15 @@ async function checkSocket(createFn, successEvent, timeoutMs) {
14466
14238
  };
14467
14239
  socket.once(successEvent, () => {
14468
14240
  cleanup();
14469
- resolve4({ ok: true, ms: Date.now() - t0 });
14241
+ resolve3({ ok: true, ms: Date.now() - t0 });
14470
14242
  });
14471
14243
  socket.once("timeout", () => {
14472
14244
  cleanup();
14473
- resolve4({ ok: false, ms: Date.now() - t0, error: `timed out after ${timeoutMs}ms` });
14245
+ resolve3({ ok: false, ms: Date.now() - t0, error: `timed out after ${timeoutMs}ms` });
14474
14246
  });
14475
14247
  socket.once("error", (err) => {
14476
14248
  cleanup();
14477
- resolve4({ ok: false, ms: Date.now() - t0, error: err.message });
14249
+ resolve3({ ok: false, ms: Date.now() - t0, error: err.message });
14478
14250
  });
14479
14251
  });
14480
14252
  }
@@ -14802,23 +14574,23 @@ function suggestSubcommand(action, knownActions, knownPaths = []) {
14802
14574
 
14803
14575
  // src/commands/upgrade.ts
14804
14576
  import { spawnSync as spawnSync2 } from "child_process";
14805
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
14806
- import { dirname as dirname8, join as join15 } from "path";
14577
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
14578
+ import { dirname as dirname8, join as join14 } from "path";
14807
14579
  import { homedir as homedir11 } from "os";
14808
14580
  var PACKAGES = ["@okx_ai/okx-trade-mcp", "@okx_ai/okx-trade-cli"];
14809
- var CACHE_FILE2 = join15(homedir11(), ".okx", "last_check");
14581
+ var CACHE_FILE2 = join14(homedir11(), ".okx", "last_check");
14810
14582
  var THROTTLE_MS = 12 * 60 * 60 * 1e3;
14811
- var NPM_BIN = join15(dirname8(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
14583
+ var NPM_BIN = join14(dirname8(process.execPath), process.platform === "win32" ? "npm.cmd" : "npm");
14812
14584
  function readLastCheck() {
14813
14585
  try {
14814
- return parseInt(readFileSync11(CACHE_FILE2, "utf-8").trim(), 10) || 0;
14586
+ return parseInt(readFileSync9(CACHE_FILE2, "utf-8").trim(), 10) || 0;
14815
14587
  } catch {
14816
14588
  return 0;
14817
14589
  }
14818
14590
  }
14819
14591
  function writeLastCheck() {
14820
14592
  try {
14821
- mkdirSync11(join15(homedir11(), ".okx"), { recursive: true });
14593
+ mkdirSync11(join14(homedir11(), ".okx"), { recursive: true });
14822
14594
  writeFileSync8(CACHE_FILE2, String(Math.floor(Date.now() / 1e3)), "utf-8");
14823
14595
  } catch {
14824
14596
  }
@@ -15974,6 +15746,63 @@ var CLI_REGISTRY = {
15974
15746
  description: "Upgrade okx CLI and MCP server to the latest stable version",
15975
15747
  usage: "okx upgrade [--check] [--beta] [--force] [--json]"
15976
15748
  },
15749
+ // ── outcomes ───────────────────────────────────────────────────────────────
15750
+ // External binary wrapper - forwards to the okx-outcomes binary (formerly okx-predict).
15751
+ // All toolName=null because outcomes commands are not exposed as MCP tools.
15752
+ outcomes: {
15753
+ description: "OKX Outcomes markets (YES/NO event contracts) via external okx-outcomes binary",
15754
+ commands: {
15755
+ // Note: events / event / event-markets / market / trending / ticker /
15756
+ // candles live UNDER the `data` namespace in the upstream binary.
15757
+ // Calling them as top-level commands prints the binary's help text
15758
+ // instead of returning JSON. Always invoke as `okx outcomes data <cmd>`.
15759
+ data: {
15760
+ toolName: null,
15761
+ usage: "okx outcomes data <events|event|event-markets|market|trending|ticker|candles> [args...]",
15762
+ description: "Public market data namespace: events, event(-markets), market, trending, ticker, candles"
15763
+ },
15764
+ search: {
15765
+ toolName: null,
15766
+ usage: "okx outcomes search <keyword> [--limit <n>] [--cursor <c>]",
15767
+ description: "Search events/markets by keyword"
15768
+ },
15769
+ account: {
15770
+ toolName: null,
15771
+ usage: "okx outcomes account <balance|order|orders|positions|closed-positions|trades>",
15772
+ description: "HMAC-auth account queries"
15773
+ },
15774
+ clob: {
15775
+ toolName: null,
15776
+ usage: "okx outcomes clob <price|prices|midpoint|midpoints|spread|spreads|book|books|order|orders|trades|create-order|market-order|cancel-oid|cancel-all|heartbeat>",
15777
+ description: "CLOB market data (--asset) + EIP-712 signed order operations"
15778
+ },
15779
+ ctf: {
15780
+ toolName: null,
15781
+ usage: "okx outcomes ctf <split|merge|redeem> --market <id> [--amount <xp>]",
15782
+ description: "Conditional Token Framework: split xp into YES/NO, merge, redeem"
15783
+ },
15784
+ wallet: {
15785
+ toolName: null,
15786
+ usage: "okx outcomes wallet show",
15787
+ description: "Show derived wallet address (from PREDICTIONS_AGENT_PRIVATE_KEY)"
15788
+ },
15789
+ status: {
15790
+ toolName: null,
15791
+ usage: "okx outcomes status [--json]",
15792
+ description: "Health check: API + balance reachability"
15793
+ },
15794
+ setup: {
15795
+ toolName: null,
15796
+ usage: "okx outcomes setup",
15797
+ description: "Interactive .env wizard for PREDICTIONS_* env vars"
15798
+ },
15799
+ shell: {
15800
+ toolName: null,
15801
+ usage: "okx outcomes shell",
15802
+ description: "Interactive REPL (do not invoke from agent context)"
15803
+ }
15804
+ }
15805
+ },
15977
15806
  // ── list-tools ──────────────────────────────────────────────────────────────
15978
15807
  "list-tools": {
15979
15808
  description: "List all available tools and their parameters (use --json for machine-readable output)",
@@ -16846,6 +16675,30 @@ function parseCli(argv) {
16846
16675
  }
16847
16676
  return { values, positionals };
16848
16677
  }
16678
+ function peekFirstPositional(argv) {
16679
+ const booleanFlags = /* @__PURE__ */ new Set();
16680
+ for (const [name, opt] of Object.entries(CLI_OPTIONS)) {
16681
+ const o = opt;
16682
+ if (o.type === "boolean") {
16683
+ booleanFlags.add(name);
16684
+ if (o.short) booleanFlags.add(o.short);
16685
+ }
16686
+ }
16687
+ for (let i = 0; i < argv.length; i++) {
16688
+ const tok = argv[i];
16689
+ if (tok === "--") {
16690
+ const next2 = argv[i + 1];
16691
+ return next2 === void 0 ? void 0 : { module: next2, idx: i + 1 };
16692
+ }
16693
+ if (!tok.startsWith("-")) return { module: tok, idx: i };
16694
+ if (tok.includes("=")) continue;
16695
+ const name = tok.replace(/^--?/, "");
16696
+ if (booleanFlags.has(name)) continue;
16697
+ const next = argv[i + 1];
16698
+ if (next !== void 0 && !next.startsWith("-")) i++;
16699
+ }
16700
+ return void 0;
16701
+ }
16849
16702
 
16850
16703
  // src/commands/market.ts
16851
16704
  function getData2(result) {
@@ -18825,7 +18678,7 @@ Config saved to ${p}
18825
18678
  }
18826
18679
  };
18827
18680
  function prompt(rl, question) {
18828
- return new Promise((resolve4) => rl.question(question, resolve4));
18681
+ return new Promise((resolve3) => rl.question(question, resolve3));
18829
18682
  }
18830
18683
  function cmdConfigShow(json) {
18831
18684
  const config = readFullConfig();
@@ -20248,21 +20101,18 @@ async function cmdDcdQuoteAndBuy(run, opts) {
20248
20101
 
20249
20102
  // src/commands/skill.ts
20250
20103
  import { tmpdir, homedir as homedir13 } from "os";
20251
- import { join as join17, dirname as dirname9 } from "path";
20252
- import { mkdirSync as mkdirSync12, rmSync, existsSync as existsSync10, copyFileSync as copyFileSync2 } from "fs";
20104
+ import { join as join16, dirname as dirname9 } from "path";
20105
+ import { mkdirSync as mkdirSync12, rmSync, existsSync as existsSync11, copyFileSync as copyFileSync2 } from "fs";
20253
20106
  import { execFileSync as execFileSync2 } from "child_process";
20254
20107
  import { randomUUID as randomUUID2 } from "crypto";
20255
20108
  function resolveNpx() {
20256
- const sibling = join17(dirname9(process.execPath), "npx");
20257
- if (existsSync10(sibling)) return sibling;
20109
+ const sibling = join16(dirname9(process.execPath), "npx");
20110
+ if (existsSync11(sibling)) return sibling;
20258
20111
  return "npx";
20259
20112
  }
20260
20113
  function npxEnv() {
20261
20114
  return { ...process.env, NO_COLOR: "1", FORCE_COLOR: "0" };
20262
20115
  }
20263
- function getSkillContentDir(name) {
20264
- return join17(homedir13(), ".agents", "skills", name);
20265
- }
20266
20116
  var THIRD_PARTY_INSTALL_NOTICE = "Note: This skill was created by a third-party developer, not by OKX. Review SKILL.md before use.";
20267
20117
  async function cmdSkillSearch(run, opts) {
20268
20118
  const args = {};
@@ -20312,56 +20162,16 @@ async function cmdSkillCategories(run, json) {
20312
20162
  }
20313
20163
  outputLine("");
20314
20164
  }
20315
- async function wrapVerify(fn) {
20316
- try {
20317
- return await fn();
20318
- } catch (e) {
20319
- if (e instanceof ConfigError) {
20320
- throw new Error(
20321
- `Signature verification requires authentication \u2014 run \`okx auth login\` first, or use --force to bypass.`
20322
- );
20323
- }
20324
- throw e;
20325
- }
20326
- }
20327
- async function cmdSkillAdd(name, config, json, force = false, exec = execFileSync2, _deps) {
20328
- const _download = _deps?.download ?? downloadSkillZip;
20329
- const _extract = _deps?.extract ?? extractSkillZip;
20330
- const tmpBase = join17(tmpdir(), `okx-skill-${randomUUID2()}`);
20165
+ async function cmdSkillAdd(name, config, json, exec = execFileSync2) {
20166
+ const tmpBase = join16(tmpdir(), `okx-skill-${randomUUID2()}`);
20331
20167
  mkdirSync12(tmpBase, { recursive: true });
20332
20168
  try {
20333
20169
  outputLine(`Downloading ${name}...`);
20334
20170
  const client = new OkxRestClient(config);
20335
- const zipPath = await _download(client, name, tmpBase);
20336
- const contentDir = await _extract(zipPath, join17(tmpBase, "content"));
20171
+ const zipPath = await downloadSkillZip(client, name, tmpBase);
20172
+ const contentDir = await extractSkillZip(zipPath, join16(tmpBase, "content"));
20337
20173
  const meta = readMetaJson(contentDir);
20338
20174
  validateSkillMdExists(contentDir);
20339
- outputLine("Verifying signature...");
20340
- const verifyResult = await wrapVerify(
20341
- () => verifySkillSignature(contentDir, meta.signing, {
20342
- fetchPublicKey: (keyId) => getPublicKey(client, keyId),
20343
- serverSideVerify: (sName, version, files) => serverSideVerify(client, sName, version, files),
20344
- skillName: meta.name,
20345
- skillVersion: meta.version
20346
- })
20347
- );
20348
- if (verifyResult.status === "failed") {
20349
- if (!force) {
20350
- throw new Error(`Signature verification failed: ${verifyResult.error ?? "unknown error"}. Use --force to install anyway.`);
20351
- }
20352
- process.stderr.write(`WARNING: Signature verification failed \u2014 ${verifyResult.error ?? "unknown"}. Installing anyway (--force).
20353
- `);
20354
- } else if (verifyResult.status === "verified_by_server") {
20355
- if (!json) {
20356
- outputLine(` Verified by server (v${verifyResult.serverVersion ?? "?"})`);
20357
- if (verifyResult.error) outputLine(` Note: ${verifyResult.error}`);
20358
- }
20359
- } else if (!json) {
20360
- outputLine(` Signature verified (key: ${verifyResult.publicKeyId}, files: ${verifyResult.filesChecked})`);
20361
- if (verifyResult.extraFiles?.length) {
20362
- outputLine(` Note: ${verifyResult.extraFiles.length} extra unsigned file(s) present`);
20363
- }
20364
- }
20365
20175
  outputLine("Installing to detected agents...");
20366
20176
  try {
20367
20177
  exec(resolveNpx(), ["skills", "add", contentDir, "-y", "-g"], {
@@ -20370,7 +20180,7 @@ async function cmdSkillAdd(name, config, json, force = false, exec = execFileSyn
20370
20180
  env: npxEnv()
20371
20181
  });
20372
20182
  } catch (e) {
20373
- const savedZip = join17(process.cwd(), `${name}.zip`);
20183
+ const savedZip = join16(process.cwd(), `${name}.zip`);
20374
20184
  try {
20375
20185
  copyFileSync2(zipPath, savedZip);
20376
20186
  } catch {
@@ -20379,8 +20189,7 @@ async function cmdSkillAdd(name, config, json, force = false, exec = execFileSyn
20379
20189
  errorLine(`You can manually install from: ${savedZip}`);
20380
20190
  throw e;
20381
20191
  }
20382
- const registryStatus = verifyResult.status === "failed" && force ? "bypassed" : verifyResult.status;
20383
- upsertSkillRecord(meta, void 0, registryStatus);
20192
+ upsertSkillRecord(meta);
20384
20193
  printSkillInstallResult(meta, json);
20385
20194
  } finally {
20386
20195
  rmSync(tmpBase, { recursive: true, force: true });
@@ -20411,7 +20220,7 @@ function cmdSkillRemove(name, json, exec = execFileSync2) {
20411
20220
  env: npxEnv()
20412
20221
  });
20413
20222
  } catch {
20414
- const agentsPath = getSkillContentDir(name);
20223
+ const agentsPath = join16(homedir13(), ".agents", "skills", name);
20415
20224
  try {
20416
20225
  rmSync(agentsPath, { recursive: true, force: true });
20417
20226
  } catch {
@@ -20475,59 +20284,6 @@ function cmdSkillList(json) {
20475
20284
  outputLine("");
20476
20285
  outputLine(`${skills.length} skills installed.`);
20477
20286
  }
20478
- async function cmdSkillVerify(name, config, json) {
20479
- const record = getSkillRecord(name);
20480
- if (!record) {
20481
- errorLine(`Skill "${name}" is not installed.`);
20482
- process.exitCode = 1;
20483
- return;
20484
- }
20485
- const contentDir = getSkillContentDir(name);
20486
- if (!existsSync10(contentDir)) {
20487
- errorLine(`Skill content directory not found: ${contentDir}`);
20488
- errorLine(`Try reinstalling with: okx skill add ${name}`);
20489
- process.exitCode = 1;
20490
- return;
20491
- }
20492
- const meta = tryReadMetaJson(contentDir);
20493
- const client = new OkxRestClient(config);
20494
- let result;
20495
- try {
20496
- result = await wrapVerify(
20497
- () => verifySkillSignature(contentDir, meta?.signing, {
20498
- fetchPublicKey: (keyId) => getPublicKey(client, keyId),
20499
- serverSideVerify: (sName, version, files) => serverSideVerify(client, sName, version, files),
20500
- skillName: name,
20501
- skillVersion: meta?.version
20502
- })
20503
- );
20504
- } catch (e) {
20505
- errorLine(e instanceof Error ? e.message : String(e));
20506
- process.exitCode = 1;
20507
- return;
20508
- }
20509
- if (meta) {
20510
- upsertSkillRecord(meta, void 0, result.status);
20511
- }
20512
- if (result.status === "failed") {
20513
- process.exitCode = 1;
20514
- }
20515
- if (json) {
20516
- outputLine(JSON.stringify(result, null, 2));
20517
- return;
20518
- }
20519
- if (result.status === "verified") {
20520
- outputLine(`\u2713 ${name}: signature verified (key: ${result.publicKeyId}, files: ${result.filesChecked})`);
20521
- if (result.extraFiles?.length) {
20522
- outputLine(` Note: ${result.extraFiles.length} extra unsigned file(s) present`);
20523
- }
20524
- } else if (result.status === "verified_by_server") {
20525
- outputLine(`\u2713 ${name}: verified by server (v${result.serverVersion ?? "?"})`);
20526
- if (result.error) outputLine(` Note: ${result.error}`);
20527
- } else if (result.status === "failed") {
20528
- errorLine(`\u2717 ${name}: verification failed \u2014 ${result.error ?? "unknown"}`);
20529
- }
20530
- }
20531
20287
  function printSkillInstallResult(meta, json) {
20532
20288
  if (json) {
20533
20289
  outputLine(JSON.stringify({ name: meta.name, version: meta.version, status: "installed" }, null, 2));
@@ -20678,14 +20434,14 @@ function formatBytes2(bytes) {
20678
20434
  return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
20679
20435
  }
20680
20436
  function askConfirmation2(prompt2) {
20681
- return new Promise((resolve4) => {
20437
+ return new Promise((resolve3) => {
20682
20438
  const rl = readline2.createInterface({
20683
20439
  input: process.stdin,
20684
20440
  output: process.stdout
20685
20441
  });
20686
20442
  rl.question(prompt2, (answer) => {
20687
20443
  rl.close();
20688
- resolve4(answer.trim().toLowerCase() === "y");
20444
+ resolve3(answer.trim().toLowerCase() === "y");
20689
20445
  });
20690
20446
  });
20691
20447
  }
@@ -21148,7 +20904,7 @@ async function cmdEventCancel(run, opts) {
21148
20904
  // src/index.ts
21149
20905
  var _require3 = createRequire3(import.meta.url);
21150
20906
  var CLI_VERSION2 = _require3("../package.json").version;
21151
- var GIT_HASH2 = true ? "e5abc21f" : "dev";
20907
+ var GIT_HASH2 = true ? "0614700e" : "dev";
21152
20908
  function handlePilotCommand(action, json, force, binaryPath) {
21153
20909
  if (action === "status") return cmdPilotStatus(json, binaryPath);
21154
20910
  if (action === "install") return cmdPilotInstall(json, binaryPath);
@@ -22460,13 +22216,9 @@ function requireSkillName(rest, usage) {
22460
22216
  }
22461
22217
  return name;
22462
22218
  }
22463
- function handleSkillAdd(rest, v, config, json) {
22219
+ function handleSkillAdd(rest, config, json) {
22464
22220
  const n = requireSkillName(rest, "Usage: okx skill add <name>");
22465
- if (n) return cmdSkillAdd(n, config, json, v.force ?? false);
22466
- }
22467
- function handleSkillVerify(rest, config, json) {
22468
- const n = requireSkillName(rest, "Usage: okx skill verify <name>");
22469
- if (n) return cmdSkillVerify(n, config, json);
22221
+ if (n) return cmdSkillAdd(n, config, json);
22470
22222
  }
22471
22223
  function handleSkillDownload(rest, v, config, json) {
22472
22224
  const n = requireSkillName(rest, "Usage: okx skill download <name> [--dir <path>] [--format zip|skill]");
@@ -22485,13 +22237,12 @@ function handleSkillCommand(run, action, rest, v, json, config) {
22485
22237
  if (action === "search") return cmdSkillSearch(run, { keyword: rest[0] ?? v.keyword, categories: v.categories, page: v.page, limit: v.limit, json });
22486
22238
  if (action === "categories") return cmdSkillCategories(run, json);
22487
22239
  if (action === "list") return cmdSkillList(json);
22488
- if (action === "add") return handleSkillAdd(rest, v, config, json);
22240
+ if (action === "add") return handleSkillAdd(rest, config, json);
22489
22241
  if (action === "download") return handleSkillDownload(rest, v, config, json);
22490
22242
  if (action === "remove") return handleSkillRemove(rest, json);
22491
22243
  if (action === "check") return handleSkillCheck(run, rest, json);
22492
- if (action === "verify") return handleSkillVerify(rest, config, json);
22493
22244
  errorLine(`Unknown skill command: ${action}`);
22494
- errorLine("Valid: search, categories, add, download, remove, check, list, verify");
22245
+ errorLine("Valid: search, categories, add, download, remove, check, list");
22495
22246
  process.exitCode = 1;
22496
22247
  }
22497
22248
  function handleEventCommand(run, action, rest, v, json) {
@@ -22621,7 +22372,16 @@ async function main() {
22621
22372
  err: (m) => process.stderr.write(m)
22622
22373
  });
22623
22374
  checkForUpdates("@okx_ai/okx-trade-cli", CLI_VERSION2);
22624
- const { values, positionals } = parseCli(process.argv.slice(2));
22375
+ const rawArgv = process.argv.slice(2);
22376
+ const peek = peekFirstPositional(rawArgv);
22377
+ if (peek?.module === "outcomes") {
22378
+ const after = rawArgv.slice(peek.idx + 1);
22379
+ const action2 = after[0];
22380
+ const rest2 = after.slice(1);
22381
+ const json2 = rawArgv.includes("--json") || rawArgv.includes("-j");
22382
+ return handleOutcomesCommand(action2, rest2, { json: json2 });
22383
+ }
22384
+ const { values, positionals } = parseCli(rawArgv);
22625
22385
  if (values.version) {
22626
22386
  printVersion();
22627
22387
  return;