/** * Memory Bridge — project-root resolution and store path resolution * (per-project data dir, global brain, MCP path-traversal guard). Split out * of memory-bridge.ts, which re-exports the public symbols. */ export interface ProjectRootResolution { root: string; /** Why `root` was chosen — for disclosure (doctor, debug logs), not * behavior. `explicit-anchor`: MONOMIND_PROJECT_ROOT set and valid. * `git`: a `.git` ancestor (any depth) was adopted. `monomind-at-start`: * the starting directory itself carries `.monomind` (the user is * standing in their own project — always trusted). `monomind-with-marker`: * an ancestor's `.monomind` was corroborated by an independent project * marker. `start-fallback`: nothing adoptable was found; `root` is * `start`. */ reason: 'explicit-anchor' | 'git' | 'monomind-at-start' | 'monomind-with-marker' | 'start-fallback'; /** Set only on `start-fallback`: the first bare `.monomind` ancestor that * was found but NOT adopted (no independent marker alongside it), so a * caller can tell a genuinely ambiguous user why their brain stayed put * instead of silently picking a directory that merely looked plausible. */ ignoredBareMonomind?: string; /** Set whenever MONOMIND_PROJECT_ROOT was present in the environment but * failed validation — regardless of what `reason`/`root` ended up being, * so a typo'd anchor is never silently dropped just because the ordinary * walk happened to land somewhere reasonable anyway (o-16 revision 1). */ invalidAnchor?: { value: string; problem: string; }; } /** The full resolution — root, reason and (when the walk found nothing * adoptable) which bare `.monomind` ancestor it ignored. `doctor` uses this * to disclose which directory a user's brain is keyed to and why, instead * of a plausible-but-silent path (o-16). See `getProjectRoot` for the * string-only form the other ~28 call sites use. */ export declare function getProjectRootResolution(from?: string): ProjectRootResolution; /** The directory that identifies "this project" for every Second Brain store. * * Deliberately NOT the raw cwd: keying on cwd forked the brain per directory — * `doc ingest ./docs` from a package subdir wrote to a different store, and a * different metadata file, than the identical command at the repo root, and * neither could see the other. We walk up to the nearest ancestor carrying a * `.git` marker (any depth), or a `.monomind` marker corroborated by an * independent project marker, so every directory inside one project resolves * to one brain. Nested projects still win (the walk stops at the FIRST * eligible marker), which keeps worktrees and vendored sub-repos independent. * * o-16: a BARE `.monomind` ancestor (no `.git`, no manifest) is NOT adopted. * `.monomind` is created by monomind itself as a side effect of running * anywhere — it is not independent evidence of a project, and a wrong * resolution creates the very marker that would capture every future * descendant if it were trusted alone. See `walkToProjectRoot`'s comment for * the measured incident this fixes. The starting directory's OWN `.monomind` * is still trusted unconditionally — that is the user pointing at their own * project — and `.git` at any depth is untouched, so CI/devcontainer repos * and subdirectory unification behave exactly as before. * * The walk never crosses the home directory: a dotfiles repo at `~` would * otherwise swallow every loose project underneath it into one shared brain. * `MONOMIND_PROJECT_ROOT`, if set AND VALID (absolute, exists, is a * directory, is not itself the filesystem root — see `validateAnchor`), is * an explicit anchor that skips the walk entirely — the escape hatch for * the genuinely ambiguous case (design decision 4 / AC-3c: a real, non-git * project whose root has a bare `.monomind` and no manifest has no other * way to be found from a subdirectory). An invalid anchor falls through to * the walk rather than being adopted OR silently dropped — see * `ProjectRootResolution.invalidAnchor`. * * This is `MONOMIND_PROJECT_ROOT`'s SECOND consumer in this codebase — * `mcp-tools/guidance-tools.ts:findProjectRoot()` already reads the same * env var, for a DIFFERENT marker (`.claude`, not `.monomind`/`.git`), with * a stricter rule: `if (envRoot && existsSync(join(envRoot, '.claude')))`, * i.e. it only honors the anchor when `.claude` exists there, silently * falling through to its own walk otherwise. After this revision the two * converge on ANCHOR HANDLING for the cases that matter most — a typo'd or * missing path is rejected by both (this one via `validateAnchor`, * guidance-tools' because `.claude` is absent) — but "converge" describes * only whether each accepts or rejects the anchor, not the final resolved * root: a rejected anchor falls through to each resolver's OWN walk * (`walkToProjectRoot` here; guidance-tools' own Strategy 1/2/3 chain * there), which can still land on different directories for the same * unanchored cwd. Two residual disagreements remain, both legitimate rather * than oversights: * 1. An anchor that exists and is a real directory but has no `.claude` in * it: this function honors it (memory has no reason to require a * `.claude` folder — a project's knowledge store isn't gated on whether * an agent config lives there), guidance-tools does not (`.claude` is * the one thing it's searching FOR, so its absence is a real signal, not * noise, for that consumer specifically). * 2. A RELATIVE anchor: `validateAnchor` rejects it outright (an anchor * that silently depends on cwd defeats the point of an anchor). * guidance-tools has no absolute-path check, so `existsSync(join(envRoot, * '.claude'))` would resolve a relative `envRoot` against cwd and could * accept it — narrower in practice (needs a `.claude` at that resolved * location too) but a real gap in the two resolvers' shared assumptions. * Reconciling the two resolvers' semantics into one shared rule is a * separate, larger question (tracked as o-32), not something this fix * should decide as a side effect. * * For anyone who already ran from the project root — the normal case — the * resolved path is identical to before, so their store does not move. * * `MONOMIND_CWD` wins over the real cwd, matching `getProjectCwd()` in * mcp-tools/types.ts — an MCP server is launched with whatever cwd the client * chose, and that env var is already how monograph and swarm state learn which * project they belong to. Inlined rather than imported to keep this module on * node builtins only (see the static import in document-pipeline.ts). */ export declare function getProjectRoot(from?: string): string; export declare function projectDataDir(): string; /** The personal, cross-project knowledge store. Deliberately a SIBLING of * ~/.monomind/projects (never inside it) so per-project pruning heuristics * (`cleanup --data`) can never touch it. Env-overridable for tests and for * users who keep their brain on a synced/external location. Resolved lazily * so the override works regardless of import order. */ export declare function getGlobalBrainDir(): string; /** Sentinel callers pass as dbPath to address the global brain. */ export declare const GLOBAL_BRAIN = "@global"; export declare function getDbPath(customPath?: string): string; /** Resolve the real on-disk SQLite data-dir path for a given custom path (or the * default) — the dir is still named `lancedb` for legacy path back-compat. */ export declare function bridgeGetDbPath(customPath?: string): string; //# sourceMappingURL=memory-bridge-paths.d.ts.map