@startanaicompany/crm 2.11.0 → 2.13.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.
Files changed (2) hide show
  1. package/index.js +98 -2
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -411,6 +411,22 @@ keysCmd
411
411
  }
412
412
  });
413
413
 
414
+ keysCmd
415
+ .command('set-scope <key-id>')
416
+ .description('Set the scope of an API key (admin only, feature 98b01015)')
417
+ .requiredOption('--scope <scope>', 'Scope: admin, standard, or agent')
418
+ .action(async (keyId, opts) => {
419
+ const globalOpts = program.opts();
420
+ const client = getClient(globalOpts);
421
+ try {
422
+ const res = await client.patch(`/admin/keys/${keyId}/scope`, { scope: opts.scope });
423
+ console.log(`Key scope updated to: ${opts.scope}`);
424
+ printJSON(res.data);
425
+ } catch (err) {
426
+ handleError(err);
427
+ }
428
+ });
429
+
414
430
  // ============================================================
415
431
  // LEADS COMMANDS
416
432
  // ============================================================
@@ -2217,6 +2233,22 @@ contractsCmd
2217
2233
  }
2218
2234
  });
2219
2235
 
2236
+ contractsCmd
2237
+ .command('export-pdf <id>')
2238
+ .description('Export a contract as PDF blob and save to disk (Sprint 50 T1)')
2239
+ .requiredOption('--output <file>', 'Output file path (e.g. contract.pdf)')
2240
+ .action(async (id, opts) => {
2241
+ const globalOpts = program.opts();
2242
+ const client = getClient(globalOpts);
2243
+ try {
2244
+ const res = await client.post(`/contracts/${id}/export-pdf`, {}, { responseType: 'arraybuffer' });
2245
+ fs.writeFileSync(opts.output, Buffer.from(res.data));
2246
+ console.log(`PDF saved to ${opts.output} (${res.data.byteLength} bytes)`);
2247
+ } catch (err) {
2248
+ handleError(err);
2249
+ }
2250
+ });
2251
+
2220
2252
  // ============================================================
2221
2253
  // BUDGETS commands — Sprint 5
2222
2254
  // ============================================================
@@ -2776,6 +2808,9 @@ analyticsCmd
2776
2808
  console.log('\nStage Conversion Rates:');
2777
2809
  Object.entries(d.stage_conversion_rates).forEach(([k, v]) => console.log(` ${k}: ${v}%`));
2778
2810
  }
2811
+ // Sprint 50 T3: win rate (closed_won / (closed_won + closed_lost))
2812
+ if (d.win_rate != null) console.log(`\nWin Rate: ${d.win_rate}%`);
2813
+ else console.log('\nWin Rate: N/A (no closed deals yet)');
2779
2814
  } catch (err) {
2780
2815
  handleError(err);
2781
2816
  }
@@ -3009,7 +3044,7 @@ companiesCmd
3009
3044
  name: opts.name,
3010
3045
  ...(opts.domain && { domain: opts.domain }),
3011
3046
  ...(opts.industry && { industry: opts.industry }),
3012
- ...(opts.employeeCount !== undefined && { employee_count: parseInt(opts.employeeCount) }),
3047
+ ...(opts.employeeCount !== undefined && { size: String(parseInt(opts.employeeCount)) }),
3013
3048
  ...(opts.website && { website: opts.website }),
3014
3049
  };
3015
3050
  const res = await client.post('/companies', body);
@@ -3034,7 +3069,7 @@ companiesCmd
3034
3069
  ...(opts.name && { name: opts.name }),
3035
3070
  ...(opts.domain !== undefined && { domain: opts.domain }),
3036
3071
  ...(opts.industry !== undefined && { industry: opts.industry }),
3037
- ...(opts.employeeCount !== undefined && { employee_count: parseInt(opts.employeeCount) }),
3072
+ ...(opts.employeeCount !== undefined && { size: String(parseInt(opts.employeeCount)) }),
3038
3073
  ...(opts.website !== undefined && { website: opts.website }),
3039
3074
  };
3040
3075
  const res = await client.put(`/companies/${id}`, body);
@@ -3190,4 +3225,65 @@ sequencesCmd
3190
3225
  } catch (err) { handleError(err); }
3191
3226
  });
3192
3227
 
3228
+ // ============================================================
3229
+ // GDPR COMMANDS — Sprint 50 T2
3230
+ // ============================================================
3231
+ const gdprCmd = program.command('gdpr').description('GDPR data management — erase, export, and consent');
3232
+
3233
+ gdprCmd
3234
+ .command('erase <lead-id>')
3235
+ .description('Permanently erase a lead and all associated data (GDPR right to erasure). Requires admin scope key. IRREVERSIBLE.')
3236
+ .action(async (leadId) => {
3237
+ const globalOpts = program.opts();
3238
+ const client = getClient(globalOpts);
3239
+ try {
3240
+ const res = await client.delete(`/leads/${leadId}/erase`);
3241
+ console.log('Lead permanently erased.');
3242
+ printJSON(res.data);
3243
+ } catch (err) {
3244
+ handleError(err);
3245
+ }
3246
+ });
3247
+
3248
+ gdprCmd
3249
+ .command('export <lead-id>')
3250
+ .description('Export all personal data for a lead as JSON (GDPR data portability)')
3251
+ .option('--output <file>', 'Save JSON to this file path (default: gdpr-export-<id>.json)')
3252
+ .action(async (leadId, opts) => {
3253
+ const globalOpts = program.opts();
3254
+ const client = getClient(globalOpts);
3255
+ try {
3256
+ const res = await client.get(`/leads/${leadId}/gdpr-export`);
3257
+ const outFile = opts.output || `gdpr-export-${leadId}.json`;
3258
+ fs.writeFileSync(outFile, JSON.stringify(res.data, null, 2));
3259
+ console.log(`GDPR export saved to ${outFile}`);
3260
+ } catch (err) {
3261
+ handleError(err);
3262
+ }
3263
+ });
3264
+
3265
+ gdprCmd
3266
+ .command('consent <lead-id>')
3267
+ .description('Update consent settings for a lead')
3268
+ .option('--marketing <bool>', 'Marketing consent (true/false)')
3269
+ .option('--contacted <bool>', 'Contacted consent (true/false)')
3270
+ .action(async (leadId, opts) => {
3271
+ const globalOpts = program.opts();
3272
+ const client = getClient(globalOpts);
3273
+ try {
3274
+ const body = {};
3275
+ if (opts.marketing !== undefined) body.marketing = opts.marketing === 'true' || opts.marketing === true;
3276
+ if (opts.contacted !== undefined) body.contacted = opts.contacted === 'true' || opts.contacted === true;
3277
+ if (Object.keys(body).length === 0) {
3278
+ console.error('Error: at least one of --marketing or --contacted is required');
3279
+ process.exit(1);
3280
+ }
3281
+ const res = await client.patch(`/leads/${leadId}/consent`, body);
3282
+ console.log('Consent updated.');
3283
+ printJSON(res.data);
3284
+ } catch (err) {
3285
+ handleError(err);
3286
+ }
3287
+ });
3288
+
3193
3289
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startanaicompany/crm",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "AI-first CRM CLI — manage leads and API keys from the terminal",
5
5
  "main": "index.js",
6
6
  "bin": {