exponential-cli 1.4.0 → 1.6.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/dist/index.js +172 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command14 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/auth.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -499,6 +499,60 @@ function outputInteractionPretty(interaction) {
|
|
|
499
499
|
if (interaction.notes) console.log(` ${chalk3.gray("Notes:")} ${interaction.notes}`);
|
|
500
500
|
console.log();
|
|
501
501
|
}
|
|
502
|
+
function transformOrganization(org) {
|
|
503
|
+
return {
|
|
504
|
+
id: org.id,
|
|
505
|
+
workspaceId: org.workspaceId,
|
|
506
|
+
name: org.name,
|
|
507
|
+
websiteUrl: org.websiteUrl,
|
|
508
|
+
logoUrl: org.logoUrl,
|
|
509
|
+
description: org.description,
|
|
510
|
+
industry: org.industry,
|
|
511
|
+
size: org.size,
|
|
512
|
+
contactCount: org._count?.contacts ?? null,
|
|
513
|
+
createdAt: new Date(org.createdAt).toISOString(),
|
|
514
|
+
updatedAt: new Date(org.updatedAt).toISOString()
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function outputOrganizationJson(org) {
|
|
518
|
+
console.log(JSON.stringify(transformOrganization(org), null, 2));
|
|
519
|
+
}
|
|
520
|
+
function outputOrganizationPretty(org) {
|
|
521
|
+
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
522
|
+
console.log(`
|
|
523
|
+
${chalk3.bold(org.name)}`);
|
|
524
|
+
console.log(chalk3.gray(` ID: ${org.id}`));
|
|
525
|
+
if (org.industry) console.log(` ${chalk3.magenta("Industry:")} ${org.industry}`);
|
|
526
|
+
if (org.size) console.log(` ${chalk3.cyan("Size:")} ${org.size}`);
|
|
527
|
+
if (org.websiteUrl) console.log(` ${chalk3.cyan("Website:")} ${org.websiteUrl}`);
|
|
528
|
+
if (org.description) console.log(` ${chalk3.gray("About:")} ${org.description.substring(0, 120)}${org.description.length > 120 ? "..." : ""}`);
|
|
529
|
+
if (org._count?.contacts != null) console.log(` ${chalk3.green("Contacts:")} ${org._count.contacts}`);
|
|
530
|
+
console.log();
|
|
531
|
+
}
|
|
532
|
+
function outputOrganizationsJson(organizations, nextCursor) {
|
|
533
|
+
console.log(JSON.stringify({
|
|
534
|
+
organizations: organizations.map(transformOrganization),
|
|
535
|
+
total: organizations.length,
|
|
536
|
+
nextCursor: nextCursor ?? null
|
|
537
|
+
}, null, 2));
|
|
538
|
+
}
|
|
539
|
+
function outputOrganizationsPretty(organizations) {
|
|
540
|
+
if (organizations.length === 0) {
|
|
541
|
+
console.log(chalk3.gray("No organizations found."));
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
console.log(chalk3.bold(`
|
|
545
|
+
Organizations (${organizations.length} total)`));
|
|
546
|
+
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
547
|
+
for (const org of organizations) {
|
|
548
|
+
console.log(`
|
|
549
|
+
${chalk3.bold(org.name)}`);
|
|
550
|
+
console.log(chalk3.gray(` ID: ${org.id}`));
|
|
551
|
+
if (org.industry) console.log(` ${chalk3.magenta("Industry:")} ${org.industry}`);
|
|
552
|
+
if (org._count?.contacts != null) console.log(` ${chalk3.green("Contacts:")} ${org._count.contacts}`);
|
|
553
|
+
}
|
|
554
|
+
console.log();
|
|
555
|
+
}
|
|
502
556
|
function outputDealJson(deal) {
|
|
503
557
|
console.log(JSON.stringify(transformDeal(deal), null, 2));
|
|
504
558
|
}
|
|
@@ -1417,7 +1471,7 @@ function createContactsCommand() {
|
|
|
1417
1471
|
handleError(error, useJson);
|
|
1418
1472
|
}
|
|
1419
1473
|
});
|
|
1420
|
-
contacts.command("create").description("Create a new contact").requiredOption("--workspace <id>", "Workspace ID").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--email <email>", "Email address").option("--phone <phone>", "Phone number").option("--linkedin <url>", "LinkedIn URL").option("--telegram <handle>", "Telegram handle").option("--twitter <handle>", "Twitter/X handle").option("--github <handle>", "GitHub username").option("--bluesky <handle>", "Bluesky handle").option("--about <text>", "About / bio").option("--profile-type <type>", "Profile type").option("--skills <skills>", "Skills (comma-separated)").option("--tags <tags>", "Tags (comma-separated)").option("--organization <id>", "Organization ID").action(async (options, cmd) => {
|
|
1474
|
+
contacts.command("create").description("Create a new contact").requiredOption("--workspace <id>", "Workspace ID").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--email <email>", "Email address").option("--phone <phone>", "Phone number").option("--linkedin <url>", "LinkedIn URL").option("--telegram <handle>", "Telegram handle").option("--twitter <handle>", "Twitter/X handle").option("--github <handle>", "GitHub username").option("--bluesky <handle>", "Bluesky handle").option("--about <text>", "About / bio").option("--profile-type <type>", "Profile type").option("--skills <skills>", "Skills (comma-separated)").option("--tags <tags>", "Tags (comma-separated)").option("--organization <id>", "Organization ID").option("--organization-name <name>", "Organization name (find-or-create; ignored if --organization is set)").action(async (options, cmd) => {
|
|
1421
1475
|
const globalOpts = cmd.optsWithGlobals();
|
|
1422
1476
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
1423
1477
|
try {
|
|
@@ -1437,7 +1491,8 @@ function createContactsCommand() {
|
|
|
1437
1491
|
profileType: options.profileType,
|
|
1438
1492
|
skills: options.skills?.split(",").map((s) => s.trim()),
|
|
1439
1493
|
tags: options.tags?.split(",").map((t) => t.trim()),
|
|
1440
|
-
organizationId: options.organization
|
|
1494
|
+
organizationId: options.organization,
|
|
1495
|
+
organizationName: options.organizationName
|
|
1441
1496
|
});
|
|
1442
1497
|
if (useJson) {
|
|
1443
1498
|
outputContactJson(contact);
|
|
@@ -1449,7 +1504,7 @@ function createContactsCommand() {
|
|
|
1449
1504
|
handleError(error, useJson);
|
|
1450
1505
|
}
|
|
1451
1506
|
});
|
|
1452
|
-
contacts.command("update").description("Update an existing contact").requiredOption("--id <id>", "Contact ID").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--email <email>", 'Email (use "null" to clear)').option("--phone <phone>", 'Phone (use "null" to clear)').option("--linkedin <url>", 'LinkedIn URL (use "null" to clear)').option("--telegram <handle>", 'Telegram handle (use "null" to clear)').option("--twitter <handle>", 'Twitter/X handle (use "null" to clear)').option("--github <handle>", 'GitHub username (use "null" to clear)').option("--bluesky <handle>", 'Bluesky handle (use "null" to clear)').option("--about <text>", "About / bio").option("--profile-type <type>", "Profile type").option("--skills <skills>", "Skills (comma-separated)").option("--tags <tags>", "Tags (comma-separated)").option("--organization <id>", 'Organization ID (use "null" to clear)').action(async (options, cmd) => {
|
|
1507
|
+
contacts.command("update").description("Update an existing contact").requiredOption("--id <id>", "Contact ID").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("--email <email>", 'Email (use "null" to clear)').option("--phone <phone>", 'Phone (use "null" to clear)').option("--linkedin <url>", 'LinkedIn URL (use "null" to clear)').option("--telegram <handle>", 'Telegram handle (use "null" to clear)').option("--twitter <handle>", 'Twitter/X handle (use "null" to clear)').option("--github <handle>", 'GitHub username (use "null" to clear)').option("--bluesky <handle>", 'Bluesky handle (use "null" to clear)').option("--about <text>", "About / bio").option("--profile-type <type>", "Profile type").option("--skills <skills>", "Skills (comma-separated)").option("--tags <tags>", "Tags (comma-separated)").option("--organization <id>", 'Organization ID (use "null" to clear)').option("--organization-name <name>", "Organization name (find-or-create; ignored if --organization is set)").action(async (options, cmd) => {
|
|
1453
1508
|
const globalOpts = cmd.optsWithGlobals();
|
|
1454
1509
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
1455
1510
|
const nullable = (v) => v === "null" ? null : v;
|
|
@@ -1470,7 +1525,8 @@ function createContactsCommand() {
|
|
|
1470
1525
|
profileType: options.profileType,
|
|
1471
1526
|
skills: options.skills?.split(",").map((s) => s.trim()),
|
|
1472
1527
|
tags: options.tags?.split(",").map((t) => t.trim()),
|
|
1473
|
-
organizationId: nullable(options.organization)
|
|
1528
|
+
organizationId: nullable(options.organization),
|
|
1529
|
+
organizationName: options.organizationName
|
|
1474
1530
|
});
|
|
1475
1531
|
if (useJson) {
|
|
1476
1532
|
outputContactJson(contact);
|
|
@@ -1526,6 +1582,28 @@ function createContactsCommand() {
|
|
|
1526
1582
|
handleError(error, useJson);
|
|
1527
1583
|
}
|
|
1528
1584
|
});
|
|
1585
|
+
contacts.command("enrich").description("Queue a web-search enrichment job for an existing contact (runs regardless of the workspace auto-enrich setting)").argument("<id>", "Contact ID").action(async (id, _options, cmd) => {
|
|
1586
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1587
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
1588
|
+
try {
|
|
1589
|
+
const client = getClient();
|
|
1590
|
+
const result = await client.contacts.enrich(id);
|
|
1591
|
+
if (useJson) {
|
|
1592
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1593
|
+
} else if (result.enqueued) {
|
|
1594
|
+
console.log(`
|
|
1595
|
+
\u2713 Enrichment queued for contact ${id} (job ${result.enrichmentId})`);
|
|
1596
|
+
} else if (result.reason === "already-in-flight") {
|
|
1597
|
+
console.log(`
|
|
1598
|
+
\u2022 Enrichment already in progress for contact ${id} (job ${result.enrichmentId})`);
|
|
1599
|
+
} else {
|
|
1600
|
+
console.log(`
|
|
1601
|
+
\u2022 Not queued for contact ${id}${result.reason ? ` (${result.reason})` : ""}`);
|
|
1602
|
+
}
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
handleError(error, useJson);
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1529
1607
|
return contacts;
|
|
1530
1608
|
}
|
|
1531
1609
|
|
|
@@ -2253,10 +2331,88 @@ function createLabelsCommand() {
|
|
|
2253
2331
|
return labels;
|
|
2254
2332
|
}
|
|
2255
2333
|
|
|
2256
|
-
// src/commands/
|
|
2334
|
+
// src/commands/organizations.ts
|
|
2257
2335
|
import { Command as Command9 } from "commander";
|
|
2336
|
+
var VALID_SIZES = [
|
|
2337
|
+
"1-10",
|
|
2338
|
+
"11-50",
|
|
2339
|
+
"51-200",
|
|
2340
|
+
"201-500",
|
|
2341
|
+
"501-1000",
|
|
2342
|
+
"1000+"
|
|
2343
|
+
];
|
|
2344
|
+
function createOrganizationsCommand() {
|
|
2345
|
+
const organizations = new Command9("organizations").alias("orgs").description("Manage CRM organizations");
|
|
2346
|
+
organizations.command("list").description("List organizations").requiredOption("--workspace <id>", "Workspace ID").option("--search <query>", "Search by name or description").option("--industry <industry>", "Filter by industry").option("--limit <n>", "Max results to return", parseInt).option("--cursor <cursor>", "Pagination cursor").action(async (options, cmd) => {
|
|
2347
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2348
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2349
|
+
try {
|
|
2350
|
+
const client = getClient();
|
|
2351
|
+
const result = await client.organizations.list({
|
|
2352
|
+
workspaceId: options.workspace,
|
|
2353
|
+
search: options.search,
|
|
2354
|
+
industry: options.industry,
|
|
2355
|
+
limit: options.limit,
|
|
2356
|
+
cursor: options.cursor
|
|
2357
|
+
});
|
|
2358
|
+
if (useJson) {
|
|
2359
|
+
outputOrganizationsJson(result.organizations, result.nextCursor);
|
|
2360
|
+
} else {
|
|
2361
|
+
outputOrganizationsPretty(result.organizations);
|
|
2362
|
+
}
|
|
2363
|
+
} catch (error) {
|
|
2364
|
+
handleError(error, useJson);
|
|
2365
|
+
}
|
|
2366
|
+
});
|
|
2367
|
+
organizations.command("get").description("Get an organization by ID").argument("<id>", "Organization ID").action(async (id, _options, cmd) => {
|
|
2368
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2369
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2370
|
+
try {
|
|
2371
|
+
const client = getClient();
|
|
2372
|
+
const org = await client.organizations.get(id);
|
|
2373
|
+
if (useJson) {
|
|
2374
|
+
outputOrganizationJson(org);
|
|
2375
|
+
} else {
|
|
2376
|
+
outputOrganizationPretty(org);
|
|
2377
|
+
}
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
handleError(error, useJson);
|
|
2380
|
+
}
|
|
2381
|
+
});
|
|
2382
|
+
organizations.command("create").description("Create a new organization").requiredOption("--workspace <id>", "Workspace ID").requiredOption("--name <name>", "Organization name").option("--website-url <url>", "Website URL").option("--logo-url <url>", "Logo URL").option("--description <text>", "Description").option("--industry <industry>", "Industry").option("--size <size>", `Company size (${VALID_SIZES.join(", ")})`).action(async (options, cmd) => {
|
|
2383
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2384
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2385
|
+
try {
|
|
2386
|
+
if (options.size && !VALID_SIZES.includes(options.size)) {
|
|
2387
|
+
throw new Error(`Invalid size "${options.size}". Valid: ${VALID_SIZES.join(", ")}`);
|
|
2388
|
+
}
|
|
2389
|
+
const client = getClient();
|
|
2390
|
+
const org = await client.organizations.create({
|
|
2391
|
+
workspaceId: options.workspace,
|
|
2392
|
+
name: options.name,
|
|
2393
|
+
websiteUrl: options.websiteUrl,
|
|
2394
|
+
logoUrl: options.logoUrl,
|
|
2395
|
+
description: options.description,
|
|
2396
|
+
industry: options.industry,
|
|
2397
|
+
size: options.size
|
|
2398
|
+
});
|
|
2399
|
+
if (useJson) {
|
|
2400
|
+
outputOrganizationJson(org);
|
|
2401
|
+
} else {
|
|
2402
|
+
console.log("\n\u2713 Organization created successfully");
|
|
2403
|
+
outputOrganizationPretty(org);
|
|
2404
|
+
}
|
|
2405
|
+
} catch (error) {
|
|
2406
|
+
handleError(error, useJson);
|
|
2407
|
+
}
|
|
2408
|
+
});
|
|
2409
|
+
return organizations;
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
// src/commands/products.ts
|
|
2413
|
+
import { Command as Command10 } from "commander";
|
|
2258
2414
|
function createProductsCommand() {
|
|
2259
|
-
const products = new
|
|
2415
|
+
const products = new Command10("products").description(
|
|
2260
2416
|
"Manage products. A workspace contains products; a product holds features and tickets."
|
|
2261
2417
|
);
|
|
2262
2418
|
products.command("list").description("List products in a workspace").option("--workspace <slug|id>", "Workspace slug or CUID (defaults to configured workspace)").action(async (options, cmd) => {
|
|
@@ -2319,9 +2475,9 @@ function createProductsCommand() {
|
|
|
2319
2475
|
}
|
|
2320
2476
|
|
|
2321
2477
|
// src/commands/projects.ts
|
|
2322
|
-
import { Command as
|
|
2478
|
+
import { Command as Command11 } from "commander";
|
|
2323
2479
|
function createProjectsCommand() {
|
|
2324
|
-
const projects = new
|
|
2480
|
+
const projects = new Command11("projects").description("Manage projects");
|
|
2325
2481
|
projects.command("list").description("List all projects").option("--workspace <id>", "Filter by workspace ID").option("--include-actions", "Include actions in output").action(async (options, cmd) => {
|
|
2326
2482
|
const globalOpts = cmd.optsWithGlobals();
|
|
2327
2483
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2344,7 +2500,7 @@ function createProjectsCommand() {
|
|
|
2344
2500
|
}
|
|
2345
2501
|
|
|
2346
2502
|
// src/commands/tickets.ts
|
|
2347
|
-
import { Command as
|
|
2503
|
+
import { Command as Command12 } from "commander";
|
|
2348
2504
|
function collectRepeatable(value, previous) {
|
|
2349
2505
|
return [...previous, value];
|
|
2350
2506
|
}
|
|
@@ -2387,7 +2543,7 @@ function validateTicketType(value) {
|
|
|
2387
2543
|
return value;
|
|
2388
2544
|
}
|
|
2389
2545
|
function createTicketsCommand() {
|
|
2390
|
-
const tickets = new
|
|
2546
|
+
const tickets = new Command12("tickets").description(
|
|
2391
2547
|
"Manage product backlog tickets. Tickets live under a product, link to features/epics, depend on each other, and can be implemented via actions."
|
|
2392
2548
|
);
|
|
2393
2549
|
tickets.command("list").description(
|
|
@@ -2700,7 +2856,7 @@ function createTicketsCommand() {
|
|
|
2700
2856
|
handleError(error, useJson);
|
|
2701
2857
|
}
|
|
2702
2858
|
});
|
|
2703
|
-
const comment = new
|
|
2859
|
+
const comment = new Command12("comment").description("Manage comments on a ticket");
|
|
2704
2860
|
comment.command("add").description("Add a comment to a ticket").requiredOption("--id <id>", "Ticket CUID").requiredOption("-m, --message <text>", "Comment content (markdown supported)").action(async (options, cmd) => {
|
|
2705
2861
|
const globalOpts = cmd.optsWithGlobals();
|
|
2706
2862
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2739,10 +2895,10 @@ function createTicketsCommand() {
|
|
|
2739
2895
|
}
|
|
2740
2896
|
|
|
2741
2897
|
// src/commands/workspaces.ts
|
|
2742
|
-
import { Command as
|
|
2898
|
+
import { Command as Command13 } from "commander";
|
|
2743
2899
|
import chalk5 from "chalk";
|
|
2744
2900
|
function createWorkspacesCommand() {
|
|
2745
|
-
const workspaces = new
|
|
2901
|
+
const workspaces = new Command13("workspaces").description("Manage workspaces");
|
|
2746
2902
|
workspaces.command("list").description("List all workspaces").action(async (_options, cmd) => {
|
|
2747
2903
|
const globalOpts = cmd.optsWithGlobals();
|
|
2748
2904
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2788,7 +2944,7 @@ function createWorkspacesCommand() {
|
|
|
2788
2944
|
}
|
|
2789
2945
|
|
|
2790
2946
|
// src/index.ts
|
|
2791
|
-
var program = new
|
|
2947
|
+
var program = new Command14();
|
|
2792
2948
|
program.name("exponential").description(
|
|
2793
2949
|
[
|
|
2794
2950
|
"CLI to interact with Exponential productivity app.",
|
|
@@ -2805,6 +2961,7 @@ program.addCommand(createDealsCommand());
|
|
|
2805
2961
|
program.addCommand(createEpicsCommand());
|
|
2806
2962
|
program.addCommand(createFeaturesCommand());
|
|
2807
2963
|
program.addCommand(createLabelsCommand());
|
|
2964
|
+
program.addCommand(createOrganizationsCommand());
|
|
2808
2965
|
program.addCommand(createProductsCommand());
|
|
2809
2966
|
program.addCommand(createProjectsCommand());
|
|
2810
2967
|
program.addCommand(createTicketsCommand());
|