@hasna/contacts 0.6.27 → 0.6.29

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.
@@ -1 +1 @@
1
- {"version":3,"file":"crm.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAy6B1D"}
1
+ {"version":3,"file":"crm.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/crm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAm+B1D"}
package/dist/cli/index.js CHANGED
@@ -19330,6 +19330,9 @@ var {
19330
19330
  Help
19331
19331
  } = import__.default;
19332
19332
 
19333
+ // src/cli/index.tsx
19334
+ import chalk7 from "chalk";
19335
+
19333
19336
  // src/cli/commands/core.tsx
19334
19337
  init_store();
19335
19338
  init_paths();
@@ -20686,11 +20689,49 @@ ${apps.length} application(s) need follow-up:
20686
20689
  console.log();
20687
20690
  });
20688
20691
  program2.command("seed").description("Seed demo contacts, companies, and relationships").option("--demo", "Seed demo data (professional services example)").option("--clear", "Clear existing demo data first").action(async (opts) => {
20692
+ const store = getStore();
20693
+ if (opts.clear) {
20694
+ const demoCompanyNames = [
20695
+ "KPMG Romania",
20696
+ "Escalon Services",
20697
+ "Revision Legal PLLC",
20698
+ "RAW Financial",
20699
+ "Silicon Valley Bank",
20700
+ "Hasna, Inc.",
20701
+ "Beep Media International LLC",
20702
+ "Hasna Global SRL"
20703
+ ];
20704
+ const demoContactEmails = [
20705
+ "alinaturlea@kpmg.com",
20706
+ "lsipos@kpmg.com",
20707
+ "elizabeth.robles@escalon.services",
20708
+ "drew@revisionlegal.com",
20709
+ "DYang@svb.com"
20710
+ ];
20711
+ let removedCompanies = 0;
20712
+ let removedContacts = 0;
20713
+ const { companies } = await store.listCompanies({ limit: 500 });
20714
+ for (const c of companies) {
20715
+ if (demoCompanyNames.includes(c.name)) {
20716
+ await store.deleteCompany(c.id);
20717
+ removedCompanies++;
20718
+ }
20719
+ }
20720
+ for (const email of demoContactEmails) {
20721
+ const contact = await store.getContactByEmail(email);
20722
+ if (contact) {
20723
+ await store.deleteContact(contact.id);
20724
+ removedContacts++;
20725
+ }
20726
+ }
20727
+ console.log(chalk3.green(`\u2713 Cleared demo data: ${removedCompanies} companies, ${removedContacts} contacts`));
20728
+ if (!opts.demo)
20729
+ return;
20730
+ }
20689
20731
  if (!opts.demo) {
20690
- console.log("Use --demo flag to seed demo data");
20732
+ console.log("Use --demo flag to seed demo data (add --clear to remove previously seeded demo data)");
20691
20733
  return;
20692
20734
  }
20693
- const store = getStore();
20694
20735
  console.log(chalk3.cyan("Seeding demo contacts..."));
20695
20736
  const kpmg = await store.createCompany({ name: "KPMG Romania", industry: "Accounting", description: "Romanian accounting, tax, and payroll firm" });
20696
20737
  const escalon = await store.createCompany({ name: "Escalon Services", industry: "Tax & Finance", description: "US tax preparation for multi-entity businesses", domain: "escalon.services" });
@@ -20779,7 +20820,29 @@ ${items.length} upcoming item(s) in next ${opts.days} days
20779
20820
  `));
20780
20821
  });
20781
20822
  program2.command("stats").description("Network health dashboard").option("-j, --json", "Output JSON").action(async (opts) => {
20782
- const s = await getStore().getNetworkStats();
20823
+ const store = getStore();
20824
+ let s;
20825
+ try {
20826
+ s = await store.getNetworkStats();
20827
+ } catch (err2) {
20828
+ if (!(err2 instanceof Error && err2.name === "ApiUnavailableError"))
20829
+ throw err2;
20830
+ const basic = await store.stats();
20831
+ if (opts.json) {
20832
+ console.log(JSON.stringify({ total_contacts: basic.contacts, total_companies: basic.companies, total_tags: basic.tags, total_groups: basic.groups, extended_metrics: "unavailable_in_self_hosted_mode" }, null, 2));
20833
+ return;
20834
+ }
20835
+ console.log(chalk3.bold.blue(`
20836
+ \u2501\u2501\u2501 Network Health Dashboard \u2501\u2501\u2501
20837
+ `));
20838
+ console.log(chalk3.bold(" Network Size:"));
20839
+ console.log(` ${chalk3.cyan(String(basic.contacts))} contacts ${chalk3.cyan(String(basic.companies))} companies ${chalk3.cyan(String(basic.tags))} tags ${chalk3.cyan(String(basic.groups))} groups`);
20840
+ console.log(chalk3.gray(`
20841
+ (Cold/tasks/deals/pipeline metrics are computed on-box and are not
20842
+ available in self_hosted mode \u2014 run in local mode for the full dashboard.)
20843
+ `));
20844
+ return;
20845
+ }
20783
20846
  if (opts.json) {
20784
20847
  console.log(JSON.stringify(s, null, 2));
20785
20848
  return;
@@ -20852,7 +20915,7 @@ No deals found.
20852
20915
  ${deals.length} deal(s)
20853
20916
  `));
