/** * `gsk skills sync` — client-side materializer for the backend `skills_sync` * action. * * Why client-side: `skills_sync` returns a digest-diffed bundle (base64 file * bytes for changed skills, a removal list, per-slug errors); this module * applies one such response to disk. Deliberately NOT parity with * `setup.sh` (which unconditionally `rm -rf`s then `ln -sfn`s over the mount * path — the synced skill always wins): here a pre-existing REAL directory * under `mountDir` (an inline-tar builtin, or user content) is never * clobbered by a same-named synced skill; the real dir wins and the slug is * reported failed instead. Chosen because this materializer runs on a * user's laptop, not a disposable sandbox — never `rm -rf`ing directories we * didn't create is worth a failed sync entry. Index.ts (Task 6) drives the * poll-until-`complete` loop and owns `--check`; this module only ever * applies (never diffs) a response. */ /** One file row from a `skills_sync` `update` entry. */ export interface SyncSkillFile { path: string; content_base64: string; } /** One per-slug entry in a `skills_sync` response. */ export interface SyncSkillEntry { slug: string; sha?: string; action: 'update' | 'unchanged' | 'removed' | 'error'; files?: SyncSkillFile[]; total_bytes?: number; code?: string; } /** Shape of the `data` field returned by the backend `skills_sync` action. */ export interface SyncResponseData { synced?: boolean; complete: boolean; skills: SyncSkillEntry[]; } export interface SyncOptions { storeDir?: string; mountDir?: string; } export interface ApplySyncResult { state: Record; applied: string[]; removed: string[]; failed: string[]; } /** * Folds the per-batch results of the multi-batch sync loop into single deduped * totals. A slug can recur across batches — a server `error` row carries no * recordable sha, so the server re-emits it in EVERY batch — and concatenating * per-batch arrays would multi-count it, making the summary counts and the * exit-4 gate wrong. Each category is a Set (dedup by slug); a slug's outcome * in a later batch supersedes an earlier one. It also aggregates the echoed * skill rows so `-o json` reflects every batch, not just the final one. * * Generic over the echoed-row type so the CLI can pass its own row shape * without a cast (only `slug` is required here). */ export declare class SyncAggregator { private readonly _applied; private readonly _removed; private readonly _failed; private readonly _rows; /** Fold one batch's apply result and its echoed skill rows into the totals. */ add(result: ApplySyncResult, rows: readonly Row[]): void; private categorize; get appliedCount(): number; get removedCount(): number; get failedCount(): number; /** Aggregated echoed rows (deduped by slug, last-wins). */ get skills(): Row[]; } export declare const STATE_FILENAME = "skills-sync-state.json"; export declare function defaultStoreDir(): string; export declare function defaultMountDir(): string; /** Load the persisted `{slug: sha}` digest map. Both unparseable JSON AND a * valid-JSON-but-wrong-shape file self-heal to `{}` — a dirty state file * forces a full re-diff on the next sync rather than risk skipping a change * against a state we can't trust. The shape check matters because the server * verb rejects the WHOLE sync (`bad state digest map`) on a single bad key, * so without validating here a corrupt map would wedge every sync forever; * resetting to `{}` lets it recover on the next run. */ export declare function loadState(storeDir: string): Record; /** * Apply one `skills_sync` response to disk. Never called in `--check` mode * (Task 6's caller diffs against `loadState` output itself for that path). */ export declare function applySyncResponse(data: SyncResponseData, opts?: SyncOptions): ApplySyncResult; //# sourceMappingURL=skills-sync.d.ts.map