@wirecat/cli-core 0.419.0 → 0.421.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 +48 -0
- package/dist/cli/bot/context.d.ts +3 -2
- package/dist/cli/bot/context.js +15 -0
- package/dist/cli/config-command.js +1 -2
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -1
- package/dist/cli/messenger/context.js +3 -6
- package/dist/cli/permission-keys.d.ts +2 -0
- package/dist/cli/permission-keys.js +10 -3
- package/dist/cli/preview.d.ts +2 -2
- package/dist/cli/preview.js +4 -3
- package/dist/cli/program.js +4 -8
- package/dist/cli/settings.d.ts +0 -2
- package/dist/cli/settings.js +1 -5
- package/dist/domain/providers.d.ts +20 -2
- package/dist/domain/providers.js +23 -3
- package/dist/domain/tag-consolidation.d.ts +30 -1
- package/dist/entities/index.d.ts +4 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp/surface.js +0 -4
- package/dist/mcp/tool.d.ts +1 -3
- package/dist/mcp/tool.js +1 -2
- package/dist/meetings/calendar-text.d.ts +13 -0
- package/dist/meetings/calendar-text.js +57 -0
- package/dist/meetings/event-store.d.ts +202 -0
- package/dist/meetings/event-store.js +1 -0
- package/dist/meetings/events.js +5 -1
- package/dist/meetings/index.d.ts +3 -0
- package/dist/meetings/index.js +2 -0
- package/dist/meetings/join-key.d.ts +7 -0
- package/dist/meetings/join-key.js +38 -0
- package/dist/meetings/mcp/index.d.ts +15 -15
- package/dist/meetings/model.d.ts +8 -2
- package/dist/meetings/read-answers.d.ts +6 -2
- package/dist/meetings/read-answers.js +9 -2
- package/dist/meetings/store.d.ts +2 -0
- package/dist/meetings/testing/event-store-contract.d.ts +10 -0
- package/dist/meetings/testing/event-store-contract.js +161 -0
- package/dist/meetings/testing/index.d.ts +1 -0
- package/dist/meetings/testing/index.js +1 -0
- package/dist/parity/manifest.js +0 -4
- package/dist/search/account-list.js +39 -7
- package/dist/sends/index.d.ts +1 -1
- package/dist/sends/index.js +1 -1
- package/dist/sends/permissions.d.ts +0 -13
- package/dist/sends/permissions.js +15 -142
- package/dist/services/agenda.js +5 -5
- package/dist/services/document-source.d.ts +7 -3
- package/dist/services/document-source.js +24 -12
- package/dist/services/documents/ingestion.d.ts +6 -1
- package/dist/services/documents/ingestion.js +4 -0
- package/dist/services/notes-search.js +3 -2
- package/dist/services/search-all.js +1 -0
- package/dist/services/task-tag-filters.d.ts +3 -0
- package/dist/services/task-tag-filters.js +8 -0
- package/dist/services/tasks.js +5 -9
- package/dist/store/document-transfer/index.js +12 -2
- package/dist/store/index.d.ts +2 -1
- package/dist/store/sqlite/accounts.js +1 -0
- package/dist/store/sqlite/calendar.d.ts +3 -0
- package/dist/store/sqlite/calendar.js +593 -0
- package/dist/store/sqlite/catalog.js +16 -5
- package/dist/store/sqlite/chat-rekey.js +1 -1
- package/dist/store/sqlite/chats.js +2 -2
- package/dist/store/sqlite/context-document-source.js +8 -4
- package/dist/store/sqlite/document-transfer/apply.js +24 -2
- package/dist/store/sqlite/document-transfer/collection.d.ts +19 -0
- package/dist/store/sqlite/document-transfer/collection.js +66 -0
- package/dist/store/sqlite/document-transfer/plan.js +15 -8
- package/dist/store/sqlite/document-transfer/snapshot.js +12 -7
- package/dist/store/sqlite/entity-types.d.ts +5 -1
- package/dist/store/sqlite/entity-types.js +5 -1
- package/dist/store/sqlite/events.d.ts +8 -2
- package/dist/store/sqlite/events.js +36 -12
- package/dist/store/sqlite/files.d.ts +93 -0
- package/dist/store/sqlite/files.js +293 -0
- package/dist/store/sqlite/folded.d.ts +3 -0
- package/dist/store/sqlite/folded.js +1 -0
- package/dist/store/sqlite/imported-documents.js +1 -1
- package/dist/store/sqlite/join-keys.d.ts +8 -0
- package/dist/store/sqlite/join-keys.js +27 -0
- package/dist/store/sqlite/knowledge.js +6 -6
- package/dist/store/sqlite/link-reviews.d.ts +9 -0
- package/dist/store/sqlite/link-reviews.js +12 -0
- package/dist/store/sqlite/lucene-fields.js +8 -6
- package/dist/store/sqlite/manifest.js +11 -0
- package/dist/store/sqlite/meeting-selection.js +1 -1
- package/dist/store/sqlite/meetings.js +6 -1
- package/dist/store/sqlite/migrations.generated.js +143 -0
- package/dist/store/sqlite/note-index.d.ts +8 -1
- package/dist/store/sqlite/note-index.js +14 -0
- package/dist/store/sqlite/note-search.js +6 -5
- package/dist/store/sqlite/notes.d.ts +18 -1
- package/dist/store/sqlite/notes.js +237 -40
- package/dist/store/sqlite/open-store.js +4 -0
- package/dist/store/sqlite/person-links.js +7 -2
- package/dist/store/sqlite/schema/canonical-tags.d.ts +87 -0
- package/dist/store/sqlite/schema/canonical-tags.js +8 -0
- package/dist/store/sqlite/schema/tag-consolidations.d.ts +270 -0
- package/dist/store/sqlite/schema/tag-consolidations.js +34 -0
- package/dist/store/sqlite/schema.d.ts +3589 -1634
- package/dist/store/sqlite/schema.js +191 -13
- package/dist/store/sqlite/tag-consolidation-apply.d.ts +3 -0
- package/dist/store/sqlite/tag-consolidation-apply.js +88 -0
- package/dist/store/sqlite/tag-consolidation-input.d.ts +16 -0
- package/dist/store/sqlite/tag-consolidation-input.js +52 -0
- package/dist/store/sqlite/tag-consolidation.js +51 -66
- package/dist/store/sqlite/tag-creation.js +17 -8
- package/dist/store/sqlite/tag-resolution.d.ts +5 -0
- package/dist/store/sqlite/tag-resolution.js +33 -0
- package/dist/store/sqlite/tags.d.ts +3 -1
- package/dist/store/sqlite/tags.js +70 -50
- package/dist/store/sqlite/tasks.d.ts +2 -0
- package/dist/store/sqlite/tasks.js +6 -1
- package/dist/store/sqlite/things.js +2 -1
- package/dist/store/sqlite/vocabulary.d.ts +1 -0
- package/dist/store/sqlite/vocabulary.js +30 -8
- package/dist/store/store.d.ts +6 -0
- package/dist/store/store.js +10 -0
- package/dist/store/tags.js +2 -2
- package/package.json +2 -1
- package/dist/cli/moved.d.ts +0 -18
- package/dist/cli/moved.js +0 -72
- package/dist/sends/permission-aliases.d.ts +0 -5
- package/dist/sends/permission-aliases.js +0 -50
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { Profiles } from "../search/account-list.js";
|
|
2
|
-
import type { Note,
|
|
3
|
-
/**
|
|
4
|
-
|
|
2
|
+
import type { Note, StoredAccount, StoredFile } from "../store/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Where a hit came from. The document's preferred file says it: its account's provider, its link and its edit time.
|
|
5
|
+
* A Drive document under a notes folder (before version 31 moves it) is still known by its front matter.
|
|
6
|
+
* Indexing time belongs to the local row.
|
|
7
|
+
*/
|
|
8
|
+
export declare const documentSource: (note: Note, accounts: readonly StoredAccount[], profiles: Profiles, file?: StoredFile) => {
|
|
5
9
|
kind: "document" | "note";
|
|
6
10
|
provider: string;
|
|
7
11
|
account: string;
|
|
@@ -1,18 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { isFolderProvider, kindIn } from "../domain/providers.js";
|
|
2
|
+
/**
|
|
3
|
+
* Where a hit came from. The document's preferred file says it: its account's provider, its link and its edit time.
|
|
4
|
+
* A Drive document under a notes folder (before version 31 moves it) is still known by its front matter.
|
|
5
|
+
* Indexing time belongs to the local row.
|
|
6
|
+
*/
|
|
7
|
+
export const documentSource = (note, accounts, profiles, file) => {
|
|
3
8
|
const metadata = note.frontMatter;
|
|
4
|
-
const
|
|
5
|
-
const remote = note.source === "file" &&
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
const account = accounts.find(({ id }) => String(id) === note.folderId);
|
|
10
|
+
const remote = note.source === "file" &&
|
|
11
|
+
((account !== undefined && kindIn(account.provider) === "documents") || metadata?.source === "google-drive");
|
|
12
|
+
const profile = remote && account
|
|
13
|
+
? Object.entries(profiles)
|
|
14
|
+
.flatMap(([command, named]) => Object.entries(named).map(([name, key]) => ({ command, name, key })))
|
|
15
|
+
.find(({ key }) => (key.provider === account.provider && key.account === account.account) ||
|
|
16
|
+
(isFolderProvider(key.provider) && key.account === account.name))
|
|
8
17
|
: undefined;
|
|
18
|
+
const url = file?.url ?? (remote && typeof metadata?.sourceUrl === "string" ? metadata.sourceUrl : undefined);
|
|
19
|
+
const modified = file?.externalUpdatedAt ??
|
|
20
|
+
(remote && typeof metadata?.modifiedAt === "string" && Number.isFinite(Date.parse(metadata.modifiedAt))
|
|
21
|
+
? metadata.modifiedAt
|
|
22
|
+
: undefined);
|
|
9
23
|
return {
|
|
10
24
|
kind: remote ? "document" : "note",
|
|
11
|
-
provider: profile ?
|
|
12
|
-
account: profile ?? note.folderId ?? "internal",
|
|
13
|
-
...(remote &&
|
|
14
|
-
updated_at: remote &&
|
|
15
|
-
? metadata.modifiedAt
|
|
16
|
-
: note.updatedAt,
|
|
25
|
+
provider: profile ? profile.command : "notes",
|
|
26
|
+
account: profile?.name ?? note.folderId ?? "internal",
|
|
27
|
+
...(remote && url !== undefined ? { url } : {}),
|
|
28
|
+
updated_at: remote && modified !== undefined ? modified : note.updatedAt,
|
|
17
29
|
};
|
|
18
30
|
};
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { SourceContent, SourceFile } from "../../documents/model.js";
|
|
2
2
|
import type { CatalogInput, CatalogQuery, MessageStore } from "../../store/index.js";
|
|
3
3
|
export interface IngestionOptions<M extends SourceFile> {
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The documents account's provider (`google-drive`): each principal's documents live under
|
|
6
|
+
* `{ provider, account: principal }`. Without it they live in a notes folder named `collectionName(principal)`.
|
|
7
|
+
*/
|
|
8
|
+
provider?: string;
|
|
9
|
+
collectionName?(principal: string): string;
|
|
5
10
|
externalId(id: string): string;
|
|
6
11
|
catalogInput(file: M): CatalogInput;
|
|
7
12
|
frontMatter(content: SourceContent<M>): Record<string, unknown>;
|
|
@@ -2,6 +2,10 @@ import { CliError } from "@wirecat/cli-base";
|
|
|
2
2
|
import { walkQuery } from "@wirecat/cli-base/query";
|
|
3
3
|
export const documentIngestion = (store, options) => {
|
|
4
4
|
const folder = async (principal, create) => {
|
|
5
|
+
if (options.provider)
|
|
6
|
+
return store.notes.documentsAccount({ provider: options.provider, account: principal }, create);
|
|
7
|
+
if (!options.collectionName)
|
|
8
|
+
throw new CliError("configuration_error", "document ingestion needs a provider or a collection name");
|
|
5
9
|
const name = options.collectionName(principal);
|
|
6
10
|
const found = (await store.notes.folders()).find((item) => item.name === name);
|
|
7
11
|
return found ?? (create ? await store.notes.addFolder({ name, format: "markdown" }) : undefined);
|
|
@@ -295,7 +295,7 @@ export const searchNotes = async (store, query, { limit = 20, offset = 0, tag, f
|
|
|
295
295
|
const hasMore = slice ? matched.hasMore : ordered.length > window || matched.hasMore || titled.hasMore;
|
|
296
296
|
const hits = [];
|
|
297
297
|
const counts = new Map();
|
|
298
|
-
const
|
|
298
|
+
const accounts = await store.accounts.storedAccounts();
|
|
299
299
|
const profiles = await store.accounts.profiles();
|
|
300
300
|
for (const [ref, { note, foundBy }] of page) {
|
|
301
301
|
const links = (await store.notes.links({ from: ref })).map(({ to, targetText, kind, anchor }) => ({
|
|
@@ -310,7 +310,7 @@ export const searchNotes = async (store, query, { limit = 20, offset = 0, tag, f
|
|
|
310
310
|
folder_id: note.folderId,
|
|
311
311
|
path: note.path,
|
|
312
312
|
title: note.title,
|
|
313
|
-
...documentSource(note,
|
|
313
|
+
...documentSource(note, accounts, profiles, note.source === "file" ? (await store.files.ofDocument(note.ref))[0] : undefined),
|
|
314
314
|
excerpt: firstLine(note.text, words),
|
|
315
315
|
links,
|
|
316
316
|
found_by: foundBy,
|
|
@@ -374,6 +374,7 @@ export const searchNotesOf = async (store, account, text, { accounts: list, app,
|
|
|
374
374
|
const held = [
|
|
375
375
|
{ provider: "notes", account: INTERNAL_NOTES },
|
|
376
376
|
...(await store.notes.folders()).map(({ id }) => ({ provider: "notes", account: id })),
|
|
377
|
+
...(await store.notes.documentsAccounts()).map(({ id }) => ({ provider: "notes", account: id })),
|
|
377
378
|
];
|
|
378
379
|
const named = list === undefined
|
|
379
380
|
? { accounts: held, skipped: [] }
|
|
@@ -109,6 +109,7 @@ export const searchAll = async (store, account, request, messenger = {}, searchM
|
|
|
109
109
|
const read = chosen?.map(({ account }) => account) ?? [
|
|
110
110
|
INTERNAL_NOTES,
|
|
111
111
|
...(await store.notes.folders()).map(({ id }) => id),
|
|
112
|
+
...(await store.notes.documentsAccounts()).map(({ id }) => id),
|
|
112
113
|
];
|
|
113
114
|
accounts.push(...read.map((account) => ({ resource, provider: "notes", account })));
|
|
114
115
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { walkQuery } from "@wirecat/cli-base/query";
|
|
2
|
+
export const taskTagFilters = async (store, query) => {
|
|
3
|
+
const tags = new Map();
|
|
4
|
+
for (const node of query ? walkQuery(query.root) : [])
|
|
5
|
+
if (node.field === "tag" && !tags.has(node.value))
|
|
6
|
+
tags.set(node.value, await store.tasks.tagWhere(node.value));
|
|
7
|
+
return tags;
|
|
8
|
+
};
|
package/dist/services/tasks.js
CHANGED
|
@@ -9,6 +9,7 @@ import { createTaskService, TASK_KINDS, TASK_STATES, } from "../tasks/index.js";
|
|
|
9
9
|
import { storedChatId } from "./message-resolution.js";
|
|
10
10
|
import { categorize, taskCategoryOf } from "./task-categories.js";
|
|
11
11
|
import { taskAccount } from "./task-rules.js";
|
|
12
|
+
import { taskTagFilters } from "./task-tag-filters.js";
|
|
12
13
|
export { TASK_KINDS, TASK_STATES };
|
|
13
14
|
export const TASK_QUERY = {
|
|
14
15
|
entity: "task",
|
|
@@ -68,17 +69,11 @@ export const TASK_PAIR_QUERY = {
|
|
|
68
69
|
};
|
|
69
70
|
const TIME = (sql) => ({ type: "time", sql });
|
|
70
71
|
/** `chat:` names the chat as the messenger does; `groups` holds each name already resolved to its stored id. */
|
|
71
|
-
const taskColumns = (groups) => ({
|
|
72
|
+
const taskColumns = (groups, tags) => ({
|
|
72
73
|
id: { type: "kw", sql: "t.package_id" },
|
|
73
74
|
key: { type: "kw", sql: "t.key" },
|
|
74
75
|
category: { type: "kw", sql: "t.category" },
|
|
75
|
-
tag: {
|
|
76
|
-
where: (node) => ({
|
|
77
|
-
sql: "EXISTS (SELECT 1 FROM taggings g JOIN tags n ON n.id = g.tag_id " +
|
|
78
|
-
"WHERE g.taggable_type = 'task' AND g.taggable_id = t.id AND n.name = ?)",
|
|
79
|
-
params: [node.value.trim().toLowerCase()],
|
|
80
|
-
}),
|
|
81
|
-
},
|
|
76
|
+
tag: { where: (node) => tags.get(node.value) ?? { sql: "0", params: [] } },
|
|
82
77
|
title: { type: "kw", sql: "t.title_folded", folded: true },
|
|
83
78
|
kind: { type: "enum", sql: "t.type" },
|
|
84
79
|
state: { type: "enum", sql: "t.status" },
|
|
@@ -213,7 +208,8 @@ export const tasksService = (deps, categories) => {
|
|
|
213
208
|
for (const node of query ? walkQuery(query.root) : [])
|
|
214
209
|
if (node.field === "chat" && node.operator !== "wildcard" && !groups.has(node.value))
|
|
215
210
|
groups.set(node.value, await storedChatId(deps.messenger, node.value, store, account, { includeLeft: true }));
|
|
216
|
-
const
|
|
211
|
+
const tags = await taskTagFilters(store, query);
|
|
212
|
+
const where = query ? queryFilter(query, taskColumns(groups, tags), { command: "tasks list" }) : undefined;
|
|
217
213
|
const rows = await store.tasks.query(taskAccount(account), where, { limit: limit + 1, offset });
|
|
218
214
|
const shown = rows.slice(0, limit);
|
|
219
215
|
return {
|
|
@@ -7,6 +7,7 @@ import { planTransfer } from "../sqlite/document-transfer/plan.js";
|
|
|
7
7
|
import { transferSnapshot } from "../sqlite/document-transfer/snapshot.js";
|
|
8
8
|
import { openSqlite } from "../sqlite/open.js";
|
|
9
9
|
import { openStoreContext } from "../sqlite/open-store.js";
|
|
10
|
+
import { assertReadCompatible } from "../sqlite/read-compatibility.js";
|
|
10
11
|
import { digest } from "./digest.js";
|
|
11
12
|
const locations = (options) => {
|
|
12
13
|
for (const value of [options.source, options.destination, options.collection])
|
|
@@ -51,8 +52,17 @@ const openSource = async (path) => {
|
|
|
51
52
|
}
|
|
52
53
|
};
|
|
53
54
|
const openPreviewTarget = async (path) => {
|
|
54
|
-
if (statSync(path, { throwIfNoEntry: false }))
|
|
55
|
-
|
|
55
|
+
if (statSync(path, { throwIfNoEntry: false })) {
|
|
56
|
+
const opened = await openSource(path);
|
|
57
|
+
try {
|
|
58
|
+
assertReadCompatible(opened.database);
|
|
59
|
+
return opened;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
opened.database.close();
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
56
66
|
const target = await openSqlite(":memory:");
|
|
57
67
|
try {
|
|
58
68
|
migrate(target.database);
|
package/dist/store/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { ContextEvidenceItem, ContextEvidencePage, ContextEvidenceReader, ContextEvidenceRequest, ContextEvidenceSender, ContextSource, } from "../context/evidence.js";
|
|
2
2
|
export { FACT_STATUSES, FACT_TYPES, MEMORY_KINDS, MEMORY_SCOPES, MEMORY_STATUSES, TASK_TYPES, WORK_TASK_TYPES, } from "../domain/knowledge.js";
|
|
3
|
-
export type { TagConsolidationOptions, TagConsolidationPreview, TagConsolidationStore, } from "../domain/tag-consolidation.js";
|
|
3
|
+
export type { TagConsolidationApplyOptions, TagConsolidationOptions, TagConsolidationPreview, TagConsolidationReceipt, TagConsolidationStore, } from "../domain/tag-consolidation.js";
|
|
4
4
|
export type { TagRedirectIndex, TagRedirectResolution, TagRedirectSnapshot } from "../domain/tag-redirects.js";
|
|
5
5
|
export { createTagRedirectIndex } from "../domain/tag-redirects.js";
|
|
6
6
|
export { note } from "../entities/note.js";
|
|
@@ -31,6 +31,7 @@ export { CATALOG_QUERY } from "./sqlite/catalog.js";
|
|
|
31
31
|
export type { ChatMetadata } from "./sqlite/chats.js";
|
|
32
32
|
export type { Email, EmailAddress, EmailAttachment, EmailFacts, EmailFilter, EmailInput, EmailInThread, EmailRecipient, EmailRef, EmailThread, EmailVectorHit, Mailbox, MailboxInput, MailFilter, MailStore, SenderScore, ThreadDetails, ThreadSave, } from "./sqlite/emails.js";
|
|
33
33
|
export type { Fact, FactInput, FactsStore } from "./sqlite/facts.js";
|
|
34
|
+
export type { FileListQuery, FilesStore, StoredFile } from "./sqlite/files.js";
|
|
34
35
|
export { IMPORTED_DOCUMENT_QUERY, type ImportedDocuments } from "./sqlite/imported-documents.js";
|
|
35
36
|
export type { Involvement, InvolvementStore } from "./sqlite/involvements.js";
|
|
36
37
|
export type { Annotation, KnowledgeRelation, KnowledgeStore, KnowledgeTarget, LabelledType, Organization, Project, Reminder, } from "./sqlite/knowledge.js";
|
|
@@ -111,6 +111,7 @@ export const purgeAccount = ({ orm, database }, accountKey) => {
|
|
|
111
111
|
orm.delete(accountIdentities).where(eq(accountIdentities.accountId, accountKey)).run();
|
|
112
112
|
// The inbox project and its tasks are the owner's; only the tie to the account goes.
|
|
113
113
|
orm.update(projects).set({ accountId: null }).where(eq(projects.accountId, accountKey)).run();
|
|
114
|
+
orm.run(sql `DELETE FROM files WHERE account_id = ${accountKey}`);
|
|
114
115
|
orm.delete(accounts).where(eq(accounts.id, accountKey)).run();
|
|
115
116
|
dropOrphanPeople(database, unseenBefore);
|
|
116
117
|
orm.run(sql `DELETE FROM embeddings WHERE content_hash IN (SELECT value FROM json_each(${JSON.stringify(hashes)}))
|