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/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://api.hiresquireai.com/api/v1',
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
- config.apiToken = config.apiToken || fileConfig.apiToken || '';
85
- config.baseUrl = config.baseUrl || fileConfig.baseUrl || config.baseUrl;
86
- config.webhookUrl = config.webhookUrl || fileConfig.webhookUrl;
87
- config.defaultLeniency = config.defaultLeniency || fileConfig.defaultLeniency || 5;
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;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
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=strict, 10=loose)', '5')
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
- console.log(chalk_1.default.blue('\n⏳ Waiting for completion...\n'));
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 bar = '█'.repeat(Math.floor(progress / 10)) + '░'.repeat(10 - Math.floor(progress / 10));
282
- process.stdout.write(`\r Progress: [${bar}] ${progress}% ${status.message || ''}`);
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: result.candidates,
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
- console.log(chalk_1.default.blue('⏳ Watching for status changes...\n'));
437
- const finalStatus = await api.pollForCompletion(jobId, {
438
- onProgress: (status) => {
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 bar = '█'.repeat(Math.floor(progress / 10)) + '░'.repeat(10 - Math.floor(progress / 10));
441
- console.clear();
442
- console.log(chalk_1.default.blue(`📋 Job #${jobId}\n`));
443
- console.log(chalk_1.default.gray(` Status: ${chalk_1.default.bold(status.status)}`));
444
- console.log(chalk_1.default.gray(` Progress: [${bar}] ${progress}%`));
445
- if (status.message) {
446
- console.log(chalk_1.default.gray(` Message: ${status.message}`));
447
- }
448
- },
449
- });
450
- console.log(chalk_1.default.green(`\n✓ Job ${finalStatus.status}!`));
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,jobs,emails,credits,agent-keys)')
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 pack = options.pack || 'pouch';
1032
- if (!['pouch', 'satchel', 'chest'].includes(pack)) {
1033
- throw new Error('Invalid pack. Use: pouch, satchel, or chest');
1199
+ const requestData = {};
1200
+ if (options.pack) {
1201
+ requestData.pack = options.pack;
1034
1202
  }
1035
- const response = await api.post('/credits/checkout-session', {
1036
- pack: pack,
1037
- success_url: 'https://hiresquireai.com/credits/success',
1038
- cancel_url: 'https://hiresquireai.com/credits/cancel',
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(response.data);
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
- console.log(` Pack: ${pack}`);
1046
- console.log(chalk_1.default.cyan(` Checkout URL: ${response.data.checkout_url}`));
1047
- console.log(chalk_1.default.gray(' Open this URL in your browser to complete payment.'));
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.1');
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) {