@wirecat/cli-core 0.347.0 → 0.349.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 +82 -0
- package/dist/cli/bot/copy.d.ts +1 -1
- package/dist/cli/bot/copy.js +1 -1
- package/dist/cli/embedding-choice.js +2 -1
- package/dist/cli/envelope.d.ts +4 -0
- package/dist/cli/envelope.js +4 -3
- package/dist/cli/guide.js +4 -0
- package/dist/cli/help/first-screen.js +13 -1
- package/dist/cli/help/sections.d.ts +4 -3
- package/dist/cli/help/sections.js +5 -10
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/messenger/backfill-command.js +6 -6
- package/dist/cli/messenger/context.d.ts +3 -3
- package/dist/cli/messenger/context.js +44 -17
- package/dist/cli/messenger/doctor-command.js +3 -3
- package/dist/cli/messenger/flooded.js +1 -1
- package/dist/cli/messenger/mcp-command.js +1 -1
- package/dist/cli/messenger/messages-delete-command.js +2 -1
- package/dist/cli/messenger/observed.js +24 -7
- package/dist/cli/messenger/schedule-command.js +4 -3
- package/dist/cli/messenger/serve-relay.js +1 -0
- package/dist/cli/messenger/store-maintenance-command.js +3 -3
- package/dist/cli/messenger/stored.js +36 -30
- package/dist/cli/program.js +10 -9
- package/dist/cli/runs/command.js +3 -2
- package/dist/cli/steps.d.ts +4 -0
- package/dist/cli/steps.js +9 -0
- package/dist/cli/store-settings.js +4 -3
- package/dist/context/evidence.d.ts +10 -0
- package/dist/domain/models.d.ts +11 -1
- package/dist/kit/contract.d.ts +2 -2
- package/dist/kit/contract.js +25 -0
- package/dist/kit/fake.d.ts +1 -0
- package/dist/kit/fake.js +15 -16
- package/dist/mcp/meeting-preparation.d.ts +1 -0
- package/dist/mcp/meeting-project-candidates.d.ts +1 -0
- package/dist/mcp/meeting-series-inventory.d.ts +1 -0
- package/dist/mcp/tool.js +2 -0
- package/dist/mcp/tools/messages-photo.js +2 -1
- package/dist/meetings/mcp/passage.d.ts +1 -0
- package/dist/meetings/mcp/project-evidence.d.ts +1 -0
- package/dist/meetings/mcp/search.d.ts +1 -0
- package/dist/meetings/reads.d.ts +1 -0
- package/dist/ports/messenger.d.ts +10 -2
- package/dist/runs/recording.js +1 -0
- package/dist/runs/scope.d.ts +7 -0
- package/dist/runs/scope.js +5 -0
- package/dist/services/archive.js +2 -1
- package/dist/services/chats.js +3 -2
- package/dist/services/context-evidence.d.ts +1 -1
- package/dist/services/conversations.js +2 -1
- package/dist/services/deps.js +2 -1
- package/dist/services/embeddings-maintenance.js +3 -2
- package/dist/services/index.d.ts +6 -4
- package/dist/services/index.js +1 -0
- package/dist/services/project-gathering-around.d.ts +37 -0
- package/dist/services/project-gathering-around.js +57 -0
- package/dist/services/project-gathering-request.d.ts +13 -1
- package/dist/services/project-gathering-request.js +23 -5
- package/dist/services/project-gathering.d.ts +15 -1
- package/dist/services/project-gathering.js +32 -1
- package/dist/services/search-all-meetings.d.ts +3 -4
- package/dist/services/search-all.d.ts +8 -1
- package/dist/services/search-all.js +1 -1
- package/dist/speech/transcribe.js +2 -1
- package/dist/store/chats.d.ts +2 -2
- package/dist/store/sqlite/chats.d.ts +2 -2
- package/dist/store/sqlite/chats.js +7 -7
- package/dist/store/sqlite/context-evidence.d.ts +4 -1
- package/dist/store/sqlite/context-evidence.js +12 -0
- package/dist/store/store.d.ts +2 -1
- package/dist/store/store.js +5 -1
- package/dist/store/types.d.ts +2 -2
- package/package.json +3 -3
- package/parity.json +2 -12
package/dist/runs/scope.js
CHANGED
|
@@ -21,6 +21,11 @@ export const currentRun = () => {
|
|
|
21
21
|
return processScope;
|
|
22
22
|
};
|
|
23
23
|
export const inRun = (scope, body) => scopes.run(scope, body);
|
|
24
|
+
/**
|
|
25
|
+
* A command as a person types it: `max personal store migrate`. A hint without the profile fails when copied,
|
|
26
|
+
* since no profile is assumed; outside a run with a profile it stays `max store migrate`.
|
|
27
|
+
*/
|
|
28
|
+
export const typedCommand = (tool, words, profile = currentRun().profile) => [tool, profile, words].filter((part) => part !== undefined && part !== "").join(" ");
|
|
24
29
|
/**
|
|
25
30
|
* For a one-shot command whose action runs outside `inRun` — max's `max bot`, recorded from commander's hooks, which
|
|
26
31
|
* cannot wrap the action — so its answers' `meta.run_id` names the run `runs show` finds. Never in a server.
|
package/dist/services/archive.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
2
|
import { CliError } from "@wirecat/cli-base";
|
|
3
3
|
import { capability } from "../ports/messenger.js";
|
|
4
|
+
import { typedCommand } from "../runs/scope.js";
|
|
4
5
|
import { fetchedKey, historyStartKey, } from "../store/store.js";
|
|
5
6
|
import { estimateBackfill } from "./backfill-estimate.js";
|
|
6
7
|
import { actionable, batchProgress } from "./batch.js";
|
|
@@ -11,7 +12,7 @@ import { catchUpSearch, validateCatchUp } from "./search-catchup.js";
|
|
|
11
12
|
const pushed = (deps, what) => {
|
|
12
13
|
if (deps.reads === "store") {
|
|
13
14
|
throw new CliError("validation_error", `${what} asks for older history, and this messenger pushes its history instead — keep ` +
|
|
14
|
-
`\`${deps.messenger.app.command
|
|
15
|
+
`\`${typedCommand(deps.messenger.app.command, "serve")}\` running`);
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
18
|
/** The most messages a provider hands out per history request — Telegram's cap. */
|
package/dist/services/chats.js
CHANGED
|
@@ -4,6 +4,7 @@ import { botCheckService } from "../botcheck/service.js";
|
|
|
4
4
|
import { threadIdOf } from "../domain/thread.js";
|
|
5
5
|
import { capability } from "../ports/messenger.js";
|
|
6
6
|
import { syncsOneChat } from "../ports/traits.js";
|
|
7
|
+
import { typedCommand } from "../runs/scope.js";
|
|
7
8
|
import { codeOf, guardedWrite } from "../sends/guarded.js";
|
|
8
9
|
import { newOperationId } from "../sends/send-id.js";
|
|
9
10
|
import { CHAT_COLUMNS, queryFilter, } from "../store/store.js";
|
|
@@ -147,7 +148,7 @@ export const chatsService = (deps) => ({
|
|
|
147
148
|
const counted = counts.length > 0 ? { ...known, memberCounts: counts } : known;
|
|
148
149
|
return completeness.state === "complete" || !syncsOneChat(deps.messenger)
|
|
149
150
|
? counted
|
|
150
|
-
: { ...counted, fetch:
|
|
151
|
+
: { ...counted, fetch: typedCommand(deps.messenger.app.command, `messages sync ${chatId}`) };
|
|
151
152
|
},
|
|
152
153
|
sendAs: async (chat) => {
|
|
153
154
|
if (deps.offline) {
|
|
@@ -180,7 +181,7 @@ export const chatsService = (deps) => ({
|
|
|
180
181
|
unknown,
|
|
181
182
|
...(stored?.completeness ? { completeness: stored.completeness } : {}),
|
|
182
183
|
...(stored?.completeness && stored.completeness.state !== "complete" && syncsOneChat(deps.messenger)
|
|
183
|
-
? { fetch:
|
|
184
|
+
? { fetch: typedCommand(deps.messenger.app.command, `messages sync ${id}`) }
|
|
184
185
|
: {}),
|
|
185
186
|
items,
|
|
186
187
|
};
|
|
@@ -5,5 +5,5 @@ export interface ScopedContextEvidenceReader extends ContextEvidenceReader {
|
|
|
5
5
|
usage(): ContextReadUsage;
|
|
6
6
|
}
|
|
7
7
|
export declare const createContextEvidenceReader: (port: ContextEvidenceReader, allowed: readonly ContextSource[], limits?: ContextReadLimits) => ScopedContextEvidenceReader;
|
|
8
|
-
export type { ContextEvidenceItem, ContextEvidencePage, ContextEvidenceReader, ContextEvidenceRequest, ContextSource, } from "../context/evidence.js";
|
|
8
|
+
export type { ContextEvidenceItem, ContextEvidencePage, ContextEvidenceReader, ContextEvidenceRequest, ContextIndex, ContextSource, } from "../context/evidence.js";
|
|
9
9
|
export type { ContextReadLimits, ContextReadUsage } from "../context/read-budget.js";
|
|
@@ -5,6 +5,7 @@ import { linkMessages, RULES_VERSION } from "../conversations/link.js";
|
|
|
5
5
|
import { formatLocator } from "../domain/locator.js";
|
|
6
6
|
import { formatReference } from "../domain/references.js";
|
|
7
7
|
import { conversation } from "../entities/conversation.js";
|
|
8
|
+
import { typedCommand } from "../runs/scope.js";
|
|
8
9
|
import { CONVERSATION_COLUMNS, queryFilter, } from "../store/store.js";
|
|
9
10
|
import { accountStore } from "./deps.js";
|
|
10
11
|
import { chatIdIn } from "./message-resolution.js";
|
|
@@ -38,7 +39,7 @@ export const conversationsService = (deps) => {
|
|
|
38
39
|
const store = await accountStore(deps);
|
|
39
40
|
return { store, chatId: await chatIdIn(deps.messenger, chat, store) };
|
|
40
41
|
};
|
|
41
|
-
const notBuilt = (chatId) => new CliError("not_found", `chat ${chatId} has no conversations yet — \`${deps.messenger.app.command
|
|
42
|
+
const notBuilt = (chatId) => new CliError("not_found", `chat ${chatId} has no conversations yet — \`${typedCommand(deps.messenger.app.command, `conversations build --chat ${chatId}`)}\``);
|
|
42
43
|
return {
|
|
43
44
|
build: async (chat, { maxMessages, check } = {}) => {
|
|
44
45
|
check?.();
|
package/dist/services/deps.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { isCliFailure } from "../errors/failures.js";
|
|
3
|
+
import { typedCommand } from "../runs/scope.js";
|
|
3
4
|
/** The store with the running account bound: the default for a service's reads and writes. */
|
|
4
5
|
export const accountStore = async (deps) => (await deps.store()).forAccount(await deps.account());
|
|
5
6
|
/**
|
|
@@ -49,7 +50,7 @@ export const storeIfOpen = async (deps) => {
|
|
|
49
50
|
/** Whether `chats`, `messages list|context` and `contacts` answer from the store instead of the messenger. */
|
|
50
51
|
export const fromStore = (deps) => deps.offline || deps.reads === "store";
|
|
51
52
|
/** What a store-mode read answers for a chat the store holds nothing of. */
|
|
52
|
-
export const nothingStored = (messenger) => `nothing stored for this chat yet — keep \`${messenger.app.command
|
|
53
|
+
export const nothingStored = (messenger) => `nothing stored for this chat yet — keep \`${typedCommand(messenger.app.command, "serve")}\` running`;
|
|
53
54
|
/** Where a store-mode messenger's history comes from, for what it cannot do. */
|
|
54
55
|
export const PUSHED = "this messenger's history is read from the local store";
|
|
55
56
|
export const OFFLINE = "--offline answers only from what is kept locally: `chats list|show`, `messages list|show|context` and `contacts list|show`";
|
|
@@ -6,6 +6,7 @@ import { DEFAULT_TEXT_MODEL, textModel, vectorModelKey } from "../embeddings/mod
|
|
|
6
6
|
import { remoteKey } from "../embeddings/remote.js";
|
|
7
7
|
import { CONTEXT_MESSAGES, CONTEXT_MINUTES } from "../images/context/index.js";
|
|
8
8
|
import { registeredImageProviders } from "../images/registry.js";
|
|
9
|
+
import { typedCommand } from "../runs/scope.js";
|
|
9
10
|
import { conversationsService } from "./conversations.js";
|
|
10
11
|
import { storedChatId } from "./message-resolution.js";
|
|
11
12
|
/** How much one run without `--chat` does at most, by default. */
|
|
@@ -16,11 +17,11 @@ const PER_SESSION = 8;
|
|
|
16
17
|
const PER_REQUEST = 256;
|
|
17
18
|
/** e5's tokenizer reads ~3.7 characters a token in Russian; 3 keeps the bound above the real count. */
|
|
18
19
|
const CHARS_PER_TOKEN_AT_LEAST = 3;
|
|
19
|
-
const notDownloaded = (deps, id) => new CliError("not_found", `${id} is not downloaded — \`${deps.messenger.app.command
|
|
20
|
+
const notDownloaded = (deps, id) => new CliError("not_found", `${id} is not downloaded — \`${typedCommand(deps.messenger.app.command, `models text download ${id}`)}\``, {
|
|
20
21
|
reason: "model.not-downloaded",
|
|
21
22
|
model: id,
|
|
22
23
|
});
|
|
23
|
-
export const notBuiltError = (deps, chatId) => new CliError("not_found", `chat ${chatId} has no conversations yet — \`${deps.messenger.app.command
|
|
24
|
+
export const notBuiltError = (deps, chatId) => new CliError("not_found", `chat ${chatId} has no conversations yet — \`${typedCommand(deps.messenger.app.command, `conversations build --chat ${chatId}`)}\``);
|
|
24
25
|
export const embeddingTarget = (deps, choice = DEFAULT_TEXT_MODEL) => {
|
|
25
26
|
if (typeof choice !== "string") {
|
|
26
27
|
const { remote, apiKey, concurrency = 4 } = choice;
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type BotCheckService } from "../botcheck/service.js";
|
|
2
|
-
export type { ContextEvidenceItem, ContextEvidencePage, ContextEvidenceReader, ContextEvidenceRequest, ContextReadLimits, ContextReadUsage, ContextSource, ScopedContextEvidenceReader, } from "./context-evidence.js";
|
|
2
|
+
export type { ContextEvidenceItem, ContextEvidencePage, ContextEvidenceReader, ContextEvidenceRequest, ContextIndex, ContextReadLimits, ContextReadUsage, ContextSource, ScopedContextEvidenceReader, } from "./context-evidence.js";
|
|
3
3
|
export { createContextEvidenceReader } from "./context-evidence.js";
|
|
4
4
|
export { type DownloadedModel, downloadImageModel, downloadTextModel, type ModelDownloadOptions, } from "./model-downloads.js";
|
|
5
|
-
export type { ProjectEvidenceItem, ProjectGathering, ProjectGatheringPorts, ProjectGatheringStop, ProjectSourceFetcher, } from "./project-gathering.js";
|
|
5
|
+
export type { ProjectEvidenceItem, ProjectGathering, ProjectGatheringPorts, ProjectGatheringStop, ProjectIndexCatchUp, ProjectSourceFetcher, } from "./project-gathering.js";
|
|
6
6
|
export { gatherProjectEvidence } from "./project-gathering.js";
|
|
7
|
-
export type {
|
|
7
|
+
export type { ProjectNeighbour, ProjectNeighbourReader } from "./project-gathering-around.js";
|
|
8
|
+
export { storedMessageNeighbours } from "./project-gathering-around.js";
|
|
9
|
+
export type { ProjectFetchState, ProjectGatheringBudgets, ProjectGatheringRequest, ProjectLane, ProjectLaneKind, ProjectUnitState, } from "./project-gathering-request.js";
|
|
8
10
|
import { type AccountService } from "./account.js";
|
|
9
11
|
import { type AdminService } from "./admin.js";
|
|
10
12
|
import { type AdminStatisticsService } from "./admin-statistics.js";
|
|
@@ -156,7 +158,7 @@ export { privatePeopleService } from "./private-people.js";
|
|
|
156
158
|
export { approveAsTask, type ProposalTaskStore, proposalSource } from "./proposal-tasks.js";
|
|
157
159
|
export type { RetentionQuery, RetentionService } from "./retention.js";
|
|
158
160
|
export { retentionService } from "./retention.js";
|
|
159
|
-
export { RESOURCES_SEARCHED, type SearchAllFound, type SearchAllItem, type SearchAllRequest, type SearchedResource, searchAll, } from "./search-all.js";
|
|
161
|
+
export { RESOURCES_SEARCHED, type SearchAllFound, type SearchAllItem, type SearchAllMessenger, type SearchAllRequest, type SearchedResource, searchAll, } from "./search-all.js";
|
|
160
162
|
export { type MeetingSearchCoverage, type MeetingSearchCursor, type MeetingSearchItem, RESOURCES_SEARCHED_WITH_MEETINGS, type ResourceWithMeetings, type SearchAllIncludingMeetingsFound, type SearchAllIncludingMeetingsRequest, type SearchAllWithMeetingsRequest, searchAllIncludingMeetings, searchAllWithMeetings, } from "./search-all-meetings.js";
|
|
161
163
|
export { CATCH_UP_BOUNDS, type CatchUpOptions, type CatchUpResult, catchUpSearch, validateCatchUp, } from "./search-catchup.js";
|
|
162
164
|
export { accountsOfKind, listContextOf, type SearchKind } from "./search-kind.js";
|
package/dist/services/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { botCheckService } from "../botcheck/service.js";
|
|
|
2
2
|
export { createContextEvidenceReader } from "./context-evidence.js";
|
|
3
3
|
export { downloadImageModel, downloadTextModel, } from "./model-downloads.js";
|
|
4
4
|
export { gatherProjectEvidence } from "./project-gathering.js";
|
|
5
|
+
export { storedMessageNeighbours } from "./project-gathering-around.js";
|
|
5
6
|
import { accountService } from "./account.js";
|
|
6
7
|
import { adminService } from "./admin.js";
|
|
7
8
|
import { adminStatisticsService } from "./admin-statistics.js";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { MessagesStore } from "../store/messages.js";
|
|
2
|
+
export interface ProjectNeighbour {
|
|
3
|
+
ref: string;
|
|
4
|
+
at: number;
|
|
5
|
+
sender: string | null;
|
|
6
|
+
text: string;
|
|
7
|
+
found: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** The stored messages next to a hit in its chat, oldest first, without the hit itself. */
|
|
10
|
+
export interface ProjectNeighbourReader {
|
|
11
|
+
around(ref: string, window: {
|
|
12
|
+
before: number;
|
|
13
|
+
after: number;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
ref: string;
|
|
16
|
+
at: number;
|
|
17
|
+
sender: string | null;
|
|
18
|
+
text: string;
|
|
19
|
+
}[]>;
|
|
20
|
+
}
|
|
21
|
+
export declare const storedMessageNeighbours: (messages: Pick<MessagesStore, "around">) => ProjectNeighbourReader;
|
|
22
|
+
/**
|
|
23
|
+
* Neighbours are context for reading a hit, not matches: they never join `items`, and their text counts against
|
|
24
|
+
* the run's read bytes.
|
|
25
|
+
*/
|
|
26
|
+
export declare const attachNeighbours: (items: {
|
|
27
|
+
ref: string;
|
|
28
|
+
kind: string;
|
|
29
|
+
around?: ProjectNeighbour[] | null;
|
|
30
|
+
aroundIssue?: string | null;
|
|
31
|
+
}[], reader: ProjectNeighbourReader | undefined, window: {
|
|
32
|
+
before: number;
|
|
33
|
+
after: number;
|
|
34
|
+
}, budget: {
|
|
35
|
+
remaining: () => number;
|
|
36
|
+
charge: (bytes: number) => void;
|
|
37
|
+
}, known: (ref: string) => boolean, signal?: AbortSignal) => Promise<void>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
import { formatLocator, parseLocator } from "../domain/locator.js";
|
|
3
|
+
import { excerpt } from "./excerpt.js";
|
|
4
|
+
export const storedMessageNeighbours = (messages) => ({
|
|
5
|
+
async around(ref, window) {
|
|
6
|
+
const at = parseLocator(ref);
|
|
7
|
+
const rows = await messages.around({ provider: at.provider, account: at.account }, at.chat, at.message, window);
|
|
8
|
+
return rows
|
|
9
|
+
.filter((row) => !row.anchor)
|
|
10
|
+
.map((row) => ({
|
|
11
|
+
ref: formatLocator({ ...at, message: row.id }),
|
|
12
|
+
at: Date.parse(row.timestamp),
|
|
13
|
+
sender: row.senderName,
|
|
14
|
+
text: row.text ?? "",
|
|
15
|
+
}));
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Neighbours are context for reading a hit, not matches: they never join `items`, and their text counts against
|
|
20
|
+
* the run's read bytes.
|
|
21
|
+
*/
|
|
22
|
+
export const attachNeighbours = async (items, reader, window, budget, known, signal) => {
|
|
23
|
+
if (!reader || window.before + window.after === 0)
|
|
24
|
+
return;
|
|
25
|
+
for (const item of items) {
|
|
26
|
+
if (item.kind !== "message")
|
|
27
|
+
continue;
|
|
28
|
+
if (budget.remaining() <= 0) {
|
|
29
|
+
item.around = null;
|
|
30
|
+
item.aroundIssue = "read-bytes";
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
signal?.throwIfAborted();
|
|
34
|
+
try {
|
|
35
|
+
const rows = await reader.around(item.ref, window);
|
|
36
|
+
const around = [];
|
|
37
|
+
for (const row of rows.slice(0, window.before + window.after)) {
|
|
38
|
+
const text = excerpt(row.text, "", 200);
|
|
39
|
+
const bytes = Buffer.byteLength(text);
|
|
40
|
+
if (bytes > budget.remaining()) {
|
|
41
|
+
item.aroundIssue = "read-bytes";
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
budget.charge(bytes);
|
|
45
|
+
around.push({ ...row, text, found: known(row.ref) });
|
|
46
|
+
}
|
|
47
|
+
item.around = around;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
signal?.throwIfAborted();
|
|
51
|
+
if (!(error instanceof CliError))
|
|
52
|
+
throw error;
|
|
53
|
+
item.around = null;
|
|
54
|
+
item.aroundIssue = error.code;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -2,6 +2,7 @@ import { type ContextSource } from "../context/evidence.js";
|
|
|
2
2
|
export interface ProjectGatheringRequest {
|
|
3
3
|
project: {
|
|
4
4
|
name: string;
|
|
5
|
+
key?: string;
|
|
5
6
|
background?: string;
|
|
6
7
|
aliases?: string[];
|
|
7
8
|
};
|
|
@@ -17,6 +18,11 @@ export interface ProjectGatheringRequest {
|
|
|
17
18
|
before?: number;
|
|
18
19
|
asOf?: number;
|
|
19
20
|
fetch?: "none" | "before-read";
|
|
21
|
+
index?: "update" | "as-is";
|
|
22
|
+
around?: {
|
|
23
|
+
before: number;
|
|
24
|
+
after: number;
|
|
25
|
+
};
|
|
20
26
|
budgets?: ProjectGatheringBudgets;
|
|
21
27
|
runKey?: string;
|
|
22
28
|
checkpoint?: string;
|
|
@@ -29,7 +35,7 @@ export interface ProjectGatheringBudgets {
|
|
|
29
35
|
maxElapsedMs?: number;
|
|
30
36
|
maxItems?: number;
|
|
31
37
|
}
|
|
32
|
-
export type ProjectLaneKind = "project" | "alias" | "keyword" | "person";
|
|
38
|
+
export type ProjectLaneKind = "project" | "key" | "alias" | "keyword" | "person";
|
|
33
39
|
export interface ProjectLane {
|
|
34
40
|
id: string;
|
|
35
41
|
kinds: ProjectLaneKind[];
|
|
@@ -73,6 +79,7 @@ export declare const CONTEXT_CHUNK_DAYS = 90;
|
|
|
73
79
|
export declare const projectGatheringRequest: (input: ProjectGatheringRequest, now: number) => {
|
|
74
80
|
project: {
|
|
75
81
|
name: string;
|
|
82
|
+
key: string | null;
|
|
76
83
|
background: string | null;
|
|
77
84
|
aliases: string[];
|
|
78
85
|
};
|
|
@@ -91,6 +98,11 @@ export declare const projectGatheringRequest: (input: ProjectGatheringRequest, n
|
|
|
91
98
|
asOf: number;
|
|
92
99
|
};
|
|
93
100
|
fetch: "before-read" | "none";
|
|
101
|
+
index: "as-is" | "update";
|
|
102
|
+
around: {
|
|
103
|
+
before: number;
|
|
104
|
+
after: number;
|
|
105
|
+
};
|
|
94
106
|
budgets: Required<ProjectGatheringBudgets>;
|
|
95
107
|
fingerprint: string;
|
|
96
108
|
runKey: string;
|
|
@@ -55,6 +55,8 @@ export const projectGatheringRequest = (input, now) => {
|
|
|
55
55
|
"before",
|
|
56
56
|
"asOf",
|
|
57
57
|
"fetch",
|
|
58
|
+
"index",
|
|
59
|
+
"around",
|
|
58
60
|
"budgets",
|
|
59
61
|
"runKey",
|
|
60
62
|
"checkpoint",
|
|
@@ -62,9 +64,10 @@ export const projectGatheringRequest = (input, now) => {
|
|
|
62
64
|
], "");
|
|
63
65
|
if (!input.project || typeof input.project !== "object")
|
|
64
66
|
fail("project needs a name", "project");
|
|
65
|
-
known(input.project, ["name", "background", "aliases"], "project.");
|
|
67
|
+
known(input.project, ["name", "key", "background", "aliases"], "project.");
|
|
66
68
|
const project = {
|
|
67
69
|
name: text(input.project.name, "project.name", 512),
|
|
70
|
+
key: input.project.key === undefined ? null : text(input.project.key, "project.key", 64),
|
|
68
71
|
background: input.project.background === undefined ? null : text(input.project.background, "project.background", 8192),
|
|
69
72
|
aliases: list(input.project.aliases, "project.aliases", LIMITS.lanes).map((a, i) => text(a, `project.aliases.${i}`, 512)),
|
|
70
73
|
};
|
|
@@ -104,6 +107,8 @@ export const projectGatheringRequest = (input, now) => {
|
|
|
104
107
|
found.people.push(person);
|
|
105
108
|
};
|
|
106
109
|
lane("project", laneQuery(project.name, "project.name"));
|
|
110
|
+
if (project.key)
|
|
111
|
+
lane("key", laneQuery(project.key, "project.key"));
|
|
107
112
|
for (const [i, a] of project.aliases.entries())
|
|
108
113
|
lane("alias", laneQuery(a, `project.aliases.${i}`));
|
|
109
114
|
for (const k of keywords)
|
|
@@ -113,19 +118,30 @@ export const projectGatheringRequest = (input, now) => {
|
|
|
113
118
|
if (lanes.length > LIMITS.lanes)
|
|
114
119
|
fail(`at most ${LIMITS.lanes} distinct search lanes`, "keywords");
|
|
115
120
|
const fetch = input.fetch ?? "none";
|
|
121
|
+
const index = input.index ?? "update";
|
|
122
|
+
if (index !== "update" && index !== "as-is")
|
|
123
|
+
fail("index must be update or as-is", "index");
|
|
124
|
+
if (input.around !== undefined && (!input.around || typeof input.around !== "object"))
|
|
125
|
+
fail("around needs before and after", "around");
|
|
126
|
+
if (input.around)
|
|
127
|
+
known(input.around, ["before", "after"], "around.");
|
|
128
|
+
const around = {
|
|
129
|
+
before: whole(input.around?.before ?? 2, "around.before", 0, 5),
|
|
130
|
+
after: whole(input.around?.after ?? 2, "around.after", 0, 5),
|
|
131
|
+
};
|
|
116
132
|
if (fetch !== "none" && fetch !== "before-read")
|
|
117
133
|
fail("fetch must be none or before-read", "fetch");
|
|
118
134
|
const explicit = input.after !== undefined || input.before !== undefined;
|
|
119
135
|
if (explicit && input.lookbackDays !== undefined)
|
|
120
136
|
fail("give lookbackDays or after/before, not both", "lookbackDays");
|
|
121
|
-
if (explicit &&
|
|
122
|
-
fail("an explicit window needs
|
|
137
|
+
if (explicit && input.after === undefined)
|
|
138
|
+
fail("an explicit window needs after; before defaults to asOf", "after");
|
|
123
139
|
const asOf = input.asOf === undefined ? null : whole(input.asOf, "asOf", 1, MAX_TIME);
|
|
124
140
|
const lookbackDays = explicit ? null : whole(input.lookbackDays ?? 60, "lookbackDays", 1, LIMITS.lookbackDays);
|
|
125
141
|
const window = explicit
|
|
126
142
|
? (() => {
|
|
127
143
|
const after = whole(input.after, "after", 0, MAX_TIME);
|
|
128
|
-
const before = whole(input.before, "before", after + 1, MAX_TIME);
|
|
144
|
+
const before = whole(input.before ?? asOf ?? now, "before", after + 1, MAX_TIME);
|
|
129
145
|
if (before - after > LIMITS.lookbackDays * DAY)
|
|
130
146
|
fail(`window must not exceed ${LIMITS.lookbackDays} days`, "after");
|
|
131
147
|
return { after, before, asOf: asOf ?? before };
|
|
@@ -150,7 +166,7 @@ export const projectGatheringRequest = (input, now) => {
|
|
|
150
166
|
sources.map(contextSourceKey),
|
|
151
167
|
input.scope,
|
|
152
168
|
lookbackDays,
|
|
153
|
-
explicit ? [window.after,
|
|
169
|
+
explicit ? [window.after, input.before ?? null] : null,
|
|
154
170
|
asOf,
|
|
155
171
|
fetch,
|
|
156
172
|
]))
|
|
@@ -168,6 +184,8 @@ export const projectGatheringRequest = (input, now) => {
|
|
|
168
184
|
lookbackDays,
|
|
169
185
|
window,
|
|
170
186
|
fetch,
|
|
187
|
+
index,
|
|
188
|
+
around,
|
|
171
189
|
budgets,
|
|
172
190
|
fingerprint,
|
|
173
191
|
runKey,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ContextEvidenceItem, ContextEvidenceReader, ContextSource } from "../context/evidence.js";
|
|
1
|
+
import type { ContextEvidenceItem, ContextEvidenceReader, ContextIndex, ContextSource } from "../context/evidence.js";
|
|
2
|
+
import { type ProjectNeighbour, type ProjectNeighbourReader } from "./project-gathering-around.js";
|
|
2
3
|
import { type ProjectFetchState, type ProjectGatheringRequest, type ProjectLane } from "./project-gathering-request.js";
|
|
3
4
|
/** A connector's history fetch into the store; the store reads that follow find what it saved. */
|
|
4
5
|
export interface ProjectSourceFetcher {
|
|
@@ -15,8 +16,16 @@ export interface ProjectSourceFetcher {
|
|
|
15
16
|
export interface ProjectGatheringPorts {
|
|
16
17
|
evidence: ContextEvidenceReader;
|
|
17
18
|
fetcher?: ProjectSourceFetcher;
|
|
19
|
+
index?: ContextIndex;
|
|
20
|
+
neighbours?: ProjectNeighbourReader;
|
|
18
21
|
now?: () => number;
|
|
19
22
|
}
|
|
23
|
+
export interface ProjectIndexCatchUp {
|
|
24
|
+
state: "updated" | "as-is" | "unavailable" | "failed";
|
|
25
|
+
mail: number;
|
|
26
|
+
documents: number;
|
|
27
|
+
code: string | null;
|
|
28
|
+
}
|
|
20
29
|
export interface ProjectEvidenceItem extends Omit<ContextEvidenceItem, "text"> {
|
|
21
30
|
kind: ContextSource["kind"];
|
|
22
31
|
source: number;
|
|
@@ -24,6 +33,8 @@ export interface ProjectEvidenceItem extends Omit<ContextEvidenceItem, "text"> {
|
|
|
24
33
|
textTruncated: boolean;
|
|
25
34
|
lanes: string[];
|
|
26
35
|
context: "project" | "person-only";
|
|
36
|
+
around?: ProjectNeighbour[] | null;
|
|
37
|
+
aroundIssue?: string | null;
|
|
27
38
|
}
|
|
28
39
|
export type ProjectGatheringStop = "reads" | "read-bytes" | "elapsed" | "items" | null;
|
|
29
40
|
export declare const gatherProjectEvidence: (ports: ProjectGatheringPorts, request: ProjectGatheringRequest) => Promise<{
|
|
@@ -33,6 +44,7 @@ export declare const gatherProjectEvidence: (ports: ProjectGatheringPorts, reque
|
|
|
33
44
|
resumed: boolean;
|
|
34
45
|
project: {
|
|
35
46
|
name: string;
|
|
47
|
+
key: string | null;
|
|
36
48
|
background: string | null;
|
|
37
49
|
aliases: string[];
|
|
38
50
|
};
|
|
@@ -55,6 +67,7 @@ export declare const gatherProjectEvidence: (ports: ProjectGatheringPorts, reque
|
|
|
55
67
|
code: string | null;
|
|
56
68
|
source: number;
|
|
57
69
|
}[];
|
|
70
|
+
index: ProjectIndexCatchUp;
|
|
58
71
|
units: {
|
|
59
72
|
lane: string;
|
|
60
73
|
source: number;
|
|
@@ -72,6 +85,7 @@ export declare const gatherProjectEvidence: (ports: ProjectGatheringPorts, reque
|
|
|
72
85
|
usage: {
|
|
73
86
|
reads: number;
|
|
74
87
|
readBytes: number;
|
|
88
|
+
aroundBytes: number;
|
|
75
89
|
items: number;
|
|
76
90
|
elapsedMs: number;
|
|
77
91
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { createContextEvidenceReader } from "./context-evidence.js";
|
|
3
3
|
import { excerpt } from "./excerpt.js";
|
|
4
|
+
import { attachNeighbours } from "./project-gathering-around.js";
|
|
4
5
|
import { decodeCheckpoint, encodeCheckpoint, projectGatheringRequest, projectUnits, seenKey, } from "./project-gathering-request.js";
|
|
5
6
|
const terminal = new Set(["done", "unavailable", "failed"]);
|
|
6
7
|
export const gatherProjectEvidence = async (ports, request) => {
|
|
@@ -12,6 +13,9 @@ export const gatherProjectEvidence = async (ports, request) => {
|
|
|
12
13
|
const previous = plan.checkpoint === undefined ? null : decodeCheckpoint(plan.checkpoint, plan);
|
|
13
14
|
const window = previous ?? plan.window;
|
|
14
15
|
const units = projectUnits(plan, window);
|
|
16
|
+
// A default that cannot finish one round would leave whole searches or sources unread; an explicit one is kept.
|
|
17
|
+
if (request.budgets?.maxReads === undefined)
|
|
18
|
+
plan.budgets.maxReads = Math.min(512, Math.max(48, units.length));
|
|
15
19
|
if (previous && (previous.units.length !== units.length || previous.fetched.length !== plan.sources.length))
|
|
16
20
|
throw new CliError("validation_error", "invalid project gathering checkpoint", { param: "checkpoint" });
|
|
17
21
|
const progress = previous?.units.map((u) => ({ ...u })) ??
|
|
@@ -43,7 +47,27 @@ export const gatherProjectEvidence = async (ports, request) => {
|
|
|
43
47
|
fetched[index] = { state: "failed", history: null, code: error.code };
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
|
-
const
|
|
50
|
+
const indexed = { state: "as-is", mail: 0, documents: 0, code: null };
|
|
51
|
+
const kinds = [...new Set(plan.sources.map((source) => source.kind))].filter((kind) => kind !== "message");
|
|
52
|
+
if (plan.index === "update" && kinds.length) {
|
|
53
|
+
signal?.throwIfAborted();
|
|
54
|
+
if (!ports.index || typeof ports.index.catchUp !== "function")
|
|
55
|
+
indexed.state = "unavailable";
|
|
56
|
+
else
|
|
57
|
+
try {
|
|
58
|
+
const done = await ports.index.catchUp({ kinds, signal });
|
|
59
|
+
if (!Number.isSafeInteger(done?.mail) || !Number.isSafeInteger(done?.documents))
|
|
60
|
+
throw new CliError("invalid_response", "index catch-up returned invalid counts");
|
|
61
|
+
Object.assign(indexed, { state: "updated", mail: done.mail, documents: done.documents });
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
signal?.throwIfAborted();
|
|
65
|
+
if (!(error instanceof CliError))
|
|
66
|
+
throw error;
|
|
67
|
+
Object.assign(indexed, { state: "failed", code: error.code });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const usage = { reads: 0, readBytes: 0, aroundBytes: 0, items: 0 };
|
|
47
71
|
const items = [];
|
|
48
72
|
const byRef = new Map();
|
|
49
73
|
const matchedAgain = new Map();
|
|
@@ -145,6 +169,12 @@ export const gatherProjectEvidence = async (ports, request) => {
|
|
|
145
169
|
}
|
|
146
170
|
}
|
|
147
171
|
}
|
|
172
|
+
await attachNeighbours(items, ports.neighbours, plan.around, {
|
|
173
|
+
remaining: () => plan.budgets.maxReadBytes - usage.readBytes - usage.aroundBytes,
|
|
174
|
+
charge: (bytes) => {
|
|
175
|
+
usage.aroundBytes += bytes;
|
|
176
|
+
},
|
|
177
|
+
}, (ref) => byRef.has(ref) || seen.has(seenKey(ref)), signal);
|
|
148
178
|
const totals = {
|
|
149
179
|
reads: (previous?.totals.reads ?? 0) + usage.reads,
|
|
150
180
|
readBytes: (previous?.totals.readBytes ?? 0) + usage.readBytes,
|
|
@@ -181,6 +211,7 @@ export const gatherProjectEvidence = async (ports, request) => {
|
|
|
181
211
|
scope: { origin: plan.scope, sources: plan.sources },
|
|
182
212
|
lanes: plan.lanes,
|
|
183
213
|
fetch: fetched.map((f, index) => ({ source: index, ...f })),
|
|
214
|
+
index: indexed,
|
|
184
215
|
units: units.map((unit, index) => ({
|
|
185
216
|
lane: unit.lane.id,
|
|
186
217
|
source: unit.sourceIndex,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { SearchHit } from "../meetings/index.js";
|
|
2
|
-
import type { MessengerTraits } from "../ports/traits.js";
|
|
3
2
|
import type { AccountKey, MessageStore } from "../store/store.js";
|
|
4
3
|
import type { SearchFound, SearchQuery } from "./messages.js";
|
|
5
|
-
import { type SearchAllFound, type SearchAllItem, type SearchAllRequest, type Skipped } from "./search-all.js";
|
|
4
|
+
import { type SearchAllFound, type SearchAllItem, type SearchAllMessenger, type SearchAllRequest, type Skipped } from "./search-all.js";
|
|
6
5
|
export declare const RESOURCES_SEARCHED_WITH_MEETINGS: readonly ["messages", "mail", "notes", "meetings"];
|
|
7
6
|
export type ResourceWithMeetings = (typeof RESOURCES_SEARCHED_WITH_MEETINGS)[number];
|
|
8
7
|
export interface MeetingSearchItem {
|
|
@@ -55,7 +54,7 @@ export interface SearchAllIncludingMeetingsFound extends Omit<SearchAllFound, "i
|
|
|
55
54
|
meetings?: MeetingSearchCoverage;
|
|
56
55
|
}
|
|
57
56
|
/** Opt-in fusion of the existing unified ranking and one explicitly scoped meeting archive. */
|
|
58
|
-
export declare const searchAllIncludingMeetings: (store: MessageStore, account: AccountKey, request: SearchAllIncludingMeetingsRequest, messenger?:
|
|
57
|
+
export declare const searchAllIncludingMeetings: (store: MessageStore, account: AccountKey, request: SearchAllIncludingMeetingsRequest, messenger?: SearchAllMessenger, searchMessages?: (query: SearchQuery) => Promise<SearchFound>) => Promise<SearchAllIncludingMeetingsFound>;
|
|
59
58
|
export interface SearchAllWithMeetingsRequest extends Omit<SearchAllIncludingMeetingsRequest, "meetingAccount"> {
|
|
60
59
|
/**
|
|
61
60
|
* `--source`: each kind reads the accounts the list names of it and a kind it names none of is skipped.
|
|
@@ -66,4 +65,4 @@ export interface SearchAllWithMeetingsRequest extends Omit<SearchAllIncludingMee
|
|
|
66
65
|
/** Meetings have no index to search every account at once, so they are read only when named. */
|
|
67
66
|
export declare const MEETINGS_UNNAMED = "meetings are searched only when --source names a meeting account, zoom or meetings";
|
|
68
67
|
/** `search all`: every kind but meetings, unless `--source` names a meeting account. */
|
|
69
|
-
export declare const searchAllWithMeetings: (store: MessageStore, account: AccountKey, request: SearchAllWithMeetingsRequest, messenger?:
|
|
68
|
+
export declare const searchAllWithMeetings: (store: MessageStore, account: AccountKey, request: SearchAllWithMeetingsRequest, messenger?: SearchAllMessenger, searchMessages?: (query: SearchQuery) => Promise<SearchFound>) => Promise<SearchAllIncludingMeetingsFound>;
|
|
@@ -81,9 +81,16 @@ export interface SearchAllRequest {
|
|
|
81
81
|
/** The accounts `--source` chose, per kind; a kind left out reads every account of its own. */
|
|
82
82
|
scope?: Partial<Record<SearchedResource, AccountKey[]>>;
|
|
83
83
|
}
|
|
84
|
+
export type SearchAllMessenger = Partial<Pick<MessengerTraits, "savedChatId" | "app">> & {
|
|
85
|
+
/**
|
|
86
|
+
* The tool named in a model-download hint, when it is not `app.command`: memo passes tg's identity for `group:`
|
|
87
|
+
* lists but has no `models` command. `null` names the tools that have one.
|
|
88
|
+
*/
|
|
89
|
+
hintCommand?: string | null;
|
|
90
|
+
};
|
|
84
91
|
/**
|
|
85
92
|
* `search all`: messages, mail and notes from the local store — messages also from the messenger's
|
|
86
93
|
* server, as `search messages` asks it — each list best first, merged by reciprocal rank so no
|
|
87
94
|
* resource's own scores have to be compared with another's.
|
|
88
95
|
*/
|
|
89
|
-
export declare const searchAll: (store: MessageStore, account: AccountKey, request: SearchAllRequest, messenger?:
|
|
96
|
+
export declare const searchAll: (store: MessageStore, account: AccountKey, request: SearchAllRequest, messenger?: SearchAllMessenger, searchMessages?: (query: SearchQuery) => Promise<SearchFound>) => Promise<SearchAllFound>;
|
|
@@ -21,7 +21,7 @@ export const searchAll = async (store, account, request, messenger = {}, searchM
|
|
|
21
21
|
// Each resource is read deep enough for the merged page, then the merge is cut.
|
|
22
22
|
const window = offset + request.limit;
|
|
23
23
|
const only = request.only ?? RESOURCES_SEARCHED;
|
|
24
|
-
const command = messenger.app?.command;
|
|
24
|
+
const command = messenger.hintCommand === undefined ? messenger.app?.command : (messenger.hintCommand ?? undefined);
|
|
25
25
|
const lists = [];
|
|
26
26
|
const searched = [];
|
|
27
27
|
const accounts = [];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CliError, isCliError } from "@wirecat/cli-base";
|
|
2
2
|
import { fromFile } from "../cli/settings.js";
|
|
3
3
|
import { capability } from "../ports/messenger.js";
|
|
4
|
+
import { typedCommand } from "../runs/scope.js";
|
|
4
5
|
import { installedBytes, isInstalled, megabytes, modelPath, modelsDirectory, vadPath } from "./install.js";
|
|
5
6
|
import { orderedModels, speechModel } from "./models.js";
|
|
6
7
|
/** `messenger`: its own recognition (Telegram Premium). `local`: a model on this machine. `auto`: the first, then the second. */
|
|
@@ -20,7 +21,7 @@ export const choose = (messenger, settings, flags, env = process.env) => {
|
|
|
20
21
|
};
|
|
21
22
|
/** Never a download: a model is hundreds of MB, and whether to fetch one is the owner's call. */
|
|
22
23
|
export const notDownloaded = (messenger, model) => new CliError("not_found", `the speech model ${model.id} is not on this machine — the owner downloads it once with ` +
|
|
23
|
-
`\`${messenger.app.command
|
|
24
|
+
`\`${typedCommand(messenger.app.command, `models audio download ${model.id}`)}\` (${megabytes(installedBytes(model))})`, { reason: "model.not-downloaded", model: model.id });
|
|
24
25
|
/**
|
|
25
26
|
* Over an open connection: the messenger's own transcript, or the recording's bytes for a local model.
|
|
26
27
|
* The model runs after the connection closes — a minute of speech should not hold a socket open.
|
package/dist/store/chats.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChannelTagMatch } from "../domain/channel-tags.js";
|
|
2
|
-
import type { Chat, ChatKind, Id, Page } from "../domain/models.js";
|
|
2
|
+
import type { Chat, ChatKind, ChatUpdate, Id, Page } from "../domain/models.js";
|
|
3
3
|
import { type ChatRekey } from "./sqlite/chat-rekey.js";
|
|
4
4
|
import type { ChatMetadata } from "./sqlite/chats.js";
|
|
5
5
|
import type { ChatCompleteness } from "./sqlite/completeness.js";
|
|
@@ -7,7 +7,7 @@ import type { StoreContext } from "./sqlite/open.js";
|
|
|
7
7
|
import type { Where } from "./sqlite/query-filter.js";
|
|
8
8
|
import type { AccountKey, ChatActivity, ChatStats, StoredChatFilter } from "./types.js";
|
|
9
9
|
export interface ChatsStore {
|
|
10
|
-
saveChats(key: AccountKey, chats:
|
|
10
|
+
saveChats(key: AccountKey, chats: ChatUpdate[]): Promise<void>;
|
|
11
11
|
/** Newest first. `query` matches three letters or more of a title; `unread` keeps chats with unread messages. */
|
|
12
12
|
chats(key: AccountKey, window: {
|
|
13
13
|
limit?: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChannelTagMatch } from "../../domain/channel-tags.js";
|
|
2
|
-
import type { Chat, Id, Member, Page } from "../../domain/models.js";
|
|
2
|
+
import type { Chat, ChatUpdate, Id, Member, Page } from "../../domain/models.js";
|
|
3
3
|
import type { AccountKey, StoredChatFilter } from "../types.js";
|
|
4
4
|
import type { StoreContext } from "./open.js";
|
|
5
5
|
/** The chat's own id, when the store key is a chat of this account. */
|
|
@@ -7,7 +7,7 @@ export declare const chatOf: ({ orm }: StoreContext, accountKey: number, chatKey
|
|
|
7
7
|
export declare const findChatPk: ({ orm }: StoreContext, accountKey: number, chatId: Id) => number | undefined;
|
|
8
8
|
/** A chat known only from its messages, until the chat list names it. */
|
|
9
9
|
export declare const chatPkFor: (context: StoreContext, accountKey: number, chatId: Id) => number;
|
|
10
|
-
export declare const upsertChat: (context: StoreContext, accountKey: number, chat:
|
|
10
|
+
export declare const upsertChat: (context: StoreContext, accountKey: number, chat: ChatUpdate) => void;
|
|
11
11
|
/** Replaces who is in the chat, whole. */
|
|
12
12
|
export declare const writeMembers: (context: StoreContext, key: AccountKey, accountKey: number, chatId: Id, memberIds: Id[]) => void;
|
|
13
13
|
export declare const members: ({ orm }: StoreContext, chatKey: number) => Member[];
|