/** * Shared helpers for the chat-scoped backlog scripts (`backlog-add`, * `backlog-resync`, `backlog-pull`, `backlog-list`). Keeps the "local file is * authoritative, remote sync is a strictly additive side effect" contract — and * the file shape — in one place. */ /** Natural-key identification of the server-side `Plan` a backlog item targets. */ export interface PlanTarget { owner: string; repo: string; trackingName?: string; issueNumber?: number; } /** * One item in a per-chat backlog file. Fields beyond `id`/`text`/`status`/ * `createdAt` are optional and read as defaults when absent, so files written * by older CLI versions stay valid (`version` remains `'1.0'`). */ export interface BlockedRef { kind: 'plan' | 'pr' | 'item' | 'issue'; ref: string; resolvedAt?: string; } export interface BacklogItem { id: string; text: string; /** * Item state. The project-level server uses the state machine * (`parked|ready|planned|done|archived`); older files/servers used * `open|done`. {@link normStatus} bridges either to the legacy pair. */ status: string; createdAt: string; synced?: boolean; remoteId?: string | null; /** Where this item came from. Added by `backlog-add` (local) / `backlog-pull`. */ origin?: 'local' | 'dashboard' | 'other-session'; /** Last-known server status for a synced item (set by the pull). */ remoteStatus?: 'open' | 'done'; /** ISO timestamp of the last pull that touched this item. */ pulledAt?: string; /** ISO timestamp when this item was marked done (locally or via the server). */ doneAt?: string; /** Item kind (`plan|local|note|external`); defaults to `plan` server-side. */ type?: 'plan' | 'local' | 'note' | 'external'; /** Optional markdown detail written by the capturing agent. */ detail?: string | null; /** Typed blocker refs proposed at capture time. */ blockedBy?: BlockedRef[]; /** Auto-launch override: start the item's own plan when its last blocker resolves. */ autoLaunch?: boolean; } /** The on-disk shape of `.hublaunch/.backlogs/.json`. */ export interface BacklogFile { version: string; key: string; createdAt: string; sessionId: string | null; items: BacklogItem[]; } /** Resolve the per-chat backlog file path for a validated `key`. */ export declare function backlogFilePath(repoRoot: string, key: string): string; /** Outcome of {@link readBacklogFile}: loaded data, or a reason it couldn't be. */ export type ReadBacklogResult = { ok: true; data: BacklogFile; } | { ok: false; reason: 'missing' | 'corrupt'; }; /** * Read and parse a backlog file. Returns `{ ok: false, reason: 'missing' }` * when the file does not exist and `{ ok: false, reason: 'corrupt' }` when it * cannot be parsed — never throws, so callers can map each to the right * `skipped` reason without a try/catch. */ export declare function readBacklogFile(path: string): Promise; /** * Write a backlog file atomically: serialize to `.tmp` then rename over * the target, so a crash mid-write never leaves a half-written (corrupt) file. */ export declare function writeBacklogFileAtomic(path: string, data: BacklogFile): Promise; /** * Resolve a remote-sync target from `--project`/`--tracking-name`/`--issue`. * Returns `null` when `--project` is absent/malformed, or when neither * `--tracking-name` nor `--issue` was supplied — in which case remote sync is * skipped entirely (no attempt, no error). When both are present `trackingName` * wins server-side, but both are forwarded. */ export declare function resolvePlanTarget(project: string, trackingName: string, issue: string): PlanTarget | null; /** * Classify a pulled server item's `origin` relative to the local chat's * captured session id: `local` when the same session pushed it, * `other-session` when a different session did, `dashboard` when the server * recorded no session (created in the web UI). */ export declare function serverItemOrigin(clientSessionId: string | null | undefined, fileSessionId: string | null): 'local' | 'other-session' | 'dashboard'; /** * Attempt to push a single backlog item to the configured `hula-project` * server. Best-effort and non-blocking: returns the server-side item id on * success, or `null` on any failure (not configured for remote, network error, * a 404 because no matching `Plan` exists yet, or any other error). Never * throws — the caller keeps the local write authoritative regardless. * * @param repoRoot - resolved git repo root (to load `.hublaunch/hublaunch.config.js`) * @param target - natural-key identification of the target `Plan` * @param text - the backlog item's free text * @param clientSessionId - the backlog file's captured session id (or null) * @returns the server-side item id, or `null` when the push did not succeed */ export declare function pushBacklogItemBestEffort(repoRoot: string, target: PlanTarget, text: string, clientSessionId: string | null, fields?: { type?: string; detail?: string | null; blockedBy?: BlockedRef[]; autoLaunch?: boolean; }): Promise; /** * Push every not-yet-synced item in `data` to the server (best-effort, one * item at a time, one failure never aborts the rest). Mutates each * successfully-pushed item in place (`synced: true`, `remoteId`, and backfills * `origin: 'local'` when unset) and returns the number pushed. Does NOT write * the file — the caller owns persistence so `backlog-pull` can push, then * merge, then write once. * * This is the shared "resync" step used by both `backlog-resync` (which then * writes if anything changed) and `backlog-pull` (which writes after merging). */ export declare function resyncBacklogFile(repoRoot: string, data: BacklogFile, target: PlanTarget): Promise; /** Structured result of {@link pullBacklog} (also the JSON `backlog-pull` emits). */ export interface PullBacklogResult { pushed: number; pulled: number; statusPushed: number; open: number; done: number; skipped?: string; } /** * Two-way sync of a per-chat backlog file against the server, keyed by the plan * `target`. Pushes unsynced local items, pulls server items merged by * `remoteId`, applies the conflict rule (server `done` wins over local `open`; * local `done` is PATCHed back to a server `open`), appends unseen server items, * and writes the file atomically. * * Best-effort like the other backlog steps: never throws. A missing/corrupt * file, an unconfigured remote, a 404 (plan not tracked / endpoint absent) and * any other server error are all reported via `skipped` with `status: success` * left to the caller. On any post-validation server error the local file is * still persisted when the push phase changed it. * * `open`/`done` counts reflect the merged file (0 when the file is * missing/corrupt). */ export declare function pullBacklog(repoRoot: string, key: string, target: PlanTarget): Promise; //# sourceMappingURL=backlog-sync.d.ts.map