@cabaltrading/cli 0.4.1 → 0.4.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 +333 -126
- package/dist/mcp-server.js +5 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3389,6 +3389,7 @@ var init_dbc_configs = __esm(() => {
|
|
|
3389
3389
|
name: z20.string().min(1).max(100),
|
|
3390
3390
|
description: z20.string().max(500).optional(),
|
|
3391
3391
|
config: z20.record(z20.string(), z20.unknown()).optional(),
|
|
3392
|
+
feeClaimer: z20.string().min(32).max(44).optional(),
|
|
3392
3393
|
isProtocolApproved: z20.boolean().default(false)
|
|
3393
3394
|
});
|
|
3394
3395
|
dbcConfigRequestSchema = z20.discriminatedUnion("mode", [
|
|
@@ -3494,7 +3495,9 @@ var init_device_code = __esm(() => {
|
|
|
3494
3495
|
apiKey: z21.string().optional(),
|
|
3495
3496
|
agentName: z21.string().optional(),
|
|
3496
3497
|
solanaAddress: z21.string().optional(),
|
|
3497
|
-
handle: z21.string().optional()
|
|
3498
|
+
handle: z21.string().optional(),
|
|
3499
|
+
avatarUrl: z21.string().nullable().optional(),
|
|
3500
|
+
claimed: z21.boolean().optional()
|
|
3498
3501
|
});
|
|
3499
3502
|
deviceCodePollResponseSchema = successEnvelope(deviceCodePollResponseDataSchema);
|
|
3500
3503
|
});
|
|
@@ -3869,7 +3872,7 @@ async function createServer() {
|
|
|
3869
3872
|
const res = await fetch(`${baseUrl}/skill.json`);
|
|
3870
3873
|
if (!res.ok)
|
|
3871
3874
|
throw new Error(`Failed to fetch skill.json: ${res.status}`);
|
|
3872
|
-
const data = await res.json();
|
|
3875
|
+
const data = z22.record(z22.string(), z22.unknown()).parse(await res.json());
|
|
3873
3876
|
return textResult(data);
|
|
3874
3877
|
} catch (error) {
|
|
3875
3878
|
return textResult(toStructuredError(error));
|
|
@@ -3968,15 +3971,14 @@ async function loginCommand(options = {}) {
|
|
|
3968
3971
|
body: JSON.stringify(options.ref ? { referralCode: options.ref } : {})
|
|
3969
3972
|
});
|
|
3970
3973
|
if (!res.ok) {
|
|
3971
|
-
const data2 = await res.json().catch(() => ({}));
|
|
3972
3974
|
spinner.fail("Failed to get login code");
|
|
3973
|
-
console.log(chalk2.red(
|
|
3975
|
+
console.log(chalk2.red(" Server error"));
|
|
3974
3976
|
return false;
|
|
3975
3977
|
}
|
|
3976
|
-
const
|
|
3977
|
-
deviceCode = data.deviceCode;
|
|
3978
|
-
userCode = data.userCode;
|
|
3979
|
-
verificationUrl = data.verificationUrl;
|
|
3978
|
+
const parsed = deviceCodeCreateResponseSchema.parse(await res.json());
|
|
3979
|
+
deviceCode = parsed.data.deviceCode;
|
|
3980
|
+
userCode = parsed.data.userCode;
|
|
3981
|
+
verificationUrl = parsed.data.verificationUrl;
|
|
3980
3982
|
spinner.stop();
|
|
3981
3983
|
} catch (error) {
|
|
3982
3984
|
spinner.fail("Failed to connect to server");
|
|
@@ -4010,7 +4012,8 @@ async function loginCommand(options = {}) {
|
|
|
4010
4012
|
const res = await fetch(`${apiBase}/auth/device-code/poll?code=${deviceCode}`);
|
|
4011
4013
|
if (!res.ok)
|
|
4012
4014
|
continue;
|
|
4013
|
-
const
|
|
4015
|
+
const parsed = deviceCodePollResponseSchema.parse(await res.json());
|
|
4016
|
+
const data = parsed.data;
|
|
4014
4017
|
if (data.status === "completed") {
|
|
4015
4018
|
pollSpinner.succeed(chalk2.green("Logged in!"));
|
|
4016
4019
|
console.log("");
|
|
@@ -4035,8 +4038,15 @@ async function loginCommand(options = {}) {
|
|
|
4035
4038
|
if (data.solanaAddress)
|
|
4036
4039
|
console.log(` ${chalk2.dim("Wallet:")} ${chalk2.cyan(data.solanaAddress)}`);
|
|
4037
4040
|
console.log("");
|
|
4041
|
+
const needsOnboard = !data.handle || !data.avatarUrl || !data.claimed;
|
|
4042
|
+
if (needsOnboard) {
|
|
4043
|
+
console.log(chalk2.dim(" Run `cabal-cli onboard` to finish setting up your profile."));
|
|
4044
|
+
}
|
|
4038
4045
|
console.log(chalk2.dim(" Run `cabal-cli status` to check balances."));
|
|
4039
|
-
|
|
4046
|
+
if (!needsOnboard) {
|
|
4047
|
+
console.log(chalk2.dim(" Run `cabal-cli trade` to make your first trade."));
|
|
4048
|
+
}
|
|
4049
|
+
console.log("");
|
|
4040
4050
|
}
|
|
4041
4051
|
return true;
|
|
4042
4052
|
}
|
|
@@ -4056,12 +4066,28 @@ function sleep(ms) {
|
|
|
4056
4066
|
}
|
|
4057
4067
|
var POLL_INTERVAL_MS = 5000, TIMEOUT_MS;
|
|
4058
4068
|
var init_login = __esm(() => {
|
|
4069
|
+
init_src();
|
|
4059
4070
|
init_browser();
|
|
4060
4071
|
init_env();
|
|
4061
4072
|
init_errors2();
|
|
4062
4073
|
TIMEOUT_MS = 10 * 60 * 1000;
|
|
4063
4074
|
});
|
|
4064
4075
|
|
|
4076
|
+
// src/lib/tty.ts
|
|
4077
|
+
function isTTY() {
|
|
4078
|
+
return !!process.stdin.isTTY;
|
|
4079
|
+
}
|
|
4080
|
+
function exitMissingFlags(command, missing) {
|
|
4081
|
+
console.error(`Error: this command requires an interactive terminal, or provide these flags:
|
|
4082
|
+
`);
|
|
4083
|
+
for (const { flag, description } of missing) {
|
|
4084
|
+
console.error(` ${flag.padEnd(22)} ${description}`);
|
|
4085
|
+
}
|
|
4086
|
+
console.error(`
|
|
4087
|
+
Example: cabal-cli ${command} ${missing.map((f) => f.flag + " <value>").join(" ")}`);
|
|
4088
|
+
process.exit(1);
|
|
4089
|
+
}
|
|
4090
|
+
|
|
4065
4091
|
// src/commands/onboard.ts
|
|
4066
4092
|
var exports_onboard = {};
|
|
4067
4093
|
__export(exports_onboard, {
|
|
@@ -4080,21 +4106,21 @@ async function onboardCommand(options) {
|
|
|
4080
4106
|
process.exit(1);
|
|
4081
4107
|
}
|
|
4082
4108
|
if (step === "connect") {
|
|
4083
|
-
await stepConnect();
|
|
4109
|
+
await stepConnect(options);
|
|
4084
4110
|
return;
|
|
4085
4111
|
}
|
|
4086
4112
|
const client = requireClient();
|
|
4087
4113
|
if (step === "profile")
|
|
4088
|
-
await stepProfile(client);
|
|
4114
|
+
await stepProfile(client, options);
|
|
4089
4115
|
else if (step === "avatar")
|
|
4090
|
-
await stepAvatar(client);
|
|
4116
|
+
await stepAvatar(client, options);
|
|
4091
4117
|
else if (step === "verify")
|
|
4092
|
-
await stepVerify(client);
|
|
4118
|
+
await stepVerify(client, options);
|
|
4093
4119
|
return;
|
|
4094
4120
|
}
|
|
4095
|
-
await runWizard();
|
|
4121
|
+
await runWizard(options);
|
|
4096
4122
|
}
|
|
4097
|
-
async function runWizard() {
|
|
4123
|
+
async function runWizard(options) {
|
|
4098
4124
|
if (isConfigured()) {
|
|
4099
4125
|
const client2 = requireClient();
|
|
4100
4126
|
let steps;
|
|
@@ -4103,14 +4129,27 @@ async function runWizard() {
|
|
|
4103
4129
|
} catch {
|
|
4104
4130
|
console.log(chalk3.yellow(`Saved API key is invalid. Starting fresh.
|
|
4105
4131
|
`));
|
|
4106
|
-
const newClient = await stepConnect();
|
|
4132
|
+
const newClient = await stepConnect(options);
|
|
4107
4133
|
if (!newClient)
|
|
4108
4134
|
return;
|
|
4109
|
-
await continueWizard(newClient);
|
|
4135
|
+
await continueWizard(newClient, 1, options);
|
|
4110
4136
|
return;
|
|
4111
4137
|
}
|
|
4112
4138
|
const allDone = steps.every((s) => s.done);
|
|
4113
4139
|
const firstIncomplete = steps.findIndex((s) => !s.done);
|
|
4140
|
+
if (options.confirm) {
|
|
4141
|
+
if (allDone) {
|
|
4142
|
+
console.log(chalk3.green.bold("All onboarding steps already complete."));
|
|
4143
|
+
return;
|
|
4144
|
+
}
|
|
4145
|
+
await continueWizard(client2, firstIncomplete, options);
|
|
4146
|
+
return;
|
|
4147
|
+
}
|
|
4148
|
+
if (!isTTY()) {
|
|
4149
|
+
exitMissingFlags("onboard", [
|
|
4150
|
+
{ flag: "-y, --confirm", description: "Auto-continue through wizard (required in non-TTY)" }
|
|
4151
|
+
]);
|
|
4152
|
+
}
|
|
4114
4153
|
printProgress(steps);
|
|
4115
4154
|
if (allDone) {
|
|
4116
4155
|
const { action: action2 } = await inquirer.prompt([
|
|
@@ -4126,10 +4165,10 @@ async function runWizard() {
|
|
|
4126
4165
|
]);
|
|
4127
4166
|
if (action2 === "quit")
|
|
4128
4167
|
return;
|
|
4129
|
-
const newClient = await stepConnect();
|
|
4168
|
+
const newClient = await stepConnect(options);
|
|
4130
4169
|
if (!newClient)
|
|
4131
4170
|
return;
|
|
4132
|
-
await continueWizard(newClient);
|
|
4171
|
+
await continueWizard(newClient, 1, options);
|
|
4133
4172
|
return;
|
|
4134
4173
|
}
|
|
4135
4174
|
const { action } = await inquirer.prompt([
|
|
@@ -4147,25 +4186,30 @@ async function runWizard() {
|
|
|
4147
4186
|
if (action === "quit")
|
|
4148
4187
|
return;
|
|
4149
4188
|
if (action === "reconfigure") {
|
|
4150
|
-
const newClient = await stepConnect();
|
|
4189
|
+
const newClient = await stepConnect(options);
|
|
4151
4190
|
if (!newClient)
|
|
4152
4191
|
return;
|
|
4153
|
-
await continueWizard(newClient);
|
|
4192
|
+
await continueWizard(newClient, 1, options);
|
|
4154
4193
|
return;
|
|
4155
4194
|
}
|
|
4156
|
-
await continueWizard(client2, firstIncomplete);
|
|
4195
|
+
await continueWizard(client2, firstIncomplete, options);
|
|
4157
4196
|
return;
|
|
4158
4197
|
}
|
|
4159
|
-
const client = await stepConnect();
|
|
4198
|
+
const client = await stepConnect(options);
|
|
4160
4199
|
if (!client)
|
|
4161
4200
|
return;
|
|
4162
|
-
await continueWizard(client);
|
|
4201
|
+
await continueWizard(client, 1, options);
|
|
4163
4202
|
}
|
|
4164
|
-
async function continueWizard(client, startIdx = 1) {
|
|
4203
|
+
async function continueWizard(client, startIdx = 1, options = {}) {
|
|
4165
4204
|
for (let i = startIdx;i < STEP_ORDER.length; i++) {
|
|
4166
4205
|
const step = STEP_ORDER[i];
|
|
4167
4206
|
console.log("");
|
|
4168
|
-
if (i > startIdx) {
|
|
4207
|
+
if (i > startIdx && !options.confirm) {
|
|
4208
|
+
if (!isTTY()) {
|
|
4209
|
+
exitMissingFlags("onboard", [
|
|
4210
|
+
{ flag: "-y, --confirm", description: "Auto-continue through wizard (required in non-TTY)" }
|
|
4211
|
+
]);
|
|
4212
|
+
}
|
|
4169
4213
|
const { action } = await inquirer.prompt([
|
|
4170
4214
|
{
|
|
4171
4215
|
type: "list",
|
|
@@ -4184,22 +4228,38 @@ async function continueWizard(client, startIdx = 1) {
|
|
|
4184
4228
|
continue;
|
|
4185
4229
|
}
|
|
4186
4230
|
if (step === "profile")
|
|
4187
|
-
await stepProfile(client);
|
|
4231
|
+
await stepProfile(client, options);
|
|
4188
4232
|
else if (step === "avatar")
|
|
4189
|
-
await stepAvatar(client);
|
|
4233
|
+
await stepAvatar(client, options);
|
|
4190
4234
|
else if (step === "verify")
|
|
4191
|
-
await stepVerify(client);
|
|
4235
|
+
await stepVerify(client, options);
|
|
4192
4236
|
}
|
|
4193
4237
|
console.log("");
|
|
4194
4238
|
console.log(chalk3.green.bold("Onboarding complete!"));
|
|
4195
4239
|
console.log(chalk3.dim("Run `cabal-cli status` to check your agent.\n"));
|
|
4196
4240
|
}
|
|
4197
|
-
async function stepConnect(apiKeyArg) {
|
|
4241
|
+
async function stepConnect(options, apiKeyArg) {
|
|
4198
4242
|
console.log(chalk3.bold(`
|
|
4199
4243
|
Step 1: Connect
|
|
4200
4244
|
`));
|
|
4201
4245
|
let apiKey = apiKeyArg;
|
|
4202
4246
|
if (!apiKey) {
|
|
4247
|
+
if (isConfigured()) {
|
|
4248
|
+
const creds = getCredentials();
|
|
4249
|
+
if (creds.CABAL_API_KEY) {
|
|
4250
|
+
try {
|
|
4251
|
+
const client = new AgentClient(creds.CABAL_API_KEY, creds.NEXT_PUBLIC_SITE_URL);
|
|
4252
|
+
await client.getStatus();
|
|
4253
|
+
console.log(chalk3.dim(` Already connected. Using existing API key.
|
|
4254
|
+
`));
|
|
4255
|
+
return client;
|
|
4256
|
+
} catch {}
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
if (!isTTY()) {
|
|
4260
|
+
console.error("Error: No valid API key found. Run `cabal-cli login` in a terminal first.");
|
|
4261
|
+
process.exit(1);
|
|
4262
|
+
}
|
|
4203
4263
|
console.log(" To connect your agent, you need an API key.");
|
|
4204
4264
|
console.log(" If you already have one, paste it below.");
|
|
4205
4265
|
console.log("");
|
|
@@ -4290,7 +4350,7 @@ async function stepConnect(apiKeyArg) {
|
|
|
4290
4350
|
return null;
|
|
4291
4351
|
}
|
|
4292
4352
|
}
|
|
4293
|
-
async function stepProfile(client) {
|
|
4353
|
+
async function stepProfile(client, options = {}) {
|
|
4294
4354
|
console.log(chalk3.bold(`
|
|
4295
4355
|
Step 2: Profile
|
|
4296
4356
|
`));
|
|
@@ -4305,61 +4365,86 @@ async function stepProfile(client) {
|
|
|
4305
4365
|
printCliError(error);
|
|
4306
4366
|
return;
|
|
4307
4367
|
}
|
|
4308
|
-
|
|
4368
|
+
if (!isTTY()) {
|
|
4369
|
+
const missing = [];
|
|
4370
|
+
if (!options.name)
|
|
4371
|
+
missing.push({ flag: "--name", description: "Display name" });
|
|
4372
|
+
if (!options.handle)
|
|
4373
|
+
missing.push({ flag: "--handle", description: "Unique handle" });
|
|
4374
|
+
if (!options.bio)
|
|
4375
|
+
missing.push({ flag: "--bio", description: "Agent bio" });
|
|
4376
|
+
if (!options.strategy)
|
|
4377
|
+
missing.push({ flag: "--strategy", description: "Trading strategy" });
|
|
4378
|
+
if (missing.length > 0)
|
|
4379
|
+
exitMissingFlags("onboard --step profile", missing);
|
|
4380
|
+
}
|
|
4381
|
+
let name, handle, bio, strategy;
|
|
4382
|
+
if (options.name && options.handle && options.bio && options.strategy) {
|
|
4383
|
+
name = options.name;
|
|
4384
|
+
handle = options.handle;
|
|
4385
|
+
bio = options.bio;
|
|
4386
|
+
strategy = options.strategy;
|
|
4387
|
+
} else {
|
|
4388
|
+
console.log(chalk3.dim(` Press Enter to keep current values.
|
|
4309
4389
|
`));
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4390
|
+
const answers = await inquirer.prompt([
|
|
4391
|
+
{
|
|
4392
|
+
type: "input",
|
|
4393
|
+
name: "name",
|
|
4394
|
+
message: "Display name:",
|
|
4395
|
+
default: options.name ?? agent2.name
|
|
4396
|
+
},
|
|
4397
|
+
{
|
|
4398
|
+
type: "input",
|
|
4399
|
+
name: "handle",
|
|
4400
|
+
message: "Handle (unique):",
|
|
4401
|
+
default: options.handle ?? agent2.handle ?? undefined,
|
|
4402
|
+
validate: async (input) => {
|
|
4403
|
+
if (!input)
|
|
4404
|
+
return true;
|
|
4405
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(input))
|
|
4406
|
+
return "Handle must be alphanumeric with _ or -";
|
|
4407
|
+
if (input.length > 120)
|
|
4408
|
+
return "Handle must be 120 characters or fewer";
|
|
4409
|
+
if (input === agent2.handle)
|
|
4410
|
+
return true;
|
|
4411
|
+
try {
|
|
4412
|
+
const result2 = await client.checkHandle(input);
|
|
4413
|
+
if (!result2.available)
|
|
4414
|
+
return result2.reason ?? "Handle is not available";
|
|
4415
|
+
return true;
|
|
4416
|
+
} catch {
|
|
4417
|
+
return "Could not validate handle — try again";
|
|
4418
|
+
}
|
|
4338
4419
|
}
|
|
4420
|
+
},
|
|
4421
|
+
{
|
|
4422
|
+
type: "input",
|
|
4423
|
+
name: "bio",
|
|
4424
|
+
message: "Bio:",
|
|
4425
|
+
default: options.bio ?? agent2.bio ?? undefined
|
|
4426
|
+
},
|
|
4427
|
+
{
|
|
4428
|
+
type: "input",
|
|
4429
|
+
name: "strategy",
|
|
4430
|
+
message: "Strategy:",
|
|
4431
|
+
default: options.strategy ?? agent2.strategy ?? undefined
|
|
4339
4432
|
}
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
},
|
|
4347
|
-
{
|
|
4348
|
-
type: "input",
|
|
4349
|
-
name: "strategy",
|
|
4350
|
-
message: "Strategy:",
|
|
4351
|
-
default: agent2.strategy ?? undefined
|
|
4352
|
-
}
|
|
4353
|
-
]);
|
|
4433
|
+
]);
|
|
4434
|
+
name = answers.name;
|
|
4435
|
+
handle = answers.handle;
|
|
4436
|
+
bio = answers.bio;
|
|
4437
|
+
strategy = answers.strategy;
|
|
4438
|
+
}
|
|
4354
4439
|
const updates = {};
|
|
4355
|
-
if (
|
|
4356
|
-
updates.name =
|
|
4357
|
-
if (
|
|
4358
|
-
updates.handle =
|
|
4359
|
-
if (
|
|
4360
|
-
updates.bio =
|
|
4361
|
-
if (
|
|
4362
|
-
updates.strategy =
|
|
4440
|
+
if (name && name !== agent2.name)
|
|
4441
|
+
updates.name = name;
|
|
4442
|
+
if (handle && handle !== agent2.handle)
|
|
4443
|
+
updates.handle = handle;
|
|
4444
|
+
if (bio && bio !== agent2.bio)
|
|
4445
|
+
updates.bio = bio;
|
|
4446
|
+
if (strategy && strategy !== agent2.strategy)
|
|
4447
|
+
updates.strategy = strategy;
|
|
4363
4448
|
if (Object.keys(updates).length === 0) {
|
|
4364
4449
|
console.log(chalk3.dim(`
|
|
4365
4450
|
No changes made.
|
|
@@ -4376,10 +4461,62 @@ async function stepProfile(client) {
|
|
|
4376
4461
|
printCliError(error);
|
|
4377
4462
|
}
|
|
4378
4463
|
}
|
|
4379
|
-
async function stepAvatar(client) {
|
|
4464
|
+
async function stepAvatar(client, options = {}) {
|
|
4380
4465
|
console.log(chalk3.bold(`
|
|
4381
4466
|
Step 3: Avatar
|
|
4382
4467
|
`));
|
|
4468
|
+
if (options.skipAvatar) {
|
|
4469
|
+
console.log(chalk3.dim(` Skipped avatar step.
|
|
4470
|
+
`));
|
|
4471
|
+
return;
|
|
4472
|
+
}
|
|
4473
|
+
if (options.avatarId) {
|
|
4474
|
+
const selectSpinner = ora2("Selecting avatar...").start();
|
|
4475
|
+
try {
|
|
4476
|
+
await client.selectAvatar(options.avatarId);
|
|
4477
|
+
selectSpinner.succeed("Avatar updated!");
|
|
4478
|
+
} catch (error) {
|
|
4479
|
+
selectSpinner.fail("Failed to select avatar");
|
|
4480
|
+
printCliError(error);
|
|
4481
|
+
}
|
|
4482
|
+
console.log("");
|
|
4483
|
+
return;
|
|
4484
|
+
}
|
|
4485
|
+
if (options.avatar) {
|
|
4486
|
+
const genSpinner = ora2("Generating avatar...").start();
|
|
4487
|
+
try {
|
|
4488
|
+
const result2 = await client.generateAvatar(options.avatar);
|
|
4489
|
+
genSpinner.succeed("Avatar generated!");
|
|
4490
|
+
console.log("");
|
|
4491
|
+
if (result2.generationId) {
|
|
4492
|
+
console.log(` ${chalk3.dim("Generation ID:")} ${result2.generationId}`);
|
|
4493
|
+
}
|
|
4494
|
+
console.log(` ${chalk3.dim("Image URL:")} ${chalk3.cyan(result2.imageUrl)}`);
|
|
4495
|
+
console.log(` ${chalk3.dim("Credits left:")} ${result2.creditsRemaining}`);
|
|
4496
|
+
if (result2.generationId) {
|
|
4497
|
+
const selectSpinner = ora2("Setting avatar...").start();
|
|
4498
|
+
try {
|
|
4499
|
+
await client.selectAvatar(result2.generationId);
|
|
4500
|
+
selectSpinner.succeed("Avatar set!");
|
|
4501
|
+
} catch (err2) {
|
|
4502
|
+
selectSpinner.fail("Failed to set avatar");
|
|
4503
|
+
printCliError(err2);
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
} catch (error) {
|
|
4507
|
+
genSpinner.fail("Failed to generate avatar");
|
|
4508
|
+
printCliError(error);
|
|
4509
|
+
}
|
|
4510
|
+
console.log("");
|
|
4511
|
+
return;
|
|
4512
|
+
}
|
|
4513
|
+
if (!isTTY()) {
|
|
4514
|
+
exitMissingFlags("onboard --step avatar", [
|
|
4515
|
+
{ flag: "--avatar", description: "Generate avatar from this description" },
|
|
4516
|
+
{ flag: "--avatar-id", description: "Select an existing avatar generation by ID" },
|
|
4517
|
+
{ flag: "--skip-avatar", description: "Skip avatar step entirely" }
|
|
4518
|
+
]);
|
|
4519
|
+
}
|
|
4383
4520
|
const spinner = ora2("Fetching avatar credits...").start();
|
|
4384
4521
|
try {
|
|
4385
4522
|
const credits = await client.getAvatarCredits();
|
|
@@ -4494,20 +4631,36 @@ async function stepAvatar(client) {
|
|
|
4494
4631
|
printCliError(error);
|
|
4495
4632
|
}
|
|
4496
4633
|
}
|
|
4497
|
-
async function stepVerify(client) {
|
|
4634
|
+
async function stepVerify(client, options = {}) {
|
|
4498
4635
|
console.log(chalk3.bold(`
|
|
4499
4636
|
Step 4: Verify (optional)
|
|
4500
4637
|
`));
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4638
|
+
if (options.skipVerify) {
|
|
4639
|
+
console.log(chalk3.dim(` Skipped verification.
|
|
4640
|
+
`));
|
|
4641
|
+
return;
|
|
4642
|
+
}
|
|
4643
|
+
let tweetUrl;
|
|
4644
|
+
if (options.tweetUrl) {
|
|
4645
|
+
tweetUrl = options.tweetUrl;
|
|
4646
|
+
} else if (!isTTY()) {
|
|
4647
|
+
exitMissingFlags("onboard --step verify", [
|
|
4648
|
+
{ flag: "--tweet-url", description: "Tweet URL for verification" },
|
|
4649
|
+
{ flag: "--skip-verify", description: "Skip verification step" }
|
|
4650
|
+
]);
|
|
4651
|
+
} else {
|
|
4652
|
+
console.log(" Claim your agent by tweeting a verification post.");
|
|
4653
|
+
console.log(` ${chalk3.dim("Dashboard:")} ${chalk3.cyan(DASHBOARD_URL)}`);
|
|
4654
|
+
console.log("");
|
|
4655
|
+
const answer = await inquirer.prompt([
|
|
4656
|
+
{
|
|
4657
|
+
type: "input",
|
|
4658
|
+
name: "tweetUrl",
|
|
4659
|
+
message: "Tweet URL (or press Enter to skip):"
|
|
4660
|
+
}
|
|
4661
|
+
]);
|
|
4662
|
+
tweetUrl = answer.tweetUrl;
|
|
4663
|
+
}
|
|
4511
4664
|
if (!tweetUrl.trim()) {
|
|
4512
4665
|
console.log(chalk3.dim("\n Skipped verification. You can verify later with `cabal-cli onboard --step verify`.\n"));
|
|
4513
4666
|
return;
|
|
@@ -4737,6 +4890,13 @@ import chalk5 from "chalk";
|
|
|
4737
4890
|
import ora4 from "ora";
|
|
4738
4891
|
import inquirer2 from "inquirer";
|
|
4739
4892
|
import { z as z23 } from "zod";
|
|
4893
|
+
async function promptOrFlag(flagValue, promptFn) {
|
|
4894
|
+
if (flagValue !== undefined)
|
|
4895
|
+
return flagValue;
|
|
4896
|
+
if (!isTTY())
|
|
4897
|
+
throw new Error("__missing_flag__");
|
|
4898
|
+
return promptFn();
|
|
4899
|
+
}
|
|
4740
4900
|
async function tradeCommand(options) {
|
|
4741
4901
|
if (!isConfigured()) {
|
|
4742
4902
|
console.log(chalk5.red("Error: No API key found. Run `cabal-cli init` first."));
|
|
@@ -4748,31 +4908,52 @@ async function tradeCommand(options) {
|
|
|
4748
4908
|
process.exit(1);
|
|
4749
4909
|
}
|
|
4750
4910
|
let request;
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4911
|
+
let chain;
|
|
4912
|
+
try {
|
|
4913
|
+
chain = await promptOrFlag(options.chain, async () => (await inquirer2.prompt([{
|
|
4914
|
+
type: "list",
|
|
4915
|
+
name: "chain",
|
|
4916
|
+
message: "Chain:",
|
|
4917
|
+
choices: ["solana", "hyperliquid"]
|
|
4918
|
+
}])).chain);
|
|
4919
|
+
} catch {
|
|
4920
|
+
exitMissingFlags("trade", [
|
|
4921
|
+
{ flag: "-c, --chain", description: "Chain: solana or hyperliquid" }
|
|
4922
|
+
]);
|
|
4923
|
+
}
|
|
4757
4924
|
if (chain === "solana") {
|
|
4758
|
-
|
|
4925
|
+
if (!isTTY()) {
|
|
4926
|
+
const missing = [];
|
|
4927
|
+
if (!options.input)
|
|
4928
|
+
missing.push({ flag: "-i, --input", description: "Input token (e.g. SOL, USDC)" });
|
|
4929
|
+
if (!options.output)
|
|
4930
|
+
missing.push({ flag: "-o, --output", description: "Output token (e.g. PEPE, BONK)" });
|
|
4931
|
+
if (!options.amount)
|
|
4932
|
+
missing.push({ flag: "-a, --amount", description: "Amount of input token" });
|
|
4933
|
+
if (!options.confirm)
|
|
4934
|
+
missing.push({ flag: "-y, --confirm", description: "Skip confirmation prompt" });
|
|
4935
|
+
if (missing.length > 0)
|
|
4936
|
+
exitMissingFlags("trade --chain solana", missing);
|
|
4937
|
+
}
|
|
4938
|
+
const inputToken = await promptOrFlag(options.input, async () => (await inquirer2.prompt([{
|
|
4759
4939
|
type: "input",
|
|
4760
4940
|
name: "value",
|
|
4761
4941
|
message: "Input token (e.g. SOL, USDC):",
|
|
4762
4942
|
validate: (v) => v.trim() ? true : "Required"
|
|
4763
|
-
}])).value;
|
|
4764
|
-
const outputToken = options.output
|
|
4943
|
+
}])).value);
|
|
4944
|
+
const outputToken = await promptOrFlag(options.output, async () => (await inquirer2.prompt([{
|
|
4765
4945
|
type: "input",
|
|
4766
4946
|
name: "value",
|
|
4767
4947
|
message: "Output token (e.g. PEPE, BONK):",
|
|
4768
4948
|
validate: (v) => v.trim() ? true : "Required"
|
|
4769
|
-
}])).value;
|
|
4770
|
-
const
|
|
4949
|
+
}])).value);
|
|
4950
|
+
const amountStr = options.amount ?? await promptOrFlag(undefined, async () => (await inquirer2.prompt([{
|
|
4771
4951
|
type: "input",
|
|
4772
4952
|
name: "value",
|
|
4773
4953
|
message: `Amount of ${inputToken} to swap:`,
|
|
4774
4954
|
validate: (v) => parseFloat(v) > 0 ? true : "Must be a positive number"
|
|
4775
4955
|
}])).value);
|
|
4956
|
+
const amount = parseFloat(amountStr);
|
|
4776
4957
|
request = {
|
|
4777
4958
|
chain: "solana",
|
|
4778
4959
|
inputToken: inputToken.trim().toUpperCase(),
|
|
@@ -4781,34 +4962,49 @@ async function tradeCommand(options) {
|
|
|
4781
4962
|
...options.model && { model: modelSchema.parse(options.model) }
|
|
4782
4963
|
};
|
|
4783
4964
|
} else if (chain === "hyperliquid") {
|
|
4784
|
-
|
|
4965
|
+
if (!isTTY()) {
|
|
4966
|
+
const missing = [];
|
|
4967
|
+
if (!options.coin)
|
|
4968
|
+
missing.push({ flag: "--coin", description: "Coin symbol (e.g. BTC, ETH)" });
|
|
4969
|
+
if (!options.side)
|
|
4970
|
+
missing.push({ flag: "--side", description: "Side: buy or sell" });
|
|
4971
|
+
if (!options.size)
|
|
4972
|
+
missing.push({ flag: "--size", description: "Position size" });
|
|
4973
|
+
if (!options.confirm)
|
|
4974
|
+
missing.push({ flag: "-y, --confirm", description: "Skip confirmation prompt" });
|
|
4975
|
+
if (missing.length > 0)
|
|
4976
|
+
exitMissingFlags("trade --chain hyperliquid", missing);
|
|
4977
|
+
}
|
|
4978
|
+
const coin = await promptOrFlag(options.coin, async () => (await inquirer2.prompt([{
|
|
4785
4979
|
type: "input",
|
|
4786
4980
|
name: "value",
|
|
4787
4981
|
message: "Coin (e.g. BTC, ETH):",
|
|
4788
4982
|
validate: (v) => v.trim() ? true : "Required"
|
|
4789
|
-
}])).value;
|
|
4790
|
-
const rawSide = options.side
|
|
4983
|
+
}])).value);
|
|
4984
|
+
const rawSide = await promptOrFlag(options.side, async () => (await inquirer2.prompt([{
|
|
4791
4985
|
type: "list",
|
|
4792
4986
|
name: "value",
|
|
4793
4987
|
message: "Side:",
|
|
4794
4988
|
choices: ["buy", "sell"]
|
|
4795
|
-
}])).value;
|
|
4989
|
+
}])).value);
|
|
4796
4990
|
const side = z23.enum(["buy", "sell"]).parse(rawSide);
|
|
4797
|
-
const
|
|
4991
|
+
const sizeStr = options.size ?? await promptOrFlag(undefined, async () => (await inquirer2.prompt([{
|
|
4798
4992
|
type: "input",
|
|
4799
4993
|
name: "value",
|
|
4800
4994
|
message: "Size:",
|
|
4801
4995
|
validate: (v) => parseFloat(v) > 0 ? true : "Must be a positive number"
|
|
4802
4996
|
}])).value);
|
|
4997
|
+
const size = parseFloat(sizeStr);
|
|
4803
4998
|
const orderType = z23.enum(["limit", "market"]).parse(options.orderType || "market");
|
|
4804
4999
|
let price;
|
|
4805
5000
|
if (orderType === "limit") {
|
|
4806
|
-
|
|
5001
|
+
const priceStr = options.price ?? await promptOrFlag(undefined, async () => (await inquirer2.prompt([{
|
|
4807
5002
|
type: "input",
|
|
4808
5003
|
name: "value",
|
|
4809
5004
|
message: "Limit price:",
|
|
4810
5005
|
validate: (v) => parseFloat(v) > 0 ? true : "Must be a positive number"
|
|
4811
5006
|
}])).value);
|
|
5007
|
+
price = parseFloat(priceStr);
|
|
4812
5008
|
}
|
|
4813
5009
|
request = {
|
|
4814
5010
|
chain: "hyperliquid",
|
|
@@ -4836,15 +5032,22 @@ async function tradeCommand(options) {
|
|
|
4836
5032
|
console.log(` ${chalk5.dim("Price:")} $${request.price}`);
|
|
4837
5033
|
}
|
|
4838
5034
|
console.log("");
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
5035
|
+
if (!options.confirm) {
|
|
5036
|
+
if (!isTTY()) {
|
|
5037
|
+
exitMissingFlags("trade", [
|
|
5038
|
+
{ flag: "-y, --confirm", description: "Skip confirmation prompt" }
|
|
5039
|
+
]);
|
|
5040
|
+
}
|
|
5041
|
+
const { confirm } = await inquirer2.prompt([{
|
|
5042
|
+
type: "confirm",
|
|
5043
|
+
name: "confirm",
|
|
5044
|
+
message: "Execute this trade?",
|
|
5045
|
+
default: false
|
|
5046
|
+
}]);
|
|
5047
|
+
if (!confirm) {
|
|
5048
|
+
console.log(chalk5.dim("Trade cancelled."));
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
4848
5051
|
}
|
|
4849
5052
|
const spinner = ora4("Executing trade...").start();
|
|
4850
5053
|
try {
|
|
@@ -5439,6 +5642,7 @@ import chalk14 from "chalk";
|
|
|
5439
5642
|
import ora13 from "ora";
|
|
5440
5643
|
import fs2 from "fs";
|
|
5441
5644
|
import path2 from "path";
|
|
5645
|
+
import { z as z26 } from "zod";
|
|
5442
5646
|
function getBaseUrl() {
|
|
5443
5647
|
const creds = getCredentials();
|
|
5444
5648
|
return creds.NEXT_PUBLIC_SITE_URL || "https://cabal.trading";
|
|
@@ -5449,8 +5653,7 @@ async function fetchSkillJson() {
|
|
|
5449
5653
|
if (!res.ok) {
|
|
5450
5654
|
throw new Error(`Failed to fetch skill manifest: ${res.status} ${res.statusText}`);
|
|
5451
5655
|
}
|
|
5452
|
-
|
|
5453
|
-
return { files: data.files || {}, descriptions: data.descriptions || {} };
|
|
5656
|
+
return skillManifestSchema.parse(await res.json());
|
|
5454
5657
|
}
|
|
5455
5658
|
function readInstalledManifest(dir) {
|
|
5456
5659
|
const manifestPath = path2.join(dir, MANIFEST_FILE);
|
|
@@ -5598,10 +5801,14 @@ function formatBytes(bytes) {
|
|
|
5598
5801
|
const kb = bytes / 1024;
|
|
5599
5802
|
return `${kb.toFixed(1)} KB`;
|
|
5600
5803
|
}
|
|
5601
|
-
var MANIFEST_FILE = ".cabal-skills.json";
|
|
5804
|
+
var MANIFEST_FILE = ".cabal-skills.json", skillManifestSchema;
|
|
5602
5805
|
var init_skill = __esm(() => {
|
|
5603
5806
|
init_env();
|
|
5604
5807
|
init_errors2();
|
|
5808
|
+
skillManifestSchema = z26.object({
|
|
5809
|
+
files: z26.record(z26.string(), z26.string()).optional().default({}),
|
|
5810
|
+
descriptions: z26.record(z26.string(), z26.string()).optional().default({})
|
|
5811
|
+
});
|
|
5605
5812
|
});
|
|
5606
5813
|
|
|
5607
5814
|
// src/index.ts
|
|
@@ -5643,7 +5850,7 @@ if (process.argv.includes("--mcp")) {
|
|
|
5643
5850
|
printBanner(chalk15);
|
|
5644
5851
|
await loginCommand2(options);
|
|
5645
5852
|
});
|
|
5646
|
-
program.command("onboard").description("Guided setup wizard — connect, profile, avatar, verify").option("--step <step>", "Jump to a specific step: connect, profile, avatar, verify").action(async (options) => {
|
|
5853
|
+
program.command("onboard").description("Guided setup wizard — connect, profile, avatar, verify").option("--step <step>", "Jump to a specific step: connect, profile, avatar, verify").option("--name <name>", "Display name").option("--handle <handle>", "Unique handle").option("--bio <bio>", "Agent bio").option("--strategy <strategy>", "Trading strategy").option("--avatar <description>", "Generate avatar from this description").option("--avatar-id <id>", "Select an existing avatar generation by ID").option("--skip-avatar", "Skip avatar step").option("--tweet-url <url>", "Tweet URL for verification").option("--skip-verify", "Skip verification step").option("-y, --confirm", "Auto-continue through wizard (required in non-TTY)").action(async (options) => {
|
|
5647
5854
|
printBanner(chalk15);
|
|
5648
5855
|
await onboardCommand2(options);
|
|
5649
5856
|
});
|
|
@@ -5652,7 +5859,7 @@ if (process.argv.includes("--mcp")) {
|
|
|
5652
5859
|
`));
|
|
5653
5860
|
await statusCommand2();
|
|
5654
5861
|
});
|
|
5655
|
-
program.command("trade").description("Execute a trade on Solana or Hyperliquid").option("-c, --chain <chain>", "Chain: solana or hyperliquid").option("-i, --input <token>", "Solana: input token symbol").option("-o, --output <token>", "Solana: output token symbol").option("-a, --amount <amount>", "Solana: amount of input token").option("--coin <coin>", "Hyperliquid: coin symbol").option("--side <side>", "Hyperliquid: buy or sell").option("--size <size>", "Hyperliquid: position size").option("--order-type <type>", "Hyperliquid: market or limit").option("--price <price>", "Hyperliquid: limit price").option("--model <model>", "AI model name for attribution").action(async (options) => {
|
|
5862
|
+
program.command("trade").description("Execute a trade on Solana or Hyperliquid").option("-c, --chain <chain>", "Chain: solana or hyperliquid").option("-i, --input <token>", "Solana: input token symbol").option("-o, --output <token>", "Solana: output token symbol").option("-a, --amount <amount>", "Solana: amount of input token").option("--coin <coin>", "Hyperliquid: coin symbol").option("--side <side>", "Hyperliquid: buy or sell").option("--size <size>", "Hyperliquid: position size").option("--order-type <type>", "Hyperliquid: market or limit").option("--price <price>", "Hyperliquid: limit price").option("--model <model>", "AI model name for attribution").option("-y, --confirm", "Skip confirmation prompt").action(async (options) => {
|
|
5656
5863
|
console.log(chalk15.green.bold("Cabal") + chalk15.dim(` • Trade
|
|
5657
5864
|
`));
|
|
5658
5865
|
await tradeCommand2(options);
|
package/dist/mcp-server.js
CHANGED
|
@@ -3388,6 +3388,7 @@ var init_dbc_configs = __esm(() => {
|
|
|
3388
3388
|
name: z20.string().min(1).max(100),
|
|
3389
3389
|
description: z20.string().max(500).optional(),
|
|
3390
3390
|
config: z20.record(z20.string(), z20.unknown()).optional(),
|
|
3391
|
+
feeClaimer: z20.string().min(32).max(44).optional(),
|
|
3391
3392
|
isProtocolApproved: z20.boolean().default(false)
|
|
3392
3393
|
});
|
|
3393
3394
|
dbcConfigRequestSchema = z20.discriminatedUnion("mode", [
|
|
@@ -3493,7 +3494,9 @@ var init_device_code = __esm(() => {
|
|
|
3493
3494
|
apiKey: z21.string().optional(),
|
|
3494
3495
|
agentName: z21.string().optional(),
|
|
3495
3496
|
solanaAddress: z21.string().optional(),
|
|
3496
|
-
handle: z21.string().optional()
|
|
3497
|
+
handle: z21.string().optional(),
|
|
3498
|
+
avatarUrl: z21.string().nullable().optional(),
|
|
3499
|
+
claimed: z21.boolean().optional()
|
|
3497
3500
|
});
|
|
3498
3501
|
deviceCodePollResponseSchema = successEnvelope(deviceCodePollResponseDataSchema);
|
|
3499
3502
|
});
|
|
@@ -3868,7 +3871,7 @@ async function createServer() {
|
|
|
3868
3871
|
const res = await fetch(`${baseUrl}/skill.json`);
|
|
3869
3872
|
if (!res.ok)
|
|
3870
3873
|
throw new Error(`Failed to fetch skill.json: ${res.status}`);
|
|
3871
|
-
const data = await res.json();
|
|
3874
|
+
const data = z22.record(z22.string(), z22.unknown()).parse(await res.json());
|
|
3872
3875
|
return textResult(data);
|
|
3873
3876
|
} catch (error) {
|
|
3874
3877
|
return textResult(toStructuredError(error));
|
package/package.json
CHANGED