@toothfairyai/cli 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/toothfairy.js +4012 -0
- package/package.json +1 -1
- package/src/api.js +563 -0
package/bin/toothfairy.js
CHANGED
|
@@ -3951,5 +3951,4017 @@ program
|
|
|
3951
3951
|
}
|
|
3952
3952
|
});
|
|
3953
3953
|
|
|
3954
|
+
// Agent commands
|
|
3955
|
+
program
|
|
3956
|
+
.command('create-agent')
|
|
3957
|
+
.description('Create a new agent')
|
|
3958
|
+
.option('--label <label>', 'Agent label')
|
|
3959
|
+
.option('--description <description>', 'Agent description')
|
|
3960
|
+
.option('--emoji <emoji>', 'Agent emoji')
|
|
3961
|
+
.option('--mode <mode>', 'Agent mode (retriever|coder|chatter|planner|computer|voice|accuracy)')
|
|
3962
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
3963
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
3964
|
+
.action(async (options, command) => {
|
|
3965
|
+
try {
|
|
3966
|
+
const globalOptions = command.parent.opts();
|
|
3967
|
+
const config = loadConfig(globalOptions.config);
|
|
3968
|
+
validateConfiguration(config);
|
|
3969
|
+
|
|
3970
|
+
const api = new ToothFairyAPI(
|
|
3971
|
+
config.baseUrl,
|
|
3972
|
+
config.aiUrl,
|
|
3973
|
+
config.aiStreamUrl,
|
|
3974
|
+
config.apiKey,
|
|
3975
|
+
config.workspaceId,
|
|
3976
|
+
globalOptions.verbose || options.verbose
|
|
3977
|
+
);
|
|
3978
|
+
|
|
3979
|
+
const spinner = ora('Creating agent...').start();
|
|
3980
|
+
const result = await api._makeRequest('POST', 'agent/create', {
|
|
3981
|
+
label: options.label,
|
|
3982
|
+
description: options.description,
|
|
3983
|
+
emoji: options.emoji,
|
|
3984
|
+
mode: options.mode,
|
|
3985
|
+
});
|
|
3986
|
+
spinner.stop();
|
|
3987
|
+
|
|
3988
|
+
if (options.output === 'json') {
|
|
3989
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3990
|
+
} else {
|
|
3991
|
+
console.log(chalk.green.bold('✅ Agent created successfully!'));
|
|
3992
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
3993
|
+
}
|
|
3994
|
+
} catch (error) {
|
|
3995
|
+
console.error(chalk.red(`Error creating agent: ${error.message}`));
|
|
3996
|
+
process.exit(1);
|
|
3997
|
+
}
|
|
3998
|
+
});
|
|
3999
|
+
|
|
4000
|
+
program
|
|
4001
|
+
.command('list-agents')
|
|
4002
|
+
.description('List all agents')
|
|
4003
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4004
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4005
|
+
.action(async (options, command) => {
|
|
4006
|
+
try {
|
|
4007
|
+
const globalOptions = command.parent.opts();
|
|
4008
|
+
const config = loadConfig(globalOptions.config);
|
|
4009
|
+
validateConfiguration(config);
|
|
4010
|
+
|
|
4011
|
+
const api = new ToothFairyAPI(
|
|
4012
|
+
config.baseUrl,
|
|
4013
|
+
config.aiUrl,
|
|
4014
|
+
config.aiStreamUrl,
|
|
4015
|
+
config.apiKey,
|
|
4016
|
+
config.workspaceId,
|
|
4017
|
+
globalOptions.verbose || options.verbose
|
|
4018
|
+
);
|
|
4019
|
+
|
|
4020
|
+
const spinner = ora('Fetching agents...').start();
|
|
4021
|
+
const result = await api._makeRequest('GET', 'agent/list');
|
|
4022
|
+
spinner.stop();
|
|
4023
|
+
|
|
4024
|
+
if (options.output === 'json') {
|
|
4025
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4026
|
+
} else {
|
|
4027
|
+
const agents = Array.isArray(result) ? result : result.items || [];
|
|
4028
|
+
console.log(chalk.green.bold(`Found ${agents.length} agent(s)`));
|
|
4029
|
+
agents.forEach(agent => {
|
|
4030
|
+
console.log(chalk.cyan(` • ${agent.label || 'Unnamed'} (${agent.id})`));
|
|
4031
|
+
});
|
|
4032
|
+
}
|
|
4033
|
+
} catch (error) {
|
|
4034
|
+
console.error(chalk.red(`Error listing agents: ${error.message}`));
|
|
4035
|
+
process.exit(1);
|
|
4036
|
+
}
|
|
4037
|
+
});
|
|
4038
|
+
|
|
4039
|
+
program
|
|
4040
|
+
.command('get-agent')
|
|
4041
|
+
.description('Get details of a specific agent')
|
|
4042
|
+
.argument('<id>', 'Agent ID')
|
|
4043
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4044
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4045
|
+
.action(async (agentId, options, command) => {
|
|
4046
|
+
try {
|
|
4047
|
+
const globalOptions = command.parent.opts();
|
|
4048
|
+
const config = loadConfig(globalOptions.config);
|
|
4049
|
+
validateConfiguration(config);
|
|
4050
|
+
|
|
4051
|
+
const api = new ToothFairyAPI(
|
|
4052
|
+
config.baseUrl,
|
|
4053
|
+
config.aiUrl,
|
|
4054
|
+
config.aiStreamUrl,
|
|
4055
|
+
config.apiKey,
|
|
4056
|
+
config.workspaceId,
|
|
4057
|
+
globalOptions.verbose || options.verbose
|
|
4058
|
+
);
|
|
4059
|
+
|
|
4060
|
+
const spinner = ora('Fetching agent...').start();
|
|
4061
|
+
const result = await api._makeRequest('GET', `agent/get/${agentId}`);
|
|
4062
|
+
spinner.stop();
|
|
4063
|
+
|
|
4064
|
+
if (options.output === 'json') {
|
|
4065
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4066
|
+
} else {
|
|
4067
|
+
console.log(chalk.green.bold('Agent Details'));
|
|
4068
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
4069
|
+
console.log(chalk.dim(`Label: ${result.label}`));
|
|
4070
|
+
console.log(chalk.dim(`Description: ${result.description || 'N/A'}`));
|
|
4071
|
+
console.log(chalk.dim(`Mode: ${result.mode || 'N/A'}`));
|
|
4072
|
+
}
|
|
4073
|
+
} catch (error) {
|
|
4074
|
+
console.error(chalk.red(`Error getting agent: ${error.message}`));
|
|
4075
|
+
process.exit(1);
|
|
4076
|
+
}
|
|
4077
|
+
});
|
|
4078
|
+
|
|
4079
|
+
program
|
|
4080
|
+
.command('update-agent')
|
|
4081
|
+
.description('Update an existing agent')
|
|
4082
|
+
.argument('<id>', 'Agent ID')
|
|
4083
|
+
.option('--label <label>', 'Agent label')
|
|
4084
|
+
.option('--description <description>', 'Agent description')
|
|
4085
|
+
.option('--emoji <emoji>', 'Agent emoji')
|
|
4086
|
+
.option('--mode <mode>', 'Agent mode')
|
|
4087
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4088
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4089
|
+
.action(async (agentId, options, command) => {
|
|
4090
|
+
try {
|
|
4091
|
+
const globalOptions = command.parent.opts();
|
|
4092
|
+
const config = loadConfig(globalOptions.config);
|
|
4093
|
+
validateConfiguration(config);
|
|
4094
|
+
|
|
4095
|
+
const api = new ToothFairyAPI(
|
|
4096
|
+
config.baseUrl,
|
|
4097
|
+
config.aiUrl,
|
|
4098
|
+
config.aiStreamUrl,
|
|
4099
|
+
config.apiKey,
|
|
4100
|
+
config.workspaceId,
|
|
4101
|
+
globalOptions.verbose || options.verbose
|
|
4102
|
+
);
|
|
4103
|
+
|
|
4104
|
+
const spinner = ora('Updating agent...').start();
|
|
4105
|
+
const result = await api._makeRequest('POST', `agent/update/${agentId}`, {
|
|
4106
|
+
label: options.label,
|
|
4107
|
+
description: options.description,
|
|
4108
|
+
emoji: options.emoji,
|
|
4109
|
+
mode: options.mode,
|
|
4110
|
+
});
|
|
4111
|
+
spinner.stop();
|
|
4112
|
+
|
|
4113
|
+
if (options.output === 'json') {
|
|
4114
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4115
|
+
} else {
|
|
4116
|
+
console.log(chalk.green.bold('✅ Agent updated successfully!'));
|
|
4117
|
+
}
|
|
4118
|
+
} catch (error) {
|
|
4119
|
+
console.error(chalk.red(`Error updating agent: ${error.message}`));
|
|
4120
|
+
process.exit(1);
|
|
4121
|
+
}
|
|
4122
|
+
});
|
|
4123
|
+
|
|
4124
|
+
program
|
|
4125
|
+
.command('delete-agent')
|
|
4126
|
+
.description('Delete an agent')
|
|
4127
|
+
.argument('<id>', 'Agent ID')
|
|
4128
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
4129
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4130
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4131
|
+
.action(async (agentId, options, command) => {
|
|
4132
|
+
try {
|
|
4133
|
+
const globalOptions = command.parent.opts();
|
|
4134
|
+
const config = loadConfig(globalOptions.config);
|
|
4135
|
+
validateConfiguration(config);
|
|
4136
|
+
|
|
4137
|
+
if (!options.confirm) {
|
|
4138
|
+
const readline = require('readline');
|
|
4139
|
+
const rl = readline.createInterface({
|
|
4140
|
+
input: process.stdin,
|
|
4141
|
+
output: process.stdout,
|
|
4142
|
+
});
|
|
4143
|
+
|
|
4144
|
+
const answer = await new Promise((resolve) => {
|
|
4145
|
+
rl.question(
|
|
4146
|
+
chalk.yellow(`⚠️ Are you sure you want to delete agent ${agentId}? (y/N): `),
|
|
4147
|
+
resolve
|
|
4148
|
+
);
|
|
4149
|
+
});
|
|
4150
|
+
rl.close();
|
|
4151
|
+
|
|
4152
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
4153
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
4154
|
+
process.exit(0);
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
const api = new ToothFairyAPI(
|
|
4159
|
+
config.baseUrl,
|
|
4160
|
+
config.aiUrl,
|
|
4161
|
+
config.aiStreamUrl,
|
|
4162
|
+
config.apiKey,
|
|
4163
|
+
config.workspaceId,
|
|
4164
|
+
globalOptions.verbose || options.verbose
|
|
4165
|
+
);
|
|
4166
|
+
|
|
4167
|
+
const spinner = ora('Deleting agent...').start();
|
|
4168
|
+
const result = await api._makeRequest('DELETE', `agent/delete/${agentId}`);
|
|
4169
|
+
spinner.stop();
|
|
4170
|
+
|
|
4171
|
+
if (options.output === 'json') {
|
|
4172
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4173
|
+
} else {
|
|
4174
|
+
console.log(chalk.green.bold('✅ Agent deleted successfully!'));
|
|
4175
|
+
}
|
|
4176
|
+
} catch (error) {
|
|
4177
|
+
console.error(chalk.red(`Error deleting agent: ${error.message}`));
|
|
4178
|
+
process.exit(1);
|
|
4179
|
+
}
|
|
4180
|
+
});
|
|
4181
|
+
|
|
4182
|
+
// Function commands
|
|
4183
|
+
program
|
|
4184
|
+
.command('create-function')
|
|
4185
|
+
.description('Create a new agent function')
|
|
4186
|
+
.option('--name <name>', 'Function name')
|
|
4187
|
+
.option('--description <description>', 'Function description')
|
|
4188
|
+
.option('--code <code>', 'Function code')
|
|
4189
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4190
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4191
|
+
.action(async (options, command) => {
|
|
4192
|
+
try {
|
|
4193
|
+
const globalOptions = command.parent.opts();
|
|
4194
|
+
const config = loadConfig(globalOptions.config);
|
|
4195
|
+
validateConfiguration(config);
|
|
4196
|
+
|
|
4197
|
+
const api = new ToothFairyAPI(
|
|
4198
|
+
config.baseUrl,
|
|
4199
|
+
config.aiUrl,
|
|
4200
|
+
config.aiStreamUrl,
|
|
4201
|
+
config.apiKey,
|
|
4202
|
+
config.workspaceId,
|
|
4203
|
+
globalOptions.verbose || options.verbose
|
|
4204
|
+
);
|
|
4205
|
+
|
|
4206
|
+
const spinner = ora('Creating function...').start();
|
|
4207
|
+
const result = await api._makeRequest('POST', 'function/create', {
|
|
4208
|
+
name: options.name,
|
|
4209
|
+
description: options.description,
|
|
4210
|
+
code: options.code,
|
|
4211
|
+
});
|
|
4212
|
+
spinner.stop();
|
|
4213
|
+
|
|
4214
|
+
if (options.output === 'json') {
|
|
4215
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4216
|
+
} else {
|
|
4217
|
+
console.log(chalk.green.bold('✅ Function created successfully!'));
|
|
4218
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
4219
|
+
}
|
|
4220
|
+
} catch (error) {
|
|
4221
|
+
console.error(chalk.red(`Error creating function: ${error.message}`));
|
|
4222
|
+
process.exit(1);
|
|
4223
|
+
}
|
|
4224
|
+
});
|
|
4225
|
+
|
|
4226
|
+
program
|
|
4227
|
+
.command('list-functions')
|
|
4228
|
+
.description('List all functions')
|
|
4229
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4230
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4231
|
+
.action(async (options, command) => {
|
|
4232
|
+
try {
|
|
4233
|
+
const globalOptions = command.parent.opts();
|
|
4234
|
+
const config = loadConfig(globalOptions.config);
|
|
4235
|
+
validateConfiguration(config);
|
|
4236
|
+
|
|
4237
|
+
const api = new ToothFairyAPI(
|
|
4238
|
+
config.baseUrl,
|
|
4239
|
+
config.aiUrl,
|
|
4240
|
+
config.aiStreamUrl,
|
|
4241
|
+
config.apiKey,
|
|
4242
|
+
config.workspaceId,
|
|
4243
|
+
globalOptions.verbose || options.verbose
|
|
4244
|
+
);
|
|
4245
|
+
|
|
4246
|
+
const spinner = ora('Fetching functions...').start();
|
|
4247
|
+
const result = await api._makeRequest('GET', 'function/list');
|
|
4248
|
+
spinner.stop();
|
|
4249
|
+
|
|
4250
|
+
if (options.output === 'json') {
|
|
4251
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4252
|
+
} else {
|
|
4253
|
+
const functions = Array.isArray(result) ? result : result.items || [];
|
|
4254
|
+
console.log(chalk.green.bold(`Found ${functions.length} function(s)`));
|
|
4255
|
+
functions.forEach(fn => {
|
|
4256
|
+
console.log(chalk.cyan(` • ${fn.name || 'Unnamed'} (${fn.id})`));
|
|
4257
|
+
});
|
|
4258
|
+
}
|
|
4259
|
+
} catch (error) {
|
|
4260
|
+
console.error(chalk.red(`Error listing functions: ${error.message}`));
|
|
4261
|
+
process.exit(1);
|
|
4262
|
+
}
|
|
4263
|
+
});
|
|
4264
|
+
|
|
4265
|
+
program
|
|
4266
|
+
.command('get-function')
|
|
4267
|
+
.description('Get details of a specific function')
|
|
4268
|
+
.argument('<id>', 'Function ID')
|
|
4269
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4270
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4271
|
+
.action(async (functionId, options, command) => {
|
|
4272
|
+
try {
|
|
4273
|
+
const globalOptions = command.parent.opts();
|
|
4274
|
+
const config = loadConfig(globalOptions.config);
|
|
4275
|
+
validateConfiguration(config);
|
|
4276
|
+
|
|
4277
|
+
const api = new ToothFairyAPI(
|
|
4278
|
+
config.baseUrl,
|
|
4279
|
+
config.aiUrl,
|
|
4280
|
+
config.aiStreamUrl,
|
|
4281
|
+
config.apiKey,
|
|
4282
|
+
config.workspaceId,
|
|
4283
|
+
globalOptions.verbose || options.verbose
|
|
4284
|
+
);
|
|
4285
|
+
|
|
4286
|
+
const spinner = ora('Fetching function...').start();
|
|
4287
|
+
const result = await api._makeRequest('GET', `function/get/${functionId}`);
|
|
4288
|
+
spinner.stop();
|
|
4289
|
+
|
|
4290
|
+
if (options.output === 'json') {
|
|
4291
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4292
|
+
} else {
|
|
4293
|
+
console.log(chalk.green.bold('Function Details'));
|
|
4294
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
4295
|
+
console.log(chalk.dim(`Name: ${result.name}`));
|
|
4296
|
+
console.log(chalk.dim(`Description: ${result.description || 'N/A'}`));
|
|
4297
|
+
}
|
|
4298
|
+
} catch (error) {
|
|
4299
|
+
console.error(chalk.red(`Error getting function: ${error.message}`));
|
|
4300
|
+
process.exit(1);
|
|
4301
|
+
}
|
|
4302
|
+
});
|
|
4303
|
+
|
|
4304
|
+
program
|
|
4305
|
+
.command('update-function')
|
|
4306
|
+
.description('Update an existing function')
|
|
4307
|
+
.argument('<id>', 'Function ID')
|
|
4308
|
+
.option('--name <name>', 'Function name')
|
|
4309
|
+
.option('--description <description>', 'Function description')
|
|
4310
|
+
.option('--code <code>', 'Function code')
|
|
4311
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4312
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4313
|
+
.action(async (functionId, options, command) => {
|
|
4314
|
+
try {
|
|
4315
|
+
const globalOptions = command.parent.opts();
|
|
4316
|
+
const config = loadConfig(globalOptions.config);
|
|
4317
|
+
validateConfiguration(config);
|
|
4318
|
+
|
|
4319
|
+
const api = new ToothFairyAPI(
|
|
4320
|
+
config.baseUrl,
|
|
4321
|
+
config.aiUrl,
|
|
4322
|
+
config.aiStreamUrl,
|
|
4323
|
+
config.apiKey,
|
|
4324
|
+
config.workspaceId,
|
|
4325
|
+
globalOptions.verbose || options.verbose
|
|
4326
|
+
);
|
|
4327
|
+
|
|
4328
|
+
const spinner = ora('Updating function...').start();
|
|
4329
|
+
const result = await api._makeRequest('POST', `function/update/${functionId}`, {
|
|
4330
|
+
name: options.name,
|
|
4331
|
+
description: options.description,
|
|
4332
|
+
code: options.code,
|
|
4333
|
+
});
|
|
4334
|
+
spinner.stop();
|
|
4335
|
+
|
|
4336
|
+
if (options.output === 'json') {
|
|
4337
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4338
|
+
} else {
|
|
4339
|
+
console.log(chalk.green.bold('✅ Function updated successfully!'));
|
|
4340
|
+
}
|
|
4341
|
+
} catch (error) {
|
|
4342
|
+
console.error(chalk.red(`Error updating function: ${error.message}`));
|
|
4343
|
+
process.exit(1);
|
|
4344
|
+
}
|
|
4345
|
+
});
|
|
4346
|
+
|
|
4347
|
+
program
|
|
4348
|
+
.command('delete-function')
|
|
4349
|
+
.description('Delete a function')
|
|
4350
|
+
.argument('<id>', 'Function ID')
|
|
4351
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
4352
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4353
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4354
|
+
.action(async (functionId, options, command) => {
|
|
4355
|
+
try {
|
|
4356
|
+
const globalOptions = command.parent.opts();
|
|
4357
|
+
const config = loadConfig(globalOptions.config);
|
|
4358
|
+
validateConfiguration(config);
|
|
4359
|
+
|
|
4360
|
+
if (!options.confirm) {
|
|
4361
|
+
const readline = require('readline');
|
|
4362
|
+
const rl = readline.createInterface({
|
|
4363
|
+
input: process.stdin,
|
|
4364
|
+
output: process.stdout,
|
|
4365
|
+
});
|
|
4366
|
+
|
|
4367
|
+
const answer = await new Promise((resolve) => {
|
|
4368
|
+
rl.question(
|
|
4369
|
+
chalk.yellow(`⚠️ Are you sure you want to delete function ${functionId}? (y/N): `),
|
|
4370
|
+
resolve
|
|
4371
|
+
);
|
|
4372
|
+
});
|
|
4373
|
+
rl.close();
|
|
4374
|
+
|
|
4375
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
4376
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
4377
|
+
process.exit(0);
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
|
|
4381
|
+
const api = new ToothFairyAPI(
|
|
4382
|
+
config.baseUrl,
|
|
4383
|
+
config.aiUrl,
|
|
4384
|
+
config.aiStreamUrl,
|
|
4385
|
+
config.apiKey,
|
|
4386
|
+
config.workspaceId,
|
|
4387
|
+
globalOptions.verbose || options.verbose
|
|
4388
|
+
);
|
|
4389
|
+
|
|
4390
|
+
const spinner = ora('Deleting function...').start();
|
|
4391
|
+
const result = await api._makeRequest('DELETE', `function/delete/${functionId}`);
|
|
4392
|
+
spinner.stop();
|
|
4393
|
+
|
|
4394
|
+
if (options.output === 'json') {
|
|
4395
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4396
|
+
} else {
|
|
4397
|
+
console.log(chalk.green.bold('✅ Function deleted successfully!'));
|
|
4398
|
+
}
|
|
4399
|
+
} catch (error) {
|
|
4400
|
+
console.error(chalk.red(`Error deleting function: ${error.message}`));
|
|
4401
|
+
process.exit(1);
|
|
4402
|
+
}
|
|
4403
|
+
});
|
|
4404
|
+
|
|
4405
|
+
// Channel commands
|
|
4406
|
+
program
|
|
4407
|
+
.command('create-channel')
|
|
4408
|
+
.description('Create a new channel')
|
|
4409
|
+
.option('--name <name>', 'Channel name')
|
|
4410
|
+
.option('--type <type>', 'Channel type')
|
|
4411
|
+
.option('--config <config>', 'Channel configuration (JSON)')
|
|
4412
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4413
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4414
|
+
.action(async (options, command) => {
|
|
4415
|
+
try {
|
|
4416
|
+
const globalOptions = command.parent.opts();
|
|
4417
|
+
const config = loadConfig(globalOptions.config);
|
|
4418
|
+
validateConfiguration(config);
|
|
4419
|
+
|
|
4420
|
+
const api = new ToothFairyAPI(
|
|
4421
|
+
config.baseUrl,
|
|
4422
|
+
config.aiUrl,
|
|
4423
|
+
config.aiStreamUrl,
|
|
4424
|
+
config.apiKey,
|
|
4425
|
+
config.workspaceId,
|
|
4426
|
+
globalOptions.verbose || options.verbose
|
|
4427
|
+
);
|
|
4428
|
+
|
|
4429
|
+
let channelConfig = {};
|
|
4430
|
+
if (options.config) {
|
|
4431
|
+
try {
|
|
4432
|
+
channelConfig = JSON.parse(options.config);
|
|
4433
|
+
} catch (e) {
|
|
4434
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
4435
|
+
process.exit(1);
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
const spinner = ora('Creating channel...').start();
|
|
4440
|
+
const result = await api._makeRequest('POST', 'channel/create', {
|
|
4441
|
+
name: options.name,
|
|
4442
|
+
type: options.type,
|
|
4443
|
+
config: channelConfig,
|
|
4444
|
+
});
|
|
4445
|
+
spinner.stop();
|
|
4446
|
+
|
|
4447
|
+
if (options.output === 'json') {
|
|
4448
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4449
|
+
} else {
|
|
4450
|
+
console.log(chalk.green.bold('✅ Channel created successfully!'));
|
|
4451
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
4452
|
+
}
|
|
4453
|
+
} catch (error) {
|
|
4454
|
+
console.error(chalk.red(`Error creating channel: ${error.message}`));
|
|
4455
|
+
process.exit(1);
|
|
4456
|
+
}
|
|
4457
|
+
});
|
|
4458
|
+
|
|
4459
|
+
program
|
|
4460
|
+
.command('list-channels')
|
|
4461
|
+
.description('List all channels')
|
|
4462
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4463
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4464
|
+
.action(async (options, command) => {
|
|
4465
|
+
try {
|
|
4466
|
+
const globalOptions = command.parent.opts();
|
|
4467
|
+
const config = loadConfig(globalOptions.config);
|
|
4468
|
+
validateConfiguration(config);
|
|
4469
|
+
|
|
4470
|
+
const api = new ToothFairyAPI(
|
|
4471
|
+
config.baseUrl,
|
|
4472
|
+
config.aiUrl,
|
|
4473
|
+
config.aiStreamUrl,
|
|
4474
|
+
config.apiKey,
|
|
4475
|
+
config.workspaceId,
|
|
4476
|
+
globalOptions.verbose || options.verbose
|
|
4477
|
+
);
|
|
4478
|
+
|
|
4479
|
+
const spinner = ora('Fetching channels...').start();
|
|
4480
|
+
const result = await api._makeRequest('GET', 'channel/list');
|
|
4481
|
+
spinner.stop();
|
|
4482
|
+
|
|
4483
|
+
if (options.output === 'json') {
|
|
4484
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4485
|
+
} else {
|
|
4486
|
+
const channels = Array.isArray(result) ? result : result.items || [];
|
|
4487
|
+
console.log(chalk.green.bold(`Found ${channels.length} channel(s)`));
|
|
4488
|
+
channels.forEach(ch => {
|
|
4489
|
+
console.log(chalk.cyan(` • ${ch.name || 'Unnamed'} (${ch.id})`));
|
|
4490
|
+
});
|
|
4491
|
+
}
|
|
4492
|
+
} catch (error) {
|
|
4493
|
+
console.error(chalk.red(`Error listing channels: ${error.message}`));
|
|
4494
|
+
process.exit(1);
|
|
4495
|
+
}
|
|
4496
|
+
});
|
|
4497
|
+
|
|
4498
|
+
program
|
|
4499
|
+
.command('get-channel')
|
|
4500
|
+
.description('Get details of a specific channel')
|
|
4501
|
+
.argument('<id>', 'Channel ID')
|
|
4502
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4503
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4504
|
+
.action(async (channelId, options, command) => {
|
|
4505
|
+
try {
|
|
4506
|
+
const globalOptions = command.parent.opts();
|
|
4507
|
+
const config = loadConfig(globalOptions.config);
|
|
4508
|
+
validateConfiguration(config);
|
|
4509
|
+
|
|
4510
|
+
const api = new ToothFairyAPI(
|
|
4511
|
+
config.baseUrl,
|
|
4512
|
+
config.aiUrl,
|
|
4513
|
+
config.aiStreamUrl,
|
|
4514
|
+
config.apiKey,
|
|
4515
|
+
config.workspaceId,
|
|
4516
|
+
globalOptions.verbose || options.verbose
|
|
4517
|
+
);
|
|
4518
|
+
|
|
4519
|
+
const spinner = ora('Fetching channel...').start();
|
|
4520
|
+
const result = await api._makeRequest('GET', `channel/get/${channelId}`);
|
|
4521
|
+
spinner.stop();
|
|
4522
|
+
|
|
4523
|
+
if (options.output === 'json') {
|
|
4524
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4525
|
+
} else {
|
|
4526
|
+
console.log(chalk.green.bold('Channel Details'));
|
|
4527
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
4528
|
+
console.log(chalk.dim(`Name: ${result.name}`));
|
|
4529
|
+
console.log(chalk.dim(`Type: ${result.type || 'N/A'}`));
|
|
4530
|
+
}
|
|
4531
|
+
} catch (error) {
|
|
4532
|
+
console.error(chalk.red(`Error getting channel: ${error.message}`));
|
|
4533
|
+
process.exit(1);
|
|
4534
|
+
}
|
|
4535
|
+
});
|
|
4536
|
+
|
|
4537
|
+
program
|
|
4538
|
+
.command('update-channel')
|
|
4539
|
+
.description('Update an existing channel')
|
|
4540
|
+
.argument('<id>', 'Channel ID')
|
|
4541
|
+
.option('--name <name>', 'Channel name')
|
|
4542
|
+
.option('--type <type>', 'Channel type')
|
|
4543
|
+
.option('--config <config>', 'Channel configuration (JSON)')
|
|
4544
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4545
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4546
|
+
.action(async (channelId, options, command) => {
|
|
4547
|
+
try {
|
|
4548
|
+
const globalOptions = command.parent.opts();
|
|
4549
|
+
const config = loadConfig(globalOptions.config);
|
|
4550
|
+
validateConfiguration(config);
|
|
4551
|
+
|
|
4552
|
+
const api = new ToothFairyAPI(
|
|
4553
|
+
config.baseUrl,
|
|
4554
|
+
config.aiUrl,
|
|
4555
|
+
config.aiStreamUrl,
|
|
4556
|
+
config.apiKey,
|
|
4557
|
+
config.workspaceId,
|
|
4558
|
+
globalOptions.verbose || options.verbose
|
|
4559
|
+
);
|
|
4560
|
+
|
|
4561
|
+
let channelConfig = {};
|
|
4562
|
+
if (options.config) {
|
|
4563
|
+
try {
|
|
4564
|
+
channelConfig = JSON.parse(options.config);
|
|
4565
|
+
} catch (e) {
|
|
4566
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
4567
|
+
process.exit(1);
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
const spinner = ora('Updating channel...').start();
|
|
4572
|
+
const result = await api._makeRequest('POST', 'channel/update', {
|
|
4573
|
+
id: channelId,
|
|
4574
|
+
name: options.name,
|
|
4575
|
+
type: options.type,
|
|
4576
|
+
config: channelConfig,
|
|
4577
|
+
});
|
|
4578
|
+
spinner.stop();
|
|
4579
|
+
|
|
4580
|
+
if (options.output === 'json') {
|
|
4581
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4582
|
+
} else {
|
|
4583
|
+
console.log(chalk.green.bold('✅ Channel updated successfully!'));
|
|
4584
|
+
}
|
|
4585
|
+
} catch (error) {
|
|
4586
|
+
console.error(chalk.red(`Error updating channel: ${error.message}`));
|
|
4587
|
+
process.exit(1);
|
|
4588
|
+
}
|
|
4589
|
+
});
|
|
4590
|
+
|
|
4591
|
+
program
|
|
4592
|
+
.command('delete-channel')
|
|
4593
|
+
.description('Delete a channel')
|
|
4594
|
+
.argument('<id>', 'Channel ID')
|
|
4595
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
4596
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4597
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4598
|
+
.action(async (channelId, options, command) => {
|
|
4599
|
+
try {
|
|
4600
|
+
const globalOptions = command.parent.opts();
|
|
4601
|
+
const config = loadConfig(globalOptions.config);
|
|
4602
|
+
validateConfiguration(config);
|
|
4603
|
+
|
|
4604
|
+
if (!options.confirm) {
|
|
4605
|
+
const readline = require('readline');
|
|
4606
|
+
const rl = readline.createInterface({
|
|
4607
|
+
input: process.stdin,
|
|
4608
|
+
output: process.stdout,
|
|
4609
|
+
});
|
|
4610
|
+
|
|
4611
|
+
const answer = await new Promise((resolve) => {
|
|
4612
|
+
rl.question(
|
|
4613
|
+
chalk.yellow(`⚠️ Are you sure you want to delete channel ${channelId}? (y/N): `),
|
|
4614
|
+
resolve
|
|
4615
|
+
);
|
|
4616
|
+
});
|
|
4617
|
+
rl.close();
|
|
4618
|
+
|
|
4619
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
4620
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
4621
|
+
process.exit(0);
|
|
4622
|
+
}
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4625
|
+
const api = new ToothFairyAPI(
|
|
4626
|
+
config.baseUrl,
|
|
4627
|
+
config.aiUrl,
|
|
4628
|
+
config.aiStreamUrl,
|
|
4629
|
+
config.apiKey,
|
|
4630
|
+
config.workspaceId,
|
|
4631
|
+
globalOptions.verbose || options.verbose
|
|
4632
|
+
);
|
|
4633
|
+
|
|
4634
|
+
const spinner = ora('Deleting channel...').start();
|
|
4635
|
+
const result = await api._makeRequest('DELETE', `channel/delete/${channelId}`);
|
|
4636
|
+
spinner.stop();
|
|
4637
|
+
|
|
4638
|
+
if (options.output === 'json') {
|
|
4639
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4640
|
+
} else {
|
|
4641
|
+
console.log(chalk.green.bold('✅ Channel deleted successfully!'));
|
|
4642
|
+
}
|
|
4643
|
+
} catch (error) {
|
|
4644
|
+
console.error(chalk.red(`Error deleting channel: ${error.message}`));
|
|
4645
|
+
process.exit(1);
|
|
4646
|
+
}
|
|
4647
|
+
});
|
|
4648
|
+
|
|
4649
|
+
// Billing command
|
|
4650
|
+
program
|
|
4651
|
+
.command('billing')
|
|
4652
|
+
.description('Get monthly billing costs')
|
|
4653
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4654
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4655
|
+
.action(async (options, command) => {
|
|
4656
|
+
try {
|
|
4657
|
+
const globalOptions = command.parent.opts();
|
|
4658
|
+
const config = loadConfig(globalOptions.config);
|
|
4659
|
+
validateConfiguration(config);
|
|
4660
|
+
|
|
4661
|
+
const api = new ToothFairyAPI(
|
|
4662
|
+
config.baseUrl,
|
|
4663
|
+
config.aiUrl,
|
|
4664
|
+
config.aiStreamUrl,
|
|
4665
|
+
config.apiKey,
|
|
4666
|
+
config.workspaceId,
|
|
4667
|
+
globalOptions.verbose || options.verbose
|
|
4668
|
+
);
|
|
4669
|
+
|
|
4670
|
+
const spinner = ora('Fetching billing information...').start();
|
|
4671
|
+
const result = await api._makeRequest('GET', 'billing/monthCosts');
|
|
4672
|
+
spinner.stop();
|
|
4673
|
+
|
|
4674
|
+
if (options.output === 'json') {
|
|
4675
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4676
|
+
} else {
|
|
4677
|
+
console.log(chalk.green.bold('💰 Monthly Billing'));
|
|
4678
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
4679
|
+
}
|
|
4680
|
+
} catch (error) {
|
|
4681
|
+
console.error(chalk.red(`Error fetching billing: ${error.message}`));
|
|
4682
|
+
process.exit(1);
|
|
4683
|
+
}
|
|
4684
|
+
});
|
|
4685
|
+
|
|
4686
|
+
// Embedding command
|
|
4687
|
+
program
|
|
4688
|
+
.command('get-embedding')
|
|
4689
|
+
.description('Get embedding for text')
|
|
4690
|
+
.argument('<text>', 'Text to get embedding for')
|
|
4691
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4692
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4693
|
+
.action(async (text, options, command) => {
|
|
4694
|
+
try {
|
|
4695
|
+
const globalOptions = command.parent.opts();
|
|
4696
|
+
const config = loadConfig(globalOptions.config);
|
|
4697
|
+
validateConfiguration(config);
|
|
4698
|
+
|
|
4699
|
+
const api = new ToothFairyAPI(
|
|
4700
|
+
config.baseUrl,
|
|
4701
|
+
config.aiUrl,
|
|
4702
|
+
config.aiStreamUrl,
|
|
4703
|
+
config.apiKey,
|
|
4704
|
+
config.workspaceId,
|
|
4705
|
+
globalOptions.verbose || options.verbose
|
|
4706
|
+
);
|
|
4707
|
+
|
|
4708
|
+
const spinner = ora('Generating embedding...').start();
|
|
4709
|
+
const result = await api._makeRequest('GET', 'embedding/get', { text });
|
|
4710
|
+
spinner.stop();
|
|
4711
|
+
|
|
4712
|
+
if (options.output === 'json') {
|
|
4713
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4714
|
+
} else {
|
|
4715
|
+
console.log(chalk.green.bold('🔢 Embedding Generated'));
|
|
4716
|
+
console.log(chalk.dim(`Dimensions: ${result.embedding?.length || 'N/A'}`));
|
|
4717
|
+
}
|
|
4718
|
+
} catch (error) {
|
|
4719
|
+
console.error(chalk.red(`Error getting embedding: ${error.message}`));
|
|
4720
|
+
process.exit(1);
|
|
4721
|
+
}
|
|
4722
|
+
});
|
|
4723
|
+
|
|
4724
|
+
// Dictionary commands
|
|
4725
|
+
program
|
|
4726
|
+
.command('get-dictionary')
|
|
4727
|
+
.description('Get dictionary entry')
|
|
4728
|
+
.argument('<id>', 'Dictionary ID')
|
|
4729
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4730
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4731
|
+
.action(async (dictId, options, command) => {
|
|
4732
|
+
try {
|
|
4733
|
+
const globalOptions = command.parent.opts();
|
|
4734
|
+
const config = loadConfig(globalOptions.config);
|
|
4735
|
+
validateConfiguration(config);
|
|
4736
|
+
|
|
4737
|
+
const api = new ToothFairyAPI(
|
|
4738
|
+
config.baseUrl,
|
|
4739
|
+
config.aiUrl,
|
|
4740
|
+
config.aiStreamUrl,
|
|
4741
|
+
config.apiKey,
|
|
4742
|
+
config.workspaceId,
|
|
4743
|
+
globalOptions.verbose || options.verbose
|
|
4744
|
+
);
|
|
4745
|
+
|
|
4746
|
+
const spinner = ora('Fetching dictionary...').start();
|
|
4747
|
+
const result = await api._makeRequest('GET', `dictionary/get/${dictId}`);
|
|
4748
|
+
spinner.stop();
|
|
4749
|
+
|
|
4750
|
+
if (options.output === 'json') {
|
|
4751
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4752
|
+
} else {
|
|
4753
|
+
console.log(chalk.green.bold('Dictionary Entry'));
|
|
4754
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
4755
|
+
}
|
|
4756
|
+
} catch (error) {
|
|
4757
|
+
console.error(chalk.red(`Error getting dictionary: ${error.message}`));
|
|
4758
|
+
process.exit(1);
|
|
4759
|
+
}
|
|
4760
|
+
});
|
|
4761
|
+
|
|
4762
|
+
program
|
|
4763
|
+
.command('list-dictionaries')
|
|
4764
|
+
.description('List all dictionaries')
|
|
4765
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4766
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4767
|
+
.action(async (options, command) => {
|
|
4768
|
+
try {
|
|
4769
|
+
const globalOptions = command.parent.opts();
|
|
4770
|
+
const config = loadConfig(globalOptions.config);
|
|
4771
|
+
validateConfiguration(config);
|
|
4772
|
+
|
|
4773
|
+
const api = new ToothFairyAPI(
|
|
4774
|
+
config.baseUrl,
|
|
4775
|
+
config.aiUrl,
|
|
4776
|
+
config.aiStreamUrl,
|
|
4777
|
+
config.apiKey,
|
|
4778
|
+
config.workspaceId,
|
|
4779
|
+
globalOptions.verbose || options.verbose
|
|
4780
|
+
);
|
|
4781
|
+
|
|
4782
|
+
const spinner = ora('Fetching dictionaries...').start();
|
|
4783
|
+
const result = await api._makeRequest('GET', 'dictionary/list');
|
|
4784
|
+
spinner.stop();
|
|
4785
|
+
|
|
4786
|
+
if (options.output === 'json') {
|
|
4787
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4788
|
+
} else {
|
|
4789
|
+
const dicts = Array.isArray(result) ? result : result.items || [];
|
|
4790
|
+
console.log(chalk.green.bold(`Found ${dicts.length} dictionary/ies`));
|
|
4791
|
+
dicts.forEach(d => {
|
|
4792
|
+
console.log(chalk.cyan(` • ${d.id}`));
|
|
4793
|
+
});
|
|
4794
|
+
}
|
|
4795
|
+
} catch (error) {
|
|
4796
|
+
console.error(chalk.red(`Error listing dictionaries: ${error.message}`));
|
|
4797
|
+
process.exit(1);
|
|
4798
|
+
}
|
|
4799
|
+
});
|
|
4800
|
+
|
|
4801
|
+
// Connection commands
|
|
4802
|
+
program
|
|
4803
|
+
.command('list-connections')
|
|
4804
|
+
.description('List all connections')
|
|
4805
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4806
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4807
|
+
.action(async (options, command) => {
|
|
4808
|
+
try {
|
|
4809
|
+
const globalOptions = command.parent.opts();
|
|
4810
|
+
const config = loadConfig(globalOptions.config);
|
|
4811
|
+
validateConfiguration(config);
|
|
4812
|
+
|
|
4813
|
+
const api = new ToothFairyAPI(
|
|
4814
|
+
config.baseUrl,
|
|
4815
|
+
config.aiUrl,
|
|
4816
|
+
config.aiStreamUrl,
|
|
4817
|
+
config.apiKey,
|
|
4818
|
+
config.workspaceId,
|
|
4819
|
+
globalOptions.verbose || options.verbose
|
|
4820
|
+
);
|
|
4821
|
+
|
|
4822
|
+
const spinner = ora('Fetching connections...').start();
|
|
4823
|
+
const result = await api._makeRequest('GET', 'connection/list');
|
|
4824
|
+
spinner.stop();
|
|
4825
|
+
|
|
4826
|
+
if (options.output === 'json') {
|
|
4827
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4828
|
+
} else {
|
|
4829
|
+
const connections = Array.isArray(result) ? result : result.items || [];
|
|
4830
|
+
console.log(chalk.green.bold(`Found ${connections.length} connection(s)`));
|
|
4831
|
+
connections.forEach(c => {
|
|
4832
|
+
console.log(chalk.cyan(` • ${c.id}`));
|
|
4833
|
+
});
|
|
4834
|
+
}
|
|
4835
|
+
} catch (error) {
|
|
4836
|
+
console.error(chalk.red(`Error listing connections: ${error.message}`));
|
|
4837
|
+
process.exit(1);
|
|
4838
|
+
}
|
|
4839
|
+
});
|
|
4840
|
+
|
|
4841
|
+
program
|
|
4842
|
+
.command('get-connection')
|
|
4843
|
+
.description('Get details of a specific connection')
|
|
4844
|
+
.argument('<id>', 'Connection ID')
|
|
4845
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4846
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4847
|
+
.action(async (connectionId, options, command) => {
|
|
4848
|
+
try {
|
|
4849
|
+
const globalOptions = command.parent.opts();
|
|
4850
|
+
const config = loadConfig(globalOptions.config);
|
|
4851
|
+
validateConfiguration(config);
|
|
4852
|
+
|
|
4853
|
+
const api = new ToothFairyAPI(
|
|
4854
|
+
config.baseUrl,
|
|
4855
|
+
config.aiUrl,
|
|
4856
|
+
config.aiStreamUrl,
|
|
4857
|
+
config.apiKey,
|
|
4858
|
+
config.workspaceId,
|
|
4859
|
+
globalOptions.verbose || options.verbose
|
|
4860
|
+
);
|
|
4861
|
+
|
|
4862
|
+
const spinner = ora('Fetching connection...').start();
|
|
4863
|
+
const result = await api._makeRequest('GET', `connection/get/${connectionId}`);
|
|
4864
|
+
spinner.stop();
|
|
4865
|
+
|
|
4866
|
+
if (options.output === 'json') {
|
|
4867
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4868
|
+
} else {
|
|
4869
|
+
console.log(chalk.green.bold('Connection Details'));
|
|
4870
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
4871
|
+
}
|
|
4872
|
+
} catch (error) {
|
|
4873
|
+
console.error(chalk.red(`Error getting connection: ${error.message}`));
|
|
4874
|
+
process.exit(1);
|
|
4875
|
+
}
|
|
4876
|
+
});
|
|
4877
|
+
|
|
4878
|
+
program
|
|
4879
|
+
.command('delete-connection')
|
|
4880
|
+
.description('Delete a connection')
|
|
4881
|
+
.argument('<id>', 'Connection ID')
|
|
4882
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
4883
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4884
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4885
|
+
.action(async (connectionId, options, command) => {
|
|
4886
|
+
try {
|
|
4887
|
+
const globalOptions = command.parent.opts();
|
|
4888
|
+
const config = loadConfig(globalOptions.config);
|
|
4889
|
+
validateConfiguration(config);
|
|
4890
|
+
|
|
4891
|
+
if (!options.confirm) {
|
|
4892
|
+
const readline = require('readline');
|
|
4893
|
+
const rl = readline.createInterface({
|
|
4894
|
+
input: process.stdin,
|
|
4895
|
+
output: process.stdout,
|
|
4896
|
+
});
|
|
4897
|
+
|
|
4898
|
+
const answer = await new Promise((resolve) => {
|
|
4899
|
+
rl.question(
|
|
4900
|
+
chalk.yellow(`⚠️ Are you sure you want to delete connection ${connectionId}? (y/N): `),
|
|
4901
|
+
resolve
|
|
4902
|
+
);
|
|
4903
|
+
});
|
|
4904
|
+
rl.close();
|
|
4905
|
+
|
|
4906
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
4907
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
4908
|
+
process.exit(0);
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
|
|
4912
|
+
const api = new ToothFairyAPI(
|
|
4913
|
+
config.baseUrl,
|
|
4914
|
+
config.aiUrl,
|
|
4915
|
+
config.aiStreamUrl,
|
|
4916
|
+
config.apiKey,
|
|
4917
|
+
config.workspaceId,
|
|
4918
|
+
globalOptions.verbose || options.verbose
|
|
4919
|
+
);
|
|
4920
|
+
|
|
4921
|
+
const spinner = ora('Deleting connection...').start();
|
|
4922
|
+
const result = await api._makeRequest('DELETE', `connection/delete/${connectionId}`);
|
|
4923
|
+
spinner.stop();
|
|
4924
|
+
|
|
4925
|
+
if (options.output === 'json') {
|
|
4926
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4927
|
+
} else {
|
|
4928
|
+
console.log(chalk.green.bold('✅ Connection deleted successfully!'));
|
|
4929
|
+
}
|
|
4930
|
+
} catch (error) {
|
|
4931
|
+
console.error(chalk.red(`Error deleting connection: ${error.message}`));
|
|
4932
|
+
process.exit(1);
|
|
4933
|
+
}
|
|
4934
|
+
});
|
|
4935
|
+
|
|
4936
|
+
// Member commands
|
|
4937
|
+
program
|
|
4938
|
+
.command('list-members')
|
|
4939
|
+
.description('List all members')
|
|
4940
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4941
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4942
|
+
.action(async (options, command) => {
|
|
4943
|
+
try {
|
|
4944
|
+
const globalOptions = command.parent.opts();
|
|
4945
|
+
const config = loadConfig(globalOptions.config);
|
|
4946
|
+
validateConfiguration(config);
|
|
4947
|
+
|
|
4948
|
+
const api = new ToothFairyAPI(
|
|
4949
|
+
config.baseUrl,
|
|
4950
|
+
config.aiUrl,
|
|
4951
|
+
config.aiStreamUrl,
|
|
4952
|
+
config.apiKey,
|
|
4953
|
+
config.workspaceId,
|
|
4954
|
+
globalOptions.verbose || options.verbose
|
|
4955
|
+
);
|
|
4956
|
+
|
|
4957
|
+
const spinner = ora('Fetching members...').start();
|
|
4958
|
+
const result = await api._makeRequest('GET', 'member/list');
|
|
4959
|
+
spinner.stop();
|
|
4960
|
+
|
|
4961
|
+
if (options.output === 'json') {
|
|
4962
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4963
|
+
} else {
|
|
4964
|
+
const members = Array.isArray(result) ? result : result.items || [];
|
|
4965
|
+
console.log(chalk.green.bold(`Found ${members.length} member(s)`));
|
|
4966
|
+
members.forEach(m => {
|
|
4967
|
+
console.log(chalk.cyan(` • ${m.name || m.email || m.id}`));
|
|
4968
|
+
});
|
|
4969
|
+
}
|
|
4970
|
+
} catch (error) {
|
|
4971
|
+
console.error(chalk.red(`Error listing members: ${error.message}`));
|
|
4972
|
+
process.exit(1);
|
|
4973
|
+
}
|
|
4974
|
+
});
|
|
4975
|
+
|
|
4976
|
+
program
|
|
4977
|
+
.command('get-member')
|
|
4978
|
+
.description('Get details of a specific member')
|
|
4979
|
+
.argument('<id>', 'Member ID')
|
|
4980
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
4981
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
4982
|
+
.action(async (memberId, options, command) => {
|
|
4983
|
+
try {
|
|
4984
|
+
const globalOptions = command.parent.opts();
|
|
4985
|
+
const config = loadConfig(globalOptions.config);
|
|
4986
|
+
validateConfiguration(config);
|
|
4987
|
+
|
|
4988
|
+
const api = new ToothFairyAPI(
|
|
4989
|
+
config.baseUrl,
|
|
4990
|
+
config.aiUrl,
|
|
4991
|
+
config.aiStreamUrl,
|
|
4992
|
+
config.apiKey,
|
|
4993
|
+
config.workspaceId,
|
|
4994
|
+
globalOptions.verbose || options.verbose
|
|
4995
|
+
);
|
|
4996
|
+
|
|
4997
|
+
const spinner = ora('Fetching member...').start();
|
|
4998
|
+
const result = await api._makeRequest('GET', `member/get/${memberId}`);
|
|
4999
|
+
spinner.stop();
|
|
5000
|
+
|
|
5001
|
+
if (options.output === 'json') {
|
|
5002
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5003
|
+
} else {
|
|
5004
|
+
console.log(chalk.green.bold('Member Details'));
|
|
5005
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
5006
|
+
}
|
|
5007
|
+
} catch (error) {
|
|
5008
|
+
console.error(chalk.red(`Error getting member: ${error.message}`));
|
|
5009
|
+
process.exit(1);
|
|
5010
|
+
}
|
|
5011
|
+
});
|
|
5012
|
+
|
|
5013
|
+
program
|
|
5014
|
+
.command('update-member')
|
|
5015
|
+
.description('Update a member')
|
|
5016
|
+
.argument('<id>', 'Member ID')
|
|
5017
|
+
.option('--name <name>', 'Member name')
|
|
5018
|
+
.option('--email <email>', 'Member email')
|
|
5019
|
+
.option('--role <role>', 'Member role')
|
|
5020
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5021
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5022
|
+
.action(async (memberId, options, command) => {
|
|
5023
|
+
try {
|
|
5024
|
+
const globalOptions = command.parent.opts();
|
|
5025
|
+
const config = loadConfig(globalOptions.config);
|
|
5026
|
+
validateConfiguration(config);
|
|
5027
|
+
|
|
5028
|
+
const api = new ToothFairyAPI(
|
|
5029
|
+
config.baseUrl,
|
|
5030
|
+
config.aiUrl,
|
|
5031
|
+
config.aiStreamUrl,
|
|
5032
|
+
config.apiKey,
|
|
5033
|
+
config.workspaceId,
|
|
5034
|
+
globalOptions.verbose || options.verbose
|
|
5035
|
+
);
|
|
5036
|
+
|
|
5037
|
+
const spinner = ora('Updating member...').start();
|
|
5038
|
+
const result = await api._makeRequest('POST', 'member/update', {
|
|
5039
|
+
id: memberId,
|
|
5040
|
+
name: options.name,
|
|
5041
|
+
email: options.email,
|
|
5042
|
+
role: options.role,
|
|
5043
|
+
});
|
|
5044
|
+
spinner.stop();
|
|
5045
|
+
|
|
5046
|
+
if (options.output === 'json') {
|
|
5047
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5048
|
+
} else {
|
|
5049
|
+
console.log(chalk.green.bold('✅ Member updated successfully!'));
|
|
5050
|
+
}
|
|
5051
|
+
} catch (error) {
|
|
5052
|
+
console.error(chalk.red(`Error updating member: ${error.message}`));
|
|
5053
|
+
process.exit(1);
|
|
5054
|
+
}
|
|
5055
|
+
});
|
|
5056
|
+
|
|
5057
|
+
program
|
|
5058
|
+
.command('delete-member')
|
|
5059
|
+
.description('Delete a member')
|
|
5060
|
+
.argument('<id>', 'Member ID')
|
|
5061
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
5062
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5063
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5064
|
+
.action(async (memberId, options, command) => {
|
|
5065
|
+
try {
|
|
5066
|
+
const globalOptions = command.parent.opts();
|
|
5067
|
+
const config = loadConfig(globalOptions.config);
|
|
5068
|
+
validateConfiguration(config);
|
|
5069
|
+
|
|
5070
|
+
if (!options.confirm) {
|
|
5071
|
+
const readline = require('readline');
|
|
5072
|
+
const rl = readline.createInterface({
|
|
5073
|
+
input: process.stdin,
|
|
5074
|
+
output: process.stdout,
|
|
5075
|
+
});
|
|
5076
|
+
|
|
5077
|
+
const answer = await new Promise((resolve) => {
|
|
5078
|
+
rl.question(
|
|
5079
|
+
chalk.yellow(`⚠️ Are you sure you want to delete member ${memberId}? (y/N): `),
|
|
5080
|
+
resolve
|
|
5081
|
+
);
|
|
5082
|
+
});
|
|
5083
|
+
rl.close();
|
|
5084
|
+
|
|
5085
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
5086
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
5087
|
+
process.exit(0);
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5090
|
+
|
|
5091
|
+
const api = new ToothFairyAPI(
|
|
5092
|
+
config.baseUrl,
|
|
5093
|
+
config.aiUrl,
|
|
5094
|
+
config.aiStreamUrl,
|
|
5095
|
+
config.apiKey,
|
|
5096
|
+
config.workspaceId,
|
|
5097
|
+
globalOptions.verbose || options.verbose
|
|
5098
|
+
);
|
|
5099
|
+
|
|
5100
|
+
const spinner = ora('Deleting member...').start();
|
|
5101
|
+
const result = await api._makeRequest('DELETE', `member/delete/${memberId}`);
|
|
5102
|
+
spinner.stop();
|
|
5103
|
+
|
|
5104
|
+
if (options.output === 'json') {
|
|
5105
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5106
|
+
} else {
|
|
5107
|
+
console.log(chalk.green.bold('✅ Member deleted successfully!'));
|
|
5108
|
+
}
|
|
5109
|
+
} catch (error) {
|
|
5110
|
+
console.error(chalk.red(`Error deleting member: ${error.message}`));
|
|
5111
|
+
process.exit(1);
|
|
5112
|
+
}
|
|
5113
|
+
});
|
|
5114
|
+
|
|
5115
|
+
// Site commands
|
|
5116
|
+
program
|
|
5117
|
+
.command('list-sites')
|
|
5118
|
+
.description('List all sites')
|
|
5119
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5120
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5121
|
+
.action(async (options, command) => {
|
|
5122
|
+
try {
|
|
5123
|
+
const globalOptions = command.parent.opts();
|
|
5124
|
+
const config = loadConfig(globalOptions.config);
|
|
5125
|
+
validateConfiguration(config);
|
|
5126
|
+
|
|
5127
|
+
const api = new ToothFairyAPI(
|
|
5128
|
+
config.baseUrl,
|
|
5129
|
+
config.aiUrl,
|
|
5130
|
+
config.aiStreamUrl,
|
|
5131
|
+
config.apiKey,
|
|
5132
|
+
config.workspaceId,
|
|
5133
|
+
globalOptions.verbose || options.verbose
|
|
5134
|
+
);
|
|
5135
|
+
|
|
5136
|
+
const spinner = ora('Fetching sites...').start();
|
|
5137
|
+
const result = await api._makeRequest('GET', 'site/list');
|
|
5138
|
+
spinner.stop();
|
|
5139
|
+
|
|
5140
|
+
if (options.output === 'json') {
|
|
5141
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5142
|
+
} else {
|
|
5143
|
+
const sites = Array.isArray(result) ? result : result.items || [];
|
|
5144
|
+
console.log(chalk.green.bold(`Found ${sites.length} site(s)`));
|
|
5145
|
+
sites.forEach(s => {
|
|
5146
|
+
console.log(chalk.cyan(` • ${s.name || s.id}`));
|
|
5147
|
+
});
|
|
5148
|
+
}
|
|
5149
|
+
} catch (error) {
|
|
5150
|
+
console.error(chalk.red(`Error listing sites: ${error.message}`));
|
|
5151
|
+
process.exit(1);
|
|
5152
|
+
}
|
|
5153
|
+
});
|
|
5154
|
+
|
|
5155
|
+
program
|
|
5156
|
+
.command('get-site')
|
|
5157
|
+
.description('Get details of a specific site')
|
|
5158
|
+
.argument('<id>', 'Site ID')
|
|
5159
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5160
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5161
|
+
.action(async (siteId, options, command) => {
|
|
5162
|
+
try {
|
|
5163
|
+
const globalOptions = command.parent.opts();
|
|
5164
|
+
const config = loadConfig(globalOptions.config);
|
|
5165
|
+
validateConfiguration(config);
|
|
5166
|
+
|
|
5167
|
+
const api = new ToothFairyAPI(
|
|
5168
|
+
config.baseUrl,
|
|
5169
|
+
config.aiUrl,
|
|
5170
|
+
config.aiStreamUrl,
|
|
5171
|
+
config.apiKey,
|
|
5172
|
+
config.workspaceId,
|
|
5173
|
+
globalOptions.verbose || options.verbose
|
|
5174
|
+
);
|
|
5175
|
+
|
|
5176
|
+
const spinner = ora('Fetching site...').start();
|
|
5177
|
+
const result = await api._makeRequest('GET', `site/get/${siteId}`);
|
|
5178
|
+
spinner.stop();
|
|
5179
|
+
|
|
5180
|
+
if (options.output === 'json') {
|
|
5181
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5182
|
+
} else {
|
|
5183
|
+
console.log(chalk.green.bold('Site Details'));
|
|
5184
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
5185
|
+
}
|
|
5186
|
+
} catch (error) {
|
|
5187
|
+
console.error(chalk.red(`Error getting site: ${error.message}`));
|
|
5188
|
+
process.exit(1);
|
|
5189
|
+
}
|
|
5190
|
+
});
|
|
5191
|
+
|
|
5192
|
+
program
|
|
5193
|
+
.command('update-site')
|
|
5194
|
+
.description('Update a site')
|
|
5195
|
+
.argument('<id>', 'Site ID')
|
|
5196
|
+
.option('--name <name>', 'Site name')
|
|
5197
|
+
.option('--url <url>', 'Site URL')
|
|
5198
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5199
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5200
|
+
.action(async (siteId, options, command) => {
|
|
5201
|
+
try {
|
|
5202
|
+
const globalOptions = command.parent.opts();
|
|
5203
|
+
const config = loadConfig(globalOptions.config);
|
|
5204
|
+
validateConfiguration(config);
|
|
5205
|
+
|
|
5206
|
+
const api = new ToothFairyAPI(
|
|
5207
|
+
config.baseUrl,
|
|
5208
|
+
config.aiUrl,
|
|
5209
|
+
config.aiStreamUrl,
|
|
5210
|
+
config.apiKey,
|
|
5211
|
+
config.workspaceId,
|
|
5212
|
+
globalOptions.verbose || options.verbose
|
|
5213
|
+
);
|
|
5214
|
+
|
|
5215
|
+
const spinner = ora('Updating site...').start();
|
|
5216
|
+
const result = await api._makeRequest('POST', 'site/update', {
|
|
5217
|
+
id: siteId,
|
|
5218
|
+
name: options.name,
|
|
5219
|
+
url: options.url,
|
|
5220
|
+
});
|
|
5221
|
+
spinner.stop();
|
|
5222
|
+
|
|
5223
|
+
if (options.output === 'json') {
|
|
5224
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5225
|
+
} else {
|
|
5226
|
+
console.log(chalk.green.bold('✅ Site updated successfully!'));
|
|
5227
|
+
}
|
|
5228
|
+
} catch (error) {
|
|
5229
|
+
console.error(chalk.red(`Error updating site: ${error.message}`));
|
|
5230
|
+
process.exit(1);
|
|
5231
|
+
}
|
|
5232
|
+
});
|
|
5233
|
+
|
|
5234
|
+
program
|
|
5235
|
+
.command('delete-site')
|
|
5236
|
+
.description('Delete a site')
|
|
5237
|
+
.argument('<id>', 'Site ID')
|
|
5238
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
5239
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5240
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5241
|
+
.action(async (siteId, options, command) => {
|
|
5242
|
+
try {
|
|
5243
|
+
const globalOptions = command.parent.opts();
|
|
5244
|
+
const config = loadConfig(globalOptions.config);
|
|
5245
|
+
validateConfiguration(config);
|
|
5246
|
+
|
|
5247
|
+
if (!options.confirm) {
|
|
5248
|
+
const readline = require('readline');
|
|
5249
|
+
const rl = readline.createInterface({
|
|
5250
|
+
input: process.stdin,
|
|
5251
|
+
output: process.stdout,
|
|
5252
|
+
});
|
|
5253
|
+
|
|
5254
|
+
const answer = await new Promise((resolve) => {
|
|
5255
|
+
rl.question(
|
|
5256
|
+
chalk.yellow(`⚠️ Are you sure you want to delete site ${siteId}? (y/N): `),
|
|
5257
|
+
resolve
|
|
5258
|
+
);
|
|
5259
|
+
});
|
|
5260
|
+
rl.close();
|
|
5261
|
+
|
|
5262
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
5263
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
5264
|
+
process.exit(0);
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
|
|
5268
|
+
const api = new ToothFairyAPI(
|
|
5269
|
+
config.baseUrl,
|
|
5270
|
+
config.aiUrl,
|
|
5271
|
+
config.aiStreamUrl,
|
|
5272
|
+
config.apiKey,
|
|
5273
|
+
config.workspaceId,
|
|
5274
|
+
globalOptions.verbose || options.verbose
|
|
5275
|
+
);
|
|
5276
|
+
|
|
5277
|
+
const spinner = ora('Deleting site...').start();
|
|
5278
|
+
const result = await api._makeRequest('DELETE', `site/delete/${siteId}`);
|
|
5279
|
+
spinner.stop();
|
|
5280
|
+
|
|
5281
|
+
if (options.output === 'json') {
|
|
5282
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5283
|
+
} else {
|
|
5284
|
+
console.log(chalk.green.bold('✅ Site deleted successfully!'));
|
|
5285
|
+
}
|
|
5286
|
+
} catch (error) {
|
|
5287
|
+
console.error(chalk.red(`Error deleting site: ${error.message}`));
|
|
5288
|
+
process.exit(1);
|
|
5289
|
+
}
|
|
5290
|
+
});
|
|
5291
|
+
|
|
5292
|
+
// Stream commands
|
|
5293
|
+
program
|
|
5294
|
+
.command('list-streams')
|
|
5295
|
+
.description('List all streams')
|
|
5296
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5297
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5298
|
+
.action(async (options, command) => {
|
|
5299
|
+
try {
|
|
5300
|
+
const globalOptions = command.parent.opts();
|
|
5301
|
+
const config = loadConfig(globalOptions.config);
|
|
5302
|
+
validateConfiguration(config);
|
|
5303
|
+
|
|
5304
|
+
const api = new ToothFairyAPI(
|
|
5305
|
+
config.baseUrl,
|
|
5306
|
+
config.aiUrl,
|
|
5307
|
+
config.aiStreamUrl,
|
|
5308
|
+
config.apiKey,
|
|
5309
|
+
config.workspaceId,
|
|
5310
|
+
globalOptions.verbose || options.verbose
|
|
5311
|
+
);
|
|
5312
|
+
|
|
5313
|
+
const spinner = ora('Fetching streams...').start();
|
|
5314
|
+
const result = await api._makeRequest('GET', 'stream/list');
|
|
5315
|
+
spinner.stop();
|
|
5316
|
+
|
|
5317
|
+
if (options.output === 'json') {
|
|
5318
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5319
|
+
} else {
|
|
5320
|
+
const streams = Array.isArray(result) ? result : result.items || [];
|
|
5321
|
+
console.log(chalk.green.bold(`Found ${streams.length} stream(s)`));
|
|
5322
|
+
streams.forEach(s => {
|
|
5323
|
+
console.log(chalk.cyan(` • ${s.id}`));
|
|
5324
|
+
});
|
|
5325
|
+
}
|
|
5326
|
+
} catch (error) {
|
|
5327
|
+
console.error(chalk.red(`Error listing streams: ${error.message}`));
|
|
5328
|
+
process.exit(1);
|
|
5329
|
+
}
|
|
5330
|
+
});
|
|
5331
|
+
|
|
5332
|
+
program
|
|
5333
|
+
.command('get-stream')
|
|
5334
|
+
.description('Get details of a specific stream')
|
|
5335
|
+
.argument('<id>', 'Stream ID')
|
|
5336
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5337
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5338
|
+
.action(async (streamId, options, command) => {
|
|
5339
|
+
try {
|
|
5340
|
+
const globalOptions = command.parent.opts();
|
|
5341
|
+
const config = loadConfig(globalOptions.config);
|
|
5342
|
+
validateConfiguration(config);
|
|
5343
|
+
|
|
5344
|
+
const api = new ToothFairyAPI(
|
|
5345
|
+
config.baseUrl,
|
|
5346
|
+
config.aiUrl,
|
|
5347
|
+
config.aiStreamUrl,
|
|
5348
|
+
config.apiKey,
|
|
5349
|
+
config.workspaceId,
|
|
5350
|
+
globalOptions.verbose || options.verbose
|
|
5351
|
+
);
|
|
5352
|
+
|
|
5353
|
+
const spinner = ora('Fetching stream...').start();
|
|
5354
|
+
const result = await api._makeRequest('GET', `stream/get/${streamId}`);
|
|
5355
|
+
spinner.stop();
|
|
5356
|
+
|
|
5357
|
+
if (options.output === 'json') {
|
|
5358
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5359
|
+
} else {
|
|
5360
|
+
console.log(chalk.green.bold('Stream Details'));
|
|
5361
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
5362
|
+
}
|
|
5363
|
+
} catch (error) {
|
|
5364
|
+
console.error(chalk.red(`Error getting stream: ${error.message}`));
|
|
5365
|
+
process.exit(1);
|
|
5366
|
+
}
|
|
5367
|
+
});
|
|
5368
|
+
|
|
5369
|
+
// Request commands
|
|
5370
|
+
program
|
|
5371
|
+
.command('list-requests')
|
|
5372
|
+
.description('List all requests')
|
|
5373
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5374
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5375
|
+
.action(async (options, command) => {
|
|
5376
|
+
try {
|
|
5377
|
+
const globalOptions = command.parent.opts();
|
|
5378
|
+
const config = loadConfig(globalOptions.config);
|
|
5379
|
+
validateConfiguration(config);
|
|
5380
|
+
|
|
5381
|
+
const api = new ToothFairyAPI(
|
|
5382
|
+
config.baseUrl,
|
|
5383
|
+
config.aiUrl,
|
|
5384
|
+
config.aiStreamUrl,
|
|
5385
|
+
config.apiKey,
|
|
5386
|
+
config.workspaceId,
|
|
5387
|
+
globalOptions.verbose || options.verbose
|
|
5388
|
+
);
|
|
5389
|
+
|
|
5390
|
+
const spinner = ora('Fetching requests...').start();
|
|
5391
|
+
const result = await api._makeRequest('GET', 'request/list');
|
|
5392
|
+
spinner.stop();
|
|
5393
|
+
|
|
5394
|
+
if (options.output === 'json') {
|
|
5395
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5396
|
+
} else {
|
|
5397
|
+
const requests = Array.isArray(result) ? result : result.items || [];
|
|
5398
|
+
console.log(chalk.green.bold(`Found ${requests.length} request(s)`));
|
|
5399
|
+
requests.forEach(r => {
|
|
5400
|
+
console.log(chalk.cyan(` • ${r.id}`));
|
|
5401
|
+
});
|
|
5402
|
+
}
|
|
5403
|
+
} catch (error) {
|
|
5404
|
+
console.error(chalk.red(`Error listing requests: ${error.message}`));
|
|
5405
|
+
process.exit(1);
|
|
5406
|
+
}
|
|
5407
|
+
});
|
|
5408
|
+
|
|
5409
|
+
program
|
|
5410
|
+
.command('get-request')
|
|
5411
|
+
.description('Get details of a specific request')
|
|
5412
|
+
.argument('<id>', 'Request ID')
|
|
5413
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5414
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5415
|
+
.action(async (requestId, options, command) => {
|
|
5416
|
+
try {
|
|
5417
|
+
const globalOptions = command.parent.opts();
|
|
5418
|
+
const config = loadConfig(globalOptions.config);
|
|
5419
|
+
validateConfiguration(config);
|
|
5420
|
+
|
|
5421
|
+
const api = new ToothFairyAPI(
|
|
5422
|
+
config.baseUrl,
|
|
5423
|
+
config.aiUrl,
|
|
5424
|
+
config.aiStreamUrl,
|
|
5425
|
+
config.apiKey,
|
|
5426
|
+
config.workspaceId,
|
|
5427
|
+
globalOptions.verbose || options.verbose
|
|
5428
|
+
);
|
|
5429
|
+
|
|
5430
|
+
const spinner = ora('Fetching request...').start();
|
|
5431
|
+
const result = await api._makeRequest('GET', `request/get/${requestId}`);
|
|
5432
|
+
spinner.stop();
|
|
5433
|
+
|
|
5434
|
+
if (options.output === 'json') {
|
|
5435
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5436
|
+
} else {
|
|
5437
|
+
console.log(chalk.green.bold('Request Details'));
|
|
5438
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
5439
|
+
}
|
|
5440
|
+
} catch (error) {
|
|
5441
|
+
console.error(chalk.red(`Error getting request: ${error.message}`));
|
|
5442
|
+
process.exit(1);
|
|
5443
|
+
}
|
|
5444
|
+
});
|
|
5445
|
+
|
|
5446
|
+
// Secret commands
|
|
5447
|
+
program
|
|
5448
|
+
.command('create-secret')
|
|
5449
|
+
.description('Create a new secret')
|
|
5450
|
+
.option('--name <name>', 'Secret name')
|
|
5451
|
+
.option('--value <value>', 'Secret value')
|
|
5452
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5453
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5454
|
+
.action(async (options, command) => {
|
|
5455
|
+
try {
|
|
5456
|
+
const globalOptions = command.parent.opts();
|
|
5457
|
+
const config = loadConfig(globalOptions.config);
|
|
5458
|
+
validateConfiguration(config);
|
|
5459
|
+
|
|
5460
|
+
const api = new ToothFairyAPI(
|
|
5461
|
+
config.baseUrl,
|
|
5462
|
+
config.aiUrl,
|
|
5463
|
+
config.aiStreamUrl,
|
|
5464
|
+
config.apiKey,
|
|
5465
|
+
config.workspaceId,
|
|
5466
|
+
globalOptions.verbose || options.verbose
|
|
5467
|
+
);
|
|
5468
|
+
|
|
5469
|
+
const spinner = ora('Creating secret...').start();
|
|
5470
|
+
const result = await api._makeRequest('POST', 'secret/create', {
|
|
5471
|
+
name: options.name,
|
|
5472
|
+
value: options.value,
|
|
5473
|
+
});
|
|
5474
|
+
spinner.stop();
|
|
5475
|
+
|
|
5476
|
+
if (options.output === 'json') {
|
|
5477
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5478
|
+
} else {
|
|
5479
|
+
console.log(chalk.green.bold('✅ Secret created successfully!'));
|
|
5480
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
5481
|
+
}
|
|
5482
|
+
} catch (error) {
|
|
5483
|
+
console.error(chalk.red(`Error creating secret: ${error.message}`));
|
|
5484
|
+
process.exit(1);
|
|
5485
|
+
}
|
|
5486
|
+
});
|
|
5487
|
+
|
|
5488
|
+
program
|
|
5489
|
+
.command('delete-secret')
|
|
5490
|
+
.description('Delete a secret')
|
|
5491
|
+
.argument('<id>', 'Secret ID')
|
|
5492
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
5493
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5494
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5495
|
+
.action(async (secretId, options, command) => {
|
|
5496
|
+
try {
|
|
5497
|
+
const globalOptions = command.parent.opts();
|
|
5498
|
+
const config = loadConfig(globalOptions.config);
|
|
5499
|
+
validateConfiguration(config);
|
|
5500
|
+
|
|
5501
|
+
if (!options.confirm) {
|
|
5502
|
+
const readline = require('readline');
|
|
5503
|
+
const rl = readline.createInterface({
|
|
5504
|
+
input: process.stdin,
|
|
5505
|
+
output: process.stdout,
|
|
5506
|
+
});
|
|
5507
|
+
|
|
5508
|
+
const answer = await new Promise((resolve) => {
|
|
5509
|
+
rl.question(
|
|
5510
|
+
chalk.yellow(`⚠️ Are you sure you want to delete secret ${secretId}? (y/N): `),
|
|
5511
|
+
resolve
|
|
5512
|
+
);
|
|
5513
|
+
});
|
|
5514
|
+
rl.close();
|
|
5515
|
+
|
|
5516
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
5517
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
5518
|
+
process.exit(0);
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
|
|
5522
|
+
const api = new ToothFairyAPI(
|
|
5523
|
+
config.baseUrl,
|
|
5524
|
+
config.aiUrl,
|
|
5525
|
+
config.aiStreamUrl,
|
|
5526
|
+
config.apiKey,
|
|
5527
|
+
config.workspaceId,
|
|
5528
|
+
globalOptions.verbose || options.verbose
|
|
5529
|
+
);
|
|
5530
|
+
|
|
5531
|
+
const spinner = ora('Deleting secret...').start();
|
|
5532
|
+
const result = await api._makeRequest('DELETE', `secret/delete/${secretId}`);
|
|
5533
|
+
spinner.stop();
|
|
5534
|
+
|
|
5535
|
+
if (options.output === 'json') {
|
|
5536
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5537
|
+
} else {
|
|
5538
|
+
console.log(chalk.green.bold('✅ Secret deleted successfully!'));
|
|
5539
|
+
}
|
|
5540
|
+
} catch (error) {
|
|
5541
|
+
console.error(chalk.red(`Error deleting secret: ${error.message}`));
|
|
5542
|
+
process.exit(1);
|
|
5543
|
+
}
|
|
5544
|
+
});
|
|
5545
|
+
|
|
5546
|
+
// Hook commands
|
|
5547
|
+
program
|
|
5548
|
+
.command('create-hook')
|
|
5549
|
+
.description('Create a new hook')
|
|
5550
|
+
.option('--name <name>', 'Hook name')
|
|
5551
|
+
.option('--url <url>', 'Hook URL')
|
|
5552
|
+
.option('--events <events>', 'Events to trigger on (comma-separated)')
|
|
5553
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5554
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5555
|
+
.action(async (options, command) => {
|
|
5556
|
+
try {
|
|
5557
|
+
const globalOptions = command.parent.opts();
|
|
5558
|
+
const config = loadConfig(globalOptions.config);
|
|
5559
|
+
validateConfiguration(config);
|
|
5560
|
+
|
|
5561
|
+
const api = new ToothFairyAPI(
|
|
5562
|
+
config.baseUrl,
|
|
5563
|
+
config.aiUrl,
|
|
5564
|
+
config.aiStreamUrl,
|
|
5565
|
+
config.apiKey,
|
|
5566
|
+
config.workspaceId,
|
|
5567
|
+
globalOptions.verbose || options.verbose
|
|
5568
|
+
);
|
|
5569
|
+
|
|
5570
|
+
const events = options.events ? options.events.split(',').map(e => e.trim()) : [];
|
|
5571
|
+
|
|
5572
|
+
const spinner = ora('Creating hook...').start();
|
|
5573
|
+
const result = await api._makeRequest('POST', 'hook/create', {
|
|
5574
|
+
name: options.name,
|
|
5575
|
+
url: options.url,
|
|
5576
|
+
events,
|
|
5577
|
+
});
|
|
5578
|
+
spinner.stop();
|
|
5579
|
+
|
|
5580
|
+
if (options.output === 'json') {
|
|
5581
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5582
|
+
} else {
|
|
5583
|
+
console.log(chalk.green.bold('✅ Hook created successfully!'));
|
|
5584
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
5585
|
+
}
|
|
5586
|
+
} catch (error) {
|
|
5587
|
+
console.error(chalk.red(`Error creating hook: ${error.message}`));
|
|
5588
|
+
process.exit(1);
|
|
5589
|
+
}
|
|
5590
|
+
});
|
|
5591
|
+
|
|
5592
|
+
program
|
|
5593
|
+
.command('list-hooks')
|
|
5594
|
+
.description('List all hooks')
|
|
5595
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5596
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5597
|
+
.action(async (options, command) => {
|
|
5598
|
+
try {
|
|
5599
|
+
const globalOptions = command.parent.opts();
|
|
5600
|
+
const config = loadConfig(globalOptions.config);
|
|
5601
|
+
validateConfiguration(config);
|
|
5602
|
+
|
|
5603
|
+
const api = new ToothFairyAPI(
|
|
5604
|
+
config.baseUrl,
|
|
5605
|
+
config.aiUrl,
|
|
5606
|
+
config.aiStreamUrl,
|
|
5607
|
+
config.apiKey,
|
|
5608
|
+
config.workspaceId,
|
|
5609
|
+
globalOptions.verbose || options.verbose
|
|
5610
|
+
);
|
|
5611
|
+
|
|
5612
|
+
const spinner = ora('Fetching hooks...').start();
|
|
5613
|
+
const result = await api._makeRequest('GET', 'hook/list');
|
|
5614
|
+
spinner.stop();
|
|
5615
|
+
|
|
5616
|
+
if (options.output === 'json') {
|
|
5617
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5618
|
+
} else {
|
|
5619
|
+
const hooks = Array.isArray(result) ? result : result.items || [];
|
|
5620
|
+
console.log(chalk.green.bold(`Found ${hooks.length} hook(s)`));
|
|
5621
|
+
hooks.forEach(h => {
|
|
5622
|
+
console.log(chalk.cyan(` • ${h.name || 'Unnamed'} (${h.id})`));
|
|
5623
|
+
});
|
|
5624
|
+
}
|
|
5625
|
+
} catch (error) {
|
|
5626
|
+
console.error(chalk.red(`Error listing hooks: ${error.message}`));
|
|
5627
|
+
process.exit(1);
|
|
5628
|
+
}
|
|
5629
|
+
});
|
|
5630
|
+
|
|
5631
|
+
program
|
|
5632
|
+
.command('get-hook')
|
|
5633
|
+
.description('Get details of a specific hook')
|
|
5634
|
+
.argument('<id>', 'Hook ID')
|
|
5635
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5636
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5637
|
+
.action(async (hookId, options, command) => {
|
|
5638
|
+
try {
|
|
5639
|
+
const globalOptions = command.parent.opts();
|
|
5640
|
+
const config = loadConfig(globalOptions.config);
|
|
5641
|
+
validateConfiguration(config);
|
|
5642
|
+
|
|
5643
|
+
const api = new ToothFairyAPI(
|
|
5644
|
+
config.baseUrl,
|
|
5645
|
+
config.aiUrl,
|
|
5646
|
+
config.aiStreamUrl,
|
|
5647
|
+
config.apiKey,
|
|
5648
|
+
config.workspaceId,
|
|
5649
|
+
globalOptions.verbose || options.verbose
|
|
5650
|
+
);
|
|
5651
|
+
|
|
5652
|
+
const spinner = ora('Fetching hook...').start();
|
|
5653
|
+
const result = await api._makeRequest('GET', `hook/get/${hookId}`);
|
|
5654
|
+
spinner.stop();
|
|
5655
|
+
|
|
5656
|
+
if (options.output === 'json') {
|
|
5657
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5658
|
+
} else {
|
|
5659
|
+
console.log(chalk.green.bold('Hook Details'));
|
|
5660
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
5661
|
+
}
|
|
5662
|
+
} catch (error) {
|
|
5663
|
+
console.error(chalk.red(`Error getting hook: ${error.message}`));
|
|
5664
|
+
process.exit(1);
|
|
5665
|
+
}
|
|
5666
|
+
});
|
|
5667
|
+
|
|
5668
|
+
program
|
|
5669
|
+
.command('update-hook')
|
|
5670
|
+
.description('Update an existing hook')
|
|
5671
|
+
.argument('<id>', 'Hook ID')
|
|
5672
|
+
.option('--name <name>', 'Hook name')
|
|
5673
|
+
.option('--url <url>', 'Hook URL')
|
|
5674
|
+
.option('--events <events>', 'Events to trigger on (comma-separated)')
|
|
5675
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5676
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5677
|
+
.action(async (hookId, options, command) => {
|
|
5678
|
+
try {
|
|
5679
|
+
const globalOptions = command.parent.opts();
|
|
5680
|
+
const config = loadConfig(globalOptions.config);
|
|
5681
|
+
validateConfiguration(config);
|
|
5682
|
+
|
|
5683
|
+
const api = new ToothFairyAPI(
|
|
5684
|
+
config.baseUrl,
|
|
5685
|
+
config.aiUrl,
|
|
5686
|
+
config.aiStreamUrl,
|
|
5687
|
+
config.apiKey,
|
|
5688
|
+
config.workspaceId,
|
|
5689
|
+
globalOptions.verbose || options.verbose
|
|
5690
|
+
);
|
|
5691
|
+
|
|
5692
|
+
const events = options.events ? options.events.split(',').map(e => e.trim()) : [];
|
|
5693
|
+
|
|
5694
|
+
const spinner = ora('Updating hook...').start();
|
|
5695
|
+
const result = await api._makeRequest('POST', `hook/update/${hookId}`, {
|
|
5696
|
+
name: options.name,
|
|
5697
|
+
url: options.url,
|
|
5698
|
+
events,
|
|
5699
|
+
});
|
|
5700
|
+
spinner.stop();
|
|
5701
|
+
|
|
5702
|
+
if (options.output === 'json') {
|
|
5703
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5704
|
+
} else {
|
|
5705
|
+
console.log(chalk.green.bold('✅ Hook updated successfully!'));
|
|
5706
|
+
}
|
|
5707
|
+
} catch (error) {
|
|
5708
|
+
console.error(chalk.red(`Error updating hook: ${error.message}`));
|
|
5709
|
+
process.exit(1);
|
|
5710
|
+
}
|
|
5711
|
+
});
|
|
5712
|
+
|
|
5713
|
+
program
|
|
5714
|
+
.command('delete-hook')
|
|
5715
|
+
.description('Delete a hook')
|
|
5716
|
+
.argument('<id>', 'Hook ID')
|
|
5717
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
5718
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5719
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5720
|
+
.action(async (hookId, options, command) => {
|
|
5721
|
+
try {
|
|
5722
|
+
const globalOptions = command.parent.opts();
|
|
5723
|
+
const config = loadConfig(globalOptions.config);
|
|
5724
|
+
validateConfiguration(config);
|
|
5725
|
+
|
|
5726
|
+
if (!options.confirm) {
|
|
5727
|
+
const readline = require('readline');
|
|
5728
|
+
const rl = readline.createInterface({
|
|
5729
|
+
input: process.stdin,
|
|
5730
|
+
output: process.stdout,
|
|
5731
|
+
});
|
|
5732
|
+
|
|
5733
|
+
const answer = await new Promise((resolve) => {
|
|
5734
|
+
rl.question(
|
|
5735
|
+
chalk.yellow(`⚠️ Are you sure you want to delete hook ${hookId}? (y/N): `),
|
|
5736
|
+
resolve
|
|
5737
|
+
);
|
|
5738
|
+
});
|
|
5739
|
+
rl.close();
|
|
5740
|
+
|
|
5741
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
5742
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
5743
|
+
process.exit(0);
|
|
5744
|
+
}
|
|
5745
|
+
}
|
|
5746
|
+
|
|
5747
|
+
const api = new ToothFairyAPI(
|
|
5748
|
+
config.baseUrl,
|
|
5749
|
+
config.aiUrl,
|
|
5750
|
+
config.aiStreamUrl,
|
|
5751
|
+
config.apiKey,
|
|
5752
|
+
config.workspaceId,
|
|
5753
|
+
globalOptions.verbose || options.verbose
|
|
5754
|
+
);
|
|
5755
|
+
|
|
5756
|
+
const spinner = ora('Deleting hook...').start();
|
|
5757
|
+
const result = await api._makeRequest('DELETE', `hook/delete/${hookId}`);
|
|
5758
|
+
spinner.stop();
|
|
5759
|
+
|
|
5760
|
+
if (options.output === 'json') {
|
|
5761
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5762
|
+
} else {
|
|
5763
|
+
console.log(chalk.green.bold('✅ Hook deleted successfully!'));
|
|
5764
|
+
}
|
|
5765
|
+
} catch (error) {
|
|
5766
|
+
console.error(chalk.red(`Error deleting hook: ${error.message}`));
|
|
5767
|
+
process.exit(1);
|
|
5768
|
+
}
|
|
5769
|
+
});
|
|
5770
|
+
|
|
5771
|
+
// Benchmark commands
|
|
5772
|
+
program
|
|
5773
|
+
.command('create-benchmark')
|
|
5774
|
+
.description('Create a new benchmark')
|
|
5775
|
+
.option('--name <name>', 'Benchmark name')
|
|
5776
|
+
.option('--description <description>', 'Benchmark description')
|
|
5777
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5778
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5779
|
+
.action(async (options, command) => {
|
|
5780
|
+
try {
|
|
5781
|
+
const globalOptions = command.parent.opts();
|
|
5782
|
+
const config = loadConfig(globalOptions.config);
|
|
5783
|
+
validateConfiguration(config);
|
|
5784
|
+
|
|
5785
|
+
const api = new ToothFairyAPI(
|
|
5786
|
+
config.baseUrl,
|
|
5787
|
+
config.aiUrl,
|
|
5788
|
+
config.aiStreamUrl,
|
|
5789
|
+
config.apiKey,
|
|
5790
|
+
config.workspaceId,
|
|
5791
|
+
globalOptions.verbose || options.verbose
|
|
5792
|
+
);
|
|
5793
|
+
|
|
5794
|
+
const spinner = ora('Creating benchmark...').start();
|
|
5795
|
+
const result = await api._makeRequest('POST', 'benchmark/create', {
|
|
5796
|
+
name: options.name,
|
|
5797
|
+
description: options.description,
|
|
5798
|
+
});
|
|
5799
|
+
spinner.stop();
|
|
5800
|
+
|
|
5801
|
+
if (options.output === 'json') {
|
|
5802
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5803
|
+
} else {
|
|
5804
|
+
console.log(chalk.green.bold('✅ Benchmark created successfully!'));
|
|
5805
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
5806
|
+
}
|
|
5807
|
+
} catch (error) {
|
|
5808
|
+
console.error(chalk.red(`Error creating benchmark: ${error.message}`));
|
|
5809
|
+
process.exit(1);
|
|
5810
|
+
}
|
|
5811
|
+
});
|
|
5812
|
+
|
|
5813
|
+
program
|
|
5814
|
+
.command('list-benchmarks')
|
|
5815
|
+
.description('List all benchmarks')
|
|
5816
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5817
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5818
|
+
.action(async (options, command) => {
|
|
5819
|
+
try {
|
|
5820
|
+
const globalOptions = command.parent.opts();
|
|
5821
|
+
const config = loadConfig(globalOptions.config);
|
|
5822
|
+
validateConfiguration(config);
|
|
5823
|
+
|
|
5824
|
+
const api = new ToothFairyAPI(
|
|
5825
|
+
config.baseUrl,
|
|
5826
|
+
config.aiUrl,
|
|
5827
|
+
config.aiStreamUrl,
|
|
5828
|
+
config.apiKey,
|
|
5829
|
+
config.workspaceId,
|
|
5830
|
+
globalOptions.verbose || options.verbose
|
|
5831
|
+
);
|
|
5832
|
+
|
|
5833
|
+
const spinner = ora('Fetching benchmarks...').start();
|
|
5834
|
+
const result = await api._makeRequest('GET', 'benchmark/list');
|
|
5835
|
+
spinner.stop();
|
|
5836
|
+
|
|
5837
|
+
if (options.output === 'json') {
|
|
5838
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5839
|
+
} else {
|
|
5840
|
+
const benchmarks = Array.isArray(result) ? result : result.items || [];
|
|
5841
|
+
console.log(chalk.green.bold(`Found ${benchmarks.length} benchmark(s)`));
|
|
5842
|
+
benchmarks.forEach(b => {
|
|
5843
|
+
console.log(chalk.cyan(` • ${b.name || 'Unnamed'} (${b.id})`));
|
|
5844
|
+
});
|
|
5845
|
+
}
|
|
5846
|
+
} catch (error) {
|
|
5847
|
+
console.error(chalk.red(`Error listing benchmarks: ${error.message}`));
|
|
5848
|
+
process.exit(1);
|
|
5849
|
+
}
|
|
5850
|
+
});
|
|
5851
|
+
|
|
5852
|
+
program
|
|
5853
|
+
.command('get-benchmark')
|
|
5854
|
+
.description('Get details of a specific benchmark')
|
|
5855
|
+
.argument('<id>', 'Benchmark ID')
|
|
5856
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5857
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5858
|
+
.action(async (benchmarkId, options, command) => {
|
|
5859
|
+
try {
|
|
5860
|
+
const globalOptions = command.parent.opts();
|
|
5861
|
+
const config = loadConfig(globalOptions.config);
|
|
5862
|
+
validateConfiguration(config);
|
|
5863
|
+
|
|
5864
|
+
const api = new ToothFairyAPI(
|
|
5865
|
+
config.baseUrl,
|
|
5866
|
+
config.aiUrl,
|
|
5867
|
+
config.aiStreamUrl,
|
|
5868
|
+
config.apiKey,
|
|
5869
|
+
config.workspaceId,
|
|
5870
|
+
globalOptions.verbose || options.verbose
|
|
5871
|
+
);
|
|
5872
|
+
|
|
5873
|
+
const spinner = ora('Fetching benchmark...').start();
|
|
5874
|
+
const result = await api._makeRequest('GET', `benchmark/get/${benchmarkId}`);
|
|
5875
|
+
spinner.stop();
|
|
5876
|
+
|
|
5877
|
+
if (options.output === 'json') {
|
|
5878
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5879
|
+
} else {
|
|
5880
|
+
console.log(chalk.green.bold('Benchmark Details'));
|
|
5881
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
5882
|
+
}
|
|
5883
|
+
} catch (error) {
|
|
5884
|
+
console.error(chalk.red(`Error getting benchmark: ${error.message}`));
|
|
5885
|
+
process.exit(1);
|
|
5886
|
+
}
|
|
5887
|
+
});
|
|
5888
|
+
|
|
5889
|
+
program
|
|
5890
|
+
.command('update-benchmark')
|
|
5891
|
+
.description('Update an existing benchmark')
|
|
5892
|
+
.argument('<id>', 'Benchmark ID')
|
|
5893
|
+
.option('--name <name>', 'Benchmark name')
|
|
5894
|
+
.option('--description <description>', 'Benchmark description')
|
|
5895
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5896
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5897
|
+
.action(async (benchmarkId, options, command) => {
|
|
5898
|
+
try {
|
|
5899
|
+
const globalOptions = command.parent.opts();
|
|
5900
|
+
const config = loadConfig(globalOptions.config);
|
|
5901
|
+
validateConfiguration(config);
|
|
5902
|
+
|
|
5903
|
+
const api = new ToothFairyAPI(
|
|
5904
|
+
config.baseUrl,
|
|
5905
|
+
config.aiUrl,
|
|
5906
|
+
config.aiStreamUrl,
|
|
5907
|
+
config.apiKey,
|
|
5908
|
+
config.workspaceId,
|
|
5909
|
+
globalOptions.verbose || options.verbose
|
|
5910
|
+
);
|
|
5911
|
+
|
|
5912
|
+
const spinner = ora('Updating benchmark...').start();
|
|
5913
|
+
const result = await api._makeRequest('POST', `benchmark/update/${benchmarkId}`, {
|
|
5914
|
+
name: options.name,
|
|
5915
|
+
description: options.description,
|
|
5916
|
+
});
|
|
5917
|
+
spinner.stop();
|
|
5918
|
+
|
|
5919
|
+
if (options.output === 'json') {
|
|
5920
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5921
|
+
} else {
|
|
5922
|
+
console.log(chalk.green.bold('✅ Benchmark updated successfully!'));
|
|
5923
|
+
}
|
|
5924
|
+
} catch (error) {
|
|
5925
|
+
console.error(chalk.red(`Error updating benchmark: ${error.message}`));
|
|
5926
|
+
process.exit(1);
|
|
5927
|
+
}
|
|
5928
|
+
});
|
|
5929
|
+
|
|
5930
|
+
program
|
|
5931
|
+
.command('delete-benchmark')
|
|
5932
|
+
.description('Delete a benchmark')
|
|
5933
|
+
.argument('<id>', 'Benchmark ID')
|
|
5934
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
5935
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5936
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5937
|
+
.action(async (benchmarkId, options, command) => {
|
|
5938
|
+
try {
|
|
5939
|
+
const globalOptions = command.parent.opts();
|
|
5940
|
+
const config = loadConfig(globalOptions.config);
|
|
5941
|
+
validateConfiguration(config);
|
|
5942
|
+
|
|
5943
|
+
if (!options.confirm) {
|
|
5944
|
+
const readline = require('readline');
|
|
5945
|
+
const rl = readline.createInterface({
|
|
5946
|
+
input: process.stdin,
|
|
5947
|
+
output: process.stdout,
|
|
5948
|
+
});
|
|
5949
|
+
|
|
5950
|
+
const answer = await new Promise((resolve) => {
|
|
5951
|
+
rl.question(
|
|
5952
|
+
chalk.yellow(`⚠️ Are you sure you want to delete benchmark ${benchmarkId}? (y/N): `),
|
|
5953
|
+
resolve
|
|
5954
|
+
);
|
|
5955
|
+
});
|
|
5956
|
+
rl.close();
|
|
5957
|
+
|
|
5958
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
5959
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
5960
|
+
process.exit(0);
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
|
|
5964
|
+
const api = new ToothFairyAPI(
|
|
5965
|
+
config.baseUrl,
|
|
5966
|
+
config.aiUrl,
|
|
5967
|
+
config.aiStreamUrl,
|
|
5968
|
+
config.apiKey,
|
|
5969
|
+
config.workspaceId,
|
|
5970
|
+
globalOptions.verbose || options.verbose
|
|
5971
|
+
);
|
|
5972
|
+
|
|
5973
|
+
const spinner = ora('Deleting benchmark...').start();
|
|
5974
|
+
const result = await api._makeRequest('DELETE', `benchmark/delete/${benchmarkId}`);
|
|
5975
|
+
spinner.stop();
|
|
5976
|
+
|
|
5977
|
+
if (options.output === 'json') {
|
|
5978
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5979
|
+
} else {
|
|
5980
|
+
console.log(chalk.green.bold('✅ Benchmark deleted successfully!'));
|
|
5981
|
+
}
|
|
5982
|
+
} catch (error) {
|
|
5983
|
+
console.error(chalk.red(`Error deleting benchmark: ${error.message}`));
|
|
5984
|
+
process.exit(1);
|
|
5985
|
+
}
|
|
5986
|
+
});
|
|
5987
|
+
|
|
5988
|
+
// Scheduled Job commands
|
|
5989
|
+
program
|
|
5990
|
+
.command('create-scheduled-job')
|
|
5991
|
+
.description('Create a new scheduled job')
|
|
5992
|
+
.option('--name <name>', 'Job name')
|
|
5993
|
+
.option('--schedule <schedule>', 'Cron schedule expression')
|
|
5994
|
+
.option('--task <task>', 'Task to execute')
|
|
5995
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
5996
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
5997
|
+
.action(async (options, command) => {
|
|
5998
|
+
try {
|
|
5999
|
+
const globalOptions = command.parent.opts();
|
|
6000
|
+
const config = loadConfig(globalOptions.config);
|
|
6001
|
+
validateConfiguration(config);
|
|
6002
|
+
|
|
6003
|
+
const api = new ToothFairyAPI(
|
|
6004
|
+
config.baseUrl,
|
|
6005
|
+
config.aiUrl,
|
|
6006
|
+
config.aiStreamUrl,
|
|
6007
|
+
config.apiKey,
|
|
6008
|
+
config.workspaceId,
|
|
6009
|
+
globalOptions.verbose || options.verbose
|
|
6010
|
+
);
|
|
6011
|
+
|
|
6012
|
+
const spinner = ora('Creating scheduled job...').start();
|
|
6013
|
+
const result = await api._makeRequest('POST', 'scheduled_job/create', {
|
|
6014
|
+
name: options.name,
|
|
6015
|
+
schedule: options.schedule,
|
|
6016
|
+
task: options.task,
|
|
6017
|
+
});
|
|
6018
|
+
spinner.stop();
|
|
6019
|
+
|
|
6020
|
+
if (options.output === 'json') {
|
|
6021
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6022
|
+
} else {
|
|
6023
|
+
console.log(chalk.green.bold('✅ Scheduled job created successfully!'));
|
|
6024
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
6025
|
+
}
|
|
6026
|
+
} catch (error) {
|
|
6027
|
+
console.error(chalk.red(`Error creating scheduled job: ${error.message}`));
|
|
6028
|
+
process.exit(1);
|
|
6029
|
+
}
|
|
6030
|
+
});
|
|
6031
|
+
|
|
6032
|
+
program
|
|
6033
|
+
.command('list-scheduled-jobs')
|
|
6034
|
+
.description('List all scheduled jobs')
|
|
6035
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6036
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6037
|
+
.action(async (options, command) => {
|
|
6038
|
+
try {
|
|
6039
|
+
const globalOptions = command.parent.opts();
|
|
6040
|
+
const config = loadConfig(globalOptions.config);
|
|
6041
|
+
validateConfiguration(config);
|
|
6042
|
+
|
|
6043
|
+
const api = new ToothFairyAPI(
|
|
6044
|
+
config.baseUrl,
|
|
6045
|
+
config.aiUrl,
|
|
6046
|
+
config.aiStreamUrl,
|
|
6047
|
+
config.apiKey,
|
|
6048
|
+
config.workspaceId,
|
|
6049
|
+
globalOptions.verbose || options.verbose
|
|
6050
|
+
);
|
|
6051
|
+
|
|
6052
|
+
const spinner = ora('Fetching scheduled jobs...').start();
|
|
6053
|
+
const result = await api._makeRequest('GET', 'scheduled_job/list');
|
|
6054
|
+
spinner.stop();
|
|
6055
|
+
|
|
6056
|
+
if (options.output === 'json') {
|
|
6057
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6058
|
+
} else {
|
|
6059
|
+
const jobs = Array.isArray(result) ? result : result.items || [];
|
|
6060
|
+
console.log(chalk.green.bold(`Found ${jobs.length} scheduled job(s)`));
|
|
6061
|
+
jobs.forEach(j => {
|
|
6062
|
+
console.log(chalk.cyan(` • ${j.name || 'Unnamed'} (${j.id})`));
|
|
6063
|
+
});
|
|
6064
|
+
}
|
|
6065
|
+
} catch (error) {
|
|
6066
|
+
console.error(chalk.red(`Error listing scheduled jobs: ${error.message}`));
|
|
6067
|
+
process.exit(1);
|
|
6068
|
+
}
|
|
6069
|
+
});
|
|
6070
|
+
|
|
6071
|
+
program
|
|
6072
|
+
.command('get-scheduled-job')
|
|
6073
|
+
.description('Get details of a specific scheduled job')
|
|
6074
|
+
.argument('<id>', 'Scheduled Job ID')
|
|
6075
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6076
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6077
|
+
.action(async (jobId, options, command) => {
|
|
6078
|
+
try {
|
|
6079
|
+
const globalOptions = command.parent.opts();
|
|
6080
|
+
const config = loadConfig(globalOptions.config);
|
|
6081
|
+
validateConfiguration(config);
|
|
6082
|
+
|
|
6083
|
+
const api = new ToothFairyAPI(
|
|
6084
|
+
config.baseUrl,
|
|
6085
|
+
config.aiUrl,
|
|
6086
|
+
config.aiStreamUrl,
|
|
6087
|
+
config.apiKey,
|
|
6088
|
+
config.workspaceId,
|
|
6089
|
+
globalOptions.verbose || options.verbose
|
|
6090
|
+
);
|
|
6091
|
+
|
|
6092
|
+
const spinner = ora('Fetching scheduled job...').start();
|
|
6093
|
+
const result = await api._makeRequest('GET', `scheduled_job/get/${jobId}`);
|
|
6094
|
+
spinner.stop();
|
|
6095
|
+
|
|
6096
|
+
if (options.output === 'json') {
|
|
6097
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6098
|
+
} else {
|
|
6099
|
+
console.log(chalk.green.bold('Scheduled Job Details'));
|
|
6100
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
6101
|
+
}
|
|
6102
|
+
} catch (error) {
|
|
6103
|
+
console.error(chalk.red(`Error getting scheduled job: ${error.message}`));
|
|
6104
|
+
process.exit(1);
|
|
6105
|
+
}
|
|
6106
|
+
});
|
|
6107
|
+
|
|
6108
|
+
program
|
|
6109
|
+
.command('update-scheduled-job')
|
|
6110
|
+
.description('Update an existing scheduled job')
|
|
6111
|
+
.argument('<id>', 'Scheduled Job ID')
|
|
6112
|
+
.option('--name <name>', 'Job name')
|
|
6113
|
+
.option('--schedule <schedule>', 'Cron schedule expression')
|
|
6114
|
+
.option('--task <task>', 'Task to execute')
|
|
6115
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6116
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6117
|
+
.action(async (jobId, options, command) => {
|
|
6118
|
+
try {
|
|
6119
|
+
const globalOptions = command.parent.opts();
|
|
6120
|
+
const config = loadConfig(globalOptions.config);
|
|
6121
|
+
validateConfiguration(config);
|
|
6122
|
+
|
|
6123
|
+
const api = new ToothFairyAPI(
|
|
6124
|
+
config.baseUrl,
|
|
6125
|
+
config.aiUrl,
|
|
6126
|
+
config.aiStreamUrl,
|
|
6127
|
+
config.apiKey,
|
|
6128
|
+
config.workspaceId,
|
|
6129
|
+
globalOptions.verbose || options.verbose
|
|
6130
|
+
);
|
|
6131
|
+
|
|
6132
|
+
const spinner = ora('Updating scheduled job...').start();
|
|
6133
|
+
const result = await api._makeRequest('POST', `scheduled_job/update/${jobId}`, {
|
|
6134
|
+
name: options.name,
|
|
6135
|
+
schedule: options.schedule,
|
|
6136
|
+
task: options.task,
|
|
6137
|
+
});
|
|
6138
|
+
spinner.stop();
|
|
6139
|
+
|
|
6140
|
+
if (options.output === 'json') {
|
|
6141
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6142
|
+
} else {
|
|
6143
|
+
console.log(chalk.green.bold('✅ Scheduled job updated successfully!'));
|
|
6144
|
+
}
|
|
6145
|
+
} catch (error) {
|
|
6146
|
+
console.error(chalk.red(`Error updating scheduled job: ${error.message}`));
|
|
6147
|
+
process.exit(1);
|
|
6148
|
+
}
|
|
6149
|
+
});
|
|
6150
|
+
|
|
6151
|
+
program
|
|
6152
|
+
.command('delete-scheduled-job')
|
|
6153
|
+
.description('Delete a scheduled job')
|
|
6154
|
+
.argument('<id>', 'Scheduled Job ID')
|
|
6155
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
6156
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6157
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6158
|
+
.action(async (jobId, options, command) => {
|
|
6159
|
+
try {
|
|
6160
|
+
const globalOptions = command.parent.opts();
|
|
6161
|
+
const config = loadConfig(globalOptions.config);
|
|
6162
|
+
validateConfiguration(config);
|
|
6163
|
+
|
|
6164
|
+
if (!options.confirm) {
|
|
6165
|
+
const readline = require('readline');
|
|
6166
|
+
const rl = readline.createInterface({
|
|
6167
|
+
input: process.stdin,
|
|
6168
|
+
output: process.stdout,
|
|
6169
|
+
});
|
|
6170
|
+
|
|
6171
|
+
const answer = await new Promise((resolve) => {
|
|
6172
|
+
rl.question(
|
|
6173
|
+
chalk.yellow(`⚠️ Are you sure you want to delete scheduled job ${jobId}? (y/N): `),
|
|
6174
|
+
resolve
|
|
6175
|
+
);
|
|
6176
|
+
});
|
|
6177
|
+
rl.close();
|
|
6178
|
+
|
|
6179
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
6180
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
6181
|
+
process.exit(0);
|
|
6182
|
+
}
|
|
6183
|
+
}
|
|
6184
|
+
|
|
6185
|
+
const api = new ToothFairyAPI(
|
|
6186
|
+
config.baseUrl,
|
|
6187
|
+
config.aiUrl,
|
|
6188
|
+
config.aiStreamUrl,
|
|
6189
|
+
config.apiKey,
|
|
6190
|
+
config.workspaceId,
|
|
6191
|
+
globalOptions.verbose || options.verbose
|
|
6192
|
+
);
|
|
6193
|
+
|
|
6194
|
+
const spinner = ora('Deleting scheduled job...').start();
|
|
6195
|
+
const result = await api._makeRequest('DELETE', `scheduled_job/delete/${jobId}`);
|
|
6196
|
+
spinner.stop();
|
|
6197
|
+
|
|
6198
|
+
if (options.output === 'json') {
|
|
6199
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6200
|
+
} else {
|
|
6201
|
+
console.log(chalk.green.bold('✅ Scheduled job deleted successfully!'));
|
|
6202
|
+
}
|
|
6203
|
+
} catch (error) {
|
|
6204
|
+
console.error(chalk.red(`Error deleting scheduled job: ${error.message}`));
|
|
6205
|
+
process.exit(1);
|
|
6206
|
+
}
|
|
6207
|
+
});
|
|
6208
|
+
|
|
6209
|
+
// Authorisation commands
|
|
6210
|
+
program
|
|
6211
|
+
.command('create-authorisation')
|
|
6212
|
+
.description('Create a new authorisation')
|
|
6213
|
+
.option('--name <name>', 'Authorisation name')
|
|
6214
|
+
.option('--permissions <permissions>', 'Permissions (JSON)')
|
|
6215
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6216
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6217
|
+
.action(async (options, command) => {
|
|
6218
|
+
try {
|
|
6219
|
+
const globalOptions = command.parent.opts();
|
|
6220
|
+
const config = loadConfig(globalOptions.config);
|
|
6221
|
+
validateConfiguration(config);
|
|
6222
|
+
|
|
6223
|
+
const api = new ToothFairyAPI(
|
|
6224
|
+
config.baseUrl,
|
|
6225
|
+
config.aiUrl,
|
|
6226
|
+
config.aiStreamUrl,
|
|
6227
|
+
config.apiKey,
|
|
6228
|
+
config.workspaceId,
|
|
6229
|
+
globalOptions.verbose || options.verbose
|
|
6230
|
+
);
|
|
6231
|
+
|
|
6232
|
+
let permissions = {};
|
|
6233
|
+
if (options.permissions) {
|
|
6234
|
+
try {
|
|
6235
|
+
permissions = JSON.parse(options.permissions);
|
|
6236
|
+
} catch (e) {
|
|
6237
|
+
console.error(chalk.red('Invalid JSON in permissions'));
|
|
6238
|
+
process.exit(1);
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
|
|
6242
|
+
const spinner = ora('Creating authorisation...').start();
|
|
6243
|
+
const result = await api._makeRequest('POST', 'authorisation/create', {
|
|
6244
|
+
name: options.name,
|
|
6245
|
+
permissions,
|
|
6246
|
+
});
|
|
6247
|
+
spinner.stop();
|
|
6248
|
+
|
|
6249
|
+
if (options.output === 'json') {
|
|
6250
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6251
|
+
} else {
|
|
6252
|
+
console.log(chalk.green.bold('✅ Authorisation created successfully!'));
|
|
6253
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
6254
|
+
}
|
|
6255
|
+
} catch (error) {
|
|
6256
|
+
console.error(chalk.red(`Error creating authorisation: ${error.message}`));
|
|
6257
|
+
process.exit(1);
|
|
6258
|
+
}
|
|
6259
|
+
});
|
|
6260
|
+
|
|
6261
|
+
program
|
|
6262
|
+
.command('list-authorisations')
|
|
6263
|
+
.description('List all authorisations')
|
|
6264
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6265
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6266
|
+
.action(async (options, command) => {
|
|
6267
|
+
try {
|
|
6268
|
+
const globalOptions = command.parent.opts();
|
|
6269
|
+
const config = loadConfig(globalOptions.config);
|
|
6270
|
+
validateConfiguration(config);
|
|
6271
|
+
|
|
6272
|
+
const api = new ToothFairyAPI(
|
|
6273
|
+
config.baseUrl,
|
|
6274
|
+
config.aiUrl,
|
|
6275
|
+
config.aiStreamUrl,
|
|
6276
|
+
config.apiKey,
|
|
6277
|
+
config.workspaceId,
|
|
6278
|
+
globalOptions.verbose || options.verbose
|
|
6279
|
+
);
|
|
6280
|
+
|
|
6281
|
+
const spinner = ora('Fetching authorisations...').start();
|
|
6282
|
+
const result = await api._makeRequest('GET', 'authorisation/list');
|
|
6283
|
+
spinner.stop();
|
|
6284
|
+
|
|
6285
|
+
if (options.output === 'json') {
|
|
6286
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6287
|
+
} else {
|
|
6288
|
+
const auths = Array.isArray(result) ? result : result.items || [];
|
|
6289
|
+
console.log(chalk.green.bold(`Found ${auths.length} authorisation(s)`));
|
|
6290
|
+
auths.forEach(a => {
|
|
6291
|
+
console.log(chalk.cyan(` • ${a.name || 'Unnamed'} (${a.id})`));
|
|
6292
|
+
});
|
|
6293
|
+
}
|
|
6294
|
+
} catch (error) {
|
|
6295
|
+
console.error(chalk.red(`Error listing authorisations: ${error.message}`));
|
|
6296
|
+
process.exit(1);
|
|
6297
|
+
}
|
|
6298
|
+
});
|
|
6299
|
+
|
|
6300
|
+
program
|
|
6301
|
+
.command('get-authorisation')
|
|
6302
|
+
.description('Get details of a specific authorisation')
|
|
6303
|
+
.argument('<id>', 'Authorisation ID')
|
|
6304
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6305
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6306
|
+
.action(async (authId, options, command) => {
|
|
6307
|
+
try {
|
|
6308
|
+
const globalOptions = command.parent.opts();
|
|
6309
|
+
const config = loadConfig(globalOptions.config);
|
|
6310
|
+
validateConfiguration(config);
|
|
6311
|
+
|
|
6312
|
+
const api = new ToothFairyAPI(
|
|
6313
|
+
config.baseUrl,
|
|
6314
|
+
config.aiUrl,
|
|
6315
|
+
config.aiStreamUrl,
|
|
6316
|
+
config.apiKey,
|
|
6317
|
+
config.workspaceId,
|
|
6318
|
+
globalOptions.verbose || options.verbose
|
|
6319
|
+
);
|
|
6320
|
+
|
|
6321
|
+
const spinner = ora('Fetching authorisation...').start();
|
|
6322
|
+
const result = await api._makeRequest('GET', `authorisation/get/${authId}`);
|
|
6323
|
+
spinner.stop();
|
|
6324
|
+
|
|
6325
|
+
if (options.output === 'json') {
|
|
6326
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6327
|
+
} else {
|
|
6328
|
+
console.log(chalk.green.bold('Authorisation Details'));
|
|
6329
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
6330
|
+
}
|
|
6331
|
+
} catch (error) {
|
|
6332
|
+
console.error(chalk.red(`Error getting authorisation: ${error.message}`));
|
|
6333
|
+
process.exit(1);
|
|
6334
|
+
}
|
|
6335
|
+
});
|
|
6336
|
+
|
|
6337
|
+
program
|
|
6338
|
+
.command('update-authorisation')
|
|
6339
|
+
.description('Update an existing authorisation')
|
|
6340
|
+
.argument('<id>', 'Authorisation ID')
|
|
6341
|
+
.option('--name <name>', 'Authorisation name')
|
|
6342
|
+
.option('--permissions <permissions>', 'Permissions (JSON)')
|
|
6343
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6344
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6345
|
+
.action(async (authId, options, command) => {
|
|
6346
|
+
try {
|
|
6347
|
+
const globalOptions = command.parent.opts();
|
|
6348
|
+
const config = loadConfig(globalOptions.config);
|
|
6349
|
+
validateConfiguration(config);
|
|
6350
|
+
|
|
6351
|
+
const api = new ToothFairyAPI(
|
|
6352
|
+
config.baseUrl,
|
|
6353
|
+
config.aiUrl,
|
|
6354
|
+
config.aiStreamUrl,
|
|
6355
|
+
config.apiKey,
|
|
6356
|
+
config.workspaceId,
|
|
6357
|
+
globalOptions.verbose || options.verbose
|
|
6358
|
+
);
|
|
6359
|
+
|
|
6360
|
+
let permissions = {};
|
|
6361
|
+
if (options.permissions) {
|
|
6362
|
+
try {
|
|
6363
|
+
permissions = JSON.parse(options.permissions);
|
|
6364
|
+
} catch (e) {
|
|
6365
|
+
console.error(chalk.red('Invalid JSON in permissions'));
|
|
6366
|
+
process.exit(1);
|
|
6367
|
+
}
|
|
6368
|
+
}
|
|
6369
|
+
|
|
6370
|
+
const spinner = ora('Updating authorisation...').start();
|
|
6371
|
+
const result = await api._makeRequest('POST', 'authorisation/update', {
|
|
6372
|
+
id: authId,
|
|
6373
|
+
name: options.name,
|
|
6374
|
+
permissions,
|
|
6375
|
+
});
|
|
6376
|
+
spinner.stop();
|
|
6377
|
+
|
|
6378
|
+
if (options.output === 'json') {
|
|
6379
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6380
|
+
} else {
|
|
6381
|
+
console.log(chalk.green.bold('✅ Authorisation updated successfully!'));
|
|
6382
|
+
}
|
|
6383
|
+
} catch (error) {
|
|
6384
|
+
console.error(chalk.red(`Error updating authorisation: ${error.message}`));
|
|
6385
|
+
process.exit(1);
|
|
6386
|
+
}
|
|
6387
|
+
});
|
|
6388
|
+
|
|
6389
|
+
program
|
|
6390
|
+
.command('delete-authorisation')
|
|
6391
|
+
.description('Delete an authorisation')
|
|
6392
|
+
.argument('<id>', 'Authorisation ID')
|
|
6393
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
6394
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6395
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6396
|
+
.action(async (authId, options, command) => {
|
|
6397
|
+
try {
|
|
6398
|
+
const globalOptions = command.parent.opts();
|
|
6399
|
+
const config = loadConfig(globalOptions.config);
|
|
6400
|
+
validateConfiguration(config);
|
|
6401
|
+
|
|
6402
|
+
if (!options.confirm) {
|
|
6403
|
+
const readline = require('readline');
|
|
6404
|
+
const rl = readline.createInterface({
|
|
6405
|
+
input: process.stdin,
|
|
6406
|
+
output: process.stdout,
|
|
6407
|
+
});
|
|
6408
|
+
|
|
6409
|
+
const answer = await new Promise((resolve) => {
|
|
6410
|
+
rl.question(
|
|
6411
|
+
chalk.yellow(`⚠️ Are you sure you want to delete authorisation ${authId}? (y/N): `),
|
|
6412
|
+
resolve
|
|
6413
|
+
);
|
|
6414
|
+
});
|
|
6415
|
+
rl.close();
|
|
6416
|
+
|
|
6417
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
6418
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
6419
|
+
process.exit(0);
|
|
6420
|
+
}
|
|
6421
|
+
}
|
|
6422
|
+
|
|
6423
|
+
const api = new ToothFairyAPI(
|
|
6424
|
+
config.baseUrl,
|
|
6425
|
+
config.aiUrl,
|
|
6426
|
+
config.aiStreamUrl,
|
|
6427
|
+
config.apiKey,
|
|
6428
|
+
config.workspaceId,
|
|
6429
|
+
globalOptions.verbose || options.verbose
|
|
6430
|
+
);
|
|
6431
|
+
|
|
6432
|
+
const spinner = ora('Deleting authorisation...').start();
|
|
6433
|
+
const result = await api._makeRequest('DELETE', `authorisation/delete/${authId}`);
|
|
6434
|
+
spinner.stop();
|
|
6435
|
+
|
|
6436
|
+
if (options.output === 'json') {
|
|
6437
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6438
|
+
} else {
|
|
6439
|
+
console.log(chalk.green.bold('✅ Authorisation deleted successfully!'));
|
|
6440
|
+
}
|
|
6441
|
+
} catch (error) {
|
|
6442
|
+
console.error(chalk.red(`Error deleting authorisation: ${error.message}`));
|
|
6443
|
+
process.exit(1);
|
|
6444
|
+
}
|
|
6445
|
+
});
|
|
6446
|
+
|
|
6447
|
+
// Charting Settings commands
|
|
6448
|
+
program
|
|
6449
|
+
.command('get-charting-settings')
|
|
6450
|
+
.description('Get charting settings')
|
|
6451
|
+
.argument('<id>', 'Settings ID')
|
|
6452
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6453
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6454
|
+
.action(async (settingsId, options, command) => {
|
|
6455
|
+
try {
|
|
6456
|
+
const globalOptions = command.parent.opts();
|
|
6457
|
+
const config = loadConfig(globalOptions.config);
|
|
6458
|
+
validateConfiguration(config);
|
|
6459
|
+
|
|
6460
|
+
const api = new ToothFairyAPI(
|
|
6461
|
+
config.baseUrl,
|
|
6462
|
+
config.aiUrl,
|
|
6463
|
+
config.aiStreamUrl,
|
|
6464
|
+
config.apiKey,
|
|
6465
|
+
config.workspaceId,
|
|
6466
|
+
globalOptions.verbose || options.verbose
|
|
6467
|
+
);
|
|
6468
|
+
|
|
6469
|
+
const spinner = ora('Fetching charting settings...').start();
|
|
6470
|
+
const result = await api._makeRequest('GET', `charting_settings/get/${settingsId}`);
|
|
6471
|
+
spinner.stop();
|
|
6472
|
+
|
|
6473
|
+
if (options.output === 'json') {
|
|
6474
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6475
|
+
} else {
|
|
6476
|
+
console.log(chalk.green.bold('Charting Settings'));
|
|
6477
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
6478
|
+
}
|
|
6479
|
+
} catch (error) {
|
|
6480
|
+
console.error(chalk.red(`Error getting charting settings: ${error.message}`));
|
|
6481
|
+
process.exit(1);
|
|
6482
|
+
}
|
|
6483
|
+
});
|
|
6484
|
+
|
|
6485
|
+
program
|
|
6486
|
+
.command('update-charting-settings')
|
|
6487
|
+
.description('Update charting settings')
|
|
6488
|
+
.argument('<id>', 'Settings ID')
|
|
6489
|
+
.option('--config <config>', 'Settings configuration (JSON)')
|
|
6490
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6491
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6492
|
+
.action(async (settingsId, options, command) => {
|
|
6493
|
+
try {
|
|
6494
|
+
const globalOptions = command.parent.opts();
|
|
6495
|
+
const config = loadConfig(globalOptions.config);
|
|
6496
|
+
validateConfiguration(config);
|
|
6497
|
+
|
|
6498
|
+
const api = new ToothFairyAPI(
|
|
6499
|
+
config.baseUrl,
|
|
6500
|
+
config.aiUrl,
|
|
6501
|
+
config.aiStreamUrl,
|
|
6502
|
+
config.apiKey,
|
|
6503
|
+
config.workspaceId,
|
|
6504
|
+
globalOptions.verbose || options.verbose
|
|
6505
|
+
);
|
|
6506
|
+
|
|
6507
|
+
let settingsConfig = {};
|
|
6508
|
+
if (options.config) {
|
|
6509
|
+
try {
|
|
6510
|
+
settingsConfig = JSON.parse(options.config);
|
|
6511
|
+
} catch (e) {
|
|
6512
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
6513
|
+
process.exit(1);
|
|
6514
|
+
}
|
|
6515
|
+
}
|
|
6516
|
+
|
|
6517
|
+
const spinner = ora('Updating charting settings...').start();
|
|
6518
|
+
const result = await api._makeRequest('POST', 'charting_settings/update', {
|
|
6519
|
+
id: settingsId,
|
|
6520
|
+
...settingsConfig,
|
|
6521
|
+
});
|
|
6522
|
+
spinner.stop();
|
|
6523
|
+
|
|
6524
|
+
if (options.output === 'json') {
|
|
6525
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6526
|
+
} else {
|
|
6527
|
+
console.log(chalk.green.bold('✅ Charting settings updated successfully!'));
|
|
6528
|
+
}
|
|
6529
|
+
} catch (error) {
|
|
6530
|
+
console.error(chalk.red(`Error updating charting settings: ${error.message}`));
|
|
6531
|
+
process.exit(1);
|
|
6532
|
+
}
|
|
6533
|
+
});
|
|
6534
|
+
|
|
6535
|
+
// Embeddings Settings commands
|
|
6536
|
+
program
|
|
6537
|
+
.command('get-embeddings-settings')
|
|
6538
|
+
.description('Get embeddings settings')
|
|
6539
|
+
.argument('<id>', 'Settings ID')
|
|
6540
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6541
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6542
|
+
.action(async (settingsId, options, command) => {
|
|
6543
|
+
try {
|
|
6544
|
+
const globalOptions = command.parent.opts();
|
|
6545
|
+
const config = loadConfig(globalOptions.config);
|
|
6546
|
+
validateConfiguration(config);
|
|
6547
|
+
|
|
6548
|
+
const api = new ToothFairyAPI(
|
|
6549
|
+
config.baseUrl,
|
|
6550
|
+
config.aiUrl,
|
|
6551
|
+
config.aiStreamUrl,
|
|
6552
|
+
config.apiKey,
|
|
6553
|
+
config.workspaceId,
|
|
6554
|
+
globalOptions.verbose || options.verbose
|
|
6555
|
+
);
|
|
6556
|
+
|
|
6557
|
+
const spinner = ora('Fetching embeddings settings...').start();
|
|
6558
|
+
const result = await api._makeRequest('GET', `embeddings_settings/get/${settingsId}`);
|
|
6559
|
+
spinner.stop();
|
|
6560
|
+
|
|
6561
|
+
if (options.output === 'json') {
|
|
6562
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6563
|
+
} else {
|
|
6564
|
+
console.log(chalk.green.bold('Embeddings Settings'));
|
|
6565
|
+
console.log(chalk.dim(JSON.stringify(result, null, 2)));
|
|
6566
|
+
}
|
|
6567
|
+
} catch (error) {
|
|
6568
|
+
console.error(chalk.red(`Error getting embeddings settings: ${error.message}`));
|
|
6569
|
+
process.exit(1);
|
|
6570
|
+
}
|
|
6571
|
+
});
|
|
6572
|
+
|
|
6573
|
+
program
|
|
6574
|
+
.command('update-embeddings-settings')
|
|
6575
|
+
.description('Update embeddings settings')
|
|
6576
|
+
.argument('<id>', 'Settings ID')
|
|
6577
|
+
.option('--config <config>', 'Settings configuration (JSON)')
|
|
6578
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6579
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6580
|
+
.action(async (settingsId, options, command) => {
|
|
6581
|
+
try {
|
|
6582
|
+
const globalOptions = command.parent.opts();
|
|
6583
|
+
const config = loadConfig(globalOptions.config);
|
|
6584
|
+
validateConfiguration(config);
|
|
6585
|
+
|
|
6586
|
+
const api = new ToothFairyAPI(
|
|
6587
|
+
config.baseUrl,
|
|
6588
|
+
config.aiUrl,
|
|
6589
|
+
config.aiStreamUrl,
|
|
6590
|
+
config.apiKey,
|
|
6591
|
+
config.workspaceId,
|
|
6592
|
+
globalOptions.verbose || options.verbose
|
|
6593
|
+
);
|
|
6594
|
+
|
|
6595
|
+
let settingsConfig = {};
|
|
6596
|
+
if (options.config) {
|
|
6597
|
+
try {
|
|
6598
|
+
settingsConfig = JSON.parse(options.config);
|
|
6599
|
+
} catch (e) {
|
|
6600
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
6601
|
+
process.exit(1);
|
|
6602
|
+
}
|
|
6603
|
+
}
|
|
6604
|
+
|
|
6605
|
+
const spinner = ora('Updating embeddings settings...').start();
|
|
6606
|
+
const result = await api._makeRequest('POST', 'embeddings_settings/update', {
|
|
6607
|
+
id: settingsId,
|
|
6608
|
+
...settingsConfig,
|
|
6609
|
+
});
|
|
6610
|
+
spinner.stop();
|
|
6611
|
+
|
|
6612
|
+
if (options.output === 'json') {
|
|
6613
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6614
|
+
} else {
|
|
6615
|
+
console.log(chalk.green.bold('✅ Embeddings settings updated successfully!'));
|
|
6616
|
+
}
|
|
6617
|
+
} catch (error) {
|
|
6618
|
+
console.error(chalk.red(`Error updating embeddings settings: ${error.message}`));
|
|
6619
|
+
process.exit(1);
|
|
6620
|
+
}
|
|
6621
|
+
});
|
|
6622
|
+
|
|
6623
|
+
// Authorization Management Commands
|
|
6624
|
+
program
|
|
6625
|
+
.command('create-authorization')
|
|
6626
|
+
.description('Create a new authorization')
|
|
6627
|
+
.option('--name <name>', 'Authorization name')
|
|
6628
|
+
.option('--type <type>', 'Authorization type')
|
|
6629
|
+
.option('--config <config>', 'Authorization configuration (JSON)')
|
|
6630
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6631
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6632
|
+
.action(async (options, command) => {
|
|
6633
|
+
try {
|
|
6634
|
+
const globalOptions = command.parent.opts();
|
|
6635
|
+
const config = loadConfig(globalOptions.config);
|
|
6636
|
+
validateConfiguration(config);
|
|
6637
|
+
|
|
6638
|
+
const api = new ToothFairyAPI(
|
|
6639
|
+
config.baseUrl,
|
|
6640
|
+
config.aiUrl,
|
|
6641
|
+
config.aiStreamUrl,
|
|
6642
|
+
config.apiKey,
|
|
6643
|
+
config.workspaceId,
|
|
6644
|
+
globalOptions.verbose || options.verbose
|
|
6645
|
+
);
|
|
6646
|
+
|
|
6647
|
+
let authConfig = {};
|
|
6648
|
+
if (options.config) {
|
|
6649
|
+
try {
|
|
6650
|
+
authConfig = JSON.parse(options.config);
|
|
6651
|
+
} catch (e) {
|
|
6652
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
6653
|
+
process.exit(1);
|
|
6654
|
+
}
|
|
6655
|
+
}
|
|
6656
|
+
|
|
6657
|
+
const spinner = ora('Creating authorization...').start();
|
|
6658
|
+
const result = await api.createAuthorization({
|
|
6659
|
+
name: options.name,
|
|
6660
|
+
type: options.type,
|
|
6661
|
+
...authConfig,
|
|
6662
|
+
});
|
|
6663
|
+
spinner.stop();
|
|
6664
|
+
|
|
6665
|
+
if (options.output === 'json') {
|
|
6666
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6667
|
+
} else {
|
|
6668
|
+
console.log(chalk.green.bold('✅ Authorization created successfully!'));
|
|
6669
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
6670
|
+
}
|
|
6671
|
+
} catch (error) {
|
|
6672
|
+
console.error(chalk.red(`Error creating authorization: ${error.message}`));
|
|
6673
|
+
process.exit(1);
|
|
6674
|
+
}
|
|
6675
|
+
});
|
|
6676
|
+
|
|
6677
|
+
program
|
|
6678
|
+
.command('list-authorizations')
|
|
6679
|
+
.description('List all authorizations')
|
|
6680
|
+
.option('--limit <number>', 'Maximum number to return', '50')
|
|
6681
|
+
.option('--offset <number>', 'Number to skip', '0')
|
|
6682
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6683
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6684
|
+
.action(async (options, command) => {
|
|
6685
|
+
try {
|
|
6686
|
+
const globalOptions = command.parent.opts();
|
|
6687
|
+
const config = loadConfig(globalOptions.config);
|
|
6688
|
+
validateConfiguration(config);
|
|
6689
|
+
|
|
6690
|
+
const api = new ToothFairyAPI(
|
|
6691
|
+
config.baseUrl,
|
|
6692
|
+
config.aiUrl,
|
|
6693
|
+
config.aiStreamUrl,
|
|
6694
|
+
config.apiKey,
|
|
6695
|
+
config.workspaceId,
|
|
6696
|
+
globalOptions.verbose || options.verbose
|
|
6697
|
+
);
|
|
6698
|
+
|
|
6699
|
+
const spinner = ora('Fetching authorizations...').start();
|
|
6700
|
+
const result = await api.listAuthorizations(
|
|
6701
|
+
parseInt(options.limit),
|
|
6702
|
+
parseInt(options.offset)
|
|
6703
|
+
);
|
|
6704
|
+
spinner.stop();
|
|
6705
|
+
|
|
6706
|
+
if (options.output === 'json') {
|
|
6707
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6708
|
+
} else {
|
|
6709
|
+
const auths = Array.isArray(result) ? result : result.items || [];
|
|
6710
|
+
console.log(chalk.green.bold(`Found ${auths.length} authorization(s)`));
|
|
6711
|
+
auths.forEach(auth => {
|
|
6712
|
+
console.log(chalk.cyan(` • ${auth.name || 'Unnamed'} (${auth.id})`));
|
|
6713
|
+
});
|
|
6714
|
+
}
|
|
6715
|
+
} catch (error) {
|
|
6716
|
+
console.error(chalk.red(`Error listing authorizations: ${error.message}`));
|
|
6717
|
+
process.exit(1);
|
|
6718
|
+
}
|
|
6719
|
+
});
|
|
6720
|
+
|
|
6721
|
+
program
|
|
6722
|
+
.command('get-authorization')
|
|
6723
|
+
.description('Get details of a specific authorization')
|
|
6724
|
+
.argument('<id>', 'Authorization ID')
|
|
6725
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6726
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6727
|
+
.action(async (authId, options, command) => {
|
|
6728
|
+
try {
|
|
6729
|
+
const globalOptions = command.parent.opts();
|
|
6730
|
+
const config = loadConfig(globalOptions.config);
|
|
6731
|
+
validateConfiguration(config);
|
|
6732
|
+
|
|
6733
|
+
const api = new ToothFairyAPI(
|
|
6734
|
+
config.baseUrl,
|
|
6735
|
+
config.aiUrl,
|
|
6736
|
+
config.aiStreamUrl,
|
|
6737
|
+
config.apiKey,
|
|
6738
|
+
config.workspaceId,
|
|
6739
|
+
globalOptions.verbose || options.verbose
|
|
6740
|
+
);
|
|
6741
|
+
|
|
6742
|
+
const spinner = ora('Fetching authorization...').start();
|
|
6743
|
+
const result = await api.getAuthorization(authId);
|
|
6744
|
+
spinner.stop();
|
|
6745
|
+
|
|
6746
|
+
if (options.output === 'json') {
|
|
6747
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6748
|
+
} else {
|
|
6749
|
+
console.log(chalk.green.bold('Authorization Details'));
|
|
6750
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
6751
|
+
console.log(chalk.dim(`Name: ${result.name || 'N/A'}`));
|
|
6752
|
+
console.log(chalk.dim(`Type: ${result.type || 'N/A'}`));
|
|
6753
|
+
}
|
|
6754
|
+
} catch (error) {
|
|
6755
|
+
console.error(chalk.red(`Error getting authorization: ${error.message}`));
|
|
6756
|
+
process.exit(1);
|
|
6757
|
+
}
|
|
6758
|
+
});
|
|
6759
|
+
|
|
6760
|
+
program
|
|
6761
|
+
.command('update-authorization')
|
|
6762
|
+
.description('Update an existing authorization')
|
|
6763
|
+
.option('--id <id>', 'Authorization ID')
|
|
6764
|
+
.option('--name <name>', 'Authorization name')
|
|
6765
|
+
.option('--type <type>', 'Authorization type')
|
|
6766
|
+
.option('--config <config>', 'Authorization configuration (JSON)')
|
|
6767
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6768
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6769
|
+
.action(async (options, command) => {
|
|
6770
|
+
try {
|
|
6771
|
+
const globalOptions = command.parent.opts();
|
|
6772
|
+
const config = loadConfig(globalOptions.config);
|
|
6773
|
+
validateConfiguration(config);
|
|
6774
|
+
|
|
6775
|
+
const api = new ToothFairyAPI(
|
|
6776
|
+
config.baseUrl,
|
|
6777
|
+
config.aiUrl,
|
|
6778
|
+
config.aiStreamUrl,
|
|
6779
|
+
config.apiKey,
|
|
6780
|
+
config.workspaceId,
|
|
6781
|
+
globalOptions.verbose || options.verbose
|
|
6782
|
+
);
|
|
6783
|
+
|
|
6784
|
+
let authConfig = {};
|
|
6785
|
+
if (options.config) {
|
|
6786
|
+
try {
|
|
6787
|
+
authConfig = JSON.parse(options.config);
|
|
6788
|
+
} catch (e) {
|
|
6789
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
6790
|
+
process.exit(1);
|
|
6791
|
+
}
|
|
6792
|
+
}
|
|
6793
|
+
|
|
6794
|
+
const spinner = ora('Updating authorization...').start();
|
|
6795
|
+
const result = await api.updateAuthorization({
|
|
6796
|
+
id: options.id,
|
|
6797
|
+
name: options.name,
|
|
6798
|
+
type: options.type,
|
|
6799
|
+
...authConfig,
|
|
6800
|
+
});
|
|
6801
|
+
spinner.stop();
|
|
6802
|
+
|
|
6803
|
+
if (options.output === 'json') {
|
|
6804
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6805
|
+
} else {
|
|
6806
|
+
console.log(chalk.green.bold('✅ Authorization updated successfully!'));
|
|
6807
|
+
}
|
|
6808
|
+
} catch (error) {
|
|
6809
|
+
console.error(chalk.red(`Error updating authorization: ${error.message}`));
|
|
6810
|
+
process.exit(1);
|
|
6811
|
+
}
|
|
6812
|
+
});
|
|
6813
|
+
|
|
6814
|
+
program
|
|
6815
|
+
.command('delete-authorization')
|
|
6816
|
+
.description('Delete an authorization')
|
|
6817
|
+
.argument('<id>', 'Authorization ID')
|
|
6818
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
6819
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6820
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6821
|
+
.action(async (authId, options, command) => {
|
|
6822
|
+
try {
|
|
6823
|
+
const globalOptions = command.parent.opts();
|
|
6824
|
+
const config = loadConfig(globalOptions.config);
|
|
6825
|
+
validateConfiguration(config);
|
|
6826
|
+
|
|
6827
|
+
const api = new ToothFairyAPI(
|
|
6828
|
+
config.baseUrl,
|
|
6829
|
+
config.aiUrl,
|
|
6830
|
+
config.aiStreamUrl,
|
|
6831
|
+
config.apiKey,
|
|
6832
|
+
config.workspaceId,
|
|
6833
|
+
globalOptions.verbose || options.verbose
|
|
6834
|
+
);
|
|
6835
|
+
|
|
6836
|
+
if (!options.confirm) {
|
|
6837
|
+
const readline = require('readline');
|
|
6838
|
+
const rl = readline.createInterface({
|
|
6839
|
+
input: process.stdin,
|
|
6840
|
+
output: process.stdout,
|
|
6841
|
+
});
|
|
6842
|
+
|
|
6843
|
+
const answer = await new Promise((resolve) => {
|
|
6844
|
+
rl.question(
|
|
6845
|
+
chalk.yellow(
|
|
6846
|
+
`⚠️ Are you sure you want to delete authorization ${authId}? (y/N): `
|
|
6847
|
+
),
|
|
6848
|
+
resolve
|
|
6849
|
+
);
|
|
6850
|
+
});
|
|
6851
|
+
|
|
6852
|
+
rl.close();
|
|
6853
|
+
|
|
6854
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
6855
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
6856
|
+
process.exit(0);
|
|
6857
|
+
}
|
|
6858
|
+
}
|
|
6859
|
+
|
|
6860
|
+
const spinner = ora('Deleting authorization...').start();
|
|
6861
|
+
const result = await api.deleteAuthorization(authId);
|
|
6862
|
+
spinner.stop();
|
|
6863
|
+
|
|
6864
|
+
if (options.output === 'json') {
|
|
6865
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6866
|
+
} else {
|
|
6867
|
+
console.log(chalk.green.bold('✅ Authorization deleted successfully!'));
|
|
6868
|
+
}
|
|
6869
|
+
} catch (error) {
|
|
6870
|
+
console.error(chalk.red(`Error deleting authorization: ${error.message}`));
|
|
6871
|
+
process.exit(1);
|
|
6872
|
+
}
|
|
6873
|
+
});
|
|
6874
|
+
|
|
6875
|
+
// Benchmark Management Commands
|
|
6876
|
+
program
|
|
6877
|
+
.command('create-benchmark')
|
|
6878
|
+
.description('Create a new benchmark')
|
|
6879
|
+
.option('--name <name>', 'Benchmark name')
|
|
6880
|
+
.option('--description <description>', 'Benchmark description')
|
|
6881
|
+
.option('--questions <questions>', 'Questions JSON array')
|
|
6882
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6883
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6884
|
+
.action(async (options, command) => {
|
|
6885
|
+
try {
|
|
6886
|
+
const globalOptions = command.parent.opts();
|
|
6887
|
+
const config = loadConfig(globalOptions.config);
|
|
6888
|
+
validateConfiguration(config);
|
|
6889
|
+
|
|
6890
|
+
const api = new ToothFairyAPI(
|
|
6891
|
+
config.baseUrl,
|
|
6892
|
+
config.aiUrl,
|
|
6893
|
+
config.aiStreamUrl,
|
|
6894
|
+
config.apiKey,
|
|
6895
|
+
config.workspaceId,
|
|
6896
|
+
globalOptions.verbose || options.verbose
|
|
6897
|
+
);
|
|
6898
|
+
|
|
6899
|
+
let questions = [];
|
|
6900
|
+
if (options.questions) {
|
|
6901
|
+
try {
|
|
6902
|
+
questions = JSON.parse(options.questions);
|
|
6903
|
+
} catch (e) {
|
|
6904
|
+
console.error(chalk.red('Invalid JSON in questions'));
|
|
6905
|
+
process.exit(1);
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
|
|
6909
|
+
const spinner = ora('Creating benchmark...').start();
|
|
6910
|
+
const result = await api.createBenchmark({
|
|
6911
|
+
name: options.name,
|
|
6912
|
+
description: options.description,
|
|
6913
|
+
questions: questions,
|
|
6914
|
+
});
|
|
6915
|
+
spinner.stop();
|
|
6916
|
+
|
|
6917
|
+
if (options.output === 'json') {
|
|
6918
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6919
|
+
} else {
|
|
6920
|
+
console.log(chalk.green.bold('✅ Benchmark created successfully!'));
|
|
6921
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
6922
|
+
}
|
|
6923
|
+
} catch (error) {
|
|
6924
|
+
console.error(chalk.red(`Error creating benchmark: ${error.message}`));
|
|
6925
|
+
process.exit(1);
|
|
6926
|
+
}
|
|
6927
|
+
});
|
|
6928
|
+
|
|
6929
|
+
program
|
|
6930
|
+
.command('list-benchmarks')
|
|
6931
|
+
.description('List all benchmarks')
|
|
6932
|
+
.option('--limit <number>', 'Maximum number to return', '50')
|
|
6933
|
+
.option('--offset <number>', 'Number to skip', '0')
|
|
6934
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6935
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6936
|
+
.action(async (options, command) => {
|
|
6937
|
+
try {
|
|
6938
|
+
const globalOptions = command.parent.opts();
|
|
6939
|
+
const config = loadConfig(globalOptions.config);
|
|
6940
|
+
validateConfiguration(config);
|
|
6941
|
+
|
|
6942
|
+
const api = new ToothFairyAPI(
|
|
6943
|
+
config.baseUrl,
|
|
6944
|
+
config.aiUrl,
|
|
6945
|
+
config.aiStreamUrl,
|
|
6946
|
+
config.apiKey,
|
|
6947
|
+
config.workspaceId,
|
|
6948
|
+
globalOptions.verbose || options.verbose
|
|
6949
|
+
);
|
|
6950
|
+
|
|
6951
|
+
const spinner = ora('Fetching benchmarks...').start();
|
|
6952
|
+
const result = await api.listBenchmarks(
|
|
6953
|
+
parseInt(options.limit),
|
|
6954
|
+
parseInt(options.offset)
|
|
6955
|
+
);
|
|
6956
|
+
spinner.stop();
|
|
6957
|
+
|
|
6958
|
+
if (options.output === 'json') {
|
|
6959
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6960
|
+
} else {
|
|
6961
|
+
const benchmarks = Array.isArray(result) ? result : result.items || [];
|
|
6962
|
+
console.log(chalk.green.bold(`Found ${benchmarks.length} benchmark(s)`));
|
|
6963
|
+
benchmarks.forEach(bm => {
|
|
6964
|
+
console.log(chalk.cyan(` • ${bm.name || 'Unnamed'} (${bm.id})`));
|
|
6965
|
+
});
|
|
6966
|
+
}
|
|
6967
|
+
} catch (error) {
|
|
6968
|
+
console.error(chalk.red(`Error listing benchmarks: ${error.message}`));
|
|
6969
|
+
process.exit(1);
|
|
6970
|
+
}
|
|
6971
|
+
});
|
|
6972
|
+
|
|
6973
|
+
program
|
|
6974
|
+
.command('get-benchmark')
|
|
6975
|
+
.description('Get details of a specific benchmark')
|
|
6976
|
+
.argument('<id>', 'Benchmark ID')
|
|
6977
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
6978
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
6979
|
+
.action(async (benchmarkId, options, command) => {
|
|
6980
|
+
try {
|
|
6981
|
+
const globalOptions = command.parent.opts();
|
|
6982
|
+
const config = loadConfig(globalOptions.config);
|
|
6983
|
+
validateConfiguration(config);
|
|
6984
|
+
|
|
6985
|
+
const api = new ToothFairyAPI(
|
|
6986
|
+
config.baseUrl,
|
|
6987
|
+
config.aiUrl,
|
|
6988
|
+
config.aiStreamUrl,
|
|
6989
|
+
config.apiKey,
|
|
6990
|
+
config.workspaceId,
|
|
6991
|
+
globalOptions.verbose || options.verbose
|
|
6992
|
+
);
|
|
6993
|
+
|
|
6994
|
+
const spinner = ora('Fetching benchmark...').start();
|
|
6995
|
+
const result = await api.getBenchmark(benchmarkId);
|
|
6996
|
+
spinner.stop();
|
|
6997
|
+
|
|
6998
|
+
if (options.output === 'json') {
|
|
6999
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7000
|
+
} else {
|
|
7001
|
+
console.log(chalk.green.bold('Benchmark Details'));
|
|
7002
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7003
|
+
console.log(chalk.dim(`Name: ${result.name || 'N/A'}`));
|
|
7004
|
+
console.log(chalk.dim(`Description: ${result.description || 'N/A'}`));
|
|
7005
|
+
}
|
|
7006
|
+
} catch (error) {
|
|
7007
|
+
console.error(chalk.red(`Error getting benchmark: ${error.message}`));
|
|
7008
|
+
process.exit(1);
|
|
7009
|
+
}
|
|
7010
|
+
});
|
|
7011
|
+
|
|
7012
|
+
program
|
|
7013
|
+
.command('update-benchmark')
|
|
7014
|
+
.description('Update an existing benchmark')
|
|
7015
|
+
.option('--id <id>', 'Benchmark ID')
|
|
7016
|
+
.option('--name <name>', 'Benchmark name')
|
|
7017
|
+
.option('--description <description>', 'Benchmark description')
|
|
7018
|
+
.option('--questions <questions>', 'Questions JSON array')
|
|
7019
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7020
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7021
|
+
.action(async (options, command) => {
|
|
7022
|
+
try {
|
|
7023
|
+
const globalOptions = command.parent.opts();
|
|
7024
|
+
const config = loadConfig(globalOptions.config);
|
|
7025
|
+
validateConfiguration(config);
|
|
7026
|
+
|
|
7027
|
+
const api = new ToothFairyAPI(
|
|
7028
|
+
config.baseUrl,
|
|
7029
|
+
config.aiUrl,
|
|
7030
|
+
config.aiStreamUrl,
|
|
7031
|
+
config.apiKey,
|
|
7032
|
+
config.workspaceId,
|
|
7033
|
+
globalOptions.verbose || options.verbose
|
|
7034
|
+
);
|
|
7035
|
+
|
|
7036
|
+
let questions = undefined;
|
|
7037
|
+
if (options.questions) {
|
|
7038
|
+
try {
|
|
7039
|
+
questions = JSON.parse(options.questions);
|
|
7040
|
+
} catch (e) {
|
|
7041
|
+
console.error(chalk.red('Invalid JSON in questions'));
|
|
7042
|
+
process.exit(1);
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
7045
|
+
|
|
7046
|
+
const spinner = ora('Updating benchmark...').start();
|
|
7047
|
+
const result = await api.updateBenchmark({
|
|
7048
|
+
id: options.id,
|
|
7049
|
+
name: options.name,
|
|
7050
|
+
description: options.description,
|
|
7051
|
+
questions: questions,
|
|
7052
|
+
});
|
|
7053
|
+
spinner.stop();
|
|
7054
|
+
|
|
7055
|
+
if (options.output === 'json') {
|
|
7056
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7057
|
+
} else {
|
|
7058
|
+
console.log(chalk.green.bold('✅ Benchmark updated successfully!'));
|
|
7059
|
+
}
|
|
7060
|
+
} catch (error) {
|
|
7061
|
+
console.error(chalk.red(`Error updating benchmark: ${error.message}`));
|
|
7062
|
+
process.exit(1);
|
|
7063
|
+
}
|
|
7064
|
+
});
|
|
7065
|
+
|
|
7066
|
+
program
|
|
7067
|
+
.command('delete-benchmark')
|
|
7068
|
+
.description('Delete a benchmark')
|
|
7069
|
+
.argument('<id>', 'Benchmark ID')
|
|
7070
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
7071
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7072
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7073
|
+
.action(async (benchmarkId, options, command) => {
|
|
7074
|
+
try {
|
|
7075
|
+
const globalOptions = command.parent.opts();
|
|
7076
|
+
const config = loadConfig(globalOptions.config);
|
|
7077
|
+
validateConfiguration(config);
|
|
7078
|
+
|
|
7079
|
+
const api = new ToothFairyAPI(
|
|
7080
|
+
config.baseUrl,
|
|
7081
|
+
config.aiUrl,
|
|
7082
|
+
config.aiStreamUrl,
|
|
7083
|
+
config.apiKey,
|
|
7084
|
+
config.workspaceId,
|
|
7085
|
+
globalOptions.verbose || options.verbose
|
|
7086
|
+
);
|
|
7087
|
+
|
|
7088
|
+
if (!options.confirm) {
|
|
7089
|
+
const readline = require('readline');
|
|
7090
|
+
const rl = readline.createInterface({
|
|
7091
|
+
input: process.stdin,
|
|
7092
|
+
output: process.stdout,
|
|
7093
|
+
});
|
|
7094
|
+
|
|
7095
|
+
const answer = await new Promise((resolve) => {
|
|
7096
|
+
rl.question(
|
|
7097
|
+
chalk.yellow(
|
|
7098
|
+
`⚠️ Are you sure you want to delete benchmark ${benchmarkId}? (y/N): `
|
|
7099
|
+
),
|
|
7100
|
+
resolve
|
|
7101
|
+
);
|
|
7102
|
+
});
|
|
7103
|
+
|
|
7104
|
+
rl.close();
|
|
7105
|
+
|
|
7106
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
7107
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
7108
|
+
process.exit(0);
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
|
|
7112
|
+
const spinner = ora('Deleting benchmark...').start();
|
|
7113
|
+
const result = await api.deleteBenchmark(benchmarkId);
|
|
7114
|
+
spinner.stop();
|
|
7115
|
+
|
|
7116
|
+
if (options.output === 'json') {
|
|
7117
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7118
|
+
} else {
|
|
7119
|
+
console.log(chalk.green.bold('✅ Benchmark deleted successfully!'));
|
|
7120
|
+
}
|
|
7121
|
+
} catch (error) {
|
|
7122
|
+
console.error(chalk.red(`Error deleting benchmark: ${error.message}`));
|
|
7123
|
+
process.exit(1);
|
|
7124
|
+
}
|
|
7125
|
+
});
|
|
7126
|
+
|
|
7127
|
+
// Billing Commands
|
|
7128
|
+
program
|
|
7129
|
+
.command('billing-month-costs')
|
|
7130
|
+
.description('Get monthly usage and cost information')
|
|
7131
|
+
.argument('<month>', 'Month number (1-12)')
|
|
7132
|
+
.argument('<year>', 'Year (4-digit)')
|
|
7133
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7134
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7135
|
+
.action(async (month, year, options, command) => {
|
|
7136
|
+
try {
|
|
7137
|
+
const globalOptions = command.parent.opts();
|
|
7138
|
+
const config = loadConfig(globalOptions.config);
|
|
7139
|
+
validateConfiguration(config);
|
|
7140
|
+
|
|
7141
|
+
const api = new ToothFairyAPI(
|
|
7142
|
+
config.baseUrl,
|
|
7143
|
+
config.aiUrl,
|
|
7144
|
+
config.aiStreamUrl,
|
|
7145
|
+
config.apiKey,
|
|
7146
|
+
config.workspaceId,
|
|
7147
|
+
globalOptions.verbose || options.verbose
|
|
7148
|
+
);
|
|
7149
|
+
|
|
7150
|
+
const monthNum = parseInt(month);
|
|
7151
|
+
const yearNum = parseInt(year);
|
|
7152
|
+
|
|
7153
|
+
if (isNaN(monthNum) || monthNum < 1 || monthNum > 12) {
|
|
7154
|
+
console.error(chalk.red('Error: Month must be a number between 1 and 12'));
|
|
7155
|
+
process.exit(1);
|
|
7156
|
+
}
|
|
7157
|
+
|
|
7158
|
+
if (isNaN(yearNum) || yearNum < 2020 || yearNum > 2100) {
|
|
7159
|
+
console.error(chalk.red('Error: Year must be a valid 4-digit year'));
|
|
7160
|
+
process.exit(1);
|
|
7161
|
+
}
|
|
7162
|
+
|
|
7163
|
+
const spinner = ora('Fetching billing information...').start();
|
|
7164
|
+
const result = await api.getMonthCosts(monthNum, yearNum);
|
|
7165
|
+
spinner.stop();
|
|
7166
|
+
|
|
7167
|
+
if (options.output === 'json') {
|
|
7168
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7169
|
+
} else {
|
|
7170
|
+
console.log(chalk.green.bold(`Billing Information for ${month}/${year}`));
|
|
7171
|
+
console.log();
|
|
7172
|
+
|
|
7173
|
+
if (result.apiUsage) {
|
|
7174
|
+
console.log(chalk.cyan('API Usage:'));
|
|
7175
|
+
if (result.apiUsage.totalUoI !== undefined) {
|
|
7176
|
+
console.log(chalk.dim(` Total Units of Interaction: ${result.apiUsage.totalUoI}`));
|
|
7177
|
+
}
|
|
7178
|
+
if (result.apiUsage.totalCostUSD !== undefined) {
|
|
7179
|
+
console.log(chalk.dim(` Total Cost: $${result.apiUsage.totalCostUSD}`));
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
|
|
7183
|
+
if (result.trainingUsage) {
|
|
7184
|
+
console.log(chalk.cyan('Training Usage:'));
|
|
7185
|
+
console.log(chalk.dim(` See --verbose for details`));
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
} catch (error) {
|
|
7189
|
+
console.error(chalk.red(`Error getting billing information: ${error.message}`));
|
|
7190
|
+
process.exit(1);
|
|
7191
|
+
}
|
|
7192
|
+
});
|
|
7193
|
+
|
|
7194
|
+
// Channel Management Commands
|
|
7195
|
+
program
|
|
7196
|
+
.command('create-channel')
|
|
7197
|
+
.description('Create a new communication channel')
|
|
7198
|
+
.option('--name <name>', 'Channel name')
|
|
7199
|
+
.option('--channel <channel>', 'Channel type (sms|whatsapp|email)')
|
|
7200
|
+
.option('--provider <provider>', 'Service provider')
|
|
7201
|
+
.option('--senderid <senderid>', 'Sender ID')
|
|
7202
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7203
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7204
|
+
.action(async (options, command) => {
|
|
7205
|
+
try {
|
|
7206
|
+
const globalOptions = command.parent.opts();
|
|
7207
|
+
const config = loadConfig(globalOptions.config);
|
|
7208
|
+
validateConfiguration(config);
|
|
7209
|
+
|
|
7210
|
+
const api = new ToothFairyAPI(
|
|
7211
|
+
config.baseUrl,
|
|
7212
|
+
config.aiUrl,
|
|
7213
|
+
config.aiStreamUrl,
|
|
7214
|
+
config.apiKey,
|
|
7215
|
+
config.workspaceId,
|
|
7216
|
+
globalOptions.verbose || options.verbose
|
|
7217
|
+
);
|
|
7218
|
+
|
|
7219
|
+
const spinner = ora('Creating channel...').start();
|
|
7220
|
+
const result = await api.createChannel({
|
|
7221
|
+
name: options.name,
|
|
7222
|
+
channel: options.channel,
|
|
7223
|
+
provider: options.provider,
|
|
7224
|
+
senderid: options.senderid,
|
|
7225
|
+
});
|
|
7226
|
+
spinner.stop();
|
|
7227
|
+
|
|
7228
|
+
if (options.output === 'json') {
|
|
7229
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7230
|
+
} else {
|
|
7231
|
+
console.log(chalk.green.bold('✅ Channel created successfully!'));
|
|
7232
|
+
console.log(chalk.dim(`ID: ${result.id || 'N/A'}`));
|
|
7233
|
+
}
|
|
7234
|
+
} catch (error) {
|
|
7235
|
+
console.error(chalk.red(`Error creating channel: ${error.message}`));
|
|
7236
|
+
process.exit(1);
|
|
7237
|
+
}
|
|
7238
|
+
});
|
|
7239
|
+
|
|
7240
|
+
program
|
|
7241
|
+
.command('list-channels')
|
|
7242
|
+
.description('List all channels')
|
|
7243
|
+
.option('--limit <number>', 'Maximum number to return', '50')
|
|
7244
|
+
.option('--offset <number>', 'Number to skip', '0')
|
|
7245
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7246
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7247
|
+
.action(async (options, command) => {
|
|
7248
|
+
try {
|
|
7249
|
+
const globalOptions = command.parent.opts();
|
|
7250
|
+
const config = loadConfig(globalOptions.config);
|
|
7251
|
+
validateConfiguration(config);
|
|
7252
|
+
|
|
7253
|
+
const api = new ToothFairyAPI(
|
|
7254
|
+
config.baseUrl,
|
|
7255
|
+
config.aiUrl,
|
|
7256
|
+
config.aiStreamUrl,
|
|
7257
|
+
config.apiKey,
|
|
7258
|
+
config.workspaceId,
|
|
7259
|
+
globalOptions.verbose || options.verbose
|
|
7260
|
+
);
|
|
7261
|
+
|
|
7262
|
+
const spinner = ora('Fetching channels...').start();
|
|
7263
|
+
const result = await api.listChannels(
|
|
7264
|
+
parseInt(options.limit),
|
|
7265
|
+
parseInt(options.offset)
|
|
7266
|
+
);
|
|
7267
|
+
spinner.stop();
|
|
7268
|
+
|
|
7269
|
+
if (options.output === 'json') {
|
|
7270
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7271
|
+
} else {
|
|
7272
|
+
const channels = Array.isArray(result) ? result : result.items || [];
|
|
7273
|
+
console.log(chalk.green.bold(`Found ${channels.length} channel(s)`));
|
|
7274
|
+
channels.forEach(ch => {
|
|
7275
|
+
console.log(chalk.cyan(` • ${ch.name || 'Unnamed'} (${ch.id})`));
|
|
7276
|
+
});
|
|
7277
|
+
}
|
|
7278
|
+
} catch (error) {
|
|
7279
|
+
console.error(chalk.red(`Error listing channels: ${error.message}`));
|
|
7280
|
+
process.exit(1);
|
|
7281
|
+
}
|
|
7282
|
+
});
|
|
7283
|
+
|
|
7284
|
+
program
|
|
7285
|
+
.command('get-channel')
|
|
7286
|
+
.description('Get details of a specific channel')
|
|
7287
|
+
.argument('<id>', 'Channel ID')
|
|
7288
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7289
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7290
|
+
.action(async (channelId, options, command) => {
|
|
7291
|
+
try {
|
|
7292
|
+
const globalOptions = command.parent.opts();
|
|
7293
|
+
const config = loadConfig(globalOptions.config);
|
|
7294
|
+
validateConfiguration(config);
|
|
7295
|
+
|
|
7296
|
+
const api = new ToothFairyAPI(
|
|
7297
|
+
config.baseUrl,
|
|
7298
|
+
config.aiUrl,
|
|
7299
|
+
config.aiStreamUrl,
|
|
7300
|
+
config.apiKey,
|
|
7301
|
+
config.workspaceId,
|
|
7302
|
+
globalOptions.verbose || options.verbose
|
|
7303
|
+
);
|
|
7304
|
+
|
|
7305
|
+
const spinner = ora('Fetching channel...').start();
|
|
7306
|
+
const result = await api.getChannel(channelId);
|
|
7307
|
+
spinner.stop();
|
|
7308
|
+
|
|
7309
|
+
if (options.output === 'json') {
|
|
7310
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7311
|
+
} else {
|
|
7312
|
+
console.log(chalk.green.bold('Channel Details'));
|
|
7313
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7314
|
+
console.log(chalk.dim(`Name: ${result.name || 'N/A'}`));
|
|
7315
|
+
console.log(chalk.dim(`Channel: ${result.channel || 'N/A'}`));
|
|
7316
|
+
console.log(chalk.dim(`Provider: ${result.provider || 'N/A'}`));
|
|
7317
|
+
}
|
|
7318
|
+
} catch (error) {
|
|
7319
|
+
console.error(chalk.red(`Error getting channel: ${error.message}`));
|
|
7320
|
+
process.exit(1);
|
|
7321
|
+
}
|
|
7322
|
+
});
|
|
7323
|
+
|
|
7324
|
+
program
|
|
7325
|
+
.command('update-channel')
|
|
7326
|
+
.description('Update an existing channel')
|
|
7327
|
+
.option('--id <id>', 'Channel ID')
|
|
7328
|
+
.option('--name <name>', 'Channel name')
|
|
7329
|
+
.option('--channel <channel>', 'Channel type')
|
|
7330
|
+
.option('--provider <provider>', 'Service provider')
|
|
7331
|
+
.option('--senderid <senderid>', 'Sender ID')
|
|
7332
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7333
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7334
|
+
.action(async (options, command) => {
|
|
7335
|
+
try {
|
|
7336
|
+
const globalOptions = command.parent.opts();
|
|
7337
|
+
const config = loadConfig(globalOptions.config);
|
|
7338
|
+
validateConfiguration(config);
|
|
7339
|
+
|
|
7340
|
+
const api = new ToothFairyAPI(
|
|
7341
|
+
config.baseUrl,
|
|
7342
|
+
config.aiUrl,
|
|
7343
|
+
config.aiStreamUrl,
|
|
7344
|
+
config.apiKey,
|
|
7345
|
+
config.workspaceId,
|
|
7346
|
+
globalOptions.verbose || options.verbose
|
|
7347
|
+
);
|
|
7348
|
+
|
|
7349
|
+
const spinner = ora('Updating channel...').start();
|
|
7350
|
+
const result = await api.updateChannel({
|
|
7351
|
+
id: options.id,
|
|
7352
|
+
name: options.name,
|
|
7353
|
+
channel: options.channel,
|
|
7354
|
+
provider: options.provider,
|
|
7355
|
+
senderid: options.senderid,
|
|
7356
|
+
});
|
|
7357
|
+
spinner.stop();
|
|
7358
|
+
|
|
7359
|
+
if (options.output === 'json') {
|
|
7360
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7361
|
+
} else {
|
|
7362
|
+
console.log(chalk.green.bold('✅ Channel updated successfully!'));
|
|
7363
|
+
}
|
|
7364
|
+
} catch (error) {
|
|
7365
|
+
console.error(chalk.red(`Error updating channel: ${error.message}`));
|
|
7366
|
+
process.exit(1);
|
|
7367
|
+
}
|
|
7368
|
+
});
|
|
7369
|
+
|
|
7370
|
+
program
|
|
7371
|
+
.command('delete-channel')
|
|
7372
|
+
.description('Delete a channel')
|
|
7373
|
+
.argument('<id>', 'Channel ID')
|
|
7374
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
7375
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7376
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7377
|
+
.action(async (channelId, options, command) => {
|
|
7378
|
+
try {
|
|
7379
|
+
const globalOptions = command.parent.opts();
|
|
7380
|
+
const config = loadConfig(globalOptions.config);
|
|
7381
|
+
validateConfiguration(config);
|
|
7382
|
+
|
|
7383
|
+
const api = new ToothFairyAPI(
|
|
7384
|
+
config.baseUrl,
|
|
7385
|
+
config.aiUrl,
|
|
7386
|
+
config.aiStreamUrl,
|
|
7387
|
+
config.apiKey,
|
|
7388
|
+
config.workspaceId,
|
|
7389
|
+
globalOptions.verbose || options.verbose
|
|
7390
|
+
);
|
|
7391
|
+
|
|
7392
|
+
if (!options.confirm) {
|
|
7393
|
+
const readline = require('readline');
|
|
7394
|
+
const rl = readline.createInterface({
|
|
7395
|
+
input: process.stdin,
|
|
7396
|
+
output: process.stdout,
|
|
7397
|
+
});
|
|
7398
|
+
|
|
7399
|
+
const answer = await new Promise((resolve) => {
|
|
7400
|
+
rl.question(
|
|
7401
|
+
chalk.yellow(
|
|
7402
|
+
`⚠️ Are you sure you want to delete channel ${channelId}? (y/N): `
|
|
7403
|
+
),
|
|
7404
|
+
resolve
|
|
7405
|
+
);
|
|
7406
|
+
});
|
|
7407
|
+
|
|
7408
|
+
rl.close();
|
|
7409
|
+
|
|
7410
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
7411
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
7412
|
+
process.exit(0);
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
|
|
7416
|
+
const spinner = ora('Deleting channel...').start();
|
|
7417
|
+
const result = await api.deleteChannel(channelId);
|
|
7418
|
+
spinner.stop();
|
|
7419
|
+
|
|
7420
|
+
if (options.output === 'json') {
|
|
7421
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7422
|
+
} else {
|
|
7423
|
+
console.log(chalk.green.bold('✅ Channel deleted successfully!'));
|
|
7424
|
+
}
|
|
7425
|
+
} catch (error) {
|
|
7426
|
+
console.error(chalk.red(`Error deleting channel: ${error.message}`));
|
|
7427
|
+
process.exit(1);
|
|
7428
|
+
}
|
|
7429
|
+
});
|
|
7430
|
+
|
|
7431
|
+
// Connection Management Commands
|
|
7432
|
+
program
|
|
7433
|
+
.command('list-connections')
|
|
7434
|
+
.description('List all connections')
|
|
7435
|
+
.option('--limit <number>', 'Maximum number to return', '50')
|
|
7436
|
+
.option('--offset <number>', 'Number to skip', '0')
|
|
7437
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7438
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7439
|
+
.action(async (options, command) => {
|
|
7440
|
+
try {
|
|
7441
|
+
const globalOptions = command.parent.opts();
|
|
7442
|
+
const config = loadConfig(globalOptions.config);
|
|
7443
|
+
validateConfiguration(config);
|
|
7444
|
+
|
|
7445
|
+
const api = new ToothFairyAPI(
|
|
7446
|
+
config.baseUrl,
|
|
7447
|
+
config.aiUrl,
|
|
7448
|
+
config.aiStreamUrl,
|
|
7449
|
+
config.apiKey,
|
|
7450
|
+
config.workspaceId,
|
|
7451
|
+
globalOptions.verbose || options.verbose
|
|
7452
|
+
);
|
|
7453
|
+
|
|
7454
|
+
const spinner = ora('Fetching connections...').start();
|
|
7455
|
+
const result = await api.listConnections(
|
|
7456
|
+
parseInt(options.limit),
|
|
7457
|
+
parseInt(options.offset)
|
|
7458
|
+
);
|
|
7459
|
+
spinner.stop();
|
|
7460
|
+
|
|
7461
|
+
if (options.output === 'json') {
|
|
7462
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7463
|
+
} else {
|
|
7464
|
+
const connections = Array.isArray(result) ? result : result.items || [];
|
|
7465
|
+
console.log(chalk.green.bold(`Found ${connections.length} connection(s)`));
|
|
7466
|
+
connections.forEach(conn => {
|
|
7467
|
+
console.log(chalk.cyan(` • ${conn.name || 'Unnamed'} (${conn.id})`));
|
|
7468
|
+
});
|
|
7469
|
+
}
|
|
7470
|
+
} catch (error) {
|
|
7471
|
+
console.error(chalk.red(`Error listing connections: ${error.message}`));
|
|
7472
|
+
process.exit(1);
|
|
7473
|
+
}
|
|
7474
|
+
});
|
|
7475
|
+
|
|
7476
|
+
program
|
|
7477
|
+
.command('get-connection')
|
|
7478
|
+
.description('Get details of a specific connection')
|
|
7479
|
+
.argument('<id>', 'Connection ID')
|
|
7480
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7481
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7482
|
+
.action(async (connectionId, options, command) => {
|
|
7483
|
+
try {
|
|
7484
|
+
const globalOptions = command.parent.opts();
|
|
7485
|
+
const config = loadConfig(globalOptions.config);
|
|
7486
|
+
validateConfiguration(config);
|
|
7487
|
+
|
|
7488
|
+
const api = new ToothFairyAPI(
|
|
7489
|
+
config.baseUrl,
|
|
7490
|
+
config.aiUrl,
|
|
7491
|
+
config.aiStreamUrl,
|
|
7492
|
+
config.apiKey,
|
|
7493
|
+
config.workspaceId,
|
|
7494
|
+
globalOptions.verbose || options.verbose
|
|
7495
|
+
);
|
|
7496
|
+
|
|
7497
|
+
const spinner = ora('Fetching connection...').start();
|
|
7498
|
+
const result = await api.getConnection(connectionId);
|
|
7499
|
+
spinner.stop();
|
|
7500
|
+
|
|
7501
|
+
if (options.output === 'json') {
|
|
7502
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7503
|
+
} else {
|
|
7504
|
+
console.log(chalk.green.bold('Connection Details'));
|
|
7505
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7506
|
+
console.log(chalk.dim(`Name: ${result.name || 'N/A'}`));
|
|
7507
|
+
console.log(chalk.dim(`Type: ${result.type || 'N/A'}`));
|
|
7508
|
+
console.log(chalk.dim(`Host: ${result.host || 'N/A'}`));
|
|
7509
|
+
}
|
|
7510
|
+
} catch (error) {
|
|
7511
|
+
console.error(chalk.red(`Error getting connection: ${error.message}`));
|
|
7512
|
+
process.exit(1);
|
|
7513
|
+
}
|
|
7514
|
+
});
|
|
7515
|
+
|
|
7516
|
+
program
|
|
7517
|
+
.command('delete-connection')
|
|
7518
|
+
.description('Delete a connection')
|
|
7519
|
+
.argument('<id>', 'Connection ID')
|
|
7520
|
+
.option('--confirm', 'Skip confirmation prompt')
|
|
7521
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7522
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7523
|
+
.action(async (connectionId, options, command) => {
|
|
7524
|
+
try {
|
|
7525
|
+
const globalOptions = command.parent.opts();
|
|
7526
|
+
const config = loadConfig(globalOptions.config);
|
|
7527
|
+
validateConfiguration(config);
|
|
7528
|
+
|
|
7529
|
+
const api = new ToothFairyAPI(
|
|
7530
|
+
config.baseUrl,
|
|
7531
|
+
config.aiUrl,
|
|
7532
|
+
config.aiStreamUrl,
|
|
7533
|
+
config.apiKey,
|
|
7534
|
+
config.workspaceId,
|
|
7535
|
+
globalOptions.verbose || options.verbose
|
|
7536
|
+
);
|
|
7537
|
+
|
|
7538
|
+
if (!options.confirm) {
|
|
7539
|
+
const readline = require('readline');
|
|
7540
|
+
const rl = readline.createInterface({
|
|
7541
|
+
input: process.stdin,
|
|
7542
|
+
output: process.stdout,
|
|
7543
|
+
});
|
|
7544
|
+
|
|
7545
|
+
const answer = await new Promise((resolve) => {
|
|
7546
|
+
rl.question(
|
|
7547
|
+
chalk.yellow(
|
|
7548
|
+
`⚠️ Are you sure you want to delete connection ${connectionId}? (y/N): `
|
|
7549
|
+
),
|
|
7550
|
+
resolve
|
|
7551
|
+
);
|
|
7552
|
+
});
|
|
7553
|
+
|
|
7554
|
+
rl.close();
|
|
7555
|
+
|
|
7556
|
+
if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {
|
|
7557
|
+
console.log(chalk.gray('Deletion cancelled.'));
|
|
7558
|
+
process.exit(0);
|
|
7559
|
+
}
|
|
7560
|
+
}
|
|
7561
|
+
|
|
7562
|
+
const spinner = ora('Deleting connection...').start();
|
|
7563
|
+
const result = await api.deleteConnection(connectionId);
|
|
7564
|
+
spinner.stop();
|
|
7565
|
+
|
|
7566
|
+
if (options.output === 'json') {
|
|
7567
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7568
|
+
} else {
|
|
7569
|
+
console.log(chalk.green.bold('✅ Connection deleted successfully!'));
|
|
7570
|
+
}
|
|
7571
|
+
} catch (error) {
|
|
7572
|
+
console.error(chalk.red(`Error deleting connection: ${error.message}`));
|
|
7573
|
+
process.exit(1);
|
|
7574
|
+
}
|
|
7575
|
+
});
|
|
7576
|
+
|
|
7577
|
+
// Dictionary Management Commands
|
|
7578
|
+
program
|
|
7579
|
+
.command('list-dictionaries')
|
|
7580
|
+
.description('List all dictionary entries')
|
|
7581
|
+
.option('--limit <number>', 'Maximum number to return', '50')
|
|
7582
|
+
.option('--offset <number>', 'Number to skip', '0')
|
|
7583
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7584
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7585
|
+
.action(async (options, command) => {
|
|
7586
|
+
try {
|
|
7587
|
+
const globalOptions = command.parent.opts();
|
|
7588
|
+
const config = loadConfig(globalOptions.config);
|
|
7589
|
+
validateConfiguration(config);
|
|
7590
|
+
|
|
7591
|
+
const api = new ToothFairyAPI(
|
|
7592
|
+
config.baseUrl,
|
|
7593
|
+
config.aiUrl,
|
|
7594
|
+
config.aiStreamUrl,
|
|
7595
|
+
config.apiKey,
|
|
7596
|
+
config.workspaceId,
|
|
7597
|
+
globalOptions.verbose || options.verbose
|
|
7598
|
+
);
|
|
7599
|
+
|
|
7600
|
+
const spinner = ora('Fetching dictionary entries...').start();
|
|
7601
|
+
const result = await api.listDictionaries(
|
|
7602
|
+
parseInt(options.limit),
|
|
7603
|
+
parseInt(options.offset)
|
|
7604
|
+
);
|
|
7605
|
+
spinner.stop();
|
|
7606
|
+
|
|
7607
|
+
if (options.output === 'json') {
|
|
7608
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7609
|
+
} else {
|
|
7610
|
+
const dicts = Array.isArray(result) ? result : result.items || [];
|
|
7611
|
+
console.log(chalk.green.bold(`Found ${dicts.length} dictionary entr(y/ies)`));
|
|
7612
|
+
dicts.forEach(dict => {
|
|
7613
|
+
console.log(chalk.cyan(` • ${dict.sourceText || 'N/A'} → ${dict.targetText || 'N/A'} (${dict.id})`));
|
|
7614
|
+
});
|
|
7615
|
+
}
|
|
7616
|
+
} catch (error) {
|
|
7617
|
+
console.error(chalk.red(`Error listing dictionaries: ${error.message}`));
|
|
7618
|
+
process.exit(1);
|
|
7619
|
+
}
|
|
7620
|
+
});
|
|
7621
|
+
|
|
7622
|
+
program
|
|
7623
|
+
.command('get-dictionary')
|
|
7624
|
+
.description('Get details of a specific dictionary entry')
|
|
7625
|
+
.argument('<id>', 'Dictionary entry ID')
|
|
7626
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7627
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7628
|
+
.action(async (dictionaryId, options, command) => {
|
|
7629
|
+
try {
|
|
7630
|
+
const globalOptions = command.parent.opts();
|
|
7631
|
+
const config = loadConfig(globalOptions.config);
|
|
7632
|
+
validateConfiguration(config);
|
|
7633
|
+
|
|
7634
|
+
const api = new ToothFairyAPI(
|
|
7635
|
+
config.baseUrl,
|
|
7636
|
+
config.aiUrl,
|
|
7637
|
+
config.aiStreamUrl,
|
|
7638
|
+
config.apiKey,
|
|
7639
|
+
config.workspaceId,
|
|
7640
|
+
globalOptions.verbose || options.verbose
|
|
7641
|
+
);
|
|
7642
|
+
|
|
7643
|
+
const spinner = ora('Fetching dictionary entry...').start();
|
|
7644
|
+
const result = await api.getDictionary(dictionaryId);
|
|
7645
|
+
spinner.stop();
|
|
7646
|
+
|
|
7647
|
+
if (options.output === 'json') {
|
|
7648
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7649
|
+
} else {
|
|
7650
|
+
console.log(chalk.green.bold('Dictionary Entry Details'));
|
|
7651
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7652
|
+
console.log(chalk.dim(`Source: ${result.sourceText || 'N/A'}`));
|
|
7653
|
+
console.log(chalk.dim(`Target: ${result.targetText || 'N/A'}`));
|
|
7654
|
+
console.log(chalk.dim(`Source Language: ${result.sourceLanguage || 'N/A'}`));
|
|
7655
|
+
console.log(chalk.dim(`Target Language: ${result.targetLanguage || 'N/A'}`));
|
|
7656
|
+
}
|
|
7657
|
+
} catch (error) {
|
|
7658
|
+
console.error(chalk.red(`Error getting dictionary entry: ${error.message}`));
|
|
7659
|
+
process.exit(1);
|
|
7660
|
+
}
|
|
7661
|
+
});
|
|
7662
|
+
|
|
7663
|
+
// Embedding Management Commands
|
|
7664
|
+
program
|
|
7665
|
+
.command('get-embedding')
|
|
7666
|
+
.description('Get details of a specific embedding')
|
|
7667
|
+
.argument('<id>', 'Embedding ID')
|
|
7668
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7669
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7670
|
+
.action(async (embeddingId, options, command) => {
|
|
7671
|
+
try {
|
|
7672
|
+
const globalOptions = command.parent.opts();
|
|
7673
|
+
const config = loadConfig(globalOptions.config);
|
|
7674
|
+
validateConfiguration(config);
|
|
7675
|
+
|
|
7676
|
+
const api = new ToothFairyAPI(
|
|
7677
|
+
config.baseUrl,
|
|
7678
|
+
config.aiUrl,
|
|
7679
|
+
config.aiStreamUrl,
|
|
7680
|
+
config.apiKey,
|
|
7681
|
+
config.workspaceId,
|
|
7682
|
+
globalOptions.verbose || options.verbose
|
|
7683
|
+
);
|
|
7684
|
+
|
|
7685
|
+
const spinner = ora('Fetching embedding...').start();
|
|
7686
|
+
const result = await api.getEmbedding(embeddingId);
|
|
7687
|
+
spinner.stop();
|
|
7688
|
+
|
|
7689
|
+
if (options.output === 'json') {
|
|
7690
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7691
|
+
} else {
|
|
7692
|
+
console.log(chalk.green.bold('Embedding Details'));
|
|
7693
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7694
|
+
console.log(chalk.dim(`Chunk ID: ${result.chunk_id || 'N/A'}`));
|
|
7695
|
+
console.log(chalk.dim(`Title: ${result.title || 'N/A'}`));
|
|
7696
|
+
}
|
|
7697
|
+
} catch (error) {
|
|
7698
|
+
console.error(chalk.red(`Error getting embedding: ${error.message}`));
|
|
7699
|
+
process.exit(1);
|
|
7700
|
+
}
|
|
7701
|
+
});
|
|
7702
|
+
|
|
7703
|
+
// Settings Management Commands
|
|
7704
|
+
program
|
|
7705
|
+
.command('get-charting-settings')
|
|
7706
|
+
.description('Get charting settings for the workspace')
|
|
7707
|
+
.argument('<id>', 'Settings ID')
|
|
7708
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7709
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7710
|
+
.action(async (settingsId, options, command) => {
|
|
7711
|
+
try {
|
|
7712
|
+
const globalOptions = command.parent.opts();
|
|
7713
|
+
const config = loadConfig(globalOptions.config);
|
|
7714
|
+
validateConfiguration(config);
|
|
7715
|
+
|
|
7716
|
+
const api = new ToothFairyAPI(
|
|
7717
|
+
config.baseUrl,
|
|
7718
|
+
config.aiUrl,
|
|
7719
|
+
config.aiStreamUrl,
|
|
7720
|
+
config.apiKey,
|
|
7721
|
+
config.workspaceId,
|
|
7722
|
+
globalOptions.verbose || options.verbose
|
|
7723
|
+
);
|
|
7724
|
+
|
|
7725
|
+
const spinner = ora('Fetching charting settings...').start();
|
|
7726
|
+
const result = await api.getChartingSettings(settingsId);
|
|
7727
|
+
spinner.stop();
|
|
7728
|
+
|
|
7729
|
+
if (options.output === 'json') {
|
|
7730
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7731
|
+
} else {
|
|
7732
|
+
console.log(chalk.green.bold('Charting Settings'));
|
|
7733
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7734
|
+
console.log(chalk.dim(`Primary Color: ${result.primaryColor || 'N/A'}`));
|
|
7735
|
+
console.log(chalk.dim(`Secondary Color: ${result.secondaryColor || 'N/A'}`));
|
|
7736
|
+
}
|
|
7737
|
+
} catch (error) {
|
|
7738
|
+
console.error(chalk.red(`Error getting charting settings: ${error.message}`));
|
|
7739
|
+
process.exit(1);
|
|
7740
|
+
}
|
|
7741
|
+
});
|
|
7742
|
+
|
|
7743
|
+
program
|
|
7744
|
+
.command('update-charting-settings')
|
|
7745
|
+
.description('Update charting settings for the workspace')
|
|
7746
|
+
.argument('<id>', 'Settings ID')
|
|
7747
|
+
.option('--config <config>', 'Settings configuration (JSON)')
|
|
7748
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7749
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7750
|
+
.action(async (settingsId, options, command) => {
|
|
7751
|
+
try {
|
|
7752
|
+
const globalOptions = command.parent.opts();
|
|
7753
|
+
const config = loadConfig(globalOptions.config);
|
|
7754
|
+
validateConfiguration(config);
|
|
7755
|
+
|
|
7756
|
+
const api = new ToothFairyAPI(
|
|
7757
|
+
config.baseUrl,
|
|
7758
|
+
config.aiUrl,
|
|
7759
|
+
config.aiStreamUrl,
|
|
7760
|
+
config.apiKey,
|
|
7761
|
+
config.workspaceId,
|
|
7762
|
+
globalOptions.verbose || options.verbose
|
|
7763
|
+
);
|
|
7764
|
+
|
|
7765
|
+
let settingsConfig = {};
|
|
7766
|
+
if (options.config) {
|
|
7767
|
+
try {
|
|
7768
|
+
settingsConfig = JSON.parse(options.config);
|
|
7769
|
+
} catch (e) {
|
|
7770
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
7771
|
+
process.exit(1);
|
|
7772
|
+
}
|
|
7773
|
+
}
|
|
7774
|
+
|
|
7775
|
+
const spinner = ora('Updating charting settings...').start();
|
|
7776
|
+
const result = await api.updateChartingSettings({
|
|
7777
|
+
id: settingsId,
|
|
7778
|
+
...settingsConfig,
|
|
7779
|
+
});
|
|
7780
|
+
spinner.stop();
|
|
7781
|
+
|
|
7782
|
+
if (options.output === 'json') {
|
|
7783
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7784
|
+
} else {
|
|
7785
|
+
console.log(chalk.green.bold('✅ Charting settings updated successfully!'));
|
|
7786
|
+
}
|
|
7787
|
+
} catch (error) {
|
|
7788
|
+
console.error(chalk.red(`Error updating charting settings: ${error.message}`));
|
|
7789
|
+
process.exit(1);
|
|
7790
|
+
}
|
|
7791
|
+
});
|
|
7792
|
+
|
|
7793
|
+
program
|
|
7794
|
+
.command('get-embeddings-settings')
|
|
7795
|
+
.description('Get embeddings settings for the workspace')
|
|
7796
|
+
.argument('<id>', 'Settings ID')
|
|
7797
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7798
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7799
|
+
.action(async (settingsId, options, command) => {
|
|
7800
|
+
try {
|
|
7801
|
+
const globalOptions = command.parent.opts();
|
|
7802
|
+
const config = loadConfig(globalOptions.config);
|
|
7803
|
+
validateConfiguration(config);
|
|
7804
|
+
|
|
7805
|
+
const api = new ToothFairyAPI(
|
|
7806
|
+
config.baseUrl,
|
|
7807
|
+
config.aiUrl,
|
|
7808
|
+
config.aiStreamUrl,
|
|
7809
|
+
config.apiKey,
|
|
7810
|
+
config.workspaceId,
|
|
7811
|
+
globalOptions.verbose || options.verbose
|
|
7812
|
+
);
|
|
7813
|
+
|
|
7814
|
+
const spinner = ora('Fetching embeddings settings...').start();
|
|
7815
|
+
const result = await api.getEmbeddingsSettings(settingsId);
|
|
7816
|
+
spinner.stop();
|
|
7817
|
+
|
|
7818
|
+
if (options.output === 'json') {
|
|
7819
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7820
|
+
} else {
|
|
7821
|
+
console.log(chalk.green.bold('Embeddings Settings'));
|
|
7822
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7823
|
+
console.log(chalk.dim(`Max Chunk Words: ${result.maxChunkWords || 'N/A'}`));
|
|
7824
|
+
console.log(chalk.dim(`Chunking Strategy: ${result.chunkingStrategy || 'N/A'}`));
|
|
7825
|
+
}
|
|
7826
|
+
} catch (error) {
|
|
7827
|
+
console.error(chalk.red(`Error getting embeddings settings: ${error.message}`));
|
|
7828
|
+
process.exit(1);
|
|
7829
|
+
}
|
|
7830
|
+
});
|
|
7831
|
+
|
|
7832
|
+
program
|
|
7833
|
+
.command('update-embeddings-settings')
|
|
7834
|
+
.description('Update embeddings settings for the workspace')
|
|
7835
|
+
.argument('<id>', 'Settings ID')
|
|
7836
|
+
.option('--config <config>', 'Settings configuration (JSON)')
|
|
7837
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7838
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7839
|
+
.action(async (settingsId, options, command) => {
|
|
7840
|
+
try {
|
|
7841
|
+
const globalOptions = command.parent.opts();
|
|
7842
|
+
const config = loadConfig(globalOptions.config);
|
|
7843
|
+
validateConfiguration(config);
|
|
7844
|
+
|
|
7845
|
+
const api = new ToothFairyAPI(
|
|
7846
|
+
config.baseUrl,
|
|
7847
|
+
config.aiUrl,
|
|
7848
|
+
config.aiStreamUrl,
|
|
7849
|
+
config.apiKey,
|
|
7850
|
+
config.workspaceId,
|
|
7851
|
+
globalOptions.verbose || options.verbose
|
|
7852
|
+
);
|
|
7853
|
+
|
|
7854
|
+
let settingsConfig = {};
|
|
7855
|
+
if (options.config) {
|
|
7856
|
+
try {
|
|
7857
|
+
settingsConfig = JSON.parse(options.config);
|
|
7858
|
+
} catch (e) {
|
|
7859
|
+
console.error(chalk.red('Invalid JSON in config'));
|
|
7860
|
+
process.exit(1);
|
|
7861
|
+
}
|
|
7862
|
+
}
|
|
7863
|
+
|
|
7864
|
+
const spinner = ora('Updating embeddings settings...').start();
|
|
7865
|
+
const result = await api.updateEmbeddingsSettings({
|
|
7866
|
+
id: settingsId,
|
|
7867
|
+
...settingsConfig,
|
|
7868
|
+
});
|
|
7869
|
+
spinner.stop();
|
|
7870
|
+
|
|
7871
|
+
if (options.output === 'json') {
|
|
7872
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7873
|
+
} else {
|
|
7874
|
+
console.log(chalk.green.bold('✅ Embeddings settings updated successfully!'));
|
|
7875
|
+
}
|
|
7876
|
+
} catch (error) {
|
|
7877
|
+
console.error(chalk.red(`Error updating embeddings settings: ${error.message}`));
|
|
7878
|
+
process.exit(1);
|
|
7879
|
+
}
|
|
7880
|
+
});
|
|
7881
|
+
|
|
7882
|
+
// Stream Management Commands
|
|
7883
|
+
program
|
|
7884
|
+
.command('list-streams')
|
|
7885
|
+
.description('List all streams')
|
|
7886
|
+
.option('--limit <number>', 'Maximum number to return', '50')
|
|
7887
|
+
.option('--offset <number>', 'Number to skip', '0')
|
|
7888
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7889
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7890
|
+
.action(async (options, command) => {
|
|
7891
|
+
try {
|
|
7892
|
+
const globalOptions = command.parent.opts();
|
|
7893
|
+
const config = loadConfig(globalOptions.config);
|
|
7894
|
+
validateConfiguration(config);
|
|
7895
|
+
|
|
7896
|
+
const api = new ToothFairyAPI(
|
|
7897
|
+
config.baseUrl,
|
|
7898
|
+
config.aiUrl,
|
|
7899
|
+
config.aiStreamUrl,
|
|
7900
|
+
config.apiKey,
|
|
7901
|
+
config.workspaceId,
|
|
7902
|
+
globalOptions.verbose || options.verbose
|
|
7903
|
+
);
|
|
7904
|
+
|
|
7905
|
+
const spinner = ora('Fetching streams...').start();
|
|
7906
|
+
const result = await api.listStreams(
|
|
7907
|
+
parseInt(options.limit),
|
|
7908
|
+
parseInt(options.offset)
|
|
7909
|
+
);
|
|
7910
|
+
spinner.stop();
|
|
7911
|
+
|
|
7912
|
+
if (options.output === 'json') {
|
|
7913
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7914
|
+
} else {
|
|
7915
|
+
const streams = Array.isArray(result) ? result : result.items || [];
|
|
7916
|
+
console.log(chalk.green.bold(`Found ${streams.length} stream(s)`));
|
|
7917
|
+
streams.forEach(stream => {
|
|
7918
|
+
console.log(chalk.cyan(` • ${stream.id}`));
|
|
7919
|
+
});
|
|
7920
|
+
}
|
|
7921
|
+
} catch (error) {
|
|
7922
|
+
console.error(chalk.red(`Error listing streams: ${error.message}`));
|
|
7923
|
+
process.exit(1);
|
|
7924
|
+
}
|
|
7925
|
+
});
|
|
7926
|
+
|
|
7927
|
+
program
|
|
7928
|
+
.command('get-stream')
|
|
7929
|
+
.description('Get details of a specific stream')
|
|
7930
|
+
.argument('<id>', 'Stream ID')
|
|
7931
|
+
.option('-o, --output <format>', 'Output format (json|text)', 'text')
|
|
7932
|
+
.option('-v, --verbose', 'Show detailed information')
|
|
7933
|
+
.action(async (streamId, options, command) => {
|
|
7934
|
+
try {
|
|
7935
|
+
const globalOptions = command.parent.opts();
|
|
7936
|
+
const config = loadConfig(globalOptions.config);
|
|
7937
|
+
validateConfiguration(config);
|
|
7938
|
+
|
|
7939
|
+
const api = new ToothFairyAPI(
|
|
7940
|
+
config.baseUrl,
|
|
7941
|
+
config.aiUrl,
|
|
7942
|
+
config.aiStreamUrl,
|
|
7943
|
+
config.apiKey,
|
|
7944
|
+
config.workspaceId,
|
|
7945
|
+
globalOptions.verbose || options.verbose
|
|
7946
|
+
);
|
|
7947
|
+
|
|
7948
|
+
const spinner = ora('Fetching stream...').start();
|
|
7949
|
+
const result = await api.getStream(streamId);
|
|
7950
|
+
spinner.stop();
|
|
7951
|
+
|
|
7952
|
+
if (options.output === 'json') {
|
|
7953
|
+
console.log(JSON.stringify(result, null, 2));
|
|
7954
|
+
} else {
|
|
7955
|
+
console.log(chalk.green.bold('Stream Details'));
|
|
7956
|
+
console.log(chalk.dim(`ID: ${result.id}`));
|
|
7957
|
+
console.log(chalk.dim(`Type: ${result.type || 'N/A'}`));
|
|
7958
|
+
console.log(chalk.dim(`Status: ${result.status || 'N/A'}`));
|
|
7959
|
+
}
|
|
7960
|
+
} catch (error) {
|
|
7961
|
+
console.error(chalk.red(`Error getting stream: ${error.message}`));
|
|
7962
|
+
process.exit(1);
|
|
7963
|
+
}
|
|
7964
|
+
});
|
|
7965
|
+
|
|
3954
7966
|
// Parse command line arguments
|
|
3955
7967
|
program.parse();
|