@wirecat/cli-core 0.545.0 → 0.547.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 +228 -0
- package/dist/calendar/busy.js +4 -1
- package/dist/calendar/cli/answers.d.ts +31 -0
- package/dist/calendar/cli/answers.js +8 -0
- package/dist/calendar/cli/index.d.ts +6 -0
- package/dist/calendar/cli/index.js +43 -4
- package/dist/calendar/cli/remind.js +2 -1
- package/dist/calendar/expand.d.ts +17 -0
- package/dist/calendar/expand.js +340 -0
- package/dist/calendar/feeds.d.ts +96 -0
- package/dist/calendar/feeds.js +324 -0
- package/dist/calendar/ics.d.ts +15 -4
- package/dist/calendar/ics.js +18 -7
- package/dist/calendar/index.d.ts +3 -1
- package/dist/calendar/index.js +2 -0
- package/dist/calendar/server-search.js +3 -1
- package/dist/calendar/writes.js +15 -4
- package/dist/cli/after-dashes.d.ts +16 -0
- package/dist/cli/after-dashes.js +41 -0
- package/dist/cli/bot/context.d.ts +1 -1
- package/dist/cli/bot/context.js +9 -1
- package/dist/cli/bot/messages.js +2 -0
- package/dist/cli/bot/setup.js +1 -0
- package/dist/cli/contract-templates.js +2 -2
- package/dist/cli/entry.d.ts +2 -0
- package/dist/cli/entry.js +3 -2
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.js +2 -1
- package/dist/cli/messenger/admin-commands.js +5 -1
- package/dist/cli/messenger/admin-contacts-command.js +5 -1
- package/dist/cli/messenger/admin-folders-command.js +5 -1
- package/dist/cli/messenger/complete-command.js +1 -0
- package/dist/cli/messenger/history-query.d.ts +10 -4
- package/dist/cli/messenger/history-query.js +87 -31
- package/dist/cli/messenger/messages-command.js +12 -23
- package/dist/cli/messenger/messages-comments-command.js +4 -2
- package/dist/cli/messenger/messages-edit-command.js +1 -0
- package/dist/cli/messenger/messages-press-command.js +1 -0
- package/dist/cli/messenger/messages-send-command.js +1 -0
- package/dist/cli/messenger/observed.js +2 -2
- package/dist/cli/messenger/polls-command.js +1 -0
- package/dist/cli/messenger/private-people-command.js +5 -1
- package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
- package/dist/cli/messenger/stored.js +56 -3
- package/dist/cli/messenger/topics-command.js +1 -1
- package/dist/cli/option-hints.d.ts +6 -0
- package/dist/cli/option-hints.js +15 -0
- package/dist/cli/program.js +17 -6
- package/dist/cli/schedule/schedule-command.js +1 -0
- package/dist/domain/message-link.d.ts +3 -0
- package/dist/domain/message-link.js +9 -14
- package/dist/domain/money-words.d.ts +11 -0
- package/dist/domain/money-words.js +38 -0
- package/dist/domain/providers.d.ts +2 -0
- package/dist/domain/providers.js +15 -3
- package/dist/domain/ref-arguments.d.ts +31 -0
- package/dist/domain/ref-arguments.js +79 -0
- package/dist/domain/references.d.ts +20 -2
- package/dist/domain/references.js +132 -47
- package/dist/errors/reasons.js +31 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mail/cli/index.js +4 -4
- package/dist/mail/index.d.ts +2 -0
- package/dist/mail/index.js +2 -0
- package/dist/mail/partial.d.ts +34 -0
- package/dist/mail/partial.js +94 -0
- package/dist/mail/server-search.js +17 -9
- package/dist/mail/source.d.ts +13 -2
- package/dist/mail/source.js +7 -1
- package/dist/mail/sync-types.d.ts +112 -0
- package/dist/mail/sync-types.js +1 -0
- package/dist/mail/sync.d.ts +4 -106
- package/dist/mail/sync.js +49 -4
- package/dist/mail/testing/fake.d.ts +3 -1
- package/dist/mail/testing/fake.js +10 -2
- package/dist/meetings/mcp/index.d.ts +15 -15
- package/dist/oauth/client-file.d.ts +14 -0
- package/dist/oauth/client-file.js +28 -0
- package/dist/oauth/index.d.ts +1 -0
- package/dist/oauth/index.js +1 -0
- package/dist/ports/messenger.d.ts +3 -2
- package/dist/resolve.d.ts +3 -1
- package/dist/resolve.js +8 -0
- package/dist/search/task-signature.d.ts +5 -1
- package/dist/search/task-signature.js +27 -9
- package/dist/services/agenda.d.ts +5 -0
- package/dist/services/agenda.js +3 -1
- package/dist/services/deps.d.ts +0 -2
- package/dist/services/deps.js +0 -2
- package/dist/services/documents/ingestion.js +1 -1
- package/dist/services/documents/knowledge.d.ts +10 -6
- package/dist/services/documents/knowledge.js +25 -11
- package/dist/services/index.d.ts +6 -1
- package/dist/services/index.js +6 -1
- package/dist/services/message-resolution.d.ts +4 -1
- package/dist/services/message-resolution.js +19 -3
- package/dist/services/messages.d.ts +2 -0
- package/dist/services/messages.js +40 -36
- package/dist/services/money-words.d.ts +3 -0
- package/dist/services/money-words.js +5 -0
- package/dist/services/proposal-tasks.d.ts +3 -2
- package/dist/services/proposal-tasks.js +5 -2
- package/dist/services/proposals/ids.d.ts +5 -0
- package/dist/services/proposals/ids.js +43 -0
- package/dist/services/proposals/index.d.ts +3 -0
- package/dist/services/proposals/index.js +2 -0
- package/dist/services/proposals/kinds/action.d.ts +7 -0
- package/dist/services/proposals/kinds/action.js +45 -0
- package/dist/services/proposals/kinds/fact.d.ts +4 -0
- package/dist/services/proposals/kinds/fact.js +43 -0
- package/dist/services/proposals/kinds/findings.d.ts +7 -0
- package/dist/services/proposals/kinds/findings.js +75 -0
- package/dist/services/proposals/kinds/key-document.d.ts +9 -0
- package/dist/services/proposals/kinds/key-document.js +75 -0
- package/dist/services/proposals/kinds/memory.d.ts +4 -0
- package/dist/services/proposals/kinds/memory.js +42 -0
- package/dist/services/proposals/kinds/relationship.d.ts +10 -0
- package/dist/services/proposals/kinds/relationship.js +82 -0
- package/dist/services/proposals/kinds/shared.d.ts +25 -0
- package/dist/services/proposals/kinds/shared.js +49 -0
- package/dist/services/proposals/registry.d.ts +9 -0
- package/dist/services/proposals/registry.js +129 -0
- package/dist/services/proposals/types.d.ts +85 -0
- package/dist/services/proposals/types.js +1 -0
- package/dist/services/questions.d.ts +7 -2
- package/dist/services/questions.js +13 -4
- package/dist/services/server-search.d.ts +7 -4
- package/dist/services/server-search.js +5 -2
- package/dist/services/stored-project-gathering.d.ts +9 -0
- package/dist/services/stored-project-gathering.js +9 -4
- package/dist/services/task-categories.d.ts +2 -0
- package/dist/services/task-categories.js +19 -8
- package/dist/services/tasks.js +8 -4
- package/dist/store/decisions.d.ts +65 -0
- package/dist/store/decisions.js +55 -0
- package/dist/store/evidence-findings.d.ts +6 -6
- package/dist/store/index.d.ts +4 -3
- package/dist/store/index.js +2 -1
- package/dist/store/meeting-findings.d.ts +2 -0
- package/dist/store/messages.d.ts +4 -9
- package/dist/store/sqlite/actors.d.ts +13 -2
- package/dist/store/sqlite/actors.js +24 -1
- package/dist/store/sqlite/email-locations.d.ts +16 -0
- package/dist/store/sqlite/email-locations.js +26 -0
- package/dist/store/sqlite/emails.d.ts +6 -2
- package/dist/store/sqlite/emails.js +2 -1
- package/dist/store/sqlite/evidence-findings.js +13 -3
- package/dist/store/sqlite/evidence-sources.js +2 -2
- package/dist/store/sqlite/facts.d.ts +16 -8
- package/dist/store/sqlite/facts.js +48 -15
- package/dist/store/sqlite/findings-core.d.ts +2 -1
- package/dist/store/sqlite/findings-core.js +4 -4
- package/dist/store/sqlite/identities.js +1 -1
- package/dist/store/sqlite/knowledge.d.ts +43 -7
- package/dist/store/sqlite/knowledge.js +62 -17
- package/dist/store/sqlite/meeting-findings.js +6 -6
- package/dist/store/sqlite/memories.d.ts +12 -8
- package/dist/store/sqlite/memories.js +33 -10
- package/dist/store/sqlite/notes.d.ts +5 -1
- package/dist/store/sqlite/notes.js +22 -6
- package/dist/store/sqlite/open-store.d.ts +4 -1
- package/dist/store/sqlite/open-store.js +8 -2
- package/dist/store/sqlite/open.d.ts +3 -0
- package/dist/store/sqlite/proposed-actions.d.ts +21 -8
- package/dist/store/sqlite/proposed-actions.js +29 -9
- package/dist/store/sqlite/reads.d.ts +13 -2
- package/dist/store/sqlite/reads.js +8 -4
- package/dist/store/sqlite/relation-proposals.d.ts +34 -0
- package/dist/store/sqlite/relation-proposals.js +114 -0
- package/dist/store/sqlite/things.d.ts +0 -1
- package/dist/store/sqlite/things.js +25 -24
- package/dist/store/store.d.ts +3 -0
- package/dist/store/store.js +2 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { QueryAst } from "@wirecat/cli-base/query";
|
|
2
|
-
import type { Author, Fact, Link, LinkInput, LinkListFilter, Memory, MemoryInput, MessageStore, Note } from "../../store/index.js";
|
|
2
|
+
import type { Author, Decider, Fact, Link, LinkInput, LinkListFilter, Memory, MemoryInput, MessageStore, Note } from "../../store/index.js";
|
|
3
3
|
export interface DocumentKnowledge {
|
|
4
4
|
documents(principal: string, query: QueryAst | undefined, page: {
|
|
5
5
|
limit: number;
|
|
@@ -14,7 +14,7 @@ export interface DocumentKnowledge {
|
|
|
14
14
|
}): Promise<string[]>;
|
|
15
15
|
links(principal: string, ref: string, filter?: Omit<LinkListFilter, "from" | "to">): Promise<Link[]>;
|
|
16
16
|
addLink(principal: string, ref: string, input: Omit<LinkInput, "from" | "origin">): Promise<Link>;
|
|
17
|
-
removeLink(principal: string, ref: string, id: string): Promise<unknown>;
|
|
17
|
+
removeLink(principal: string, ref: string, id: string, by: Decider): Promise<unknown>;
|
|
18
18
|
notes(principal: string, ref: string, options?: {
|
|
19
19
|
search?: string;
|
|
20
20
|
limit?: number;
|
|
@@ -28,7 +28,7 @@ export interface DocumentKnowledge {
|
|
|
28
28
|
editNote(principal: string, ref: string, noteRef: string, text: string, revision: number): Promise<Note>;
|
|
29
29
|
removeNote(principal: string, ref: string, noteRef: string): Promise<unknown>;
|
|
30
30
|
addMemory(principal: string, ref: string, input: Pick<MemoryInput, "body" | "kind" | "scope" | "status" | "supersedes"> & {
|
|
31
|
-
author
|
|
31
|
+
author: MemoryInput["author"];
|
|
32
32
|
}): Promise<Memory>;
|
|
33
33
|
memories(principal: string, ref: string, options?: {
|
|
34
34
|
scope?: Memory["scope"];
|
|
@@ -36,7 +36,9 @@ export interface DocumentKnowledge {
|
|
|
36
36
|
status?: Memory["status"];
|
|
37
37
|
limit?: number;
|
|
38
38
|
}): Promise<Memory[]>;
|
|
39
|
-
memory(principal: string, ref: string, memoryRef: string, action?: "show"
|
|
39
|
+
memory(principal: string, ref: string, memoryRef: string, action?: "show"): Promise<Memory>;
|
|
40
|
+
/** `by` decides: the owner, or an agent for the owner that did not propose it. */
|
|
41
|
+
memory(principal: string, ref: string, memoryRef: string, action: "confirm" | "stale", by: Decider): Promise<Memory>;
|
|
40
42
|
searchMemories(principal: string, ref: string, query: string, scope?: Memory["scope"]): Promise<{
|
|
41
43
|
items: Memory[];
|
|
42
44
|
limit_reached: boolean;
|
|
@@ -45,7 +47,7 @@ export interface DocumentKnowledge {
|
|
|
45
47
|
statement: string;
|
|
46
48
|
type: Fact["type"];
|
|
47
49
|
scope?: Memory["scope"];
|
|
48
|
-
by
|
|
50
|
+
by: Author;
|
|
49
51
|
supersedes?: string;
|
|
50
52
|
occurredAt?: string;
|
|
51
53
|
}): Promise<Fact>;
|
|
@@ -54,6 +56,8 @@ export interface DocumentKnowledge {
|
|
|
54
56
|
status?: Fact["status"];
|
|
55
57
|
limit?: number;
|
|
56
58
|
}): Promise<Fact[]>;
|
|
57
|
-
fact(principal: string, ref: string, factRef: string, action?: "show"
|
|
59
|
+
fact(principal: string, ref: string, factRef: string, action?: "show"): Promise<Fact>;
|
|
60
|
+
/** `by` decides: the owner, or an agent for the owner that did not propose it; only the owner reverses. */
|
|
61
|
+
fact(principal: string, ref: string, factRef: string, action: "confirm" | "reverse", by: Decider): Promise<Fact>;
|
|
58
62
|
}
|
|
59
63
|
export declare const documentKnowledge: (store: Pick<MessageStore, "notes" | "facts" | "memories" | "knowledge">, folder: (principal: string) => Promise<string | undefined>) => DocumentKnowledge;
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
const writer = (by) => {
|
|
3
|
+
if (by === undefined)
|
|
4
|
+
throw new CliError("validation_error", "name who writes it: the owner or an agent; there is no default", {
|
|
5
|
+
reason: "proposal.decider-required",
|
|
6
|
+
});
|
|
7
|
+
return by;
|
|
8
|
+
};
|
|
9
|
+
const decider = (by) => {
|
|
10
|
+
if (by === undefined)
|
|
11
|
+
throw new CliError("validation_error", "a confirm names who decides: the owner or an agent with a reason", {
|
|
12
|
+
reason: "proposal.decider-required",
|
|
13
|
+
});
|
|
14
|
+
return by;
|
|
15
|
+
};
|
|
2
16
|
export const documentKnowledge = (store, folder) => {
|
|
3
17
|
const document = async (principal, ref) => {
|
|
4
18
|
const note = await store.notes.resolveNote(ref);
|
|
@@ -62,13 +76,13 @@ export const documentKnowledge = (store, folder) => {
|
|
|
62
76
|
},
|
|
63
77
|
addLink: async (principal, ref, input) => {
|
|
64
78
|
await document(principal, ref);
|
|
65
|
-
return store.notes.addLink({ ...input, from: ref, origin: "owner" });
|
|
79
|
+
return store.notes.addLink({ ...input, from: ref, origin: input.by === "owner" ? "owner" : "suggested" });
|
|
66
80
|
},
|
|
67
|
-
removeLink: async (principal, ref, id) => {
|
|
81
|
+
removeLink: async (principal, ref, id, by) => {
|
|
68
82
|
const links = await port.links(principal, ref);
|
|
69
83
|
if (!links.some((link) => link.id === id && link.origin === "owner"))
|
|
70
84
|
throw new CliError("not_found", "owner link is not attached to this document");
|
|
71
|
-
return store.notes.removeLink(id);
|
|
85
|
+
return store.notes.removeLink(id, by);
|
|
72
86
|
},
|
|
73
87
|
notes: async (principal, ref, options) => {
|
|
74
88
|
await document(principal, ref);
|
|
@@ -91,18 +105,18 @@ export const documentKnowledge = (store, folder) => {
|
|
|
91
105
|
await document(principal, ref);
|
|
92
106
|
if (input.supersedes)
|
|
93
107
|
await memoryFor(principal, ref, input.supersedes);
|
|
94
|
-
return store.memories.add({ ...input, subject: ref, evidence: [ref], author: input.author
|
|
108
|
+
return store.memories.add({ ...input, subject: ref, evidence: [ref], author: writer(input.author) });
|
|
95
109
|
},
|
|
96
110
|
memories: async (principal, ref, options) => {
|
|
97
111
|
await document(principal, ref);
|
|
98
112
|
return store.memories.list({ ...options, subject: ref });
|
|
99
113
|
},
|
|
100
|
-
memory: async (principal, ref, memoryRef, action = "show") => {
|
|
114
|
+
memory: async (principal, ref, memoryRef, action = "show", by) => {
|
|
101
115
|
const memory = await memoryFor(principal, ref, memoryRef);
|
|
102
116
|
if (action === "confirm")
|
|
103
|
-
return store.memories.confirm(memory.ref);
|
|
117
|
+
return store.memories.confirm(memory.ref, decider(by));
|
|
104
118
|
if (action === "stale")
|
|
105
|
-
return store.memories.markStale(memory.ref);
|
|
119
|
+
return store.memories.markStale(memory.ref, decider(by));
|
|
106
120
|
return memory;
|
|
107
121
|
},
|
|
108
122
|
searchMemories: async (principal, ref, query, scope) => {
|
|
@@ -117,7 +131,7 @@ export const documentKnowledge = (store, folder) => {
|
|
|
117
131
|
return store.facts.add({
|
|
118
132
|
type,
|
|
119
133
|
statement,
|
|
120
|
-
by: by
|
|
134
|
+
by: writer(by),
|
|
121
135
|
...(supersedes === undefined ? {} : { supersedes }),
|
|
122
136
|
...(occurredAt === undefined ? {} : { occurredAt }),
|
|
123
137
|
subject: ref,
|
|
@@ -129,12 +143,12 @@ export const documentKnowledge = (store, folder) => {
|
|
|
129
143
|
await document(principal, ref);
|
|
130
144
|
return store.facts.list({ ...options, subject: ref });
|
|
131
145
|
},
|
|
132
|
-
fact: async (principal, ref, factRef, action = "show") => {
|
|
146
|
+
fact: async (principal, ref, factRef, action = "show", by) => {
|
|
133
147
|
const fact = await factFor(principal, ref, factRef);
|
|
134
148
|
if (action === "confirm")
|
|
135
|
-
return store.facts.accept(fact.ref);
|
|
149
|
+
return store.facts.accept(fact.ref, decider(by));
|
|
136
150
|
if (action === "reverse")
|
|
137
|
-
return store.facts.reverse(fact.ref);
|
|
151
|
+
return store.facts.reverse(fact.ref, decider(by));
|
|
138
152
|
return fact;
|
|
139
153
|
},
|
|
140
154
|
};
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type BotCheckService } from "../botcheck/service.js";
|
|
2
|
+
export { amountOf, amountsOf, type TaskAmount } from "../search/task-signature.js";
|
|
3
|
+
export { AGENDA_DEFAULTS } from "./agenda.js";
|
|
2
4
|
export { type ChatCoverage, chatCoverage } from "./chat-coverage.js";
|
|
3
5
|
export type { ContextEvidenceItem, ContextEvidencePage, ContextEvidenceReader, ContextEvidenceRequest, ContextEvidenceSender, ContextIndex, ContextReadLimits, ContextReadUsage, ContextRecordReader, ContextSource, ScopedContextEvidenceReader, } from "./context-evidence.js";
|
|
4
6
|
export { contextEvidenceFingerprint, createContextEvidenceReader } from "./context-evidence.js";
|
|
@@ -9,6 +11,7 @@ export type { MediaArchiveEntry, MediaIdentity } from "./media-archive-manifest.
|
|
|
9
11
|
export type { MoveMediaArchiveOptions } from "./media-archive-move.js";
|
|
10
12
|
export { moveMediaArchive } from "./media-archive-move.js";
|
|
11
13
|
export { type DownloadedModel, downloadImageModel, downloadTextModel, type ModelDownloadOptions, } from "./model-downloads.js";
|
|
14
|
+
export { MONEY_DONE, MONEY_REQUEST, MONEY_WORDS, moneyClassesOf, PROMISE } from "./money-words.js";
|
|
12
15
|
export type { ProjectChatFetcher, ProjectChatFetchProgress, ProjectChatFetchRequest, ProjectEvidenceContext, ProjectEvidenceItem, ProjectEvidencePerson, ProjectGathering, ProjectGatheringPorts, ProjectGatheringStop, ProjectIndexCatchUp, } from "./project-gathering.js";
|
|
13
16
|
export { gatherProjectEvidence } from "./project-gathering.js";
|
|
14
17
|
export type { ProjectNeighbour, ProjectNeighbourReader } from "./project-gathering-around.js";
|
|
@@ -16,7 +19,8 @@ export { documentPassage, storedMessageNeighbours, storedNeighbours } from "./pr
|
|
|
16
19
|
export type { EvidenceMention, EvidenceMentions } from "./project-gathering-mentions.js";
|
|
17
20
|
export { findEvidenceMentions } from "./project-gathering-mentions.js";
|
|
18
21
|
export type { ProjectChatFetched, ProjectGatheringBudgets, ProjectGatheringRequest, ProjectLane, ProjectLaneKind, ProjectLinkedChat, ProjectPerson, ProjectSender, ProjectUnitState, } from "./project-gathering-request.js";
|
|
19
|
-
export {
|
|
22
|
+
export { questions } from "./questions.js";
|
|
23
|
+
export { canonicalProjectRef, gatherStoredProject, type LinkedChat, linkedChatsOf, type StoredProjectGathering, type StoredProjectInput, } from "./stored-project-gathering.js";
|
|
20
24
|
import { type AccountService } from "./account.js";
|
|
21
25
|
import { type AdminService } from "./admin.js";
|
|
22
26
|
import { type AdminStatisticsService } from "./admin-statistics.js";
|
|
@@ -177,6 +181,7 @@ export { type PackageUpgradeOutcome, type PackageUpgradePorts, type PackageUpgra
|
|
|
177
181
|
export { type PersonMeetingContext, type PersonMeetingContextItem, type PersonMeetingContextOptions, type PersonMeetingReadStore, personMeetingContext, } from "./person-meeting-context.js";
|
|
178
182
|
export { privatePeopleService } from "./private-people.js";
|
|
179
183
|
export { approveAsTask, type ProposalTaskStore, proposalSource } from "./proposal-tasks.js";
|
|
184
|
+
export { type Decided, type Decision, emptyProposalRegistry, type ProposalFilter, type ProposalKind, type ProposalRegistry, type ProposalRow, parseProposalIds, proposalRegistry, } from "./proposals/index.js";
|
|
180
185
|
export type { RetentionQuery, RetentionService } from "./retention.js";
|
|
181
186
|
export { retentionService } from "./retention.js";
|
|
182
187
|
export { RESOURCES_SEARCHED, type SearchAllFound, type SearchAllItem, type SearchAllMessenger, type SearchAllRequest, type SearchedResource, searchAll, } from "./search-all.js";
|
package/dist/services/index.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { botCheckService } from "../botcheck/service.js";
|
|
2
|
+
export { amountOf, amountsOf } from "../search/task-signature.js";
|
|
3
|
+
export { AGENDA_DEFAULTS } from "./agenda.js";
|
|
2
4
|
export { chatCoverage } from "./chat-coverage.js";
|
|
3
5
|
export { contextEvidenceFingerprint, createContextEvidenceReader } from "./context-evidence.js";
|
|
4
6
|
export { excerpt } from "./excerpt.js";
|
|
5
7
|
export { archiveMedia, checkMediaArchive } from "./media-archive.js";
|
|
6
8
|
export { moveMediaArchive } from "./media-archive-move.js";
|
|
7
9
|
export { downloadImageModel, downloadTextModel, } from "./model-downloads.js";
|
|
10
|
+
export { MONEY_DONE, MONEY_REQUEST, MONEY_WORDS, moneyClassesOf, PROMISE } from "./money-words.js";
|
|
8
11
|
export { gatherProjectEvidence } from "./project-gathering.js";
|
|
9
12
|
export { documentPassage, storedMessageNeighbours, storedNeighbours } from "./project-gathering-around.js";
|
|
10
13
|
export { findEvidenceMentions } from "./project-gathering-mentions.js";
|
|
11
|
-
export {
|
|
14
|
+
export { questions } from "./questions.js";
|
|
15
|
+
export { canonicalProjectRef, gatherStoredProject, linkedChatsOf, } from "./stored-project-gathering.js";
|
|
12
16
|
import { accountService } from "./account.js";
|
|
13
17
|
import { adminService } from "./admin.js";
|
|
14
18
|
import { adminStatisticsService } from "./admin-statistics.js";
|
|
@@ -135,6 +139,7 @@ export { upgradePackage, } from "./package-upgrade.js";
|
|
|
135
139
|
export { personMeetingContext, } from "./person-meeting-context.js";
|
|
136
140
|
export { privatePeopleService } from "./private-people.js";
|
|
137
141
|
export { approveAsTask, proposalSource } from "./proposal-tasks.js";
|
|
142
|
+
export { emptyProposalRegistry, parseProposalIds, proposalRegistry, } from "./proposals/index.js";
|
|
138
143
|
export { retentionService } from "./retention.js";
|
|
139
144
|
export { RESOURCES_SEARCHED, searchAll, } from "./search-all.js";
|
|
140
145
|
export { RESOURCES_SEARCHED_WITH_MEETINGS, searchAllIncludingMeetings, searchAllWithMeetings, } from "./search-all-meetings.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { Id } from "../domain/models.js";
|
|
1
|
+
import type { Id, Provider } from "../domain/models.js";
|
|
2
|
+
import { type ProfilesOn } from "../domain/ref-arguments.js";
|
|
2
3
|
import type { MessengerTraits } from "../ports/traits.js";
|
|
3
4
|
import type { AccountStore } from "../store/account-store.js";
|
|
4
5
|
import type { AccountKey, MessageStore } from "../store/store.js";
|
|
@@ -21,6 +22,8 @@ export declare const storedChatId: (messenger: Saved, reference: string, store:
|
|
|
21
22
|
export declare const chatIdIn: (messenger: Saved, reference: string, store: AccountStore, { includeLeft }?: {
|
|
22
23
|
includeLeft?: boolean;
|
|
23
24
|
}) => Promise<string>;
|
|
25
|
+
/** The profiles of `app` the store recorded on an account of this provider, for a refusal to name. */
|
|
26
|
+
export declare const profilesOnAccount: (store: Pick<MessageStore, "accounts">, app: string | undefined, provider: Provider) => ProfilesOn;
|
|
24
27
|
/** A chat as `--chat` names it, in whichever of the accounts holds it — one of them, or it is an error. */
|
|
25
28
|
export declare const chatAmong: (messenger: Saved, store: MessageStore, accounts: AccountKey[], reference: string) => Promise<{
|
|
26
29
|
account: AccountKey;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CliError, singleLine } from "@wirecat/cli-base";
|
|
2
|
+
import { chatReferenceOf, ensureAccount } from "../domain/ref-arguments.js";
|
|
2
3
|
import { isId, pickChat, pickPerson } from "../resolve.js";
|
|
3
4
|
import { codeOf } from "../sends/guarded.js";
|
|
4
5
|
import { nothingStored } from "./deps.js";
|
|
@@ -28,10 +29,12 @@ const LEFT_EMPTY = "you left this chat, and the store holds none of its messages
|
|
|
28
29
|
*/
|
|
29
30
|
export const storedChatId = (messenger, reference, store, account, { includeLeft = false } = {}) => {
|
|
30
31
|
const renamed = (id) => store.chats.renamedChatId(account, id);
|
|
32
|
+
const profilesOn = profilesOnAccount(store, messenger.app?.command, account.provider);
|
|
31
33
|
const among = chatIdAmong(messenger, reference, account, {
|
|
32
34
|
held: () => store.chats.chats(account, {}),
|
|
33
35
|
renamed,
|
|
34
36
|
left: async (id) => leftIn(await store.chats.chats(account, byId(id))),
|
|
37
|
+
profilesOn,
|
|
35
38
|
});
|
|
36
39
|
if (!includeLeft)
|
|
37
40
|
return among;
|
|
@@ -41,6 +44,7 @@ export const storedChatId = (messenger, reference, store, account, { includeLeft
|
|
|
41
44
|
return chatIdAmong(messenger, reference, account, {
|
|
42
45
|
held: () => store.chats.chats(account, { includeLeft: true }),
|
|
43
46
|
renamed,
|
|
47
|
+
profilesOn,
|
|
44
48
|
});
|
|
45
49
|
});
|
|
46
50
|
};
|
|
@@ -70,14 +74,26 @@ const byId = (id) => ({
|
|
|
70
74
|
where: { sql: "chats.external_id = ?", params: [id] },
|
|
71
75
|
});
|
|
72
76
|
const leftIn = ({ items }) => items.some((one) => one.membershipState === "left");
|
|
77
|
+
/** The profiles of `app` the store recorded on an account of this provider, for a refusal to name. */
|
|
78
|
+
export const profilesOnAccount = (store, app, provider) => async (account) => {
|
|
79
|
+
if (app === undefined)
|
|
80
|
+
return undefined;
|
|
81
|
+
return Object.entries((await store.accounts.profiles())[app] ?? {})
|
|
82
|
+
.filter(([, key]) => key.provider === provider && key.account === account)
|
|
83
|
+
.map(([name]) => name);
|
|
84
|
+
};
|
|
73
85
|
/** `left` is given where a left chat is refused; it lets a numeric id the store does not hold through as typed. */
|
|
74
|
-
const chatIdAmong = async (messenger, reference, account, { held, renamed, left, }) => {
|
|
86
|
+
const chatIdAmong = async (messenger, reference, account, { held, renamed, left, profilesOn, }) => {
|
|
75
87
|
const trimmed = reference.trim();
|
|
76
88
|
if (messenger.savedChatId && ["me", "self", "saved"].includes(trimmed.toLowerCase())) {
|
|
77
89
|
return messenger.savedChatId(account);
|
|
78
90
|
}
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
const named = chatReferenceOf(trimmed, account.provider);
|
|
92
|
+
if (named)
|
|
93
|
+
await ensureAccount(named, { account: account.account }, profilesOn);
|
|
94
|
+
if (named || /^-?\d+$/.test(trimmed)) {
|
|
95
|
+
const typed = named?.chat ?? trimmed;
|
|
96
|
+
const id = (await renamed(typed)) ?? typed;
|
|
81
97
|
if (await left?.(id))
|
|
82
98
|
throw new CliError("not_found", `you left chat ${id}`);
|
|
83
99
|
return id;
|
|
@@ -24,6 +24,8 @@ export interface ListWindow {
|
|
|
24
24
|
beforeTime?: number;
|
|
25
25
|
/** Read forward from this message or moment, parsed by the caller in its own words (`afterOf`). */
|
|
26
26
|
after?: After;
|
|
27
|
+
/** The window's last moment, epoch milliseconds, inclusive: a forward read stops here. */
|
|
28
|
+
until?: number;
|
|
27
29
|
/** Only the messages the owner starred (true) or did not (false); the store answers it, never the messenger. */
|
|
28
30
|
starred?: boolean;
|
|
29
31
|
/** Only this forum topic. */
|
|
@@ -3,13 +3,14 @@ import { validateFormattedText, visibleFormattedText } from "../domain/formattin
|
|
|
3
3
|
import { formatLocator } from "../domain/locator.js";
|
|
4
4
|
import { fileLinks, messageLinkTarget, validatePermalink } from "../domain/message-link.js";
|
|
5
5
|
import { pinDurationsText } from "../domain/pin-duration.js";
|
|
6
|
+
import { ensureAccount } from "../domain/ref-arguments.js";
|
|
6
7
|
import { threadIdOf } from "../domain/thread.js";
|
|
7
8
|
import { capability } from "../ports/messenger.js";
|
|
8
9
|
import { codeOf, guardedWrite, sentIds } from "../sends/guarded.js";
|
|
9
10
|
import { sendAsCheck } from "../sends/send-as.js";
|
|
10
11
|
import { newOperationId, newSendId } from "../sends/send-id.js";
|
|
11
12
|
import { uploadSize } from "../sends/upload.js";
|
|
12
|
-
import { crossAccount, fromStore
|
|
13
|
+
import { crossAccount, fromStore } from "./deps.js";
|
|
13
14
|
import { readChatId, storedChatId } from "./message-resolution.js";
|
|
14
15
|
import { accountOf, keyOf, searchStore, statsStore, topUp } from "./messages-archive-search.js";
|
|
15
16
|
import { meaningLane } from "./messages-meaning.js";
|
|
@@ -31,6 +32,14 @@ const filesOf = ({ attachments }) => {
|
|
|
31
32
|
export const messagesService = (deps) => {
|
|
32
33
|
const { guard } = deps;
|
|
33
34
|
const inStore = async (read) => read(await deps.store(), await deps.account());
|
|
35
|
+
/** A message named by a reference is read only in the account the reference names; the store is not opened to say so. */
|
|
36
|
+
const ownTarget = async (target, account) => {
|
|
37
|
+
if (account.provider !== deps.messenger.provider)
|
|
38
|
+
throw new CliError("validation_error", "that locator belongs to another account; select its profile first");
|
|
39
|
+
if (target.account === undefined)
|
|
40
|
+
return;
|
|
41
|
+
await ensureAccount({ text: target.text, account: target.account }, { account: account.account, ...(deps.profile === undefined ? {} : { profile: deps.profile }) });
|
|
42
|
+
};
|
|
34
43
|
const serverThenStore = async (store, account, query) => {
|
|
35
44
|
const server = await searchServer(deps, query);
|
|
36
45
|
const only = query.backend === "server" && server
|
|
@@ -75,8 +84,8 @@ export const messagesService = (deps) => {
|
|
|
75
84
|
await guardedWrite(guard, { operationId, chatId, kind: "pin", key: pinned ? "messages.pin" : "messages.unpin", messageId: message, notify }, () => act(chatId, message, { notify, ...(duration === undefined ? {} : { duration }) }));
|
|
76
85
|
return { operationId, chatId, messageId: message, pinned };
|
|
77
86
|
};
|
|
78
|
-
const topicPage = async (chat, threadId, { limit, before, beforeTime, after }) => {
|
|
79
|
-
if (beforeTime !== undefined || after !== undefined)
|
|
87
|
+
const topicPage = async (chat, threadId, { limit, before, beforeTime, after, until }) => {
|
|
88
|
+
if (beforeTime !== undefined || after !== undefined || until !== undefined)
|
|
80
89
|
throw new CliError("validation_error", "a topic is read back from its newest message, or from --before-id");
|
|
81
90
|
if (threadId === "1")
|
|
82
91
|
throw new CliError("validation_error", "the General topic's messages carry no topic id — read the whole chat without --topic");
|
|
@@ -86,11 +95,11 @@ export const messagesService = (deps) => {
|
|
|
86
95
|
}
|
|
87
96
|
return capability(await deps.connection(), "topicHistory", "read one forum topic")(chat, threadId, window);
|
|
88
97
|
};
|
|
89
|
-
const listPage = async (chat, { limit, before, beforeTime, after, threadId: typedThread, starred }) => {
|
|
98
|
+
const listPage = async (chat, { limit, before, beforeTime, after, until, threadId: typedThread, starred }) => {
|
|
90
99
|
if (starred !== undefined) {
|
|
91
100
|
if (!fromStore(deps))
|
|
92
101
|
throw new CliError("validation_error", "starred: reads the local store; not while reading from the messenger");
|
|
93
|
-
if (typedThread !== undefined || beforeTime !== undefined || after !== undefined)
|
|
102
|
+
if (typedThread !== undefined || beforeTime !== undefined || after !== undefined || until !== undefined)
|
|
94
103
|
throw new CliError("validation_error", "starred: pages back through the whole chat; give only id< with it");
|
|
95
104
|
return inStore(async (store, account) => store.messages.messages(account, await readChatId(deps, chat, store, account), {
|
|
96
105
|
limit,
|
|
@@ -100,28 +109,30 @@ export const messagesService = (deps) => {
|
|
|
100
109
|
}
|
|
101
110
|
const threadId = threadIdOf(typedThread);
|
|
102
111
|
if (threadId !== undefined)
|
|
103
|
-
return topicPage(chat, threadId, { limit, before, beforeTime, after });
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
return topicPage(chat, threadId, { limit, before, beforeTime, after, until });
|
|
113
|
+
if (fromStore(deps)) {
|
|
114
|
+
const window = after
|
|
115
|
+
? { limit, after, ...(until === undefined ? {} : { until }) }
|
|
116
|
+
: {
|
|
117
|
+
limit,
|
|
118
|
+
...(before === undefined ? {} : { before }),
|
|
119
|
+
// historyBefore reads strictly before its moment; the store's end is inclusive.
|
|
120
|
+
...(beforeTime === undefined ? {} : { until: beforeTime - 1 }),
|
|
121
|
+
};
|
|
122
|
+
return inStore(async (store, account) => store.messages.messages(account, await readChatId(deps, chat, store, account), window));
|
|
111
123
|
}
|
|
124
|
+
const connection = await deps.connection();
|
|
125
|
+
if (beforeTime !== undefined)
|
|
126
|
+
return capability(connection, "historyBefore", "read back from a time")(chat, { limit, time: beforeTime });
|
|
112
127
|
if (after !== undefined) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return capability(connection, "historyAfter", "read forward from a message")(chat, { limit, after });
|
|
128
|
+
const page = await capability(connection, "historyAfter", "read forward from a message")(chat, { limit, after });
|
|
129
|
+
if (until === undefined)
|
|
130
|
+
return page;
|
|
131
|
+
const items = page.items.filter((one) => Date.parse(one.timestamp) <= until);
|
|
132
|
+
return { items, hasMore: page.hasMore && items.length === page.items.length };
|
|
119
133
|
}
|
|
120
134
|
const window = { limit, ...(before === undefined ? {} : { before }) };
|
|
121
|
-
|
|
122
|
-
return inStore(async (store, account) => store.messages.messages(account, await readChatId(deps, chat, store, account), window));
|
|
123
|
-
}
|
|
124
|
-
return capability(await deps.connection(), "history", "read a chat's history")(chat, window);
|
|
135
|
+
return capability(connection, "history", "read a chat's history")(chat, window);
|
|
125
136
|
};
|
|
126
137
|
return {
|
|
127
138
|
// A provider caps its pages (Telegram at 100), so a larger --limit reads on from the last page's edge.
|
|
@@ -151,11 +162,8 @@ export const messagesService = (deps) => {
|
|
|
151
162
|
},
|
|
152
163
|
around: async (reference, message, window) => {
|
|
153
164
|
const target = messageLinkTarget(reference, message, deps.messenger.provider);
|
|
154
|
-
if (target.account !== undefined)
|
|
155
|
-
|
|
156
|
-
if (account.provider !== deps.messenger.provider || target.account !== account.account)
|
|
157
|
-
throw new CliError("validation_error", "that locator belongs to another account; select its profile first");
|
|
158
|
-
}
|
|
165
|
+
if (target.account !== undefined)
|
|
166
|
+
await ownTarget(target, await deps.account());
|
|
159
167
|
if (fromStore(deps)) {
|
|
160
168
|
return inStore(async (store, account) => store.messages.around(account, await readChatId(deps, target.chat, store, account), target.message, window));
|
|
161
169
|
}
|
|
@@ -163,9 +171,7 @@ export const messagesService = (deps) => {
|
|
|
163
171
|
},
|
|
164
172
|
thread: (reference, message, options) => inStore(async (store, account) => {
|
|
165
173
|
const target = messageLinkTarget(reference, message, deps.messenger.provider);
|
|
166
|
-
|
|
167
|
-
(target.account !== undefined && target.account !== account.account))
|
|
168
|
-
throw new CliError("validation_error", "that locator belongs to another account; select its profile first");
|
|
174
|
+
await ownTarget(target, account);
|
|
169
175
|
return readThreadContext(store, account, await storedChatId(deps.messenger, target.chat, store, account, { includeLeft: true }), target.message, options);
|
|
170
176
|
}),
|
|
171
177
|
comments: async (chat, typedPost, window) => {
|
|
@@ -184,9 +190,7 @@ export const messagesService = (deps) => {
|
|
|
184
190
|
link: async (reference, message) => {
|
|
185
191
|
const target = messageLinkTarget(reference, message, deps.messenger.provider);
|
|
186
192
|
const account = await deps.account();
|
|
187
|
-
|
|
188
|
-
(target.account !== undefined && target.account !== account.account))
|
|
189
|
-
throw new CliError("validation_error", "that locator belongs to another account; select its profile first");
|
|
193
|
+
await ownTarget(target, account);
|
|
190
194
|
if (fromStore(deps)) {
|
|
191
195
|
const store = await deps.store();
|
|
192
196
|
const chat = await readChatId(deps, target.chat, store, account);
|
|
@@ -227,8 +231,8 @@ export const messagesService = (deps) => {
|
|
|
227
231
|
},
|
|
228
232
|
download: async (reference, message) => {
|
|
229
233
|
const target = messageLinkTarget(reference, message, deps.messenger.provider);
|
|
230
|
-
if (target.account !== undefined
|
|
231
|
-
|
|
234
|
+
if (target.account !== undefined)
|
|
235
|
+
await ownTarget(target, await deps.account());
|
|
232
236
|
const connection = await deps.connection();
|
|
233
237
|
const download = capability(connection, "download", "download attachments");
|
|
234
238
|
return download((await connection.resolve(target.chat)).id, target.message);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MONEY_WORDS } from "../domain/money-words.js";
|
|
2
|
+
import { listsHit } from "./task-categories.js";
|
|
3
|
+
export { MONEY_DONE, MONEY_REQUEST, MONEY_WORDS, PROMISE } from "../domain/money-words.js";
|
|
4
|
+
/** The money classes the text's words belong to; none for a text with no money verb. */
|
|
5
|
+
export const moneyClassesOf = (text) => listsHit(text, MONEY_WORDS);
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { type Decider } from "../store/decisions.js";
|
|
1
2
|
import type { MessageStore, ProposedAction } from "../store/store.js";
|
|
2
3
|
import { type Task } from "../tasks/index.js";
|
|
3
|
-
export type ProposalTaskStore = Pick<MessageStore, "proposedActions" | "tasks">;
|
|
4
|
+
export type ProposalTaskStore = Pick<MessageStore, "proposedActions" | "tasks" | "decisionPolicy">;
|
|
4
5
|
/** The source a proposal's task keeps: found again on a retry, so one proposal never makes two tasks. */
|
|
5
6
|
export declare const proposalSource: (id: string) => string;
|
|
6
7
|
/**
|
|
7
8
|
* Approving a proposal makes it the owner's task in the account that would act; nothing is carried out.
|
|
8
9
|
* The task comes first, so an approval that failed half-way finds the same task when it is run again.
|
|
9
10
|
*/
|
|
10
|
-
export declare const approveAsTask: (store: ProposalTaskStore, id: string) => Promise<{
|
|
11
|
+
export declare const approveAsTask: (store: ProposalTaskStore, id: string, by: Decider) => Promise<{
|
|
11
12
|
proposal: ProposedAction;
|
|
12
13
|
task: Task;
|
|
13
14
|
}>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { MEETING_FINDINGS_KIND } from "../meetings/index.js";
|
|
3
|
+
import { assertMayDecide } from "../store/decisions.js";
|
|
3
4
|
import { EVIDENCE_FINDINGS_KIND } from "../store/evidence-findings.js";
|
|
5
|
+
import { proposerOfAction } from "../store/index.js";
|
|
4
6
|
import { createTaskService } from "../tasks/index.js";
|
|
5
7
|
import { taskAccount } from "./task-rules.js";
|
|
6
8
|
/** The source a proposal's task keeps: found again on a retry, so one proposal never makes two tasks. */
|
|
@@ -9,7 +11,7 @@ export const proposalSource = (id) => `proposed-action:${id}`;
|
|
|
9
11
|
* Approving a proposal makes it the owner's task in the account that would act; nothing is carried out.
|
|
10
12
|
* The task comes first, so an approval that failed half-way finds the same task when it is run again.
|
|
11
13
|
*/
|
|
12
|
-
export const approveAsTask = async (store, id) => {
|
|
14
|
+
export const approveAsTask = async (store, id, by) => {
|
|
13
15
|
const proposal = await store.proposedActions.get(id);
|
|
14
16
|
if (proposal.kind === MEETING_FINDINGS_KIND)
|
|
15
17
|
throw new CliError("validation_error", "review meeting findings through the dedicated findings command", {
|
|
@@ -23,6 +25,7 @@ export const approveAsTask = async (store, id) => {
|
|
|
23
25
|
throw new CliError("validation_error", `a ${proposal.status} action cannot be approved`, {
|
|
24
26
|
reason: "proposal.wrong-state",
|
|
25
27
|
});
|
|
28
|
+
assertMayDecide({ id: proposal.id, proposedBy: proposerOfAction(proposal) }, by, store.decisionPolicy);
|
|
26
29
|
if (proposal.account === null)
|
|
27
30
|
throw new CliError("validation_error", "a proposal names the account that would act; this one names none");
|
|
28
31
|
const { task } = await createTaskService({ store: store.tasks }).add({
|
|
@@ -33,5 +36,5 @@ export const approveAsTask = async (store, id) => {
|
|
|
33
36
|
kind: "request",
|
|
34
37
|
origin: "agent",
|
|
35
38
|
});
|
|
36
|
-
return { proposal: await store.proposedActions.approve(proposal.id, { task: task.id }), task };
|
|
39
|
+
return { proposal: await store.proposedActions.approve(proposal.id, by, { task: task.id }), task };
|
|
37
40
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
const MAX_IDS = 500;
|
|
3
|
+
const refuse = (message) => {
|
|
4
|
+
throw new CliError("validation_error", message, { reason: "proposal.ids" });
|
|
5
|
+
};
|
|
6
|
+
const range = (prefix, from, to) => {
|
|
7
|
+
const [start, end] = [Number(from), Number(to)];
|
|
8
|
+
if (start > end)
|
|
9
|
+
return refuse(`a range runs upwards: ${from}-${to}`);
|
|
10
|
+
if (end - start + 1 > MAX_IDS)
|
|
11
|
+
return refuse(`a range takes at most ${MAX_IDS} ids`);
|
|
12
|
+
return Array.from({ length: end - start + 1 }, (_, n) => `${prefix}${start + n}`);
|
|
13
|
+
};
|
|
14
|
+
const one = (token) => {
|
|
15
|
+
const bare = /^([1-9]\d*)(?:-([1-9]\d*))?$/.exec(token);
|
|
16
|
+
if (bare?.[1])
|
|
17
|
+
return bare[2] ? range("", bare[1], bare[2]) : [bare[1]];
|
|
18
|
+
const part = /^([1-9]\d*)\/([A-Za-z0-9_-]{1,64})$/.exec(token);
|
|
19
|
+
if (part)
|
|
20
|
+
return [token];
|
|
21
|
+
const prefixed = /^([a-z][a-z_]*):([1-9]\d*)(?:-(?:([a-z][a-z_]*):)?([1-9]\d*))?$/.exec(token);
|
|
22
|
+
if (prefixed?.[1] && prefixed[2]) {
|
|
23
|
+
const [, prefix, from, other, to] = prefixed;
|
|
24
|
+
if (other !== undefined && other !== prefix)
|
|
25
|
+
return refuse(`a range stays inside one prefix: ${token}`);
|
|
26
|
+
return to ? range(`${prefix}:`, from, to) : [`${prefix}:${from}`];
|
|
27
|
+
}
|
|
28
|
+
if (/^[1-9]\d*-[a-z]/.test(token))
|
|
29
|
+
return refuse(`a range stays inside one prefix: ${token}`);
|
|
30
|
+
return refuse(`not a proposal id: ${token}; use 17070, 17070-17079, fact:512 or 17080/f2`);
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Proposal ids from the command line, before any reference parsing: `17070-17079,fact:500-502,17080/f1` becomes
|
|
34
|
+
* each id once, in the order given.
|
|
35
|
+
*/
|
|
36
|
+
export const parseProposalIds = (text) => {
|
|
37
|
+
const ids = [...new Set(text.flatMap((arg) => arg.split(",")).flatMap((token) => one(token.trim())))];
|
|
38
|
+
if (ids.length === 0)
|
|
39
|
+
return refuse("name at least one proposal id");
|
|
40
|
+
if (ids.length > MAX_IDS)
|
|
41
|
+
return refuse(`decide at most ${MAX_IDS} proposals at once`);
|
|
42
|
+
return ids;
|
|
43
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type MessageStore } from "../../../store/index.js";
|
|
2
|
+
import type { ProposalKind } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Every stored proposal no other kind claims: a reply, a ban, a task to create. Confirming makes it the owner's task
|
|
5
|
+
* in the account that would act; nothing is carried out. Meeting findings are reviewed with their meeting.
|
|
6
|
+
*/
|
|
7
|
+
export declare const actionKind: (store: Pick<MessageStore, "proposedActions" | "tasks" | "decisionPolicy">, claimed: () => readonly string[]) => ProposalKind;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MEETING_FINDINGS_KIND } from "../../../meetings/index.js";
|
|
2
|
+
import { proposerOfAction } from "../../../store/index.js";
|
|
3
|
+
import { approveAsTask } from "../../proposal-tasks.js";
|
|
4
|
+
import { actionStatus, kept, projectOf, pushed, storedStatus } from "./shared.js";
|
|
5
|
+
const rowOf = (action) => ({
|
|
6
|
+
id: action.id,
|
|
7
|
+
kind: "action",
|
|
8
|
+
status: actionStatus(action.status),
|
|
9
|
+
project: projectOf(action.target),
|
|
10
|
+
subject: action.target ?? `action:${action.id}`,
|
|
11
|
+
object: null,
|
|
12
|
+
summary: action.kind,
|
|
13
|
+
proposedBy: proposerOfAction(action),
|
|
14
|
+
reason: action.reason,
|
|
15
|
+
evidence: [],
|
|
16
|
+
score: null,
|
|
17
|
+
signals: null,
|
|
18
|
+
parts: null,
|
|
19
|
+
createdAt: action.createdAt,
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Every stored proposal no other kind claims: a reply, a ban, a task to create. Confirming makes it the owner's task
|
|
23
|
+
* in the account that would act; nothing is carried out. Meeting findings are reviewed with their meeting.
|
|
24
|
+
*/
|
|
25
|
+
export const actionKind = (store, claimed) => ({
|
|
26
|
+
kind: "action",
|
|
27
|
+
list: async (filter) => {
|
|
28
|
+
const status = storedStatus(filter);
|
|
29
|
+
const actions = await store.proposedActions.list({
|
|
30
|
+
except: [...claimed(), MEETING_FINDINGS_KIND],
|
|
31
|
+
...(status === undefined ? {} : { status }),
|
|
32
|
+
...pushed(filter),
|
|
33
|
+
});
|
|
34
|
+
return kept(actions.map(rowOf), filter);
|
|
35
|
+
},
|
|
36
|
+
get: async (id) => rowOf(await store.proposedActions.get(id)),
|
|
37
|
+
decide: async (id, { confirm, by, reason }) => {
|
|
38
|
+
if (!confirm) {
|
|
39
|
+
await store.proposedActions.reject(id, by, reason);
|
|
40
|
+
return { id, kind: "action", status: "rejected", made: [] };
|
|
41
|
+
}
|
|
42
|
+
const { task } = await approveAsTask(store, id, by);
|
|
43
|
+
return { id, kind: "action", status: "confirmed", made: [`task:${task.key ?? task.id}`] };
|
|
44
|
+
},
|
|
45
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { MessageStore } from "../../../store/index.js";
|
|
2
|
+
import type { ProposalKind } from "../types.js";
|
|
3
|
+
/** Facts keep their own table and lifecycle; an agent's waits as `proposed`. */
|
|
4
|
+
export declare const factKind: (store: Pick<MessageStore, "facts">) => ProposalKind;
|