@wirecat/cli-core 0.555.0 → 0.557.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 +59 -0
- package/dist/cli/config-command.js +64 -2
- package/dist/cli/config-issues.d.ts +2 -0
- package/dist/cli/config-issues.js +11 -3
- package/dist/cli/config-repair.d.ts +26 -0
- package/dist/cli/config-repair.js +252 -0
- package/dist/cli/messenger/tasks-analysis-command.d.ts +8 -0
- package/dist/cli/messenger/tasks-analysis-command.js +184 -0
- package/dist/cli/messenger/tasks-command.js +11 -2
- package/dist/cli/steps.js +10 -0
- package/dist/domain/finance.d.ts +40 -0
- package/dist/domain/finance.js +39 -0
- package/dist/domain/money.d.ts +29 -0
- package/dist/domain/money.js +98 -0
- 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/index.d.ts +64 -2
- package/dist/entities/index.js +5 -2
- package/dist/entities/task-results.d.ts +72 -0
- package/dist/entities/task-results.js +40 -1
- package/dist/errors/reasons.d.ts +1 -1
- package/dist/errors/reasons.js +24 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mail/cli/index.d.ts +1 -0
- package/dist/mail/cli/index.js +3 -0
- package/dist/mail/cli/marks.d.ts +26 -0
- package/dist/mail/cli/marks.js +51 -0
- package/dist/mail/cli/review.js +70 -1
- package/dist/mail/index.d.ts +1 -0
- package/dist/mail/index.js +1 -0
- package/dist/mail/marks.d.ts +56 -0
- package/dist/mail/marks.js +178 -0
- package/dist/meetings/mcp/index.d.ts +15 -15
- package/dist/sends/permissions.js +1 -0
- package/dist/services/proposals/kinds/finance.d.ts +4 -0
- package/dist/services/proposals/kinds/finance.js +40 -0
- package/dist/services/proposals/registry.js +3 -0
- package/dist/services/task-analysis.d.ts +58 -0
- package/dist/services/task-analysis.js +125 -0
- package/dist/store/exports.d.ts +2 -2
- package/dist/store/index.d.ts +2 -1
- package/dist/store/sqlite/email-activity.d.ts +31 -0
- package/dist/store/sqlite/email-activity.js +38 -0
- package/dist/store/sqlite/emails.d.ts +2 -0
- package/dist/store/sqlite/emails.js +1 -0
- package/dist/store/sqlite/entity-types.d.ts +2 -0
- package/dist/store/sqlite/entity-types.js +2 -0
- package/dist/store/sqlite/finance.d.ts +199 -0
- package/dist/store/sqlite/finance.js +514 -0
- package/dist/store/sqlite/knowledge.js +3 -1
- package/dist/store/sqlite/manifest.js +2 -0
- package/dist/store/sqlite/migrations.generated.js +35 -0
- package/dist/store/sqlite/ref-summaries.js +33 -0
- package/dist/store/sqlite/schema.d.ts +1043 -0
- package/dist/store/sqlite/schema.js +98 -0
- package/dist/store/sqlite/task-analysis-marks.d.ts +7 -0
- package/dist/store/sqlite/task-analysis-marks.js +27 -0
- package/dist/store/sqlite/things.js +2 -0
- package/dist/store/store.d.ts +3 -0
- package/dist/store/store.js +5 -0
- package/dist/store/sync.d.ts +5 -1
- package/dist/store/sync.js +4 -0
- package/dist/store/types.d.ts +25 -0
- package/package.json +1 -1
- package/parity.json +29 -0
- package/skills/follow-ups/SKILL.md +22 -2
|
@@ -36,7 +36,37 @@ export interface EmailMarks {
|
|
|
36
36
|
/** The mail rule that decided how it is stored, by its id in `rules list`. */
|
|
37
37
|
ruleId: number | null;
|
|
38
38
|
}
|
|
39
|
+
/** One email as a processing mark sees it, by its store id; never its text. */
|
|
40
|
+
export interface MarkedEmail {
|
|
41
|
+
id: number;
|
|
42
|
+
externalId: string;
|
|
43
|
+
thread: string;
|
|
44
|
+
/** ms: received, or sent when that is unknown. */
|
|
45
|
+
at: number | null;
|
|
46
|
+
/** ms: when the store saved it first, and last changed it. */
|
|
47
|
+
storedAt: number;
|
|
48
|
+
changedAt: number;
|
|
49
|
+
/** Sent to many: the bulk mailbox or a List-Id. */
|
|
50
|
+
bulk: boolean;
|
|
51
|
+
envelope: boolean;
|
|
52
|
+
/** Stored from its first bytes, not whole yet. */
|
|
53
|
+
partial: boolean;
|
|
54
|
+
draft: boolean;
|
|
55
|
+
}
|
|
39
56
|
export interface MailActivityStore {
|
|
57
|
+
/**
|
|
58
|
+
* The account's live emails stored after `afterId`, oldest first, at most `limit`, and those of `ids`: what a
|
|
59
|
+
* processing mark reads next. The id is the store's insert order, so mail stored late is never behind the mark.
|
|
60
|
+
*/
|
|
61
|
+
emailsAfter(accountId: number, afterId: number, limit: number, ids?: readonly number[]): Promise<MarkedEmail[]>;
|
|
62
|
+
/** The account's newest store id; 0 with no mail. */
|
|
63
|
+
newestEmailId(accountId: number): Promise<number>;
|
|
64
|
+
/** Every `sync_cursors` value of the account whose key starts with `prefix`. */
|
|
65
|
+
statesLike(accountId: number, prefix: string): Promise<{
|
|
66
|
+
key: string;
|
|
67
|
+
value: string;
|
|
68
|
+
at: number;
|
|
69
|
+
}[]>;
|
|
40
70
|
/** Each live email's marks, by its Message-ID; one the store does not hold is left out. */
|
|
41
71
|
emailMarks(accountId: number, externalIds: readonly string[]): Promise<Map<string, EmailMarks>>;
|
|
42
72
|
/**
|
|
@@ -59,4 +89,5 @@ export declare const threadEmailIds: (database: CacheDatabase, accountId: number
|
|
|
59
89
|
until?: number;
|
|
60
90
|
}) => number[];
|
|
61
91
|
export declare const emailMarks: (database: CacheDatabase, accountId: number, externalIds: readonly string[]) => Map<string, EmailMarks>;
|
|
92
|
+
export declare const emailsAfter: (database: CacheDatabase, accountId: number, afterId: number, limit: number, ids?: readonly number[]) => MarkedEmail[];
|
|
62
93
|
export declare const mailActivity: (database: CacheDatabase) => MailActivityStore;
|
|
@@ -65,7 +65,45 @@ export const emailMarks = (database, accountId, externalIds) => {
|
|
|
65
65
|
}
|
|
66
66
|
return marks;
|
|
67
67
|
};
|
|
68
|
+
const MARKED = `
|
|
69
|
+
SELECT e.id, e.external_id, t.external_id AS thread, coalesce(e.received_at, e.sent_at) AS at, e.created_at,
|
|
70
|
+
e.updated_at, coalesce(e.draft, 0) AS draft, json_extract(e.metadata, '$.partial') IS NOT NULL AS partial,
|
|
71
|
+
coalesce(json_extract(e.headers, '$."list-id"'), json_extract(e.metadata, '$.listId')) IS NOT NULL
|
|
72
|
+
OR EXISTS (SELECT 1 FROM email_mailboxes m JOIN mailboxes b ON b.id = m.mailbox_id
|
|
73
|
+
WHERE m.email_id = e.id AND b.kind = 'bulk') AS bulk,
|
|
74
|
+
EXISTS (SELECT 1 FROM email_mailboxes m JOIN mailboxes b ON b.id = m.mailbox_id
|
|
75
|
+
WHERE m.email_id = e.id AND b.kind = 'envelope') AS envelope
|
|
76
|
+
FROM emails e JOIN email_threads t ON t.id = e.email_thread_id`;
|
|
77
|
+
const markedOf = (row) => ({
|
|
78
|
+
id: Number(row.id),
|
|
79
|
+
externalId: String(row.external_id),
|
|
80
|
+
thread: String(row.thread),
|
|
81
|
+
at: int(row.at),
|
|
82
|
+
storedAt: Number(row.created_at),
|
|
83
|
+
changedAt: Number(row.updated_at),
|
|
84
|
+
bulk: Boolean(row.bulk),
|
|
85
|
+
envelope: Boolean(row.envelope),
|
|
86
|
+
partial: Boolean(row.partial),
|
|
87
|
+
draft: Boolean(row.draft),
|
|
88
|
+
});
|
|
89
|
+
export const emailsAfter = (database, accountId, afterId, limit, ids = []) => {
|
|
90
|
+
const next = database
|
|
91
|
+
.prepare(`${MARKED} WHERE e.id > ? AND e.account_id = ? AND e.deleted_at IS NULL ORDER BY e.id LIMIT ?`)
|
|
92
|
+
.all(afterId, accountId, limit);
|
|
93
|
+
const one = database.prepare(`${MARKED} WHERE e.id = ? AND e.account_id = ? AND e.deleted_at IS NULL`);
|
|
94
|
+
const named = ids.flatMap((id) => {
|
|
95
|
+
const row = one.get(id, accountId);
|
|
96
|
+
return row ? [row] : [];
|
|
97
|
+
});
|
|
98
|
+
return [...named, ...next].map(markedOf);
|
|
99
|
+
};
|
|
68
100
|
export const mailActivity = (database) => ({
|
|
101
|
+
emailsAfter: async (accountId, afterId, limit, ids) => emailsAfter(database, accountId, afterId, limit, ids),
|
|
102
|
+
newestEmailId: async (accountId) => Number(database.prepare("SELECT max(id) AS id FROM emails WHERE account_id = ?").get(accountId)?.id ?? 0),
|
|
103
|
+
statesLike: async (accountId, prefix) => database
|
|
104
|
+
.prepare("SELECT key, value, updated_at FROM sync_cursors WHERE account_id = ? AND substr(key, 1, ?) = ?")
|
|
105
|
+
.all(accountId, prefix.length, prefix)
|
|
106
|
+
.map((row) => ({ key: String(row.key), value: String(row.value), at: Number(row.updated_at) })),
|
|
69
107
|
emailMarks: async (accountId, externalIds) => emailMarks(database, accountId, externalIds),
|
|
70
108
|
threadActivity: async (accountId, since, where) => threadActivity(database, accountId, since, where),
|
|
71
109
|
});
|
|
@@ -269,6 +269,8 @@ export interface MailStore extends PartialMailStore, MailActivityStore {
|
|
|
269
269
|
}[]>;
|
|
270
270
|
/** Live emails of one account by Message-ID, each placed in its thread; an unknown one is left out. */
|
|
271
271
|
inThreads(accountId: number, externalIds: string[]): Promise<EmailInThread[]>;
|
|
272
|
+
/** Emails by store id, as search hits in the order given; one the store does not hold is left out. */
|
|
273
|
+
emailHits(ids: readonly number[]): Promise<StoredHit[]>;
|
|
272
274
|
/** A thread's live emails, oldest first, as search hits; `window` keeps those received in (after, until], in ms. */
|
|
273
275
|
threadHits(accountId: number, thread: string, window?: {
|
|
274
276
|
after?: number;
|
|
@@ -633,6 +633,7 @@ export const mailStoreOver = ({ database, orm, now }, stemmerFor = stemmerCache(
|
|
|
633
633
|
return place ? [{ ...place, score }] : [];
|
|
634
634
|
});
|
|
635
635
|
},
|
|
636
|
+
emailHits: async (ids) => emailHitsByPk(database, [...ids]),
|
|
636
637
|
async threadHits(accountId, thread, window) {
|
|
637
638
|
return emailHitsByPk(database, threadEmailIds(database, accountId, thread, window));
|
|
638
639
|
},
|
|
@@ -20,6 +20,7 @@ export declare const ENTITY_TABLES: {
|
|
|
20
20
|
readonly file: "files";
|
|
21
21
|
readonly identity: "identities";
|
|
22
22
|
readonly image: "attachments";
|
|
23
|
+
readonly invoice: "invoices";
|
|
23
24
|
readonly meeting: "meetings";
|
|
24
25
|
readonly meeting_transcript: "meeting_transcripts";
|
|
25
26
|
readonly meeting_transcript_row: "meeting_transcript_rows";
|
|
@@ -27,6 +28,7 @@ export declare const ENTITY_TABLES: {
|
|
|
27
28
|
readonly message: "messages";
|
|
28
29
|
readonly note: "notes";
|
|
29
30
|
readonly organization: "organizations";
|
|
31
|
+
readonly payment: "payments";
|
|
30
32
|
readonly person: "persons";
|
|
31
33
|
readonly place: "places";
|
|
32
34
|
readonly project: "projects";
|
|
@@ -19,6 +19,7 @@ export const ENTITY_TABLES = {
|
|
|
19
19
|
file: "files",
|
|
20
20
|
identity: "identities",
|
|
21
21
|
image: "attachments",
|
|
22
|
+
invoice: "invoices",
|
|
22
23
|
meeting: "meetings",
|
|
23
24
|
meeting_transcript: "meeting_transcripts",
|
|
24
25
|
meeting_transcript_row: "meeting_transcript_rows",
|
|
@@ -26,6 +27,7 @@ export const ENTITY_TABLES = {
|
|
|
26
27
|
message: "messages",
|
|
27
28
|
note: "notes",
|
|
28
29
|
organization: "organizations",
|
|
30
|
+
payment: "payments",
|
|
29
31
|
person: "persons",
|
|
30
32
|
place: "places",
|
|
31
33
|
project: "projects",
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { type FinanceReview, type InvoiceDirection, type InvoiceStatus, type MoneyDirection } from "../../domain/finance.js";
|
|
2
|
+
import { type Money } from "../../domain/money.js";
|
|
3
|
+
import { type Decider } from "../decisions.js";
|
|
4
|
+
import { type Actor, type ProposedByFilter } from "./actors.js";
|
|
5
|
+
import { type Author } from "./memories.js";
|
|
6
|
+
import type { StoreContext } from "./open.js";
|
|
7
|
+
/** A `person:` or `organization:` on an invoice or a payment, with its name so a list needs no lookup. */
|
|
8
|
+
export interface Party {
|
|
9
|
+
ref: string;
|
|
10
|
+
name: string | null;
|
|
11
|
+
/** The owner's own person row. */
|
|
12
|
+
owner: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface Reviewed {
|
|
15
|
+
review: FinanceReview;
|
|
16
|
+
/** `name` is a bot's handle and `kind` whether it is an agent or a rule; both `null` for a person. */
|
|
17
|
+
author: {
|
|
18
|
+
type: Actor["type"];
|
|
19
|
+
id: string;
|
|
20
|
+
name: string | null;
|
|
21
|
+
kind: "agent" | "rule" | null;
|
|
22
|
+
};
|
|
23
|
+
model: string | null;
|
|
24
|
+
confirmedBy: {
|
|
25
|
+
type: Actor["type"];
|
|
26
|
+
id: string;
|
|
27
|
+
} | null;
|
|
28
|
+
source: string;
|
|
29
|
+
/** Why an agent or an import proposed it. */
|
|
30
|
+
reason: string | null;
|
|
31
|
+
project: string | null;
|
|
32
|
+
projectName: string | null;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
updatedAt: string;
|
|
35
|
+
}
|
|
36
|
+
export interface Invoice extends Reviewed {
|
|
37
|
+
id: string;
|
|
38
|
+
ref: string;
|
|
39
|
+
/** One line, as a list or the review inbox prints it. */
|
|
40
|
+
title: string;
|
|
41
|
+
direction: InvoiceDirection;
|
|
42
|
+
number: string | null;
|
|
43
|
+
issuer: Party | null;
|
|
44
|
+
counterparty: Party;
|
|
45
|
+
currency: string;
|
|
46
|
+
total: string;
|
|
47
|
+
/** Settled by confirmed payments. */
|
|
48
|
+
paid: string;
|
|
49
|
+
/** Still owed: `total − paid`. */
|
|
50
|
+
open: string;
|
|
51
|
+
issueDate: string | null;
|
|
52
|
+
dueDate: string | null;
|
|
53
|
+
status: InvoiceStatus;
|
|
54
|
+
}
|
|
55
|
+
export interface InvoiceLine {
|
|
56
|
+
position: number;
|
|
57
|
+
description: string;
|
|
58
|
+
quantity: string;
|
|
59
|
+
unitPrice: string | null;
|
|
60
|
+
amount: string;
|
|
61
|
+
}
|
|
62
|
+
export interface Allocation {
|
|
63
|
+
payment: string;
|
|
64
|
+
invoice: string;
|
|
65
|
+
amount: string;
|
|
66
|
+
currency: string;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
}
|
|
69
|
+
export interface InvoiceDetail extends Invoice {
|
|
70
|
+
lines: InvoiceLine[];
|
|
71
|
+
allocations: Allocation[];
|
|
72
|
+
}
|
|
73
|
+
export interface Payment extends Reviewed {
|
|
74
|
+
id: string;
|
|
75
|
+
ref: string;
|
|
76
|
+
title: string;
|
|
77
|
+
direction: MoneyDirection;
|
|
78
|
+
payer: Party | null;
|
|
79
|
+
payee: Party | null;
|
|
80
|
+
amount: string;
|
|
81
|
+
currency: string;
|
|
82
|
+
/** `YYYY-MM-DD`. */
|
|
83
|
+
date: string;
|
|
84
|
+
reference: string | null;
|
|
85
|
+
/** Allocated to invoices, confirmed or not. */
|
|
86
|
+
allocated: string;
|
|
87
|
+
unallocated: string;
|
|
88
|
+
}
|
|
89
|
+
export interface PaymentDetail extends Payment {
|
|
90
|
+
allocations: Allocation[];
|
|
91
|
+
}
|
|
92
|
+
interface Written {
|
|
93
|
+
/** The owner's entry is confirmed at once; a bot's waits as proposed for the owner. */
|
|
94
|
+
by: Author;
|
|
95
|
+
project?: string;
|
|
96
|
+
/** Where a bot's row came from, such as `agent` or an importer's name; the owner's is always `owner`. */
|
|
97
|
+
source?: string;
|
|
98
|
+
/** Why a bot proposes it, kept for the reviewer. */
|
|
99
|
+
reason?: string;
|
|
100
|
+
}
|
|
101
|
+
export interface InvoiceLineInput {
|
|
102
|
+
description: string;
|
|
103
|
+
/** A decimal string; `1` when not given. */
|
|
104
|
+
quantity?: string;
|
|
105
|
+
/** Decimal strings in the invoice's currency. Give either or both: both must agree, quantity × unit price. */
|
|
106
|
+
unitPrice?: string;
|
|
107
|
+
amount?: string;
|
|
108
|
+
}
|
|
109
|
+
export interface InvoiceInput extends Written {
|
|
110
|
+
direction: InvoiceDirection;
|
|
111
|
+
number?: string;
|
|
112
|
+
/** `person:` or `organization:`. */
|
|
113
|
+
issuer?: string;
|
|
114
|
+
counterparty: string;
|
|
115
|
+
currency: string;
|
|
116
|
+
/** `YYYY-MM-DD`. */
|
|
117
|
+
issueDate?: string;
|
|
118
|
+
dueDate?: string;
|
|
119
|
+
/** Kept as a draft until `issueInvoice`; otherwise issued at once. */
|
|
120
|
+
draft?: boolean;
|
|
121
|
+
lines: InvoiceLineInput[];
|
|
122
|
+
/** The total printed on the invoice: refused when it is not the sum of the lines. */
|
|
123
|
+
total?: string;
|
|
124
|
+
}
|
|
125
|
+
export interface PaymentInput extends Written {
|
|
126
|
+
direction: MoneyDirection;
|
|
127
|
+
payer?: string;
|
|
128
|
+
payee?: string;
|
|
129
|
+
amount: string;
|
|
130
|
+
currency: string;
|
|
131
|
+
date: string;
|
|
132
|
+
reference?: string;
|
|
133
|
+
/** Invoices it settles, in the payment's currency; a bot's count only once the owner confirms the payment. */
|
|
134
|
+
allocations?: {
|
|
135
|
+
invoice: string;
|
|
136
|
+
amount: string;
|
|
137
|
+
}[];
|
|
138
|
+
}
|
|
139
|
+
interface ListFilter {
|
|
140
|
+
project?: string;
|
|
141
|
+
review?: FinanceReview;
|
|
142
|
+
proposedBy?: ProposedByFilter;
|
|
143
|
+
/** 1–500, 100 by default; newest written first. */
|
|
144
|
+
limit?: number;
|
|
145
|
+
}
|
|
146
|
+
export interface OpenTotal extends Money {
|
|
147
|
+
invoices: number;
|
|
148
|
+
}
|
|
149
|
+
export interface FinanceStore {
|
|
150
|
+
addInvoice(input: InvoiceInput): Promise<InvoiceDetail>;
|
|
151
|
+
invoice(reference: string): Promise<InvoiceDetail>;
|
|
152
|
+
invoices(filter?: ListFilter & {
|
|
153
|
+
direction?: InvoiceDirection;
|
|
154
|
+
status?: InvoiceStatus;
|
|
155
|
+
/** Issued or partly paid. */
|
|
156
|
+
open?: boolean;
|
|
157
|
+
counterparty?: string;
|
|
158
|
+
}): Promise<Invoice[]>;
|
|
159
|
+
/** The owner sends a draft: its status then follows its allocations. */
|
|
160
|
+
issueInvoice(reference: string, by: Author): Promise<InvoiceDetail>;
|
|
161
|
+
/** The owner cancels an invoice no confirmed payment is allocated to; proposed allocations to it go. */
|
|
162
|
+
voidInvoice(reference: string, by: Author): Promise<InvoiceDetail>;
|
|
163
|
+
addPayment(input: PaymentInput): Promise<PaymentDetail>;
|
|
164
|
+
payment(reference: string): Promise<PaymentDetail>;
|
|
165
|
+
payments(filter?: ListFilter & {
|
|
166
|
+
direction?: MoneyDirection;
|
|
167
|
+
party?: string;
|
|
168
|
+
}): Promise<Payment[]>;
|
|
169
|
+
/**
|
|
170
|
+
* Settles part of an invoice with part of a payment, in one currency, never beyond either. The owner allocates any
|
|
171
|
+
* payment; a bot only one it proposed that is still proposed.
|
|
172
|
+
*/
|
|
173
|
+
allocate(input: {
|
|
174
|
+
payment: string;
|
|
175
|
+
invoice: string;
|
|
176
|
+
amount: string;
|
|
177
|
+
by: Author;
|
|
178
|
+
}): Promise<Allocation>;
|
|
179
|
+
/**
|
|
180
|
+
* The owner confirms a proposed `invoice:` or `payment:`; only the owner decides money. A payment whose allocations
|
|
181
|
+
* would settle more than an invoice's total, given the confirmed payments by then, is refused and stays proposed.
|
|
182
|
+
*/
|
|
183
|
+
confirm(reference: string, by: Decider, reason?: string): Promise<InvoiceDetail | PaymentDetail>;
|
|
184
|
+
/** The owner turns a proposal down; it stays, `rejected`, and its allocations go. */
|
|
185
|
+
reject(reference: string, by: Decider, reason?: string): Promise<InvoiceDetail | PaymentDetail>;
|
|
186
|
+
/** What is still owed on confirmed open invoices, per direction and per currency: nothing is converted. */
|
|
187
|
+
openTotals(filter?: {
|
|
188
|
+
project?: string;
|
|
189
|
+
}): Promise<{
|
|
190
|
+
receivable: OpenTotal[];
|
|
191
|
+
payable: OpenTotal[];
|
|
192
|
+
}>;
|
|
193
|
+
}
|
|
194
|
+
type FinanceOperations = {
|
|
195
|
+
[K in keyof FinanceStore]: FinanceStore[K] extends (...args: infer A) => Promise<infer R> ? (...args: A) => R : never;
|
|
196
|
+
};
|
|
197
|
+
export declare const financeOperationsOver: (context: StoreContext) => FinanceOperations;
|
|
198
|
+
export declare const financeStoreOver: (context: StoreContext) => FinanceStore;
|
|
199
|
+
export {};
|