hiresquire-cli 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +134 -3
- package/dist/api.d.ts +17 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +83 -37
- package/dist/api.js.map +1 -1
- package/dist/config.js +7 -5
- package/dist/config.js.map +1 -1
- package/dist/index.js +229 -44
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +5 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +6 -7
package/dist/config.js
CHANGED
|
@@ -74,17 +74,19 @@ class ConfigManager {
|
|
|
74
74
|
// Priority: 1. Environment variables, 2. Config file, 3. Default
|
|
75
75
|
const config = {
|
|
76
76
|
apiToken: process.env[ENV_TOKEN] || '',
|
|
77
|
-
baseUrl: process.env[ENV_BASE_URL] || 'https://
|
|
77
|
+
baseUrl: process.env[ENV_BASE_URL] || 'https://hiresquireai.com/api/v1',
|
|
78
78
|
webhookUrl: process.env[ENV_WEBHOOK_URL] || undefined,
|
|
79
79
|
defaultLeniency: 5,
|
|
80
80
|
};
|
|
81
81
|
// Load from file if exists
|
|
82
82
|
const fileConfig = this.loadFromFile();
|
|
83
83
|
if (fileConfig) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
if (!process.env[ENV_TOKEN])
|
|
85
|
+
config.apiToken = fileConfig.apiToken || '';
|
|
86
|
+
if (!process.env[ENV_BASE_URL])
|
|
87
|
+
config.baseUrl = fileConfig.baseUrl || config.baseUrl;
|
|
88
|
+
config.webhookUrl = fileConfig.webhookUrl || config.webhookUrl;
|
|
89
|
+
config.defaultLeniency = fileConfig.defaultLeniency || 5;
|
|
88
90
|
}
|
|
89
91
|
this.config = config;
|
|
90
92
|
return config;
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8JH,4CAKC;AAKD,8BAEC;AAKD,gCAEC;AA/KD,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AAGzB,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,gBAAgB,GAAG,aAAa,CAAC;AACvC,MAAM,SAAS,GAAG,sBAAsB,CAAC;AACzC,MAAM,YAAY,GAAG,qBAAqB,CAAC;AAC3C,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD,+EAA+E;AAC/E,8BAA8B;AAC9B,+EAA+E;AAE/E,MAAa,aAAa;IAItB,YAAY,UAAmB;QAFvB,WAAM,GAAkB,IAAI,CAAC;QAGjC,MAAM,SAAS,GAAG,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;QACvE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC7D,CAAC;IAED,+EAA+E;IAC/E,iBAAiB;IACjB,+EAA+E;IAE/E;;OAEG;IACH,IAAI;QACA,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,MAAM,CAAC;QACvB,CAAC;QAED,iEAAiE;QACjE,MAAM,MAAM,GAAW;YACnB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE;YACtC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -97,6 +97,21 @@ function handleError(error, context = 'Operation failed') {
|
|
|
97
97
|
}
|
|
98
98
|
process.exit(1);
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Output ASCII Logo
|
|
102
|
+
*/
|
|
103
|
+
function showLogo() {
|
|
104
|
+
if (isJsonOutput || !process.stdout.isTTY)
|
|
105
|
+
return;
|
|
106
|
+
console.log(chalk_1.default.hex('#6ee7b7').bold(`
|
|
107
|
+
_ _ _ ____ _
|
|
108
|
+
| | | |(_) _ __ ___ / ___| __ _ _ _ (_) _ __ ___
|
|
109
|
+
| |_| || || '__|/ _ \\ \\___ \\ / _\` | | | || || '__|/ _ \\
|
|
110
|
+
| _ || || | | __/ ___) | (_| | |_| || || | | __/
|
|
111
|
+
|_| |_||_||_| \\___| |____/ \\__, |\\__,_||_||_| \\___|
|
|
112
|
+
|_|
|
|
113
|
+
`));
|
|
114
|
+
}
|
|
100
115
|
/**
|
|
101
116
|
* Confirm action
|
|
102
117
|
*/
|
|
@@ -168,9 +183,10 @@ program
|
|
|
168
183
|
.requiredOption('-d, --description <description>', 'Job description (string or @file)')
|
|
169
184
|
.option('-r, --resumes <paths>', 'Resume files or directory (comma-separated or @file)')
|
|
170
185
|
.option('-z, --zip <path>', 'Path to a ZIP file containing resumes (overrides --resumes)')
|
|
171
|
-
.option('-l, --leniency <1-10>', 'Screening leniency level (1=
|
|
186
|
+
.option('-l, --leniency <1-10>', 'Screening leniency level (1=loose, 10=strict)', '5')
|
|
172
187
|
.option('-w, --webhook <url>', 'Webhook URL for notifications')
|
|
173
188
|
.option('--watch', 'Poll for completion and show results')
|
|
189
|
+
.option('--poll-timeout <seconds>', 'Maximum time to poll for completion in seconds', '300')
|
|
174
190
|
.option('--min-score <number>', 'Minimum score threshold for webhook notifications (0-100)')
|
|
175
191
|
.option('--only-top-n <number>', 'Only send top N candidates to webhook')
|
|
176
192
|
.action(async (options) => {
|
|
@@ -272,16 +288,22 @@ program
|
|
|
272
288
|
console.log(chalk_1.default.gray(` Poll: ${result.status_url}`));
|
|
273
289
|
// Watch mode
|
|
274
290
|
if (options.watch) {
|
|
291
|
+
const pollOptions = {};
|
|
275
292
|
if (!isJsonOutput) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const finalStatus = await api.pollForCompletion(result.job_id, {
|
|
279
|
-
onProgress: (status) => {
|
|
293
|
+
const pollSpinner = (0, ora_1.default)('Waiting for job completion...').start();
|
|
294
|
+
pollOptions.onProgress = (status) => {
|
|
280
295
|
const progress = status.progress || 0;
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
296
|
+
const barWidth = 20;
|
|
297
|
+
const filled = Math.floor((progress / 100) * barWidth);
|
|
298
|
+
const bar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
|
|
299
|
+
pollSpinner.text = `Waiting for job completion... [${bar}] ${progress}% ${status.message || ''}`;
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
// Convert seconds to milliseconds
|
|
303
|
+
if (options.pollTimeout) {
|
|
304
|
+
pollOptions.timeout = parseInt(options.pollTimeout) * 1000;
|
|
305
|
+
}
|
|
306
|
+
const finalStatus = await api.pollForCompletion(result.job_id, pollOptions);
|
|
285
307
|
if (!isJsonOutput) {
|
|
286
308
|
console.log(chalk_1.default.green(`\n✓ Screening complete!`));
|
|
287
309
|
console.log(chalk_1.default.blue(` Final status: ${chalk_1.default.bold(finalStatus.status)}`));
|
|
@@ -391,7 +413,9 @@ program
|
|
|
391
413
|
job_id: result.job_id,
|
|
392
414
|
job_title: result.job_title,
|
|
393
415
|
status: result.status,
|
|
394
|
-
results:
|
|
416
|
+
results: {
|
|
417
|
+
candidates: result.candidates
|
|
418
|
+
},
|
|
395
419
|
});
|
|
396
420
|
return;
|
|
397
421
|
}
|
|
@@ -417,14 +441,52 @@ program
|
|
|
417
441
|
handleError(error, 'Failed to fetch results');
|
|
418
442
|
}
|
|
419
443
|
});
|
|
444
|
+
/**
|
|
445
|
+
* Summary command - Get agent-to-human summary
|
|
446
|
+
*/
|
|
447
|
+
program
|
|
448
|
+
.command('summary')
|
|
449
|
+
.description('Get a human-readable summary of screening results')
|
|
450
|
+
.requiredOption('-j, --job <id>', 'Job ID')
|
|
451
|
+
.action(async (options) => {
|
|
452
|
+
try {
|
|
453
|
+
const api = initApi();
|
|
454
|
+
const jobId = parseInt(options.job);
|
|
455
|
+
if (isNaN(jobId)) {
|
|
456
|
+
throw new types_1.ValidationError('Invalid job ID');
|
|
457
|
+
}
|
|
458
|
+
const spinner = (0, ora_1.default)('Fetching summary...').start();
|
|
459
|
+
const result = await api.getResults(jobId);
|
|
460
|
+
spinner.stop();
|
|
461
|
+
if (isJsonOutput) {
|
|
462
|
+
outputJson({
|
|
463
|
+
success: true,
|
|
464
|
+
job_id: result.job_id,
|
|
465
|
+
summary: result.agent_summary,
|
|
466
|
+
});
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (!result.agent_summary) {
|
|
470
|
+
console.log(chalk_1.default.yellow('No summary available for this job.'));
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
console.log(chalk_1.default.blue(`🛡️ HireSquire Agent Report\n`));
|
|
474
|
+
console.log(result.agent_summary);
|
|
475
|
+
console.log();
|
|
476
|
+
}
|
|
477
|
+
catch (error) {
|
|
478
|
+
handleError(error, 'Failed to fetch summary');
|
|
479
|
+
}
|
|
480
|
+
});
|
|
420
481
|
/**
|
|
421
482
|
* Status command - Check job status
|
|
422
483
|
*/
|
|
423
484
|
program
|
|
424
485
|
.command('status')
|
|
425
|
-
.description('Check status of a screening job')
|
|
486
|
+
.description('Check the status of a screening job')
|
|
426
487
|
.requiredOption('-j, --job <id>', 'Job ID')
|
|
427
488
|
.option('-w, --watch', 'Watch for status changes')
|
|
489
|
+
.option('--poll-timeout <seconds>', 'Maximum time to poll for completion in seconds', '300')
|
|
428
490
|
.action(async (options) => {
|
|
429
491
|
try {
|
|
430
492
|
const api = initApi();
|
|
@@ -433,21 +495,33 @@ program
|
|
|
433
495
|
throw new types_1.ValidationError('Invalid job ID');
|
|
434
496
|
}
|
|
435
497
|
if (options.watch) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
498
|
+
const pollOptions = {};
|
|
499
|
+
if (!isJsonOutput) {
|
|
500
|
+
console.log(chalk_1.default.blue('\n⏳ Watching for status changes...\n'));
|
|
501
|
+
pollOptions.onProgress = (status) => {
|
|
439
502
|
const progress = status.progress || 0;
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
503
|
+
const barWidth = 20;
|
|
504
|
+
const filled = Math.floor((progress / 100) * barWidth);
|
|
505
|
+
const bar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
|
|
506
|
+
// Use process.stdout.write to update in-place if possible,
|
|
507
|
+
// or just log for simplicity in watch mode
|
|
508
|
+
process.stdout.write(`\r Status: ${chalk_1.default.bold(status.status)} | Progress: [${bar}] ${progress}% ${status.message || ''}`);
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
if (options.pollTimeout) {
|
|
512
|
+
pollOptions.timeout = parseInt(options.pollTimeout) * 1000;
|
|
513
|
+
}
|
|
514
|
+
const finalStatus = await api.pollForCompletion(jobId, pollOptions);
|
|
515
|
+
if (!isJsonOutput) {
|
|
516
|
+
console.log(chalk_1.default.green(`\n\n✓ Job ${finalStatus.status}!`));
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
outputJson({
|
|
520
|
+
success: true,
|
|
521
|
+
job_id: finalStatus.job_id,
|
|
522
|
+
status: finalStatus.status,
|
|
523
|
+
});
|
|
524
|
+
}
|
|
451
525
|
}
|
|
452
526
|
else {
|
|
453
527
|
const spinner = (0, ora_1.default)('Checking status...').start();
|
|
@@ -487,7 +561,7 @@ program
|
|
|
487
561
|
.description('Generate an email for a candidate')
|
|
488
562
|
.requiredOption('-j, --job <id>', 'Job ID')
|
|
489
563
|
.requiredOption('-c, --candidate <id>', 'Candidate ID')
|
|
490
|
-
.requiredOption('-t, --type <type>', 'Email type (invite, rejection, followup)')
|
|
564
|
+
.requiredOption('-t, --type <type>', 'Email type (invite, rejection, keep-warm, followup)')
|
|
491
565
|
.option('-m, --message <text>', 'Custom message to include')
|
|
492
566
|
.action(async (options) => {
|
|
493
567
|
try {
|
|
@@ -498,7 +572,7 @@ program
|
|
|
498
572
|
if (isNaN(jobId) || isNaN(candidateId)) {
|
|
499
573
|
throw new types_1.ValidationError('Invalid job or candidate ID');
|
|
500
574
|
}
|
|
501
|
-
const validTypes = ['invite', 'rejection', 'followup'];
|
|
575
|
+
const validTypes = ['invite', 'rejection', 'keep-warm', 'followup'];
|
|
502
576
|
if (!validTypes.includes(options.type)) {
|
|
503
577
|
throw new types_1.ValidationError(`Invalid email type. Must be: ${validTypes.join(', ')}`);
|
|
504
578
|
}
|
|
@@ -894,13 +968,13 @@ program
|
|
|
894
968
|
program
|
|
895
969
|
.command('agent-keys')
|
|
896
970
|
.description('Manage agent API keys')
|
|
897
|
-
.option('-a, --action <action>', 'Action: list, create, show, revoke', 'list')
|
|
971
|
+
.option('-a, --action <action>', 'Action: list, create, show, revoke, regenerate, update, usage', 'list')
|
|
898
972
|
.option('-n, --name <name>', 'Key name (for create)')
|
|
899
973
|
.option('-m, --monthly-limit <amount>', 'Monthly spend limit in dollars')
|
|
900
974
|
.option('-d, --daily-limit <amount>', 'Daily spend limit in dollars')
|
|
901
975
|
.option('-l, --lifetime-limit <amount>', 'Lifetime spend limit in dollars')
|
|
902
976
|
.option('-i, --id <id>', 'Key ID (for show/revoke)')
|
|
903
|
-
.option('-p, --permissions <perms>', 'Comma-separated permissions (read,
|
|
977
|
+
.option('-p, --permissions <perms>', 'Comma-separated permissions (read,write,screen,email,bulk)')
|
|
904
978
|
.action(async (options) => {
|
|
905
979
|
try {
|
|
906
980
|
const config = (0, config_1.getConfigManager)().load();
|
|
@@ -980,11 +1054,105 @@ program
|
|
|
980
1054
|
}
|
|
981
1055
|
console.log(chalk_1.default.green('✓ Agent API key revoked'));
|
|
982
1056
|
}
|
|
1057
|
+
else if (options.action === 'regenerate') {
|
|
1058
|
+
if (!options.id) {
|
|
1059
|
+
throw new Error('Key ID required. Use: --id <key_id>');
|
|
1060
|
+
}
|
|
1061
|
+
const response = await api.regenerateAgentKey(parseInt(options.id));
|
|
1062
|
+
if (isJsonOutput) {
|
|
1063
|
+
outputJson(response.data);
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
console.log(chalk_1.default.green('✓ Agent API key regenerated!'));
|
|
1067
|
+
console.log(chalk_1.default.yellow('⚠️ Save this new key - it will not be shown again:'));
|
|
1068
|
+
console.log(chalk_1.default.bold(response.data.key.key));
|
|
1069
|
+
}
|
|
1070
|
+
else if (options.action === 'update') {
|
|
1071
|
+
if (!options.id) {
|
|
1072
|
+
throw new Error('Key ID required. Use: --id <key_id>');
|
|
1073
|
+
}
|
|
1074
|
+
const response = await api.put(`/agent-keys/${options.id}`, {
|
|
1075
|
+
name: options.name,
|
|
1076
|
+
monthly_spend_limit: options.monthlyLimit ? parseFloat(options.monthlyLimit) : undefined,
|
|
1077
|
+
daily_spend_limit: options.dailyLimit ? parseFloat(options.dailyLimit) : undefined,
|
|
1078
|
+
lifetime_spend_limit: options.lifetimeLimit ? parseFloat(options.lifetimeLimit) : undefined,
|
|
1079
|
+
});
|
|
1080
|
+
if (isJsonOutput) {
|
|
1081
|
+
outputJson(response.data);
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
console.log(chalk_1.default.green('✓ Agent API key updated'));
|
|
1085
|
+
}
|
|
1086
|
+
else if (options.action === 'usage') {
|
|
1087
|
+
if (!options.id) {
|
|
1088
|
+
throw new Error('Key ID required. Use: --id <key_id>');
|
|
1089
|
+
}
|
|
1090
|
+
const response = await api.get(`/agent-keys/${options.id}/usage`);
|
|
1091
|
+
if (isJsonOutput) {
|
|
1092
|
+
outputJson(response.data);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
const usage = response.data.usage;
|
|
1096
|
+
console.log(chalk_1.default.blue(`📊 Usage for Key: ${chalk_1.default.bold(options.id)}\n`));
|
|
1097
|
+
console.log(` Daily Spent: ${chalk_1.default.green(`$${usage.day_spent.toFixed(2)}`)} / $${usage.daily_spend_limit || '∞'}`);
|
|
1098
|
+
console.log(` Monthly Spent: ${chalk_1.default.green(`$${usage.month_spent.toFixed(2)}`)} / $${usage.monthly_spend_limit || '∞'}`);
|
|
1099
|
+
console.log(` Total Spent: ${chalk_1.default.green(`$${usage.total_spent.toFixed(2)}`)} / $${usage.lifetime_spend_limit || '∞'}`);
|
|
1100
|
+
if (usage.remaining_daily !== null) {
|
|
1101
|
+
console.log(` Remaining Daily: ${chalk_1.default.cyan(`$${usage.remaining_daily.toFixed(2)}`)}`);
|
|
1102
|
+
}
|
|
1103
|
+
console.log(chalk_1.default.gray(`\n Billing Month Starts: ${usage.month_start_date}`));
|
|
1104
|
+
}
|
|
983
1105
|
}
|
|
984
1106
|
catch (error) {
|
|
985
1107
|
handleError(error, 'Failed to manage agent keys');
|
|
986
1108
|
}
|
|
987
1109
|
});
|
|
1110
|
+
/**
|
|
1111
|
+
* MCP command - Model Context Protocol bridge
|
|
1112
|
+
*/
|
|
1113
|
+
program
|
|
1114
|
+
.command('mcp')
|
|
1115
|
+
.description('Start MCP server bridge (Model Context Protocol)')
|
|
1116
|
+
.action(async () => {
|
|
1117
|
+
try {
|
|
1118
|
+
const api = initApi();
|
|
1119
|
+
const readline = require('readline');
|
|
1120
|
+
const rl = readline.createInterface({
|
|
1121
|
+
input: process.stdin,
|
|
1122
|
+
terminal: false
|
|
1123
|
+
});
|
|
1124
|
+
rl.on('line', async (line) => {
|
|
1125
|
+
if (!line.trim())
|
|
1126
|
+
return;
|
|
1127
|
+
try {
|
|
1128
|
+
const payload = JSON.parse(line);
|
|
1129
|
+
const response = await api.mcpProxy(payload);
|
|
1130
|
+
process.stdout.write(JSON.stringify(response) + '\n');
|
|
1131
|
+
}
|
|
1132
|
+
catch (e) {
|
|
1133
|
+
// Invalid JSON or API error - send JSON-RPC error back if possible
|
|
1134
|
+
const errorResponse = {
|
|
1135
|
+
jsonrpc: '2.0',
|
|
1136
|
+
error: {
|
|
1137
|
+
code: -32700,
|
|
1138
|
+
message: 'Parse error or proxy failure',
|
|
1139
|
+
data: e instanceof Error ? e.message : String(e)
|
|
1140
|
+
},
|
|
1141
|
+
id: null
|
|
1142
|
+
};
|
|
1143
|
+
process.stdout.write(JSON.stringify(errorResponse) + '\n');
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
// Handle process signals for graceful exit
|
|
1147
|
+
process.on('SIGINT', () => {
|
|
1148
|
+
rl.close();
|
|
1149
|
+
process.exit(0);
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
catch (error) {
|
|
1153
|
+
handleError(error, 'MCP bridge failed to start');
|
|
1154
|
+
}
|
|
1155
|
+
});
|
|
988
1156
|
/**
|
|
989
1157
|
* Credits command - Manage prepaid credits
|
|
990
1158
|
*/
|
|
@@ -1028,23 +1196,37 @@ program
|
|
|
1028
1196
|
});
|
|
1029
1197
|
}
|
|
1030
1198
|
else if (options.action === 'checkout') {
|
|
1031
|
-
const
|
|
1032
|
-
if (
|
|
1033
|
-
|
|
1199
|
+
const requestData = {};
|
|
1200
|
+
if (options.pack) {
|
|
1201
|
+
requestData.pack = options.pack;
|
|
1034
1202
|
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1203
|
+
else if (options.amount) {
|
|
1204
|
+
requestData.amount = parseFloat(options.amount);
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
// Default to pouch if nothing specified
|
|
1208
|
+
requestData.pack = 'pouch';
|
|
1209
|
+
}
|
|
1210
|
+
const response = await api.createCheckoutSession(requestData);
|
|
1040
1211
|
if (isJsonOutput) {
|
|
1041
|
-
outputJson(
|
|
1212
|
+
outputJson({
|
|
1213
|
+
success: true,
|
|
1214
|
+
checkout_url: response.checkout_url,
|
|
1215
|
+
amount: response.amount,
|
|
1216
|
+
expires_at: response.expires_at,
|
|
1217
|
+
});
|
|
1042
1218
|
return;
|
|
1043
1219
|
}
|
|
1044
1220
|
console.log(chalk_1.default.blue('🔗 Checkout Session Created\n'));
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1221
|
+
if (response.pack) {
|
|
1222
|
+
console.log(` Pack: ${chalk_1.default.bold(response.pack.name)} ($${response.pack.price})`);
|
|
1223
|
+
}
|
|
1224
|
+
else {
|
|
1225
|
+
console.log(` Amount: ${chalk_1.default.bold(`$${response.amount}`)}`);
|
|
1226
|
+
}
|
|
1227
|
+
console.log(chalk_1.default.cyan(`\n Payment Link: ${response.checkout_url}`));
|
|
1228
|
+
console.log(chalk_1.default.gray('\n Share this link with your manager or open it to complete payment.'));
|
|
1229
|
+
console.log(chalk_1.default.gray(` Link expires at: ${new Date(response.expires_at).toLocaleString()}`));
|
|
1048
1230
|
}
|
|
1049
1231
|
else if (options.action === 'transactions') {
|
|
1050
1232
|
const response = await api.get('/credits/transactions', {
|
|
@@ -1125,6 +1307,7 @@ program
|
|
|
1125
1307
|
.command('calendar:connect <provider>')
|
|
1126
1308
|
.description('Connect a calendar provider (calendly, calcom)')
|
|
1127
1309
|
.option('-t, --token <token>', 'API token/key for calendly/calcom')
|
|
1310
|
+
.option('--api-key <token>', 'API key for the provider (alias for --token)')
|
|
1128
1311
|
.option('-c, --calendar-id <id>', 'Calendar ID (optional)')
|
|
1129
1312
|
.action(async (provider, options) => {
|
|
1130
1313
|
try {
|
|
@@ -1134,8 +1317,8 @@ program
|
|
|
1134
1317
|
}
|
|
1135
1318
|
const api = initApi();
|
|
1136
1319
|
const params = { provider };
|
|
1137
|
-
if (options.token)
|
|
1138
|
-
params.api_key = options.token;
|
|
1320
|
+
if (options.token || options.apiKey)
|
|
1321
|
+
params.api_key = options.token || options.apiKey;
|
|
1139
1322
|
if (options.calendarId)
|
|
1140
1323
|
params.calendar_id = options.calendarId;
|
|
1141
1324
|
const spinner = !isJsonOutput ? (0, ora_1.default)('Connecting calendar...').start() : null;
|
|
@@ -1343,7 +1526,7 @@ program
|
|
|
1343
1526
|
program
|
|
1344
1527
|
.option('--json', 'Output as JSON')
|
|
1345
1528
|
.option('-v, --verbose', 'Enable verbose logging')
|
|
1346
|
-
.version('1.2.
|
|
1529
|
+
.version('1.2.2');
|
|
1347
1530
|
// ============================================================================
|
|
1348
1531
|
// Parse & Execute
|
|
1349
1532
|
// ============================================================================
|
|
@@ -1351,6 +1534,8 @@ program
|
|
|
1351
1534
|
if (process.argv.includes('--json')) {
|
|
1352
1535
|
isJsonOutput = true;
|
|
1353
1536
|
}
|
|
1537
|
+
// Show logo for interactive terminal users (unless JSON requested)
|
|
1538
|
+
showLogo();
|
|
1354
1539
|
// Show help if no command provided
|
|
1355
1540
|
const commandArgs = process.argv.slice(2).filter(arg => !arg.startsWith('-'));
|
|
1356
1541
|
if (commandArgs.length === 0) {
|