import { z } from 'zod'; /** * Which directory a projectId lives in, on this machine. * * Config discovery answers the same question by walking out from the daemon's working directory, * which works only when the daemon and the app share a tree. A daemon started in one repo, driving * an app in a sibling checkout, never finds that app's `.reticle.json` however far it walks — and * since an editor starts a user-scoped MCP server wherever it likes, that is the default * arrangement. * * `init` holds both halves at the moment it runs — the directory it is initialising and the * projectId it has just written into that directory's `.reticle.json`. Recording the pair once makes * every later session resolvable from anywhere on the machine. * * This is a CACHE, not a source of truth. `.reticle.json` on disk remains the authority; an entry * here is a hint about where to look. So every operation fails soft: a malformed file is an empty * registry, never a throw, because taking a daemon down over a stale cache would trade a small * problem for a large one. * * The contract lives in core for the same reason the daemon registry does — it is shared by a writer * (`init`, the CLI) and a reader (the daemon's artifact-root resolution), and a filename or a shape * that drifts between the two is a defect neither side can see. */ /** Sibling of `daemon-.json` in `~/.reticle`. One file, all projects. */ export declare const PROJECT_REGISTRY_FILE = "projects.json"; export declare const ProjectRegistryEntrySchema: z.ZodObject<{ /** Absolute path to the directory whose `.reticle.json` declares this project. */ directory: z.ZodString; /** When this pairing was last confirmed. Lets a future prune drop entries nobody has opened. */ lastSeenAt: z.ZodNumber; }, "strip", z.ZodTypeAny, { directory: string; lastSeenAt: number; }, { directory: string; lastSeenAt: number; }>; export type ProjectRegistryEntry = z.infer; export declare const ProjectRegistrySchema: z.ZodObject<{ version: z.ZodLiteral<1>; projects: z.ZodRecord>; }, "strip", z.ZodTypeAny, { version: 1; projects: Record; }, { version: 1; projects: Record; }>; export type ProjectRegistry = z.infer; /** A project the resolver may consider. Structurally identical to config discovery's `FoundConfig` * on purpose: both sources feed one code path, so neither becomes the privileged one. */ export interface ProjectCandidate { projectId: string; directory: string; } export declare function emptyProjectRegistry(): ProjectRegistry; /** * Record where a project lives. Pure — returns a new registry, takes its clock as an argument. * * Keyed on the id, so a project that moved (renamed, re-cloned, moved to another disk) replaces its * old path rather than leaving it behind as a competing answer. A second stale answer is exactly * what makes the resolver refuse, so letting them accumulate would break resolution for the project * that moved most recently — the one most likely to be in use. */ export declare function rememberProject(registry: ProjectRegistry, projectId: string, directory: string, now: number): ProjectRegistry; /** Every remembered project, in the shape the artifact-root resolver consumes. */ export declare function projectCandidates(registry: ProjectRegistry): ProjectCandidate[]; /** Parse a registry file's contents, failing soft to empty. Never throws. */ export declare function parseProjectRegistry(raw: unknown): ProjectRegistry;