@wirecat/cli-core 0.587.0 → 0.589.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/CHANGELOG.md +42 -0
- package/dist/cli/messenger/search-answers.js +3 -0
- package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
- package/dist/domain/deals.d.ts +8 -6
- package/dist/domain/deals.js +7 -8
- package/dist/domain/providers.d.ts +7 -1
- package/dist/domain/providers.js +3 -1
- package/dist/domain/ref-summaries.js +2 -0
- package/dist/domain/references.d.ts +1 -1
- package/dist/domain/references.js +2 -0
- package/dist/entities/hit.d.ts +2 -2
- package/dist/entities/hit.js +2 -2
- package/dist/entities/index.d.ts +1 -1
- package/dist/errors/reasons.js +6 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/search/account-list.js +1 -0
- package/dist/services/project-status/index.d.ts +1 -1
- package/dist/services/project-status/index.js +13 -12
- package/dist/services/project-status/signals/amounts.d.ts +1 -0
- package/dist/services/project-status/signals/amounts.js +4 -3
- package/dist/services/project-status/types.d.ts +2 -0
- package/dist/services/proposals/registry.js +0 -2
- package/dist/services/search-all-meetings.d.ts +1 -1
- package/dist/services/search-all-meetings.js +1 -0
- package/dist/services/search-all.d.ts +15 -5
- package/dist/services/search-all.js +46 -3
- package/dist/store/index.d.ts +1 -1
- package/dist/store/sqlite/deals.d.ts +142 -29
- package/dist/store/sqlite/deals.js +295 -156
- package/dist/store/sqlite/entity-types.d.ts +3 -1
- package/dist/store/sqlite/entity-types.js +3 -1
- package/dist/store/sqlite/knowledge.js +3 -1
- package/dist/store/sqlite/migrations.generated.js +39 -11
- package/dist/store/sqlite/ref-summaries.js +11 -7
- package/dist/store/sqlite/schema.d.ts +600 -38
- package/dist/store/sqlite/schema.js +86 -14
- package/dist/store/sqlite/things.js +2 -0
- package/package.json +1 -1
- package/dist/services/proposals/kinds/deals.d.ts +0 -4
- package/dist/services/proposals/kinds/deals.js +0 -32
|
@@ -1535,14 +1535,22 @@ export const orders = sqliteTable("orders", {
|
|
|
1535
1535
|
index("orders_by_author_type_author_id").on(table.authorType, table.authorId),
|
|
1536
1536
|
index("orders_by_confirmed_by_type_confirmed_by_id").on(table.confirmedByType, table.confirmedById),
|
|
1537
1537
|
]);
|
|
1538
|
-
/** A sales pipeline
|
|
1538
|
+
/** A sales pipeline: the stages a deal or a lead goes through, in order; the owner's own or a CRM account's. */
|
|
1539
1539
|
export const pipelines = sqliteTable("pipelines", {
|
|
1540
1540
|
id: integer("id").primaryKey(),
|
|
1541
|
+
accountId: integer("account_id").references(() => accounts.id),
|
|
1542
|
+
externalId: text("external_id"),
|
|
1543
|
+
kind: text("kind").notNull().default("deal"),
|
|
1541
1544
|
name: text("name").notNull(),
|
|
1542
|
-
nameFolded: text("name_folded").notNull()
|
|
1545
|
+
nameFolded: text("name_folded").notNull(),
|
|
1543
1546
|
createdAt: integer("created_at").notNull(),
|
|
1544
1547
|
updatedAt: integer("updated_at").notNull(),
|
|
1545
|
-
})
|
|
1548
|
+
}, (table) => [
|
|
1549
|
+
uniqueIndex("pipelines_by_account_id_external_id")
|
|
1550
|
+
.on(table.accountId, table.externalId)
|
|
1551
|
+
.where(sql `account_id IS NOT NULL AND external_id IS NOT NULL`),
|
|
1552
|
+
uniqueIndex("pipelines_by_name_folded_kind").on(table.nameFolded, table.kind).where(sql `account_id IS NULL`),
|
|
1553
|
+
]);
|
|
1546
1554
|
export const pipelineStages = sqliteTable("pipeline_stages", {
|
|
1547
1555
|
id: integer("id").primaryKey(),
|
|
1548
1556
|
pipelineId: integer("pipeline_id")
|
|
@@ -1551,11 +1559,19 @@ export const pipelineStages = sqliteTable("pipeline_stages", {
|
|
|
1551
1559
|
name: text("name").notNull(),
|
|
1552
1560
|
nameFolded: text("name_folded").notNull(),
|
|
1553
1561
|
position: integer("position").notNull(),
|
|
1562
|
+
outcome: text("outcome").notNull().default("open"),
|
|
1563
|
+
externalId: text("external_id"),
|
|
1554
1564
|
createdAt: integer("created_at").notNull(),
|
|
1555
1565
|
updatedAt: integer("updated_at").notNull(),
|
|
1556
|
-
}, (table) => [
|
|
1566
|
+
}, (table) => [
|
|
1567
|
+
unique().on(table.pipelineId, table.nameFolded),
|
|
1568
|
+
uniqueIndex("pipeline_stages_by_pipeline_id_external_id")
|
|
1569
|
+
.on(table.pipelineId, table.externalId)
|
|
1570
|
+
.where(sql `external_id IS NOT NULL`),
|
|
1571
|
+
index("pipeline_stages_by_pipeline_id_position").on(table.pipelineId, table.position),
|
|
1572
|
+
]);
|
|
1557
1573
|
/** A deal: what the owner hopes to sell, where it stands in its pipeline, and whether it ended. */
|
|
1558
|
-
export const
|
|
1574
|
+
export const deals = sqliteTable("deals", {
|
|
1559
1575
|
id: integer("id").primaryKey(),
|
|
1560
1576
|
title: text("title").notNull(),
|
|
1561
1577
|
organizationId: integer("organization_id").references(() => organizations.id),
|
|
@@ -1565,27 +1581,83 @@ export const opportunities = sqliteTable("opportunities", {
|
|
|
1565
1581
|
.references(() => pipelineStages.id),
|
|
1566
1582
|
status: text("status").notNull(),
|
|
1567
1583
|
currency: text("currency"),
|
|
1568
|
-
/** Minor units of `currency`. */
|
|
1569
1584
|
amount: integer("amount"),
|
|
1570
1585
|
closeDate: text("close_date"),
|
|
1571
1586
|
closedDate: text("closed_date"),
|
|
1572
|
-
|
|
1587
|
+
rank: real("rank"),
|
|
1588
|
+
accountId: integer("account_id").references(() => accounts.id),
|
|
1589
|
+
externalId: text("external_id"),
|
|
1590
|
+
authorType: text("author_type").notNull(),
|
|
1591
|
+
authorId: integer("author_id").notNull(),
|
|
1592
|
+
model: text("model"),
|
|
1593
|
+
source: text("source").notNull(),
|
|
1594
|
+
metadata: text("metadata"),
|
|
1595
|
+
createdAt: integer("created_at").notNull(),
|
|
1596
|
+
updatedAt: integer("updated_at").notNull(),
|
|
1597
|
+
deletedAt: integer("deleted_at"),
|
|
1598
|
+
}, (table) => [
|
|
1599
|
+
uniqueIndex("deals_by_account_id_external_id")
|
|
1600
|
+
.on(table.accountId, table.externalId)
|
|
1601
|
+
.where(sql `account_id IS NOT NULL AND external_id IS NOT NULL`),
|
|
1602
|
+
index("deals_by_organization_id").on(table.organizationId),
|
|
1603
|
+
index("deals_by_project_id").on(table.projectId),
|
|
1604
|
+
index("deals_by_stage_id").on(table.stageId),
|
|
1605
|
+
index("deals_by_author_type_author_id").on(table.authorType, table.authorId),
|
|
1606
|
+
]);
|
|
1607
|
+
/** A lead: a first contact not yet a deal, in a lead pipeline; `deal_id` is the deal it became. */
|
|
1608
|
+
export const leads = sqliteTable("leads", {
|
|
1609
|
+
id: integer("id").primaryKey(),
|
|
1610
|
+
title: text("title").notNull(),
|
|
1611
|
+
organizationId: integer("organization_id").references(() => organizations.id),
|
|
1612
|
+
projectId: integer("project_id").references(() => projects.id),
|
|
1613
|
+
stageId: integer("stage_id")
|
|
1614
|
+
.notNull()
|
|
1615
|
+
.references(() => pipelineStages.id),
|
|
1616
|
+
status: text("status").notNull(),
|
|
1617
|
+
currency: text("currency"),
|
|
1618
|
+
amount: integer("amount"),
|
|
1619
|
+
closeDate: text("close_date"),
|
|
1620
|
+
closedDate: text("closed_date"),
|
|
1621
|
+
rank: real("rank"),
|
|
1622
|
+
dealId: integer("deal_id").references(() => deals.id),
|
|
1623
|
+
accountId: integer("account_id").references(() => accounts.id),
|
|
1624
|
+
externalId: text("external_id"),
|
|
1573
1625
|
authorType: text("author_type").notNull(),
|
|
1574
1626
|
authorId: integer("author_id").notNull(),
|
|
1575
1627
|
model: text("model"),
|
|
1576
|
-
confirmedByType: text("confirmed_by_type"),
|
|
1577
|
-
confirmedById: integer("confirmed_by_id"),
|
|
1578
1628
|
source: text("source").notNull(),
|
|
1579
1629
|
metadata: text("metadata"),
|
|
1580
1630
|
createdAt: integer("created_at").notNull(),
|
|
1581
1631
|
updatedAt: integer("updated_at").notNull(),
|
|
1582
1632
|
deletedAt: integer("deleted_at"),
|
|
1583
1633
|
}, (table) => [
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
index("
|
|
1588
|
-
index("
|
|
1634
|
+
uniqueIndex("leads_by_account_id_external_id")
|
|
1635
|
+
.on(table.accountId, table.externalId)
|
|
1636
|
+
.where(sql `account_id IS NOT NULL AND external_id IS NOT NULL`),
|
|
1637
|
+
index("leads_by_organization_id").on(table.organizationId),
|
|
1638
|
+
index("leads_by_project_id").on(table.projectId),
|
|
1639
|
+
index("leads_by_stage_id").on(table.stageId),
|
|
1640
|
+
index("leads_by_deal_id").on(table.dealId),
|
|
1641
|
+
index("leads_by_author_type_author_id").on(table.authorType, table.authorId),
|
|
1642
|
+
]);
|
|
1643
|
+
/** Each stage a deal or a lead entered and when, written by triggers, so conversion between stages can be counted. */
|
|
1644
|
+
export const pipelineStageChanges = sqliteTable("pipeline_stage_changes", {
|
|
1645
|
+
id: integer("id").primaryKey(),
|
|
1646
|
+
itemType: text("item_type").notNull(),
|
|
1647
|
+
itemId: integer("item_id").notNull(),
|
|
1648
|
+
pipelineId: integer("pipeline_id")
|
|
1649
|
+
.notNull()
|
|
1650
|
+
.references(() => pipelines.id),
|
|
1651
|
+
fromStageId: integer("from_stage_id").references(() => pipelineStages.id),
|
|
1652
|
+
toStageId: integer("to_stage_id")
|
|
1653
|
+
.notNull()
|
|
1654
|
+
.references(() => pipelineStages.id),
|
|
1655
|
+
changedAt: integer("changed_at").notNull(),
|
|
1656
|
+
}, (table) => [
|
|
1657
|
+
index("pipeline_stage_changes_by_item_type_item_id").on(table.itemType, table.itemId),
|
|
1658
|
+
index("pipeline_stage_changes_by_pipeline_id").on(table.pipelineId),
|
|
1659
|
+
index("pipeline_stage_changes_by_from_stage_id").on(table.fromStageId),
|
|
1660
|
+
index("pipeline_stage_changes_by_to_stage_id").on(table.toStageId),
|
|
1589
1661
|
]);
|
|
1590
1662
|
/** What a source said about one of its records, as it said it: the layer under the entity an import makes. */
|
|
1591
1663
|
export const records = sqliteTable("records", {
|
|
@@ -21,6 +21,8 @@ const REFERABLE = {
|
|
|
21
21
|
payment: { tombstone: true },
|
|
22
22
|
order: { tombstone: true },
|
|
23
23
|
deal: { tombstone: true },
|
|
24
|
+
lead: { tombstone: true },
|
|
25
|
+
pipeline: { tombstone: false },
|
|
24
26
|
message: { tombstone: true },
|
|
25
27
|
email: { tombstone: true },
|
|
26
28
|
email_thread: { tombstone: true },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirecat/cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.589.0",
|
|
4
4
|
"description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Viacheslav Ptsarev",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { MessageStore } from "../../../store/index.js";
|
|
2
|
-
import type { ProposalKind } from "../types.js";
|
|
3
|
-
/** An agent's deal, by its own ref (`deal:12`) as orders are; only the owner decides it. */
|
|
4
|
-
export declare const dealKind: (store: Pick<MessageStore, "deals">) => ProposalKind;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { kept, proposerOfAuthor, pushed } from "./shared.js";
|
|
2
|
-
const rowOf = (deal) => ({
|
|
3
|
-
id: deal.ref,
|
|
4
|
-
kind: "deal",
|
|
5
|
-
status: deal.review,
|
|
6
|
-
project: deal.project,
|
|
7
|
-
subject: deal.ref,
|
|
8
|
-
object: deal.organization?.ref ?? null,
|
|
9
|
-
summary: `Deal ${deal.summary}`,
|
|
10
|
-
proposedBy: proposerOfAuthor(deal.author),
|
|
11
|
-
reason: deal.reason,
|
|
12
|
-
evidence: [],
|
|
13
|
-
score: null,
|
|
14
|
-
signals: null,
|
|
15
|
-
parts: null,
|
|
16
|
-
createdAt: deal.createdAt,
|
|
17
|
-
});
|
|
18
|
-
/** An agent's deal, by its own ref (`deal:12`) as orders are; only the owner decides it. */
|
|
19
|
-
export const dealKind = (store) => ({
|
|
20
|
-
kind: "deal",
|
|
21
|
-
prefix: "deal",
|
|
22
|
-
list: async (filter) => {
|
|
23
|
-
const status = filter.status ?? "proposed";
|
|
24
|
-
const deals = await store.deals.list({ ...pushed(filter), ...(status === "all" ? {} : { review: status }) });
|
|
25
|
-
return kept(deals.map(rowOf), filter);
|
|
26
|
-
},
|
|
27
|
-
get: async (id) => rowOf(await store.deals.get(id)),
|
|
28
|
-
decide: async (id, { confirm, by, reason }) => {
|
|
29
|
-
const deal = confirm ? await store.deals.confirm(id, by, reason) : await store.deals.reject(id, by, reason);
|
|
30
|
-
return { id, kind: "deal", status: confirm ? "confirmed" : "rejected", made: confirm ? [deal.ref] : [] };
|
|
31
|
-
},
|
|
32
|
-
});
|