@wirecat/cli-core 0.547.0 → 0.549.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/cli/answers.d.ts +7 -2
- package/dist/calendar/cli/answers.js +12 -4
- package/dist/calendar/cli/index.d.ts +10 -1
- package/dist/calendar/cli/index.js +18 -11
- package/dist/calendar/cli/search-all.d.ts +17 -0
- package/dist/calendar/cli/search-all.js +72 -0
- package/dist/calendar/feeds.d.ts +19 -0
- package/dist/calendar/feeds.js +52 -9
- package/dist/calendar/source.d.ts +10 -2
- package/dist/calendar/sync.d.ts +2 -0
- package/dist/calendar/sync.js +10 -6
- package/dist/calendar/testing/memory.js +39 -0
- package/dist/cli/answer-entity.d.ts +4 -0
- package/dist/cli/answer-entity.js +5 -0
- package/dist/cli/bot/context.d.ts +2 -0
- package/dist/cli/compact.d.ts +41 -0
- package/dist/cli/compact.js +313 -0
- package/dist/cli/context.d.ts +11 -2
- package/dist/cli/context.js +15 -6
- package/dist/cli/envelope.d.ts +5 -1
- package/dist/cli/envelope.js +15 -4
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/messenger/search-command.d.ts +10 -0
- package/dist/cli/messenger/search-command.js +19 -13
- package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
- package/dist/cli/program.d.ts +3 -0
- package/dist/cli/program.js +7 -1
- package/dist/domain/providers.d.ts +3 -0
- package/dist/domain/providers.js +20 -4
- package/dist/domain/ref-arguments.js +3 -7
- package/dist/domain/ref-summaries.d.ts +56 -0
- package/dist/domain/ref-summaries.js +63 -0
- package/dist/entities/index.d.ts +11 -0
- package/dist/entities/relationship.d.ts +2 -0
- package/dist/entities/relationship.js +2 -0
- package/dist/entities/task-results.d.ts +10 -0
- package/dist/entities/task-results.js +1 -0
- package/dist/errors/reasons.js +1 -0
- package/dist/meetings/event-store.d.ts +10 -0
- package/dist/meetings/testing/event-store-contract.js +36 -0
- package/dist/output-detail.js +9 -5
- package/dist/output.d.ts +5 -1
- package/dist/output.js +29 -4
- package/dist/services/proposals/kinds/relationship-update.d.ts +4 -0
- package/dist/services/proposals/kinds/relationship-update.js +53 -0
- package/dist/services/proposals/registry.js +2 -0
- package/dist/store/decisions.d.ts +3 -1
- package/dist/store/decisions.js +7 -1
- package/dist/store/index.d.ts +2 -1
- package/dist/store/sqlite/accounts.d.ts +8 -0
- package/dist/store/sqlite/accounts.js +2 -2
- package/dist/store/sqlite/calendar-forget.d.ts +17 -0
- package/dist/store/sqlite/calendar-forget.js +68 -0
- package/dist/store/sqlite/calendar.js +8 -0
- package/dist/store/sqlite/evidence-sources.d.ts +2 -2
- package/dist/store/sqlite/evidence-sources.js +41 -77
- package/dist/store/sqlite/knowledge.d.ts +17 -23
- package/dist/store/sqlite/knowledge.js +13 -13
- package/dist/store/sqlite/manifest.js +2 -0
- package/dist/store/sqlite/migrations.generated.js +12 -0
- package/dist/store/sqlite/notes.d.ts +5 -0
- package/dist/store/sqlite/notes.js +6 -2
- package/dist/store/sqlite/open-store.js +2 -0
- package/dist/store/sqlite/proposed-actions.d.ts +1 -1
- package/dist/store/sqlite/proposed-actions.js +10 -2
- package/dist/store/sqlite/ref-summaries.d.ts +17 -0
- package/dist/store/sqlite/ref-summaries.js +378 -0
- package/dist/store/sqlite/relation-proposals.d.ts +40 -0
- package/dist/store/sqlite/relation-proposals.js +88 -1
- package/dist/store/sqlite/schema.d.ts +16 -0
- package/dist/store/sqlite/schema.js +1 -0
- package/dist/store/sqlite/suggested-links.d.ts +10 -0
- package/dist/store/sqlite/suggested-links.js +68 -0
- package/dist/store/store.d.ts +3 -0
- package/dist/store/store.js +5 -0
- package/package.json +3 -3
- package/parity.json +4 -0
package/dist/entities/index.d.ts
CHANGED
|
@@ -4911,6 +4911,7 @@ export declare const ENTITIES: {
|
|
|
4911
4911
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
4912
4912
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4913
4913
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4914
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4914
4915
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4915
4916
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4916
4917
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -4925,6 +4926,7 @@ export declare const ENTITIES: {
|
|
|
4925
4926
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
4926
4927
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4927
4928
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4929
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4928
4930
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4929
4931
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
4930
4932
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5023,6 +5025,7 @@ export declare const ENTITIES: {
|
|
|
5023
5025
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5024
5026
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5025
5027
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5028
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5026
5029
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5027
5030
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5028
5031
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5037,6 +5040,7 @@ export declare const ENTITIES: {
|
|
|
5037
5040
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5038
5041
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5039
5042
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5043
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5040
5044
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5041
5045
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5042
5046
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5136,6 +5140,7 @@ export declare const ENTITIES: {
|
|
|
5136
5140
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5137
5141
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5138
5142
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5143
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5139
5144
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5140
5145
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5141
5146
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5150,6 +5155,7 @@ export declare const ENTITIES: {
|
|
|
5150
5155
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5151
5156
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5152
5157
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5158
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5153
5159
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5154
5160
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5155
5161
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5277,6 +5283,7 @@ export declare const ENTITIES: {
|
|
|
5277
5283
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5278
5284
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5279
5285
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5286
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5280
5287
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5281
5288
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5282
5289
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5291,6 +5298,7 @@ export declare const ENTITIES: {
|
|
|
5291
5298
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5292
5299
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5293
5300
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5301
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5294
5302
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5295
5303
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5296
5304
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5383,6 +5391,7 @@ export declare const ENTITIES: {
|
|
|
5383
5391
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5384
5392
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5385
5393
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5394
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5386
5395
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5387
5396
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5388
5397
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -5397,6 +5406,7 @@ export declare const ENTITIES: {
|
|
|
5397
5406
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
5398
5407
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5399
5408
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5409
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5400
5410
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5401
5411
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
5402
5412
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -6600,6 +6610,7 @@ export declare const ENTITIES: {
|
|
|
6600
6610
|
readonly to: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
|
|
6601
6611
|
readonly kind: v.PicklistSchema<readonly ["member-of", "related-to"], undefined>;
|
|
6602
6612
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
6613
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
6603
6614
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
6604
6615
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
6605
6616
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
@@ -6,6 +6,8 @@ export declare const relationship: v.StrictObjectSchema<{
|
|
|
6
6
|
readonly to: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
|
|
7
7
|
readonly kind: v.PicklistSchema<readonly ["member-of", "related-to"], undefined>;
|
|
8
8
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
9
|
+
/** A purpose from memo's config; `null` means `work`. */
|
|
10
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
9
11
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
10
12
|
/** An agent's suggestion stays unconfirmed, and `weak`, until the owner confirms it. */
|
|
11
13
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -8,6 +8,8 @@ export const relationship = v.strictObject({
|
|
|
8
8
|
to: reference,
|
|
9
9
|
kind: v.picklist(RELATION_KINDS),
|
|
10
10
|
role: v.nullable(text),
|
|
11
|
+
/** A purpose from memo's config; `null` means `work`. */
|
|
12
|
+
purpose: v.nullable(text),
|
|
11
13
|
evidence: v.nullable(text),
|
|
12
14
|
/** An agent's suggestion stays unconfirmed, and `weak`, until the owner confirms it. */
|
|
13
15
|
confirmed: v.boolean(),
|
|
@@ -53,6 +53,7 @@ export declare const taskCard: v.StrictObjectSchema<{
|
|
|
53
53
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
54
54
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
55
55
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
56
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
56
57
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
57
58
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
58
59
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -67,6 +68,7 @@ export declare const taskCard: v.StrictObjectSchema<{
|
|
|
67
68
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
68
69
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
69
70
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
71
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
70
72
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
71
73
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
72
74
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -165,6 +167,7 @@ export declare const taskCreated: v.StrictObjectSchema<{
|
|
|
165
167
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
166
168
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
167
169
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
170
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
168
171
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
169
172
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
170
173
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -179,6 +182,7 @@ export declare const taskCreated: v.StrictObjectSchema<{
|
|
|
179
182
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
180
183
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
181
184
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
185
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
182
186
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
183
187
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
184
188
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -278,6 +282,7 @@ export declare const taskLinks: v.UnionSchema<[v.StrictObjectSchema<{
|
|
|
278
282
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
279
283
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
280
284
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
285
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
281
286
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
282
287
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
283
288
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -292,6 +297,7 @@ export declare const taskLinks: v.UnionSchema<[v.StrictObjectSchema<{
|
|
|
292
297
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
293
298
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
294
299
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
300
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
295
301
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
296
302
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
297
303
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -419,6 +425,7 @@ export declare const taskMerge: v.StrictObjectSchema<{
|
|
|
419
425
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
420
426
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
421
427
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
428
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
422
429
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
423
430
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
424
431
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -433,6 +440,7 @@ export declare const taskMerge: v.StrictObjectSchema<{
|
|
|
433
440
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
434
441
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
435
442
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
443
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
436
444
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
437
445
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
438
446
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -525,6 +533,7 @@ export declare const taskUnmerge: v.StrictObjectSchema<{
|
|
|
525
533
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
526
534
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
527
535
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
536
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
528
537
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
529
538
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
530
539
|
readonly confirmed: v.BooleanSchema<undefined>;
|
|
@@ -539,6 +548,7 @@ export declare const taskUnmerge: v.StrictObjectSchema<{
|
|
|
539
548
|
readonly origin: v.PicklistSchema<readonly ["file", "owner", "suggested", "message", "calendar"], undefined>;
|
|
540
549
|
readonly target_text: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
541
550
|
readonly role: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
551
|
+
readonly purpose: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
542
552
|
readonly evidence: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
543
553
|
readonly provenance: v.NullableSchema<v.StringSchema<undefined>, undefined>;
|
|
544
554
|
readonly confirmed: v.BooleanSchema<undefined>;
|
package/dist/errors/reasons.js
CHANGED
|
@@ -144,6 +144,7 @@ const OTHERS = [
|
|
|
144
144
|
],
|
|
145
145
|
validation("name.invalid", "the name is not valid"),
|
|
146
146
|
validation("output.choose-fields", "at a terminal, --json names the fields it prints"),
|
|
147
|
+
validation("output.conflict", "two output switches ask for different output"),
|
|
147
148
|
validation("output.one-object", "a report is one JSON object; --jsonl streams lists only"),
|
|
148
149
|
validation("output.unknown-field", "the answer has no field by that name"),
|
|
149
150
|
validation("name.taken", "the name is already used"),
|
|
@@ -253,6 +253,16 @@ export interface EventStore {
|
|
|
253
253
|
saveCalendars(accountId: number, calendars: CalendarInput[], now: number): Promise<StoredCalendar[]>;
|
|
254
254
|
calendars(accountId: number): Promise<StoredCalendar[]>;
|
|
255
255
|
setCalendarSynced(calendarId: number, synced: boolean, now: number): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* The calendar and everything stored from it go, for a calendar that is not the owner's data (a followed feed): its
|
|
258
|
+
* entries, the events and series only it held, what was built from them (links, tags, search pieces, people seen
|
|
259
|
+
* only there) and its cursor. An event another calendar also holds stays, with that copy's fields; a meeting linked
|
|
260
|
+
* to a gone event stays, unlinked. Notes the owner wrote stay.
|
|
261
|
+
*/
|
|
262
|
+
forgetCalendar(calendarId: number, now: number): Promise<{
|
|
263
|
+
entries: number;
|
|
264
|
+
events: number;
|
|
265
|
+
}>;
|
|
256
266
|
/** One sync page, matched by rules 1–5, in one transaction. */
|
|
257
267
|
saveEntries(calendarId: number, entries: EntryInput[], now: number): Promise<StoredEntry[]>;
|
|
258
268
|
/**
|
|
@@ -192,6 +192,42 @@ export const eventStoreContract = (make) => {
|
|
|
192
192
|
assert.equal(occurrence?.entries[0]?.deletedAt, null);
|
|
193
193
|
assert.equal(await store.removeEntries(calendar, ["p"], CONTRACT_NOW + 1), 0);
|
|
194
194
|
}),
|
|
195
|
+
test("a forgotten calendar goes with its entries and the events only it held; a shared event keeps the other copy", async (fixture) => {
|
|
196
|
+
const { store, calendar, accountId } = fixture;
|
|
197
|
+
const feed = await second(fixture, "ics:example");
|
|
198
|
+
await store.saveEntries(calendar, [single("w1", later, { icalUid: "shared@example.com", title: "Mine" })], 2);
|
|
199
|
+
const series = {
|
|
200
|
+
...single("weekly", later, { title: "Weekly" }),
|
|
201
|
+
kind: "series",
|
|
202
|
+
recurrence: ["RRULE:FREQ=WEEKLY"],
|
|
203
|
+
};
|
|
204
|
+
await store.saveEntries(feed, [
|
|
205
|
+
single("f1", later, { icalUid: "shared@example.com", title: "Theirs", description: "longer text" }),
|
|
206
|
+
single("f2", later + HOUR, { title: "Only in the feed", participants: [{ email: "guest@example.com" }] }),
|
|
207
|
+
series,
|
|
208
|
+
], 3);
|
|
209
|
+
await store.saveSlots(feed, [
|
|
210
|
+
{
|
|
211
|
+
series: "weekly",
|
|
212
|
+
slots: [
|
|
213
|
+
{
|
|
214
|
+
...single("weekly@1", later + 2 * HOUR),
|
|
215
|
+
kind: "occurrence",
|
|
216
|
+
seriesExternalId: "weekly",
|
|
217
|
+
originalStartsAt: later + 2 * HOUR,
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
},
|
|
221
|
+
], { from: earlier, to: later + 7 * 24 * HOUR }, "cursor", 3);
|
|
222
|
+
await store.setCursor(feed, "cursor", 3);
|
|
223
|
+
const forgotten = await store.forgetCalendar(feed, 4);
|
|
224
|
+
assert.deepEqual(forgotten, { entries: 4, events: 2 });
|
|
225
|
+
assert.deepEqual((await store.calendars(accountId)).map(({ externalId }) => externalId), ["primary"]);
|
|
226
|
+
const left = await store.events({ accountId });
|
|
227
|
+
assert.deepEqual(left.map(({ title, status }) => [title, status]), [["Mine", "confirmed"]]);
|
|
228
|
+
assert.equal((await store.event(left[0]?.id))?.entries.length, 1);
|
|
229
|
+
assert.equal(await store.entry(feed, "weekly"), null);
|
|
230
|
+
}),
|
|
195
231
|
test("a calendar's cursor is its own, and null forgets it", async (fixture) => {
|
|
196
232
|
const { store, calendar } = fixture;
|
|
197
233
|
const other = await second(fixture);
|
package/dist/output-detail.js
CHANGED
|
@@ -2,13 +2,17 @@ export const DETAILS = ["brief", "full"];
|
|
|
2
2
|
/** Message fields mail never has and a messenger hit rarely fills; a null one is noise. */
|
|
3
3
|
const RARELY_SET = ["editedAt", "replyTo", "forwardedFrom", "reactions"];
|
|
4
4
|
const BRIEF = ["locator", "chatTitle", "timestamp", "senderName", "excerpt", "score"];
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
/** A messenger answer's hit (`message.hit`): already cut to an excerpt, so only `brief` changes it. */
|
|
6
|
+
const SNAKE_BRIEF = ["ref", "chat_title", "timestamp", "sender_name", "excerpt", "score"];
|
|
7
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
8
|
+
const isSnakeHit = (value) => isRecord(value) && typeof value.ref === "string" && typeof value.excerpt === "string";
|
|
9
|
+
const isHit = (value) => isSnakeHit(value) || (isRecord(value) && typeof value.locator === "string" && typeof value.text === "string");
|
|
10
|
+
const picked = (hit, keys) => Object.fromEntries(keys.flatMap((key) => (hit[key] === undefined || hit[key] === null ? [] : [[key, hit[key]]])));
|
|
9
11
|
const shaped = (hit, detail) => {
|
|
12
|
+
if (isSnakeHit(hit))
|
|
13
|
+
return detail === "brief" ? picked(hit, SNAKE_BRIEF) : hit;
|
|
10
14
|
if (detail === "brief")
|
|
11
|
-
return
|
|
15
|
+
return picked(hit, BRIEF);
|
|
12
16
|
const { text, providerMetadata, ...rest } = hit;
|
|
13
17
|
for (const key of RARELY_SET)
|
|
14
18
|
if (rest[key] === null)
|
package/dist/output.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface OutputOptions {
|
|
|
14
14
|
hitDetail?: Detail;
|
|
15
15
|
/** Takes the answer as an object in place of printing it — an agent's run (`BaseEnvironment.agent`). */
|
|
16
16
|
capture?: (value: unknown) => void;
|
|
17
|
+
/** One line per item (WC-OUT-24); anything printed past `renderAnswer` stays JSON. */
|
|
18
|
+
compact?: boolean;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* One place decides the mode, so no command can disagree with another.
|
|
@@ -23,9 +25,11 @@ export interface OutputOptions {
|
|
|
23
25
|
* instead. In every machine mode **stdout carries JSON and nothing else** — diagnostics are on stderr in all modes, which is what makes
|
|
24
26
|
* that contract hold by construction rather than by remembering.
|
|
25
27
|
*/
|
|
26
|
-
export declare const resolveOutput: ({ json, jsonl, quiet, streams, tty, color, fields, hitDetail, env, capture, }?: OutputOptions) => {
|
|
28
|
+
export declare const resolveOutput: ({ json, jsonl, quiet, streams, tty, color, fields, hitDetail, env, capture, compact, }?: OutputOptions) => {
|
|
27
29
|
format: "json" | "jsonl" | "pretty";
|
|
28
30
|
color: boolean;
|
|
29
31
|
streams: Streams;
|
|
30
32
|
renderer: Renderer;
|
|
33
|
+
compact?: boolean | undefined;
|
|
34
|
+
full?: boolean | undefined;
|
|
31
35
|
};
|
package/dist/output.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
|
-
import { createRenderer, processStreams, singleLine, } from "@wirecat/cli-base";
|
|
1
|
+
import { CliError, createRenderer, processStreams, singleLine, } from "@wirecat/cli-base";
|
|
2
|
+
import { COMPACT_FLAG } from "@wirecat/cli-base/standards";
|
|
2
3
|
import { fieldsOf, projectFields } from "./cli/result-fields.js";
|
|
3
4
|
import { atDetail } from "./output-detail.js";
|
|
5
|
+
const refuseCompact = ({ json, jsonl, fields, hitDetail }) => {
|
|
6
|
+
const other = jsonl
|
|
7
|
+
? "--jsonl"
|
|
8
|
+
: fields !== undefined
|
|
9
|
+
? "--json=…"
|
|
10
|
+
: json
|
|
11
|
+
? "--json"
|
|
12
|
+
: hitDetail === "brief"
|
|
13
|
+
? "--brief"
|
|
14
|
+
: "";
|
|
15
|
+
if (other)
|
|
16
|
+
throw new CliError("validation_error", `${COMPACT_FLAG} and ${other} ask for different output — pick one`, {
|
|
17
|
+
reason: "output.conflict",
|
|
18
|
+
param: COMPACT_FLAG,
|
|
19
|
+
});
|
|
20
|
+
};
|
|
4
21
|
/**
|
|
5
22
|
* One place decides the mode, so no command can disagree with another.
|
|
6
23
|
*
|
|
@@ -9,9 +26,11 @@ import { atDetail } from "./output-detail.js";
|
|
|
9
26
|
* instead. In every machine mode **stdout carries JSON and nothing else** — diagnostics are on stderr in all modes, which is what makes
|
|
10
27
|
* that contract hold by construction rather than by remembering.
|
|
11
28
|
*/
|
|
12
|
-
export const resolveOutput = ({ json, jsonl, quiet, streams = processStreams, tty, color, fields, hitDetail, env = process.env, capture, } = {}) => {
|
|
29
|
+
export const resolveOutput = ({ json, jsonl, quiet, streams = processStreams, tty, color, fields, hitDetail, env = process.env, capture, compact, } = {}) => {
|
|
30
|
+
if (compact)
|
|
31
|
+
refuseCompact({ json, jsonl, fields, hitDetail });
|
|
13
32
|
const interactive = tty ?? process.stdout.isTTY === true;
|
|
14
|
-
const format = jsonl ? "jsonl" : json || !interactive ? "json" : "pretty";
|
|
33
|
+
const format = jsonl ? "jsonl" : json || compact || !interactive ? "json" : "pretty";
|
|
15
34
|
const painted = format === "pretty" && (color ?? (env.NO_COLOR === undefined && env.TERM !== "dumb" && !env.CI));
|
|
16
35
|
const printing = createRenderer({ format, color: painted, streams });
|
|
17
36
|
const rendered = capture
|
|
@@ -37,7 +56,13 @@ export const resolveOutput = ({ json, jsonl, quiet, streams = processStreams, tt
|
|
|
37
56
|
stream: (items) => created.stream([...items].map((item) => projectFields(item, paths))),
|
|
38
57
|
}
|
|
39
58
|
: created;
|
|
40
|
-
return {
|
|
59
|
+
return {
|
|
60
|
+
format,
|
|
61
|
+
color: painted,
|
|
62
|
+
streams,
|
|
63
|
+
renderer: quiet ? silence(renderer) : renderer,
|
|
64
|
+
...(compact ? { compact: true, full: hitDetail === "full" } : {}),
|
|
65
|
+
};
|
|
41
66
|
};
|
|
42
67
|
/** Fields a person writes in paragraphs; every other string is a name, a title, an id or a path. */
|
|
43
68
|
const MULTI_LINE = new Set(["text", "description"]);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { MessageStore } from "../../../store/index.js";
|
|
2
|
+
import type { ProposalKind } from "../types.js";
|
|
3
|
+
/** An agent's change to a relationship's role or purpose; the owner's applies at once and never waits here. */
|
|
4
|
+
export declare const relationshipUpdateKind: (store: Pick<MessageStore, "knowledge" | "proposedActions">) => ProposalKind;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { proposerOfAction } from "../../../store/index.js";
|
|
2
|
+
import { actionStatus, kept, projectOf, pushed, storedStatus } from "./shared.js";
|
|
3
|
+
const KIND = "relationship_update";
|
|
4
|
+
const summaryOf = ({ changes }) => Object.entries(changes)
|
|
5
|
+
.map(([field, value]) => `${field} ${value ?? "cleared"}`)
|
|
6
|
+
.join(", ");
|
|
7
|
+
const rowOf = (action) => {
|
|
8
|
+
const payload = action.payload;
|
|
9
|
+
return {
|
|
10
|
+
id: action.id,
|
|
11
|
+
kind: KIND,
|
|
12
|
+
status: actionStatus(action.status),
|
|
13
|
+
project: projectOf(payload.to, payload.from),
|
|
14
|
+
subject: `relationship:${payload.relationship}`,
|
|
15
|
+
object: payload.to,
|
|
16
|
+
summary: summaryOf(payload),
|
|
17
|
+
proposedBy: proposerOfAction(action),
|
|
18
|
+
reason: action.reason,
|
|
19
|
+
evidence: [],
|
|
20
|
+
score: null,
|
|
21
|
+
signals: null,
|
|
22
|
+
parts: null,
|
|
23
|
+
createdAt: action.createdAt,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/** An agent's change to a relationship's role or purpose; the owner's applies at once and never waits here. */
|
|
27
|
+
export const relationshipUpdateKind = (store) => ({
|
|
28
|
+
kind: KIND,
|
|
29
|
+
stored: [KIND],
|
|
30
|
+
list: async (filter) => {
|
|
31
|
+
const status = storedStatus(filter);
|
|
32
|
+
const stored = await store.proposedActions.list({
|
|
33
|
+
kinds: [KIND],
|
|
34
|
+
...(status === undefined ? {} : { status }),
|
|
35
|
+
...pushed(filter),
|
|
36
|
+
});
|
|
37
|
+
return kept(stored.map(rowOf), filter);
|
|
38
|
+
},
|
|
39
|
+
get: async (id) => rowOf(await store.proposedActions.get(id)),
|
|
40
|
+
decide: async (id, { confirm, by, reason }) => {
|
|
41
|
+
const { relation } = await store.knowledge.decideRelationUpdate(id, {
|
|
42
|
+
confirm,
|
|
43
|
+
by,
|
|
44
|
+
...(reason === undefined ? {} : { reason }),
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
id,
|
|
48
|
+
kind: KIND,
|
|
49
|
+
status: confirm ? "confirmed" : "rejected",
|
|
50
|
+
made: relation ? [`relationship:${relation.id}`] : [],
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
});
|
|
@@ -6,6 +6,7 @@ import { findingsKind } from "./kinds/findings.js";
|
|
|
6
6
|
import { keyDocumentKind } from "./kinds/key-document.js";
|
|
7
7
|
import { memoryKind } from "./kinds/memory.js";
|
|
8
8
|
import { relationshipKind } from "./kinds/relationship.js";
|
|
9
|
+
import { relationshipUpdateKind } from "./kinds/relationship-update.js";
|
|
9
10
|
const PREFIX = /^([a-z][a-z_]*):/;
|
|
10
11
|
const refusalOf = (id, error) => {
|
|
11
12
|
if (!(error instanceof CliError))
|
|
@@ -118,6 +119,7 @@ export const proposalRegistry = (store) => {
|
|
|
118
119
|
const registry = emptyProposalRegistry(store);
|
|
119
120
|
for (const kind of [
|
|
120
121
|
relationshipKind(store),
|
|
122
|
+
relationshipUpdateKind(store),
|
|
121
123
|
keyDocumentKind(store),
|
|
122
124
|
factKind(store),
|
|
123
125
|
memoryKind(store),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Who proposed something waiting for the owner. `unknown` is a suggestion that names no author, such as an
|
|
3
|
-
* unconfirmed link written without provenance: only the owner decides it.
|
|
3
|
+
* unconfirmed link written without provenance: only the owner decides it. `verified: false` is a bot named only by
|
|
4
|
+
* free text anyone could write, as an old suggested link's provenance: only the owner decides that one too.
|
|
4
5
|
*/
|
|
5
6
|
export type Proposer = {
|
|
6
7
|
type: "person";
|
|
@@ -10,6 +11,7 @@ export type Proposer = {
|
|
|
10
11
|
id: string;
|
|
11
12
|
name: string;
|
|
12
13
|
kind: "agent" | "rule";
|
|
14
|
+
verified?: false;
|
|
13
15
|
} | {
|
|
14
16
|
type: "unknown";
|
|
15
17
|
};
|
package/dist/store/decisions.js
CHANGED
|
@@ -20,6 +20,8 @@ export const mayDecide = (row, by, policy = DEFAULT_DECISION_POLICY) => {
|
|
|
20
20
|
const proposer = row.proposedBy;
|
|
21
21
|
if (proposer.type === "unknown")
|
|
22
22
|
return refuse("permission_error", "proposal.owner-only", "this proposal names no author; only the owner decides it");
|
|
23
|
+
if (proposer.type === "bot" && proposer.verified === false)
|
|
24
|
+
return refuse("permission_error", "proposal.owner-only", `${proposer.name} is named only by an old link's provenance; only the owner decides it`);
|
|
23
25
|
if (proposer.type === "bot" && proposer.kind === "rule" && policy.ruleProposalsOwnerOnly)
|
|
24
26
|
return refuse("permission_error", "proposal.owner-only", `proposed by ${proposer.name}: only the owner decides it`);
|
|
25
27
|
if (proposer.type === "bot" && proposer.kind === "agent" && botKey(proposer.name) === botKey(by.bot))
|
|
@@ -39,7 +41,11 @@ export const assertMayWithdraw = (row, by) => {
|
|
|
39
41
|
if (by === "owner")
|
|
40
42
|
return;
|
|
41
43
|
const proposer = row.proposedBy;
|
|
42
|
-
if (row.proposed &&
|
|
44
|
+
if (row.proposed &&
|
|
45
|
+
proposer.type === "bot" &&
|
|
46
|
+
proposer.kind === "agent" &&
|
|
47
|
+
proposer.verified !== false &&
|
|
48
|
+
botKey(proposer.name) === botKey(by.bot))
|
|
43
49
|
return;
|
|
44
50
|
throw new CliError("permission_error", `only the owner removes or reverses ${row.id}`, {
|
|
45
51
|
reason: "proposal.owner-only",
|
package/dist/store/index.d.ts
CHANGED
|
@@ -1,5 +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 { RefState, RefSummary, RefSummaryKind, RefsStore } from "../domain/ref-summaries.js";
|
|
3
4
|
export type { TagConsolidationApplyOptions, TagConsolidationOptions, TagConsolidationPreview, TagConsolidationReceipt, TagConsolidationStore, } from "../domain/tag-consolidation.js";
|
|
4
5
|
export type { TagRedirectIndex, TagRedirectResolution, TagRedirectSnapshot } from "../domain/tag-redirects.js";
|
|
5
6
|
export { createTagRedirectIndex } from "../domain/tag-redirects.js";
|
|
@@ -51,7 +52,7 @@ export { type NearestNote, NOTE_FIELDS, type NoteChunkToEmbed, type NoteHit, typ
|
|
|
51
52
|
export type { FileNoteInput, Link, LinkInput, LinkListFilter, Note, NoteFolder, NotesStore, NoteTag, } from "./sqlite/notes.js";
|
|
52
53
|
export type { PrivateContact, PrivateContactNote } from "./sqlite/private-people.js";
|
|
53
54
|
export { PROPOSAL_STATUSES, type ProposalInput, type ProposedAction, type ProposedActionsStore, proposerOfAction, } from "./sqlite/proposed-actions.js";
|
|
54
|
-
export type { LinkDecision } from "./sqlite/relation-proposals.js";
|
|
55
|
+
export type { LinkDecision, RelationUpdate } from "./sqlite/relation-proposals.js";
|
|
55
56
|
export { fillSearchIndex, resetSearchIndex, type SearchIndexFill, type SearchIndexState, searchIndexState, } from "./sqlite/search-index.js";
|
|
56
57
|
export type { SyncStateSave } from "./sqlite/sync.js";
|
|
57
58
|
export type { TagCreationOptions, TagCreationReview } from "./sqlite/tag-creation.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CacheDatabase } from "../driver.js";
|
|
1
2
|
import type { AccountKey, StoredAccount } from "../types.js";
|
|
2
3
|
import type { StoreContext } from "./open.js";
|
|
3
4
|
/** An account's row, made on first sight; a name only replaces what was known when there is one. */
|
|
@@ -10,3 +11,10 @@ export declare const storedAccounts: ({ orm }: StoreContext) => StoredAccount[];
|
|
|
10
11
|
export declare const storedAccount: ({ orm }: StoreContext, { provider, account }: AccountKey) => StoredAccount;
|
|
11
12
|
/** Everything the account holds, children before parents: the foreign keys are enforced. */
|
|
12
13
|
export declare const purgeAccount: ({ orm, database }: StoreContext, accountKey: number) => void;
|
|
14
|
+
export declare const unreferenced: (database: CacheDatabase, table: "identities") => Set<number>;
|
|
15
|
+
/**
|
|
16
|
+
* People only the purged account had seen go with it. An identity stays while anything else points at it
|
|
17
|
+
* (another account, a tag, a note, a link), or while its person is kept: the owner, a person something
|
|
18
|
+
* points at, or one linked to an identity that stays.
|
|
19
|
+
*/
|
|
20
|
+
export declare const dropOrphanPeople: (database: CacheDatabase, unseenBefore: Set<number>) => void;
|
|
@@ -132,7 +132,7 @@ const referencesTo = (database, table, skip) => {
|
|
|
132
132
|
const pointers = pointerPairs(database).map(({ table: tbl, pointer }) => `SELECT ${pointer}_id AS id FROM "${tbl}" WHERE ${pointer}_type = '${type}'`);
|
|
133
133
|
return [...keys, ...pointers].join(" UNION ");
|
|
134
134
|
};
|
|
135
|
-
const unreferenced = (database, table) => new Set(database
|
|
135
|
+
export const unreferenced = (database, table) => new Set(database
|
|
136
136
|
.prepare(`SELECT id FROM ${table} WHERE id NOT IN (SELECT id FROM (${referencesTo(database, table, OWN)}) WHERE id IS NOT NULL)`)
|
|
137
137
|
.all()
|
|
138
138
|
.map(({ id }) => Number(id)));
|
|
@@ -141,7 +141,7 @@ const unreferenced = (database, table) => new Set(database
|
|
|
141
141
|
* (another account, a tag, a note, a link), or while its person is kept: the owner, a person something
|
|
142
142
|
* points at, or one linked to an identity that stays.
|
|
143
143
|
*/
|
|
144
|
-
const dropOrphanPeople = (database, unseenBefore) => {
|
|
144
|
+
export const dropOrphanPeople = (database, unseenBefore) => {
|
|
145
145
|
const orphans = [...unreferenced(database, "identities")].filter((id) => !unseenBefore.has(id));
|
|
146
146
|
if (orphans.length === 0)
|
|
147
147
|
return;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CacheDatabase } from "../driver.js";
|
|
2
|
+
/**
|
|
3
|
+
* `EventStore.forgetCalendar` inside its transaction: children before parents, since the foreign keys are enforced.
|
|
4
|
+
* `refresh` gives a kept event or series its fields again from the copies left.
|
|
5
|
+
*/
|
|
6
|
+
export declare const forgetCalendarRows: (database: CacheDatabase, { calendarId, accountId, cursorKey, now }: {
|
|
7
|
+
calendarId: number;
|
|
8
|
+
accountId: number;
|
|
9
|
+
cursorKey: string;
|
|
10
|
+
now: number;
|
|
11
|
+
}, refresh: {
|
|
12
|
+
event: (id: number, now: number) => void;
|
|
13
|
+
series: (id: number, now: number) => void;
|
|
14
|
+
}) => {
|
|
15
|
+
entries: number;
|
|
16
|
+
events: number;
|
|
17
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { dropOrphanPeople, unreferenced } from "./accounts.js";
|
|
2
|
+
import { dropUnusedVectors } from "./vector-index.js";
|
|
3
|
+
const distinctIds = (rows) => [...new Set(rows.map((row) => Number(row.id)))];
|
|
4
|
+
/**
|
|
5
|
+
* `EventStore.forgetCalendar` inside its transaction: children before parents, since the foreign keys are enforced.
|
|
6
|
+
* `refresh` gives a kept event or series its fields again from the copies left.
|
|
7
|
+
*/
|
|
8
|
+
export const forgetCalendarRows = (database, { calendarId, accountId, cursorKey, now }, refresh) => {
|
|
9
|
+
const unseenBefore = unreferenced(database, "identities");
|
|
10
|
+
const ids = (sql) => distinctIds(database.prepare(sql).all(calendarId));
|
|
11
|
+
const entryIds = ids("SELECT id FROM calendar_entries WHERE calendar_id = ?");
|
|
12
|
+
const eventIds = ids("SELECT event_id AS id FROM calendar_entries WHERE calendar_id = ? AND event_id IS NOT NULL");
|
|
13
|
+
const seriesIds = ids("SELECT event_series_id AS id FROM calendar_entries WHERE calendar_id = ? AND event_series_id IS NOT NULL");
|
|
14
|
+
const hashes = [];
|
|
15
|
+
const dropAround = (type, list) => {
|
|
16
|
+
const json = JSON.stringify(list);
|
|
17
|
+
const inList = "IN (SELECT value FROM json_each(?))";
|
|
18
|
+
for (const row of database
|
|
19
|
+
.prepare(`SELECT DISTINCT content_hash FROM chunks WHERE chunkable_type = ? AND chunkable_id ${inList}`)
|
|
20
|
+
.all(type, json))
|
|
21
|
+
hashes.push(String(row.content_hash));
|
|
22
|
+
database.prepare(`DELETE FROM chunks WHERE chunkable_type = ? AND chunkable_id ${inList}`).run(type, json);
|
|
23
|
+
database
|
|
24
|
+
.prepare(`DELETE FROM links WHERE (from_type = ? AND from_id ${inList}) OR (to_type = ? AND to_id ${inList})`)
|
|
25
|
+
.run(type, json, type, json);
|
|
26
|
+
for (const [table, pointer] of [
|
|
27
|
+
["taggings", "taggable"],
|
|
28
|
+
["aliases", "aliasable"],
|
|
29
|
+
["attachments", "attachable"],
|
|
30
|
+
["link_reviews", "linkable"],
|
|
31
|
+
["entity_link_events", "linkable"],
|
|
32
|
+
])
|
|
33
|
+
database.prepare(`DELETE FROM ${table} WHERE ${pointer}_type = ? AND ${pointer}_id ${inList}`).run(type, json);
|
|
34
|
+
};
|
|
35
|
+
const entries = JSON.stringify(entryIds);
|
|
36
|
+
for (const table of ["calendar_entry_participants", "calendar_entry_revisions"])
|
|
37
|
+
database.prepare(`DELETE FROM ${table} WHERE entry_id IN (SELECT value FROM json_each(?))`).run(entries);
|
|
38
|
+
dropAround("calendar_entry", entryIds);
|
|
39
|
+
// Occurrences point at their series in the same table: the pointers go first, so the order of rows is free.
|
|
40
|
+
database.prepare("UPDATE calendar_entries SET series_entry_id = NULL WHERE calendar_id = ?").run(calendarId);
|
|
41
|
+
database.prepare("DELETE FROM calendar_entries WHERE calendar_id = ?").run(calendarId);
|
|
42
|
+
const held = (column, id) => database.prepare(`SELECT 1 FROM calendar_entries WHERE ${column} = ? LIMIT 1`).get(id) !== undefined;
|
|
43
|
+
const goneSeries = seriesIds.filter((id) => !held("event_series_id", id));
|
|
44
|
+
const goneEvents = eventIds.filter((id) => !held("event_id", id));
|
|
45
|
+
const gone = (list) => JSON.stringify(list);
|
|
46
|
+
database
|
|
47
|
+
.prepare("UPDATE meetings SET event_id = NULL, updated_at = ? WHERE event_id IN (SELECT value FROM json_each(?))")
|
|
48
|
+
.run(now, gone(goneEvents));
|
|
49
|
+
dropAround("event", goneEvents);
|
|
50
|
+
database.prepare("DELETE FROM events WHERE id IN (SELECT value FROM json_each(?))").run(gone(goneEvents));
|
|
51
|
+
for (const table of ["meeting_series", "events"])
|
|
52
|
+
database
|
|
53
|
+
.prepare(`UPDATE ${table} SET event_series_id = NULL, updated_at = ? WHERE event_series_id IN (SELECT value FROM json_each(?))`)
|
|
54
|
+
.run(now, gone(goneSeries));
|
|
55
|
+
dropAround("event_series", goneSeries);
|
|
56
|
+
database.prepare("DELETE FROM event_series WHERE id IN (SELECT value FROM json_each(?))").run(gone(goneSeries));
|
|
57
|
+
for (const id of seriesIds)
|
|
58
|
+
if (!goneSeries.includes(id))
|
|
59
|
+
refresh.series(id, now);
|
|
60
|
+
for (const id of eventIds)
|
|
61
|
+
if (!goneEvents.includes(id))
|
|
62
|
+
refresh.event(id, now);
|
|
63
|
+
database.prepare("DELETE FROM sync_cursors WHERE account_id = ? AND key = ?").run(accountId, cursorKey);
|
|
64
|
+
database.prepare("DELETE FROM calendars WHERE id = ?").run(calendarId);
|
|
65
|
+
dropOrphanPeople(database, unseenBefore);
|
|
66
|
+
dropUnusedVectors(database, hashes);
|
|
67
|
+
return { entries: entryIds.length, events: goneEvents.length };
|
|
68
|
+
};
|