@mulmoclaude/core 1.12.0 → 1.14.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/assets/helps/error-recovery.md +110 -1
- package/dist/{calendarGrid-CaS9er8i.cjs → calendarGrid-BQYqOCnF.cjs} +8 -9
- package/dist/{calendarGrid-CaS9er8i.cjs.map → calendarGrid-BQYqOCnF.cjs.map} +1 -1
- package/dist/{calendarGrid-CrGxeCOG.js → calendarGrid-DivcNKkX.js} +8 -9
- package/dist/{calendarGrid-CrGxeCOG.js.map → calendarGrid-DivcNKkX.js.map} +1 -1
- package/dist/collection/core/project.d.ts +11 -0
- package/dist/collection/core/schemaZ.d.ts +4 -4
- package/dist/collection/index.cjs +5 -4
- package/dist/collection/index.js +5 -5
- package/dist/collection/registry/server/index.cjs +3 -3
- package/dist/collection/registry/server/index.cjs.map +1 -1
- package/dist/collection/registry/server/index.js +3 -3
- package/dist/collection/registry/server/index.js.map +1 -1
- package/dist/collection/server/csvQuery.d.ts +7 -2
- package/dist/collection/server/csvStore.d.ts +2 -1
- package/dist/collection/server/index.cjs +3 -3
- package/dist/collection/server/index.js +3 -3
- package/dist/collection-watchers/index.cjs +10 -25
- package/dist/collection-watchers/index.cjs.map +1 -1
- package/dist/collection-watchers/index.js +10 -25
- package/dist/collection-watchers/index.js.map +1 -1
- package/dist/{discovery-NRy3tyUA.cjs → discovery-CRDx6TS4.cjs} +88 -47
- package/dist/discovery-CRDx6TS4.cjs.map +1 -0
- package/dist/{discovery-B4CZvrXR.js → discovery-D6p4ITNR.js} +88 -47
- package/dist/discovery-D6p4ITNR.js.map +1 -0
- package/dist/{dist-pWpC-b04.cjs → dist-CsgSfWwR.cjs} +66 -1
- package/dist/{dist-pWpC-b04.cjs.map → dist-CsgSfWwR.cjs.map} +1 -1
- package/dist/{dist-Cwk0e12G.js → dist-D8zokgGo.js} +25 -2
- package/dist/{dist-Cwk0e12G.js.map → dist-D8zokgGo.js.map} +1 -1
- package/dist/feeds/index.cjs +2 -2
- package/dist/feeds/index.js +2 -2
- package/dist/feeds/server/engine.d.ts +27 -0
- package/dist/feeds/server/index.cjs +97 -26
- package/dist/feeds/server/index.cjs.map +1 -1
- package/dist/feeds/server/index.d.ts +1 -1
- package/dist/feeds/server/index.js +96 -27
- package/dist/feeds/server/index.js.map +1 -1
- package/dist/google/calendar.d.ts +23 -9
- package/dist/google/calendarStateLock.d.ts +23 -0
- package/dist/google/collectionProjection.d.ts +0 -8
- package/dist/google/collectionPush.d.ts +13 -8
- package/dist/google/collectionSync.d.ts +80 -10
- package/dist/google/index.cjs +366 -98
- package/dist/google/index.cjs.map +1 -1
- package/dist/google/index.d.ts +6 -4
- package/dist/google/index.js +357 -99
- package/dist/google/index.js.map +1 -1
- package/dist/{ingestTypes-D1GQdG8e.cjs → ingestTypes-C7IJSqv4.cjs} +2 -2
- package/dist/{ingestTypes-D1GQdG8e.cjs.map → ingestTypes-C7IJSqv4.cjs.map} +1 -1
- package/dist/{ingestTypes-XReG-li7.js → ingestTypes-DmtDLRmt.js} +2 -2
- package/dist/{ingestTypes-XReG-li7.js.map → ingestTypes-DmtDLRmt.js.map} +1 -1
- package/dist/notifier/index.cjs +1 -1
- package/dist/notifier/index.js +1 -1
- package/dist/notifier/store.d.ts +4 -4
- package/dist/{notifier-BdA5qzhe.js → notifier-Dxh8mEFh.js} +39 -25
- package/dist/notifier-Dxh8mEFh.js.map +1 -0
- package/dist/{notifier-tMsAXyXp.cjs → notifier-Wc4M24Bi.cjs} +39 -25
- package/dist/notifier-Wc4M24Bi.cjs.map +1 -0
- package/dist/plugin-vue/index.cjs +4 -2
- package/dist/plugin-vue/index.cjs.map +1 -1
- package/dist/plugin-vue/index.js +4 -2
- package/dist/plugin-vue/index.js.map +1 -1
- package/dist/project-B0j_Vf_Q.js +33 -0
- package/dist/project-B0j_Vf_Q.js.map +1 -0
- package/dist/project-C1ep9pvo.cjs +44 -0
- package/dist/project-C1ep9pvo.cjs.map +1 -0
- package/dist/{promptSafety-FD8cQn3e.cjs → promptSafety-B52GvaJc.cjs} +99 -85
- package/dist/promptSafety-B52GvaJc.cjs.map +1 -0
- package/dist/{promptSafety-C--op_6a.js → promptSafety-DJgaDjM4.js} +99 -85
- package/dist/promptSafety-DJgaDjM4.js.map +1 -0
- package/dist/remote-host/index.cjs +2 -1
- package/dist/remote-host/index.d.ts +10 -0
- package/dist/remote-host/index.js +2 -2
- package/dist/remote-host/server/index.cjs +2 -2
- package/dist/remote-host/server/index.cjs.map +1 -1
- package/dist/remote-host/server/index.js +2 -2
- package/dist/remote-host/server/index.js.map +1 -1
- package/dist/{remote-host-DkDVxNim.cjs → remote-host-CtQjagPt.cjs} +53 -1
- package/dist/remote-host-CtQjagPt.cjs.map +1 -0
- package/dist/remote-host-Dba4lF3Z.js +82 -0
- package/dist/remote-host-Dba4lF3Z.js.map +1 -0
- package/dist/remote-view/index.cjs +6 -4
- package/dist/remote-view/index.cjs.map +1 -1
- package/dist/remote-view/index.js +6 -4
- package/dist/remote-view/index.js.map +1 -1
- package/dist/scheduler/index.cjs +1 -1
- package/dist/scheduler/index.js +1 -1
- package/dist/{server-DdyIvFhz.js → server-D6EUf3BF.js} +46 -27
- package/dist/server-D6EUf3BF.js.map +1 -0
- package/dist/{server-7U-3DE2e.cjs → server-D7_oRbTJ.cjs} +46 -27
- package/dist/server-D7_oRbTJ.cjs.map +1 -0
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/whisper/index.cjs +2 -6
- package/dist/whisper/index.cjs.map +1 -1
- package/dist/whisper/index.js +2 -6
- package/dist/whisper/index.js.map +1 -1
- package/dist/wiki/index.cjs +2 -2
- package/dist/wiki/index.cjs.map +1 -1
- package/dist/wiki/index.js +2 -2
- package/dist/wiki/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/discovery-B4CZvrXR.js.map +0 -1
- package/dist/discovery-NRy3tyUA.cjs.map +0 -1
- package/dist/notifier-BdA5qzhe.js.map +0 -1
- package/dist/notifier-tMsAXyXp.cjs.map +0 -1
- package/dist/project-BWI5w_BT.cjs +0 -17
- package/dist/project-BWI5w_BT.cjs.map +0 -1
- package/dist/project-bU98ycsy.js +0 -12
- package/dist/project-bU98ycsy.js.map +0 -1
- package/dist/promptSafety-C--op_6a.js.map +0 -1
- package/dist/promptSafety-FD8cQn3e.cjs.map +0 -1
- package/dist/remote-host-D_BRFHcI.js +0 -36
- package/dist/remote-host-D_BRFHcI.js.map +0 -1
- package/dist/remote-host-DkDVxNim.cjs.map +0 -1
- package/dist/server-7U-3DE2e.cjs.map +0 -1
- package/dist/server-DdyIvFhz.js.map +0 -1
|
@@ -194,18 +194,32 @@ export interface CalendarListPage {
|
|
|
194
194
|
/** Pagination loop for CalendarList.list, extracted so it can be tested without
|
|
195
195
|
* network. Stops at the last page (no token) or the runaway page cap. */
|
|
196
196
|
export declare function collectCalendarPages(fetchPage: (pageToken?: string) => Promise<CalendarListPage>, maxPages?: number): Promise<CalendarSummary[]>;
|
|
197
|
+
/** What a calendar absent from the user's list can still tell about itself. */
|
|
198
|
+
export interface CalendarMeta {
|
|
199
|
+
/** IANA zone (`Asia/Tokyo`), `""` when Google omits it. */
|
|
200
|
+
timeZone: string;
|
|
201
|
+
/** `owner` / `writer` / `reader` / `freeBusyReader`, `""` when unreported. */
|
|
202
|
+
accessRole: string;
|
|
203
|
+
}
|
|
204
|
+
export declare const toCalendarMeta: (value: unknown) => CalendarMeta;
|
|
205
|
+
/** One calendar's zone and the caller's role on it, read by id rather than
|
|
206
|
+
* looked up in the user's list.
|
|
207
|
+
*
|
|
208
|
+
* `calendarList` only holds calendars the user has ADDED; a calendar shared
|
|
209
|
+
* with them can be readable and writable by id without appearing there, and a
|
|
210
|
+
* push still needs its zone to send an offset-less `dateTime`.
|
|
211
|
+
*
|
|
212
|
+
* Deliberately `events.list` and NOT `calendars.get`: the latter takes only
|
|
213
|
+
* full-calendar scopes (`calendar`, `calendar.readonly`, `calendar.calendars*`)
|
|
214
|
+
* and this app asks for none of them, so it answers 403 for every account it
|
|
215
|
+
* links (#2735). The events list carries the same `timeZone` — plus the
|
|
216
|
+
* `accessRole` the calendar resource does not have — under `calendar.events`,
|
|
217
|
+
* which the push already holds because it writes with it. Only the envelope is
|
|
218
|
+
* read; the one event asked for is the smallest page Google will serve. */
|
|
219
|
+
export declare function getCalendarMeta(accessToken: string, calendarId: string | undefined): Promise<CalendarMeta>;
|
|
197
220
|
/** The calendars the user has added/subscribed to (primary + secondary +
|
|
198
221
|
* shared), each with its id, name and colour, following pagination. Needs the
|
|
199
222
|
* calendar-list read scope (GOOGLE_CALENDARLIST_SCOPE). */
|
|
200
|
-
/** One calendar's own resource, addressed by id rather than looked up in the
|
|
201
|
-
* user's list.
|
|
202
|
-
*
|
|
203
|
-
* `calendarList` only holds calendars the user has ADDED; a calendar shared
|
|
204
|
-
* with them can be readable and writable by id without appearing there. This is
|
|
205
|
-
* how a push learns such a calendar's `timeZone`. Note the resource carries no
|
|
206
|
-
* `accessRole` — that is a calendarList property — so reachability here says
|
|
207
|
-
* nothing about writability. */
|
|
208
|
-
export declare function getCalendar(accessToken: string, calendarId: string | undefined): Promise<CalendarSummary>;
|
|
209
223
|
export declare function listCalendars(accessToken: string): Promise<CalendarSummary[]>;
|
|
210
224
|
/** Resolve a `colorId` (on an event or calendar) to its hex background/foreground. */
|
|
211
225
|
export declare function getCalendarColors(accessToken: string): Promise<CalendarColors>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** The clock and the sleep, injected so the timing rules can be exercised
|
|
2
|
+
* without real waits. */
|
|
3
|
+
export interface LockClock {
|
|
4
|
+
now: () => number;
|
|
5
|
+
sleep: (delay_ms: number) => Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare const liveLockClock: LockClock;
|
|
8
|
+
/** Run `mutate` with no other process mutating the same file.
|
|
9
|
+
*
|
|
10
|
+
* Fails OPEN. A workspace that cannot create the lock file — a read-only
|
|
11
|
+
* mount, a missing directory, an exhausted disk — still syncs, the way it did
|
|
12
|
+
* before #2679; the lock removes a race, it is not a precondition for
|
|
13
|
+
* correctness. The same applies to waiting the timeout out: proceeding
|
|
14
|
+
* unlocked risks the lost update this exists to prevent, whereas refusing
|
|
15
|
+
* would stop the sync outright.
|
|
16
|
+
*
|
|
17
|
+
* Note what this cannot promise. `O_EXCL` is atomic on a local filesystem and
|
|
18
|
+
* on NFSv3+, but a workspace living in a consumer sync folder (Dropbox,
|
|
19
|
+
* iCloud, Drive) has no such guarantee — there the file is replicated after
|
|
20
|
+
* the fact and both hosts believe they hold it. */
|
|
21
|
+
export declare function withCalendarStateLock<T>(lockPath: string, mutate: () => Promise<T>, clock?: LockClock): Promise<T>;
|
|
22
|
+
/** `<state file>.lock`, so each state file is serialised on its own. */
|
|
23
|
+
export declare const stateLockPath: (statePath: string) => string;
|
|
@@ -8,11 +8,3 @@ export type GoogleCalendarSourceField = (typeof GOOGLE_CALENDAR_SOURCE_FIELDS)[n
|
|
|
8
8
|
* primary field always takes the event id — upsert-by-id is what keeps the
|
|
9
9
|
* sync idempotent, so it is deliberately not remappable. */
|
|
10
10
|
export declare function toCollectionRecord(event: CalendarEventSummary, map: Record<string, GoogleCalendarSourceField>, primaryKey: string, fields: Record<string, CollectionFieldSpec>): CollectionItem;
|
|
11
|
-
/** Google's mapped values laid over whatever the record already holds.
|
|
12
|
-
*
|
|
13
|
-
* A record file is written whole (`writeItem`), so projecting alone would drop
|
|
14
|
-
* every column the map does not name — a collection cannot then carry a local
|
|
15
|
-
* note next to a mirrored event, because the next pull that touches that event
|
|
16
|
-
* silently deletes it. The projection still wins on the fields it covers: those
|
|
17
|
-
* are Google's to own. */
|
|
18
|
-
export declare function mergeIntoExisting(existing: CollectionItem | null, projected: CollectionItem): CollectionItem;
|
|
@@ -5,21 +5,26 @@ import { ShadowEvent } from './calendarPushState.js';
|
|
|
5
5
|
import { PushableSourceField } from './pushPlan.js';
|
|
6
6
|
/** What the up-front writability gate knows about the target calendar. */
|
|
7
7
|
export interface CalendarWriteTarget {
|
|
8
|
-
/** The role
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* from it (Codex review). */
|
|
8
|
+
/** The caller's role on the calendar, or null when neither source reported one.
|
|
9
|
+
* Null means unknown, never read-only: hard-denying an unknown role would
|
|
10
|
+
* refuse a calendar the user can in fact write to. */
|
|
12
11
|
accessRole: string | null;
|
|
13
12
|
/** IANA zone for rebuilding a zone-less stored clock, `""` when unreported. */
|
|
14
13
|
timeZone: string;
|
|
15
14
|
}
|
|
16
15
|
/** Whether to refuse the whole push before touching a single event.
|
|
17
16
|
*
|
|
18
|
-
* Only on POSITIVE evidence of a non-writable role.
|
|
19
|
-
* unknown and must fall through: hard-denying it
|
|
20
|
-
* outright for a calendar the user can in fact write
|
|
21
|
-
* Google's own 403 per record if the write really is
|
|
17
|
+
* Only on POSITIVE evidence of a non-writable role. A calendar whose role
|
|
18
|
+
* neither source reported is unknown and must fall through: hard-denying it
|
|
19
|
+
* would block the feature outright for a calendar the user can in fact write
|
|
20
|
+
* to. Those attempts surface Google's own 403 per record if the write really is
|
|
21
|
+
* not allowed. */
|
|
22
22
|
export declare const isDeniedAccessRole: (accessRole: string | null) => boolean;
|
|
23
|
+
/** A role Google left blank is UNKNOWN, not a denial. `isDeniedAccessRole`
|
|
24
|
+
* refuses every role it does not recognise — `""` included — so passing an
|
|
25
|
+
* unreported one straight through would refuse a calendar Google simply said
|
|
26
|
+
* nothing about. */
|
|
27
|
+
export declare const reportedAccessRole: (accessRole: string) => string | null;
|
|
23
28
|
export interface CalendarCollectionPushResult {
|
|
24
29
|
slug: string;
|
|
25
30
|
created: number;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { SystemTaskDef } from '../scheduler/adapter.js';
|
|
2
|
+
import { CollectionItem } from '../collection/core/schema.js';
|
|
2
3
|
import { LoadedCollection } from '../collection/server/discoveredCollection.js';
|
|
3
4
|
import { DeleteItemResult, WriteItemResult } from '../collection/server/io.js';
|
|
4
5
|
import { CalendarEventSummary } from './calendar.js';
|
|
6
|
+
import { CalendarPushOutcome } from './collectionPush.js';
|
|
5
7
|
import { ShadowEvent } from './calendarPushState.js';
|
|
6
8
|
export declare const GOOGLE_CALENDAR_SYNC_TASK_ID = "system:google-calendar-sync";
|
|
7
9
|
export interface CalendarCollectionSyncResult {
|
|
@@ -11,17 +13,24 @@ export interface CalendarCollectionSyncResult {
|
|
|
11
13
|
/** Events that can NEVER be stored — e.g. an id the record-file sanitiser
|
|
12
14
|
* rejects. Reported and skipped rather than retried; see `classifyWrite`. */
|
|
13
15
|
unwritable: string[];
|
|
16
|
+
/** Events left alone because the record they would overwrite holds an edit
|
|
17
|
+
* Google has not seen. NOT an error — the token still advances past them; only
|
|
18
|
+
* the baseline is held back, so the next push reports the conflict (#2684). */
|
|
19
|
+
withheld: string[];
|
|
14
20
|
/** Retryable failures. Any of these hold the sync token back. */
|
|
15
21
|
errors: string[];
|
|
16
22
|
}
|
|
17
23
|
/** `skipped` is a benign no-op; `unwritable` can never succeed so it must NOT
|
|
18
|
-
* hold the token; `error` is retryable and does hold it
|
|
24
|
+
* hold the token; `error` is retryable and does hold it; `withheld` is a
|
|
25
|
+
* deliberate refusal to overwrite a local edit. */
|
|
19
26
|
type ApplyOutcome = {
|
|
20
27
|
kind: "written";
|
|
21
28
|
} | {
|
|
22
29
|
kind: "removed";
|
|
23
30
|
} | {
|
|
24
31
|
kind: "skipped";
|
|
32
|
+
} | {
|
|
33
|
+
kind: "withheld";
|
|
25
34
|
} | {
|
|
26
35
|
kind: "unwritable";
|
|
27
36
|
message: string;
|
|
@@ -31,6 +40,24 @@ type ApplyOutcome = {
|
|
|
31
40
|
};
|
|
32
41
|
export declare function classifyWrite(eventId: string, kind: WriteItemResult["kind"]): ApplyOutcome;
|
|
33
42
|
export declare function classifyDelete(eventId: string, kind: DeleteItemResult["kind"]): ApplyOutcome;
|
|
43
|
+
/** Whether this record still says what the workspace last saw Google say.
|
|
44
|
+
*
|
|
45
|
+
* Compared against the baseline as it stood when this run STARTED READING, not
|
|
46
|
+
* as it stands now: a full re-walk clears the baseline before writing a new one
|
|
47
|
+
* (`restartFullSync`), so reading it live would answer "no baseline" for every
|
|
48
|
+
* event and protect nothing exactly when the window is widest (#2684).
|
|
49
|
+
*
|
|
50
|
+
* A record with no baseline at all is NOT withheld — that is an event this
|
|
51
|
+
* workspace has never held, so there is no local edit to lose. */
|
|
52
|
+
export declare function unsentEditGuard(schema: LoadedCollection["schema"], baseline: Record<string, ShadowEvent>): (existing: CollectionItem, eventId: string) => boolean;
|
|
53
|
+
/** What the pull may do to the record behind one event.
|
|
54
|
+
*
|
|
55
|
+
* The guard runs BEFORE the status is consulted, and that order is the whole
|
|
56
|
+
* fix: "is there something local to lose here?" outranks "what did Google do
|
|
57
|
+
* to it?". Asking about the status first is how a cancellation kept deleting
|
|
58
|
+
* records that held an edit Google had never seen (#2688), long after the
|
|
59
|
+
* same guard had been put in front of the overwrite (#2684). */
|
|
60
|
+
export declare function applyPlanFor(existing: CollectionItem | null, event: CalendarEventSummary, hasUnsentEdit: (existing: CollectionItem, eventId: string) => boolean): "withhold" | "delete" | "write";
|
|
34
61
|
/** The events of a window a pull may act on.
|
|
35
62
|
*
|
|
36
63
|
* A record the push just refused to send is edited on BOTH sides. Writing
|
|
@@ -50,15 +77,15 @@ export type UnpushedBySlug = ReadonlyMap<string, ReadonlySet<string> | null>;
|
|
|
50
77
|
* protection — would overwrite the very edits this exists to protect; the read
|
|
51
78
|
* that failed is no evidence that the pull's own writes would fail too, so they
|
|
52
79
|
* would land (CodeRabbit review #2666). */
|
|
53
|
-
export declare const PROTECTION_UNKNOWN = "could not work out which records to protect
|
|
54
|
-
/** What ONE collection's pull must leave alone: only what ITS OWN push
|
|
80
|
+
export declare const PROTECTION_UNKNOWN = "could not work out which records to protect from the pull";
|
|
81
|
+
/** What ONE collection's pull must leave alone: only what ITS OWN push did not
|
|
55
82
|
* send.
|
|
56
83
|
*
|
|
57
|
-
* Scoped per collection because a calendar can back several of them, and
|
|
58
|
-
*
|
|
59
|
-
* group starved a collection that never even declares `autoPush`:
|
|
60
|
-
*
|
|
61
|
-
*
|
|
84
|
+
* Scoped per collection because a calendar can back several of them, and one
|
|
85
|
+
* collection's unsent edit says nothing about the others. Sharing one set across
|
|
86
|
+
* the group starved a collection that never even declares `autoPush`: a
|
|
87
|
+
* neighbour's conflict froze its records — and the sync token still advanced, so
|
|
88
|
+
* Google never resent them (Codex review #2666). */
|
|
62
89
|
export declare const unpushedFor: (unpushed: UnpushedBySlug, slug: string) => ReadonlySet<string> | null;
|
|
63
90
|
/** What the calendar's BASELINE must leave alone: the union over every
|
|
64
91
|
* collection.
|
|
@@ -74,6 +101,32 @@ export declare const unpushedFor: (unpushed: UnpushedBySlug, slug: string) => Re
|
|
|
74
101
|
* A `null` (unknown) entry contributes nothing, because that collection reports
|
|
75
102
|
* a retryable error instead — which stops the baseline being saved at all. */
|
|
76
103
|
export declare const allUnpushed: (unpushed: UnpushedBySlug) => ReadonlySet<string>;
|
|
104
|
+
/** The I/O the protection rule crosses, injected so every branch of it can be
|
|
105
|
+
* exercised with fakes instead of a workspace on disk and a live Google grant.
|
|
106
|
+
* The rule is what #2666 and #2683 both got wrong, so it is worth pinning. */
|
|
107
|
+
export interface PullProtectionDeps {
|
|
108
|
+
pushNow: (collection: LoadedCollection, workspaceRoot: string) => Promise<CalendarPushOutcome>;
|
|
109
|
+
unsentEdits: (collection: LoadedCollection, workspaceRoot: string) => Promise<string[]>;
|
|
110
|
+
}
|
|
111
|
+
/** What ONE collection's pull must leave alone, pushing it first if it asked to
|
|
112
|
+
* be pushed.
|
|
113
|
+
*
|
|
114
|
+
* A collection WITHOUT `autoPush` never pushes, so its local edits are unsent by
|
|
115
|
+
* definition — the same state a failed push leaves behind, and it needs the same
|
|
116
|
+
* protection. Pulling over them destroys the edit AND advances the baseline past
|
|
117
|
+
* it, after which no conflict can be detected any more (#2683). "The push did not
|
|
118
|
+
* run" is the condition that matters here; why it did not run is not.
|
|
119
|
+
*
|
|
120
|
+
* MUST run inside the calendar lock the caller already holds — hence
|
|
121
|
+
* `pushCollectionNow` rather than `pushCalendarForCollection`, which would take
|
|
122
|
+
* the same non-reentrant lock and wait on itself forever.
|
|
123
|
+
*
|
|
124
|
+
* A failed push must not stop the pull: the pull is what keeps the collection
|
|
125
|
+
* fresh, and a revoked write grant is no reason to freeze reading. */
|
|
126
|
+
export declare function pullProtectionFor(collection: LoadedCollection, workspaceRoot: string, deps?: PullProtectionDeps): Promise<ReadonlySet<string> | null>;
|
|
127
|
+
/** Push the `autoPush` collections in this group, and answer with what every
|
|
128
|
+
* collection's pull must leave alone, keyed by collection. */
|
|
129
|
+
export declare function pushAndProtect(collections: readonly LoadedCollection[], workspaceRoot: string, deps?: PullProtectionDeps): Promise<UnpushedBySlug>;
|
|
77
130
|
/** Whether a run may take the calendar, given what the shared marker says.
|
|
78
131
|
*
|
|
79
132
|
* The scheduled door defers to it; every user-facing door claims regardless,
|
|
@@ -97,6 +150,14 @@ export type ClaimGuard = (lastSyncedAt: string | null) => boolean;
|
|
|
97
150
|
* what is genuinely new. That queue is module state, so it orders the doors
|
|
98
151
|
* into THIS process only; `claimThenSync` is what other hosts can see. */
|
|
99
152
|
export declare function syncCalendarGroup(calendarId: string | undefined, collections: readonly LoadedCollection[], workspaceRoot: string, mayClaim?: ClaimGuard): Promise<CalendarCollectionSyncResult[]>;
|
|
153
|
+
/** Every event whose baseline must NOT advance: what the push could not send,
|
|
154
|
+
* plus what the apply refused to overwrite.
|
|
155
|
+
*
|
|
156
|
+
* The two must agree exactly. The apply's refusals only became visible after it
|
|
157
|
+
* ran, so they join the union here rather than at push time — leaving them out
|
|
158
|
+
* would advance the baseline past a record the pull deliberately left holding a
|
|
159
|
+
* local edit, which is the silent overwrite this whole path exists to stop. */
|
|
160
|
+
export declare const heldBack: (unpushed: UnpushedBySlug, results: readonly CalendarCollectionSyncResult[]) => ReadonlySet<string>;
|
|
100
161
|
/** The baseline this window establishes: what Google now says per event, and
|
|
101
162
|
* `null` for a cancelled one so a recreate cannot resume from a dead baseline.
|
|
102
163
|
*
|
|
@@ -105,8 +166,17 @@ export declare function syncCalendarGroup(calendarId: string | undefined, collec
|
|
|
105
166
|
* keeps the local one would make the next push read a plain one-sided edit —
|
|
106
167
|
* no conflict to detect any more — and quietly overwrite Google. Held back, the
|
|
107
168
|
* baseline stays older than both sides, so the conflict keeps being reported
|
|
108
|
-
* until someone resolves it (#2620).
|
|
109
|
-
|
|
169
|
+
* until someone resolves it (#2620).
|
|
170
|
+
*
|
|
171
|
+
* `held` carries what those events must KEEP. Omitting them is enough on an
|
|
172
|
+
* incremental run, where the file is merged rather than replaced — but a full
|
|
173
|
+
* re-walk CLEARS the baseline first (`restartFullSync`), and there omission
|
|
174
|
+
* drops the entry for good. The next push would then read a conflicted record
|
|
175
|
+
* as a brand-new create, hit Google's duplicate-id 409 and refuse it, instead
|
|
176
|
+
* of reporting the conflict it actually is. Re-stating the pre-run value makes
|
|
177
|
+
* a held-back event behave the same either way (observed during Claude review;
|
|
178
|
+
* no bot flagged it). */
|
|
179
|
+
export declare function shadowUpdates(events: readonly CalendarEventSummary[], unpushed?: ReadonlySet<string>, held?: Record<string, ShadowEvent>): Record<string, ShadowEvent | null>;
|
|
110
180
|
/** Liveness of the collections a sync just wrote to, checked against the skill
|
|
111
181
|
* dir `deleteCollection` removes. `exists` is injected so the rule is testable
|
|
112
182
|
* without a filesystem. An empty group has no survivor by definition. */
|