20854
20917
  });
20855
- dealsCmd.command("add").description("Add a new deal").option("--title <title>", "Deal title (required)").option("--stage <stage>", "Stage: prospecting|qualified|proposal|negotiation|won|lost", "prospecting").option("--value <usd>", "Value in USD").option("--contact <id>", "Contact ID").option("--company <id>", "Company ID").option("--close-date <date>", "Expected close date (YYYY-MM-DD)").option("--notes <text>", "Notes").action(async (opts) => {
20918
+ dealsCmd.command("add").description("Add a new deal").option("--title <title>", "Deal title (required)").option("--stage <stage>", "Stage: lead|qualified|proposal|negotiation|won|lost|cancelled", "lead").option("--value <usd>", "Value in USD").option("--contact <id>", "Contact ID").option("--company <id>", "Company ID").option("--close-date <date>", "Expected close date (YYYY-MM-DD)").option("--notes <text>", "Notes").action(async (opts) => {
20856
20919
  const store = getStore();
20857
20920
  let title = opts.title;
20858
20921
  if (!title) {
@@ -20862,6 +20925,11 @@ ${deals.length} deal(s)
20862
20925
  process.exit(1);
20863
20926
  }
20864
20927
  }
20928
+ const validStages = ["lead", "qualified", "proposal", "negotiation", "won", "lost", "cancelled"];
20929
+ if (opts.stage && !validStages.includes(opts.stage)) {
20930
+ console.error(chalk3.red(`Invalid stage '${opts.stage}'. Valid stages: ${validStages.join(", ")}`));
20931
+ process.exit(1);
20932
+ }
20865
20933
  const deal = await store.createDeal({
20866
20934
  title,
20867
20935
  stage: opts.stage,
@@ -22204,4 +22272,11 @@ registerAudienceCommands(program);
22204
22272
  registerStorageCommands(program);
22205
22273
  registerWebhookCommands2?.(program, { source: "contacts" });
22206
22274
  registerEventCommands2(program, { source: "contacts", eventsCommandName: "hasna-events" });
22207
- program.parse(process.argv);
22275
+ program.parseAsync(process.argv).catch((err2) => {
22276
+ const message = err2 instanceof Error ? err2.message : String(err2);
22277
+ const isApiUnavailable = err2 instanceof Error && err2.name === "ApiUnavailableError";
22278
+ console.error(`
22279
+ ` + (isApiUnavailable ? chalk7.yellow(message) : chalk7.red(message)) + `
22280
+ `);
22281
+ process.exit(1);
22282
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/contacts",
3
- "version": "0.6.27",
3
+ "version": "0.6.29",
4
4
  "description": "Contact management for AI coding agents — CLI + MCP + Web",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",