/** * TS implementation of the heartbeat-mutating actions. Replaces the previous * flock-serialized bash writes with atomic temp+rename in Bun. Phase 6 of the * agent-hooks/agent-coord refactor. * * Atomicity guarantee: every write goes via a `.tmp.` sibling + * `renameSync`. POSIX rename is atomic within a filesystem, so concurrent * readers either see the pre-write file or the post-write file but never a * half-written intermediate. Concurrent writers serialize via the rename * (last write wins). * * Cache identity invariant: every action operates on the generation-bound row at * `.harnery/active/.json`; the canonical V3 ledger remains authoritative. * (the file IS the heartbeat). No mutations happen elsewhere. */ import { type Heartbeat } from "./heartbeat-reader.js"; import type { TaskState } from "./session-state.js"; export { type Heartbeat, readHeartbeat } from "./heartbeat-reader.js"; /** Persist operator-facing lifecycle prose in the generation-bound cache only. */ export declare function setLifecycleCache(coordRoot: string, instanceId: string, state: TaskState, reason?: string, suggestedSessionName?: string): Heartbeat | null; export declare function setTask(coordRoot: string, instanceId: string, task: string): Heartbeat | null; /** Update the disposable identity cache after a canonical V3 attestation. */ export declare function setIdentityCache(coordRoot: string, instanceId: string, name: string, agentId: string): Heartbeat | null; /** Restore the pool-assigned display name on a generation that was * materialized before the adapter's normal SessionStart naming path ran. * The durable assignment lives in `.name-history`; this only repairs the * disposable generation cache and deliberately leaves durable persona state * (`agent_id`) untouched. */ export declare function setAssignedNameCache(coordRoot: string, instanceId: string, name: string, kind?: "session" | "subagent" | "transient"): Heartbeat | null; /** * Build the copy-pasteable session name from the coord identity + the agent's * description parts. Pure (no coord-state reads) so it's unit-testable; collapses * internal whitespace and trims. Returns null when the description is empty. */ export declare function buildSuggestedName(agentName: string, descriptionParts: string[]): { suggestedName: string; description: string; } | null; /** Build the sole lifecycle-driven title: the terminal done projection. */ export declare function buildLifecycleSuggestedName(currentSessionName: string | undefined, state: TaskState): string | null; /** Stamp the sighting once the suggested name has been observed in assistant * reply text; later turns skip the transcript scan. Records WHICH name was seen, * because the skip is only valid for that one: if a later set-task mints a * different suggested name, a bare "already seen" stamp would suppress the scan * forever and leave the Stop-hook naming rule permanently unsatisfiable. */ export declare function stampSessionNameSeen(coordRoot: string, instanceId: string, name?: string): Heartbeat | null; /** * Remember which title the agent was actually asked to display. * * The gate can only ask for a display through the PostToolUse instruction, and * the title it names can change afterwards (an assigned-name rewrite of an * `Agent unknown - ...` suggestion, a lifecycle re-mint, a rebuilt cache that * re-minted from the current task). Without this record the agent's correct * display of the title it was handed matches nothing, the latch never closes, * and on Cursor no later surface can repair it. */ export declare function stampSessionNameRequested(coordRoot: string, instanceId: string, name: string): Heartbeat | null; export declare function releaseClaim(coordRoot: string, instanceId: string, path: string): Heartbeat | null; /** Materialize one V3 write-claim authority transition into the heartbeat cache. */ export declare function acquireClaim(coordRoot: string, instanceId: string, path: string): Heartbeat | null; /** A heartbeat that actually dropped a path during a group unclaim. */ export interface GroupUnclaimHit { instance_id: string; session_id?: string; platform?: string; } /** * Session-group-wide unclaim. Walks every heartbeat sharing `groupId` * (parent's session_id == group_id; * subagents inherit it) and removes the path from each one's files_touched. * Idempotent: heartbeats that don't hold the path are untouched. Returns the * heartbeats that actually dropped the path so the caller can emit the * durable `coord.claim_changed` release events; a file-only prune is silently reverted by * the next projector replay. * * Tool payloads and release calls can supply either absolute-under-coordRoot or * canonical repo-relative entries, so both sides are normalized before comparing. An exact-string match * silently no-ops on the mixed-form case and the claim never releases. * * This is the Option B fix for post-commit's pid-map attribution hole: a * subagent-held claim that doesn't live on the parent's heartbeat still gets * pruned because the walk covers the whole group. */ export declare function findGroupClaims(coordRoot: string, groupId: string, path: string): GroupUnclaimHit[]; export declare function clearCoordinationCache(coordRoot: string, instanceId: string): boolean; export declare function healPidmap(coordRoot: string, instanceId: string, pid: number): void; //# sourceMappingURL=heartbeat-writer.d.ts.map