@hiveai/core 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +8 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema.ts","../src/parser.ts","../src/paths.ts","../src/loader.ts","../src/search.ts","../src/verifier.ts","../src/relevance.ts","../src/usage.ts","../src/impact.ts","../src/prevention.ts","../src/context-throttle.ts","../src/eval.ts","../src/confidence.ts","../src/distinctive.ts","../src/skill-activation.ts","../src/specificity.ts","../src/token-budget.ts","../src/code-map.ts","../src/config.ts","../src/cross-repo.ts","../src/dep-tracker.ts","../src/contract-watcher.ts","../src/usage-log.ts","../src/briefing-preset.ts","../src/briefing-body.ts","../src/resolve-project.ts","../src/topic-suggest.ts","../src/lexical-rank.ts","../src/memory-timeline.ts","../src/conflict-candidates.ts","../src/runtime-journal.ts","../src/enforcement.ts","../src/memory-lifecycle.ts","../src/sensors.ts","../src/sensor-suggest.ts","../src/findings.ts","../src/gate-precision.ts","../src/dashboard.ts","../src/failure-coverage.ts","../src/coverage.ts","../src/eval-history.ts","../src/conflict-resolve.ts","../src/seed-git.ts","../src/seed.ts","../src/merge-memory.ts","../src/recap.ts","../src/priority.ts","../src/bridges.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const MemoryScopeSchema = z.enum([\"personal\", \"team\", \"module\", \"shared\"]);\n\nexport const MemoryStatusSchema = z.enum([\n \"draft\",\n \"proposed\",\n \"validated\",\n \"deprecated\",\n \"stale\",\n \"rejected\",\n]);\n\nexport const MemoryTypeSchema = z.enum([\n \"convention\",\n \"decision\",\n \"gotcha\",\n \"architecture\",\n \"glossary\",\n \"skill\", // reusable procedure/playbook for a recurring task (feedforward harness guide)\n \"attempt\", // failed approach — \"tried X, failed because Y, use Z instead\"\n \"session_recap\", // end-of-session summary: goal / accomplished / discoveries / next steps\n]);\n\nexport const AnchorSchema = z.object({\n commit: z.string().optional(),\n paths: z.array(z.string()).default([]),\n symbols: z.array(z.string()).default([]),\n});\n\n/**\n * An executable check derived from a memory — the \"feedback computational\" layer.\n *\n * A `gotcha`/`attempt` is normally feedforward (text the agent reads). A sensor turns\n * that lesson into a deterministic check: when a touched file matches `pattern`, the\n * memory's warning fires regardless of semantic ranking. This closes the harness loop —\n * a documented mistake becomes a permanent guardrail.\n *\n * Phase 1 implements `kind: \"regex\"` only. `shell`/`test` are reserved for a later phase\n * (they require I/O and must run from the CLI, not core).\n */\nexport const SensorSchema = z.object({\n kind: z.enum([\"regex\", \"shell\", \"test\"]).default(\"regex\"),\n /** Regex source (for kind=regex), matched against added diff lines / file content. */\n pattern: z.string().optional(),\n /** Regex flags (e.g. \"i\", \"m\"). Ignored for non-regex kinds. */\n flags: z.string().optional(),\n /** Shell/test command to run (for kind=shell|test). Executed by the CLI, never by core. */\n command: z.string().optional(),\n /** Glob-ish path prefixes the sensor applies to. Falls back to the memory's anchor paths when empty. */\n paths: z.array(z.string()).default([]),\n /** LLM-facing self-correction message: what was done wrong and what to do instead. */\n message: z.string().min(1),\n /** `warn` surfaces in review; `block` can hard-block the commit (only when the gate opts in). */\n severity: z.enum([\"warn\", \"block\"]).default(\"warn\"),\n /** True when hAIve generated this sensor automatically (vs. hand-authored). */\n autogen: z.boolean().default(false),\n /** ISO timestamp of the last time this sensor matched a diff. */\n last_fired: z.string().nullable().default(null),\n});\n\n/**\n * Progressive-disclosure activation triggers for a `skill` memory.\n *\n * A skill is a reusable playbook (feedforward harness guide). Injecting every skill\n * on every briefing bloats the context and dilutes signal (the \"instruction budget\"\n * problem). An `activation` block makes a skill surface ONLY when it is relevant:\n * its keywords match the task, or its globs match the files being edited. A skill\n * that defines `activation` and matches none of it is suppressed from the briefing;\n * a skill with no `activation` block keeps the legacy always-eligible behavior.\n */\nexport const ActivationSchema = z.object({\n /** Case-insensitive substrings matched against the task text. */\n keywords: z.array(z.string()).default([]),\n /** Glob-ish path patterns matched against the files being edited. */\n globs: z.array(z.string()).default([]),\n /** Always activate (rare — for truly universal playbooks). */\n always: z.boolean().default(false),\n});\n\nconst IsoDateString = z\n .union([z.string(), z.date()])\n .transform((v) => (v instanceof Date ? v.toISOString() : v))\n .pipe(z.string().datetime());\n\nexport const MemoryFrontmatterSchema = z\n .object({\n id: z.string().min(1),\n scope: MemoryScopeSchema.default(\"personal\"),\n module: z.string().optional(),\n type: MemoryTypeSchema,\n status: MemoryStatusSchema.default(\"draft\"),\n anchor: AnchorSchema.default({ paths: [], symbols: [] }),\n /** Optional executable check derived from this memory (feedback computational layer). */\n sensor: SensorSchema.optional(),\n /** Optional progressive-disclosure triggers — only meaningful for `type: skill`. */\n activation: ActivationSchema.optional(),\n tags: z.array(z.string()).default([]),\n domain: z.string().optional(),\n author: z.string().optional(),\n created_at: IsoDateString,\n expires_when: z.string().nullable().default(null),\n verified_at: z.string().nullable().default(null),\n stale_reason: z.string().nullable().default(null),\n related_ids: z.array(z.string()).default([]),\n last_read_at: z.string().nullable().default(null),\n topic: z.string().optional(), // stable key for upsert — same topic in same scope → update instead of create\n revision_count: z.number().int().min(0).default(0), // incremented each time a topic upsert occurs\n /**\n * When true, the AI MUST NOT act on this memory autonomously.\n * It must surface the information to the human developer and wait\n * for explicit confirmation before modifying any code.\n * Used for cross-repo breaking changes, dependency bumps, contract diffs.\n */\n requires_human_approval: z.boolean().default(false),\n })\n .refine(\n (data) => data.scope !== \"module\" || !!data.module,\n { message: \"module name is required when scope is 'module'\", path: [\"module\"] },\n );\n\n// Additional fields for cross-repo provenance (stored in frontmatter of imported memories)\nexport const CrossRepoProvenanceSchema = z.object({\n source_name: z.string(), // the crossRepoSources name from haive.config.json\n source_path: z.string(), // original file path in the source repo\n source_id: z.string(), // original memory id\n imported_at: z.string(), // ISO timestamp of import\n}).optional();\n","import matter from \"gray-matter\";\nimport { MemoryFrontmatterSchema } from \"./schema.js\";\nimport type { Activation, Memory, MemoryFrontmatter, Sensor } from \"./types.js\";\n\nconst PRIVATE_BLOCK_RE = /<private>[\\s\\S]*?<\\/private>/g;\n\nexport function stripPrivate(body: string): string {\n return body.replace(PRIVATE_BLOCK_RE, \"\").trimEnd();\n}\n\nexport function parseMemory(raw: string): Memory {\n const parsed = matter(raw);\n const frontmatter = MemoryFrontmatterSchema.parse(parsed.data);\n return {\n frontmatter,\n body: stripPrivate(parsed.content.trim()),\n };\n}\n\nfunction stripUndefined<T>(value: T): T {\n if (Array.isArray(value)) {\n return value.map((v) => stripUndefined(v)) as unknown as T;\n }\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v === undefined) continue;\n out[k] = stripUndefined(v);\n }\n return out as T;\n }\n return value;\n}\n\nexport function serializeMemory(memory: Memory): string {\n const clean = stripUndefined(memory.frontmatter) as Record<string, unknown>;\n return matter.stringify(memory.body, clean);\n}\n\nexport function newMemoryId(type: string, slug: string, date = new Date()): string {\n const isoDate = date.toISOString().slice(0, 10);\n const safeSlug = slug\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 60);\n return `${isoDate}-${type}-${safeSlug}`;\n}\n\nexport function buildFrontmatter(input: {\n type: MemoryFrontmatter[\"type\"];\n slug: string;\n scope?: MemoryFrontmatter[\"scope\"];\n module?: string;\n tags?: string[];\n domain?: string;\n author?: string;\n paths?: string[];\n symbols?: string[];\n commit?: string;\n topic?: string;\n status?: MemoryFrontmatter[\"status\"];\n relatedIds?: string[];\n sensor?: Sensor;\n activation?: Activation;\n}): MemoryFrontmatter {\n const now = new Date();\n const id = newMemoryId(input.type, input.slug, now);\n return MemoryFrontmatterSchema.parse({\n id,\n scope: input.scope ?? \"personal\",\n module: input.module,\n type: input.type,\n status: input.status ?? \"draft\",\n anchor: {\n commit: input.commit,\n paths: input.paths ?? [],\n symbols: input.symbols ?? [],\n },\n tags: input.tags ?? [],\n domain: input.domain,\n author: input.author,\n created_at: now.toISOString(),\n expires_when: null,\n topic: input.topic,\n sensor: input.sensor,\n activation: input.activation,\n revision_count: 0,\n related_ids: input.relatedIds ?? [],\n });\n}\n","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport const HAIVE_DIR = \".ai\";\n\nconst ROOT_MARKERS = [\".ai\", \".git\", \"package.json\"];\n\nexport function findProjectRoot(startDir: string = process.cwd()): string {\n let current = path.resolve(startDir);\n const fsRoot = path.parse(current).root;\n while (current !== fsRoot) {\n for (const marker of ROOT_MARKERS) {\n if (existsSync(path.join(current, marker))) return current;\n }\n current = path.dirname(current);\n }\n return path.resolve(startDir);\n}\n\nexport const PROJECT_CONTEXT_FILE = \"project-context.md\";\nexport const MEMORIES_DIR = \"memories\";\n\nexport interface HaivePaths {\n root: string;\n haiveDir: string;\n /** Disposable local layer (session journal, caches). Not team truth — see `.ai/.runtime/` layout. */\n runtimeDir: string;\n projectContext: string;\n memoriesDir: string;\n personalDir: string;\n teamDir: string;\n sharedDir: string;\n moduleDir: string;\n modulesContextDir: string;\n}\n\nexport function resolveHaivePaths(projectRoot: string): HaivePaths {\n const haiveDir = path.join(projectRoot, HAIVE_DIR);\n const memoriesDir = path.join(haiveDir, MEMORIES_DIR);\n return {\n root: projectRoot,\n haiveDir,\n runtimeDir: path.join(haiveDir, \".runtime\"),\n projectContext: path.join(haiveDir, PROJECT_CONTEXT_FILE),\n memoriesDir,\n personalDir: path.join(memoriesDir, \"personal\"),\n teamDir: path.join(memoriesDir, \"team\"),\n sharedDir: path.join(memoriesDir, \"shared\"),\n moduleDir: path.join(memoriesDir, \"module\"),\n modulesContextDir: path.join(haiveDir, \"modules\"),\n };\n}\n\nexport function memoryFilePath(\n paths: HaivePaths,\n scope: \"personal\" | \"team\" | \"module\" | \"shared\",\n id: string,\n module?: string,\n): string {\n const base =\n scope === \"personal\"\n ? paths.personalDir\n : scope === \"team\"\n ? paths.teamDir\n : scope === \"shared\"\n ? paths.sharedDir\n : path.join(paths.moduleDir, module ?? \"_unscoped\");\n return path.join(base, `${id}.md`);\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { parseMemory } from \"./parser.js\";\nimport type { Memory } from \"./types.js\";\n\nexport interface LoadedMemory {\n memory: Memory;\n filePath: string;\n}\n\nexport async function listMarkdownFilesRecursive(dir: string): Promise<string[]> {\n const out: string[] = [];\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return out;\n }\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n out.push(...(await listMarkdownFilesRecursive(full)));\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n out.push(full);\n }\n }\n return out;\n}\n\nexport async function loadMemory(filePath: string): Promise<LoadedMemory> {\n const raw = await readFile(filePath, \"utf8\");\n return { memory: parseMemory(raw), filePath };\n}\n\nexport async function loadMemoriesFromDir(dir: string): Promise<LoadedMemory[]> {\n const files = await listMarkdownFilesRecursive(dir);\n const out: LoadedMemory[] = [];\n for (const file of files) {\n try {\n out.push(await loadMemory(file));\n } catch {\n // Skip unparseable files in v0.1; future: surface a warning channel.\n }\n }\n return out;\n}\n","import type { Memory } from \"./types.js\";\n\nexport function tokenizeQuery(query: string): string[] {\n return query\n .toLowerCase()\n .split(/\\s+/)\n .map((t) => t.trim())\n .filter(Boolean);\n}\n\nexport function literalMatchesAllTokens(memory: Memory, tokens: string[]): boolean {\n if (tokens.length === 0) return true;\n const fm = memory.frontmatter;\n const idLower = fm.id.toLowerCase();\n const tagsLower = fm.tags.map((t) => t.toLowerCase());\n const bodyLower = memory.body.toLowerCase();\n const anchorPathTokens = collectAnchorPathTokens(fm.anchor.paths);\n const anchorSymbolsLower = fm.anchor.symbols.map((s) => s.toLowerCase());\n const moduleLower = fm.module?.toLowerCase();\n const domainLower = fm.domain?.toLowerCase();\n\n return tokens.every((rawTok) => {\n const tok = rawTok.toLowerCase();\n return (\n idLower.includes(tok) ||\n tagsLower.some((t) => t.includes(tok)) ||\n bodyLower.includes(tok) ||\n anchorPathTokens.some((p) => p.includes(tok)) ||\n anchorSymbolsLower.some((s) => s.includes(tok)) ||\n (moduleLower !== undefined && moduleLower.includes(tok)) ||\n (domainLower !== undefined && domainLower.includes(tok))\n );\n });\n}\n\nfunction collectAnchorPathTokens(paths: readonly string[]): string[] {\n const out = new Set<string>();\n for (const p of paths) {\n const lower = p.toLowerCase();\n out.add(lower);\n // basename without extension\n const base = lower.split(\"/\").pop() ?? lower;\n const noExt = base.replace(/\\.[a-z0-9]+$/, \"\");\n if (noExt) out.add(noExt);\n // each path segment (helps \"verifier\" match \"src/verifier.ts\")\n for (const segment of lower.split(\"/\")) {\n const seg = segment.replace(/\\.[a-z0-9]+$/, \"\");\n if (seg) out.add(seg);\n }\n }\n return [...out];\n}\n\n/**\n * OR-based fallback: returns true if the memory matches at least one token.\n * Used when all-tokens (AND) search returns 0 results.\n */\nexport function literalMatchesAnyToken(memory: Memory, tokens: string[]): boolean {\n if (tokens.length === 0) return false;\n const fm = memory.frontmatter;\n const idLower = fm.id.toLowerCase();\n const tagsLower = fm.tags.map((t) => t.toLowerCase());\n const bodyLower = memory.body.toLowerCase();\n const anchorPathTokens = collectAnchorPathTokens(fm.anchor.paths);\n const anchorSymbolsLower = fm.anchor.symbols.map((s) => s.toLowerCase());\n const moduleLower = fm.module?.toLowerCase();\n const domainLower = fm.domain?.toLowerCase();\n\n return tokens.some((rawTok) => {\n const tok = rawTok.toLowerCase();\n return (\n idLower.includes(tok) ||\n tagsLower.some((t) => t.includes(tok)) ||\n bodyLower.includes(tok) ||\n anchorPathTokens.some((p) => p.includes(tok)) ||\n anchorSymbolsLower.some((s) => s.includes(tok)) ||\n (moduleLower !== undefined && moduleLower.includes(tok)) ||\n (domainLower !== undefined && domainLower.includes(tok))\n );\n });\n}\n\nexport function pickSnippetNeedle(query: string): string {\n const tokens = tokenizeQuery(query);\n if (tokens.length === 0) return query.toLowerCase();\n return [...tokens].sort((a, b) => b.length - a.length)[0]!;\n}\n\nexport function extractSnippet(body: string, needle: string, radius = 40): string {\n const lower = body.toLowerCase();\n const idx = needle ? lower.indexOf(needle) : -1;\n if (idx < 0) {\n return body.slice(0, radius * 3).replace(/\\s+/g, \" \").trim();\n }\n const start = Math.max(0, idx - radius);\n const end = Math.min(body.length, idx + needle.length + radius);\n const snippet = body.slice(start, end).replace(/\\s+/g, \" \").trim();\n return (start > 0 ? \"…\" : \"\") + snippet + (end < body.length ? \"…\" : \"\");\n}\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { globToRegExp, isGlobPath } from \"./relevance.js\";\nimport type { Memory } from \"./types.js\";\n\nexport interface VerifyResult {\n stale: boolean;\n reason: string | null;\n checkedPaths: string[];\n checkedSymbols: string[];\n possibleRenames: string[];\n}\n\nexport interface VerifyOptions {\n /** Project root used to resolve relative anchor paths. */\n projectRoot: string;\n}\n\n/**\n * Verify that a memory's anchor still matches the current code.\n * - Every anchor.paths entry must exist on disk\n * - Every anchor.symbols entry must appear at least once across the anchor.paths\n * files (or any tracked file if no paths are recorded)\n *\n * Anchorless memories (no paths and no symbols) are always considered fresh —\n * staleness only applies to memories that opted into anchoring.\n */\nexport async function verifyAnchor(\n memory: Memory,\n options: VerifyOptions,\n): Promise<VerifyResult> {\n const anchor = memory.frontmatter.anchor;\n const checkedPaths = anchor.paths;\n const checkedSymbols = anchor.symbols;\n\n if (checkedPaths.length === 0 && checkedSymbols.length === 0) {\n return { stale: false, reason: null, checkedPaths, checkedSymbols, possibleRenames: [] };\n }\n\n const missingPaths: string[] = [];\n const existingAbsPaths: string[] = [];\n for (const rel of checkedPaths) {\n if (isGlobPath(rel)) {\n const matches = await findGlobMatches(rel, options.projectRoot);\n if (matches.length > 0) {\n existingAbsPaths.push(...matches.map((m) => path.join(options.projectRoot, m)));\n } else {\n missingPaths.push(rel);\n }\n continue;\n }\n const abs = path.isAbsolute(rel) ? rel : path.join(options.projectRoot, rel);\n if (existsSync(abs)) {\n existingAbsPaths.push(...await readableFilesForAnchor(abs));\n } else {\n missingPaths.push(rel);\n }\n }\n\n if (missingPaths.length > 0) {\n const possibleRenames = await findPossibleRenames(missingPaths, options.projectRoot);\n return {\n stale: true,\n reason: `anchor path(s) no longer exist: ${missingPaths.join(\", \")}`,\n checkedPaths,\n checkedSymbols,\n possibleRenames,\n };\n }\n\n if (checkedSymbols.length > 0) {\n if (existingAbsPaths.length === 0) {\n return {\n stale: true,\n reason: `cannot verify symbols (${checkedSymbols.join(\", \")}): no anchor paths recorded`,\n checkedPaths,\n checkedSymbols,\n possibleRenames: [],\n };\n }\n const missingSymbols: string[] = [];\n for (const sym of checkedSymbols) {\n let found = false;\n for (const file of existingAbsPaths) {\n try {\n const contents = await readFile(file, \"utf8\");\n if (contents.includes(sym)) {\n found = true;\n break;\n }\n } catch {\n // unreadable file; treat as not finding the symbol here\n }\n }\n if (!found) missingSymbols.push(sym);\n }\n if (missingSymbols.length > 0) {\n return {\n stale: true,\n reason: `anchor symbol(s) not found in any anchor path: ${missingSymbols.join(\", \")}`,\n checkedPaths,\n checkedSymbols,\n possibleRenames: [],\n };\n }\n }\n\n return { stale: false, reason: null, checkedPaths, checkedSymbols, possibleRenames: [] };\n}\n\nasync function findPossibleRenames(\n missingPaths: string[],\n projectRoot: string,\n): Promise<string[]> {\n const basenames = new Set(missingPaths.map((p) => path.basename(p)));\n const found: string[] = [];\n try {\n await walkDir(projectRoot, projectRoot, basenames, found, 0);\n } catch {\n // best-effort\n }\n return found;\n}\n\nasync function findGlobMatches(pattern: string, projectRoot: string): Promise<string[]> {\n const re = globToRegExp(pattern);\n const found: string[] = [];\n try {\n await walkAllFiles(projectRoot, projectRoot, found, 0, re);\n } catch {\n // best-effort\n }\n return found;\n}\n\nasync function readableFilesForAnchor(abs: string): Promise<string[]> {\n try {\n const s = await stat(abs);\n if (s.isDirectory()) {\n const out: string[] = [];\n await walkReadableFiles(abs, out, 0);\n return out;\n }\n if (s.isFile()) return [abs];\n } catch {\n return [abs];\n }\n return [abs];\n}\n\nasync function walkReadableFiles(dir: string, found: string[], depth: number): Promise<void> {\n if (depth > 6) return;\n let entries: string[];\n try {\n entries = await readdir(dir, { encoding: \"utf8\" });\n } catch {\n return;\n }\n for (const name of entries) {\n if (name.startsWith(\".\") || name === \"node_modules\") continue;\n const abs = path.join(dir, name);\n try {\n const s = await stat(abs);\n if (s.isDirectory()) await walkReadableFiles(abs, found, depth + 1);\n else if (s.isFile()) found.push(abs);\n } catch {\n continue;\n }\n }\n}\n\nasync function walkAllFiles(\n dir: string,\n root: string,\n found: string[],\n depth: number,\n match: RegExp,\n): Promise<void> {\n if (depth > 12) return;\n let entries: string[];\n try {\n entries = await readdir(dir, { encoding: \"utf8\" });\n } catch {\n return;\n }\n for (const name of entries) {\n if (name === \"node_modules\" || name === \".git\" || name === \".ai\") continue;\n const abs = path.join(dir, name);\n try {\n const s = await stat(abs);\n if (s.isDirectory()) {\n await walkAllFiles(abs, root, found, depth + 1, match);\n } else if (s.isFile()) {\n const rel = path.relative(root, abs).replace(/\\\\/g, \"/\");\n if (match.test(rel)) found.push(rel);\n }\n } catch {\n continue;\n }\n }\n}\n\nasync function walkDir(\n dir: string,\n root: string,\n targets: Set<string>,\n found: string[],\n depth: number,\n): Promise<void> {\n if (depth > 6) return;\n let entries: string[];\n try {\n entries = await readdir(dir, { encoding: \"utf8\" });\n } catch {\n return;\n }\n for (const name of entries) {\n if (name.startsWith(\".\") || name === \"node_modules\") continue;\n const abs = path.join(dir, name);\n let isDir = false;\n try {\n isDir = (await stat(abs)).isDirectory();\n } catch {\n continue;\n }\n if (isDir) {\n await walkDir(abs, root, targets, found, depth + 1);\n } else if (targets.has(name)) {\n found.push(path.relative(root, abs));\n }\n }\n}\n","import path from \"node:path\";\nimport type { LoadedMemory } from \"./loader.js\";\n\n/**\n * Tag stamped on memories that were pre-seeded from a stack pack at `haive init`\n * (generic framework knowledge the model already largely knows, not repo-specific\n * institutional knowledge). Briefing ranking caps these at `background` priority so\n * a generic seed never displaces a repo-specific memory — unless the seed has been\n * anchored to a file the agent is actually editing.\n */\nexport const STACK_PACK_TAG = \"stack-pack\";\n\n/** True when a memory was pre-seeded from a stack pack (carries {@link STACK_PACK_TAG}). */\nexport function isStackPackSeed(fm: { tags?: string[] } | null | undefined): boolean {\n return Boolean(fm?.tags?.includes(STACK_PACK_TAG));\n}\n\n/**\n * Tags that mark a memory as a *local dev-environment workaround* (hot-swap, nested node_modules,\n * global-install quirks) rather than repo-specific team policy. These are real, but they describe\n * tooling debt, not unguessable team knowledge — and because they get read on almost every session\n * their read_count inflates and they crowd the briefing. Ranking caps them at `background` UNLESS\n * they directly anchor a file being edited, so they stop displacing actual policy. The fix for a\n * recurring one is to repair the environment, not to keep surfacing the note.\n */\nexport const ENV_WORKAROUND_TAGS = new Set([\n \"dev-workflow\",\n \"dev-env\",\n \"hotswap\",\n \"local-setup\",\n \"tooling-debt\",\n]);\n\n/** True when a memory is tagged as a local dev-environment workaround (see {@link ENV_WORKAROUND_TAGS}). */\nexport function isEnvWorkaroundMemory(fm: { tags?: string[] } | null | undefined): boolean {\n return Boolean(fm?.tags?.some((t) => ENV_WORKAROUND_TAGS.has(t)));\n}\n\nconst MODULE_PATTERNS = [\n /^packages\\/([^/]+)\\//,\n /^apps\\/([^/]+)\\//,\n /^modules\\/([^/]+)\\//,\n /^src\\/([^/]+)\\//,\n /^libs\\/([^/]+)\\//,\n /^services\\/([^/]+)\\//,\n /^internal\\/([^/]+)\\//,\n /^projects\\/([^/]+)\\//, // Nx layout\n /^cmd\\/([^/]+)\\//, // Go-style\n];\n\n/**\n * Best-effort inference: given a list of file paths, infer module names from\n * conventional layouts (packages/X/, apps/X/, modules/X/, src/X/).\n */\nexport function inferModulesFromPaths(filePaths: string[]): string[] {\n const out = new Set<string>();\n for (const p of filePaths) {\n const norm = normalize(p);\n for (const re of MODULE_PATTERNS) {\n const m = norm.match(re);\n if (m && m[1]) out.add(m[1]);\n }\n }\n return [...out].sort();\n}\n\n/**\n * Path overlap: returns true if `a` and `b` refer to the same path or one is a\n * parent of the other. Both inputs are treated as POSIX-style relative paths.\n */\nexport function pathsOverlap(a: string, b: string): boolean {\n const na = normalize(a);\n const nb = normalize(b);\n if (isGlobPath(na)) return globOverlapsPath(na, nb);\n if (isGlobPath(nb)) return globOverlapsPath(nb, na);\n if (na === nb) return true;\n return na.startsWith(nb + \"/\") || nb.startsWith(na + \"/\");\n}\n\nexport function memoryMatchesAnchorPaths(\n memory: LoadedMemory[\"memory\"],\n inputPaths: string[],\n): boolean {\n const anchorPaths = memory.frontmatter.anchor.paths;\n if (anchorPaths.length === 0) return false;\n for (const ap of anchorPaths) {\n for (const ip of inputPaths) {\n if (pathsOverlap(ap, ip)) return true;\n }\n }\n return false;\n}\n\nfunction normalize(p: string): string {\n // Strip leading \"./\" and trailing \"/\", normalize separators.\n return p.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n}\n\nexport function isGlobPath(p: string): boolean {\n return /[*?\\[]/.test(p);\n}\n\nexport function globToRegExp(pattern: string): RegExp {\n const norm = normalize(pattern);\n let out = \"^\";\n for (let i = 0; i < norm.length; i++) {\n const ch = norm[i]!;\n const next = norm[i + 1];\n const afterNext = norm[i + 2];\n if (ch === \"*\" && next === \"*\" && afterNext === \"/\") {\n out += \"(?:.*/)?\";\n i += 2;\n } else if (ch === \"*\" && next === \"*\") {\n out += \".*\";\n i++;\n } else if (ch === \"*\") {\n out += \"[^/]*\";\n } else if (ch === \"?\") {\n out += \"[^/]\";\n } else {\n out += ch.replace(/[|\\\\{}()[\\]^$+?.]/g, \"\\\\$&\");\n }\n }\n out += \"$\";\n return new RegExp(out);\n}\n\nfunction globOverlapsPath(globPattern: string, candidate: string): boolean {\n const normalizedCandidate = normalize(candidate);\n if (globToRegExp(globPattern).test(normalizedCandidate)) return true;\n const prefix = globLiteralPrefix(globPattern);\n if (!prefix || prefix.split(\"/\").length < 2) return false;\n return normalizedCandidate === prefix ||\n normalizedCandidate.startsWith(prefix + \"/\") ||\n prefix.startsWith(normalizedCandidate + \"/\");\n}\n\nfunction globLiteralPrefix(pattern: string): string {\n const norm = normalize(pattern);\n const firstGlob = norm.search(/[*?\\[]/);\n if (firstGlob < 0) return norm;\n const slash = norm.slice(0, firstGlob).lastIndexOf(\"/\");\n return slash < 0 ? \"\" : norm.slice(0, slash);\n}\n\nexport function relPathFrom(root: string, abs: string): string {\n return path.relative(root, abs).replace(/\\\\/g, \"/\");\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport interface MemoryUsage {\n read_count: number;\n last_read_at: string | null;\n rejected_count: number;\n last_rejected_at: string | null;\n rejection_reason: string | null;\n /**\n * Number of times the memory was explicitly confirmed *useful* — i.e. an agent\n * or human recorded that it changed what they did (the closed-loop \"applied\"\n * outcome, recorded via `mem_feedback`). A far stronger utility signal than a\n * read: a memory can be surfaced many times and ignored, but `applied` means it\n * demonstrably steered work. Drives impact scoring in {@link ./impact.js}.\n */\n applied_count: number;\n last_applied_at: string | null;\n /**\n * Number of *prevention* events — times this memory's sensor actually fired on a scanned diff,\n * intercepting a known mistake before it landed. This is an OUTCOME signal (defect prevented),\n * the closest proxy hAIve has to \"did the knowledge stop a real problem?\", distinct from\n * retrieval (read) and self-reported usefulness (applied). Recorded by `haive sensors check`.\n */\n prevented_count: number;\n last_prevented_at: string | null;\n}\n\nexport interface UsageIndex {\n version: 1;\n updated_at: string;\n by_id: Record<string, MemoryUsage>;\n}\n\nexport const USAGE_FILE = \"usage.json\";\n\nexport function emptyUsage(): MemoryUsage {\n return {\n read_count: 0,\n last_read_at: null,\n rejected_count: 0,\n last_rejected_at: null,\n rejection_reason: null,\n applied_count: 0,\n last_applied_at: null,\n prevented_count: 0,\n last_prevented_at: null,\n };\n}\n\n/**\n * Normalize a possibly-partial stored usage record (older `usage.json` files\n * predate the `applied_*` fields). Always returns a full {@link MemoryUsage}.\n */\nfunction normalizeUsage(stored: Partial<MemoryUsage> | undefined): MemoryUsage {\n return { ...emptyUsage(), ...(stored ?? {}) };\n}\n\nexport function emptyUsageIndex(): UsageIndex {\n return {\n version: 1,\n updated_at: new Date().toISOString(),\n by_id: {},\n };\n}\n\nexport function usagePath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", USAGE_FILE);\n}\n\nexport async function loadUsageIndex(paths: HaivePaths): Promise<UsageIndex> {\n const file = usagePath(paths);\n if (!existsSync(file)) return emptyUsageIndex();\n const raw = await readFile(file, \"utf8\");\n try {\n const parsed = JSON.parse(raw) as UsageIndex;\n if (parsed.version !== 1) return emptyUsageIndex();\n return parsed;\n } catch {\n return emptyUsageIndex();\n }\n}\n\nexport async function saveUsageIndex(paths: HaivePaths, index: UsageIndex): Promise<void> {\n const file = usagePath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n index.updated_at = new Date().toISOString();\n await writeFile(file, JSON.stringify(index, null, 2), \"utf8\");\n}\n\nexport function getUsage(index: UsageIndex, id: string): MemoryUsage {\n return normalizeUsage(index.by_id[id]);\n}\n\nexport function bumpRead(index: UsageIndex, ids: string[]): UsageIndex {\n if (ids.length === 0) return index;\n const now = new Date().toISOString();\n for (const id of ids) {\n const current = normalizeUsage(index.by_id[id]);\n index.by_id[id] = {\n ...current,\n read_count: current.read_count + 1,\n last_read_at: now,\n };\n }\n return index;\n}\n\nexport function recordRejection(\n index: UsageIndex,\n id: string,\n reason: string | null,\n): UsageIndex {\n const current = normalizeUsage(index.by_id[id]);\n const now = new Date().toISOString();\n index.by_id[id] = {\n ...current,\n rejected_count: current.rejected_count + 1,\n last_rejected_at: now,\n rejection_reason: reason,\n };\n return index;\n}\n\n/**\n * Record that a memory was *applied* — explicitly confirmed to have changed what\n * the agent/human did. This is the closed-loop utility signal that distinguishes\n * a memory that merely got surfaced from one that demonstrably steered work.\n */\nexport function recordApplied(index: UsageIndex, id: string): UsageIndex {\n const current = normalizeUsage(index.by_id[id]);\n const now = new Date().toISOString();\n index.by_id[id] = {\n ...current,\n applied_count: current.applied_count + 1,\n last_applied_at: now,\n };\n return index;\n}\n\n/** Debounce window so re-scanning the same diff within a few minutes doesn't inflate prevention\n * counts (a pre-commit hook can run the check several times for one commit). */\nexport const PREVENTION_DEBOUNCE_MS = 5 * 60 * 1000;\n\n/**\n * Record a *prevention* event: a memory's sensor fired on a scanned diff, intercepting a known\n * mistake before it landed. Outcome signal (defect prevented), stronger than a read. Debounced by\n * {@link PREVENTION_DEBOUNCE_MS}. Returns true if a NEW event was recorded (false if debounced).\n */\nexport function recordPrevention(index: UsageIndex, id: string, now: number = Date.now()): boolean {\n const current = normalizeUsage(index.by_id[id]);\n const last = current.last_prevented_at ? Date.parse(current.last_prevented_at) : 0;\n if (Number.isFinite(last) && last > 0 && now - last < PREVENTION_DEBOUNCE_MS) {\n index.by_id[id] = current; // normalize in place, no count change\n return false;\n }\n index.by_id[id] = {\n ...current,\n prevented_count: current.prevented_count + 1,\n last_prevented_at: new Date(now).toISOString(),\n };\n return true;\n}\n\nexport const DECAY_DAYS = 90;\n\nexport function isDecaying(usage: MemoryUsage, createdAt: string): boolean {\n const threshold = Date.now() - DECAY_DAYS * 24 * 60 * 60 * 1000;\n const anchor = usage.last_read_at ?? createdAt;\n return new Date(anchor).getTime() < threshold;\n}\n\nexport async function trackReads(\n paths: HaivePaths,\n ids: string[],\n): Promise<UsageIndex> {\n if (ids.length === 0) {\n return await loadUsageIndex(paths);\n }\n const index = await loadUsageIndex(paths);\n bumpRead(index, ids);\n await saveUsageIndex(paths, index);\n return index;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport type { MemoryUsage } from \"./usage.js\";\n\n/**\n * Closed-loop memory-utility scoring — the \"did this memory actually help?\" layer.\n *\n * hAIve already tracks reads ({@link ./usage.js}) and derives a trust level from\n * status + read_count ({@link ./confidence.js}). But a read only means a memory was\n * *surfaced*, not that it *helped* — a memory can be injected on every briefing and\n * silently ignored. Harness engineering's core loop (Fowler / LangChain) is to\n * measure what demonstrably steers work and let that feed back into recall.\n *\n * `computeImpact` combines the signals hAIve already records but never correlated:\n * POSITIVE reads · applied outcomes (mem_feedback) · a sensor that actually fired\n * NEGATIVE rejections · stale/deprecated/rejected status · dormancy\n * into a single 0..1 utility score, a tier, and a prune-candidate flag. It is a pure\n * function (no I/O), unit-tested in `packages/core/test/impact.test.ts`.\n */\n\nexport type ImpactTier = \"high\" | \"medium\" | \"low\" | \"dormant\";\n\nexport interface ImpactScore {\n /** Normalized utility score in [0, 1]. */\n score: number;\n tier: ImpactTier;\n /** Human-readable breakdown of the signals that produced the score. */\n signals: string[];\n /**\n * True when the memory looks like dead weight worth reviewing/pruning:\n * more rejections than reads, or never used with no guardrail, or already\n * stale/deprecated/rejected. A memory carrying a `sensor` or with `applied`\n * outcomes is never a prune candidate — it earns its keep as a guardrail.\n */\n pruneCandidate: boolean;\n}\n\nexport interface ImpactOptions {\n /** Days with no read AND no applied outcome after which a memory is \"dormant\". */\n dormantDays?: number;\n now?: Date;\n}\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/** Default dormancy window — half the confidence hard-decay (365d), so impact reacts sooner. */\nexport const DEFAULT_DORMANT_DAYS = 120;\n\n/** Reads needed to saturate the read component of the score. */\nconst READ_SATURATION = 32;\n\nfunction clamp01(n: number): number {\n if (Number.isNaN(n)) return 0;\n return Math.max(0, Math.min(1, n));\n}\n\nfunction hasSensorFired(fm: MemoryFrontmatter): boolean {\n return Boolean(fm.sensor?.last_fired);\n}\n\nfunction isDeadStatus(fm: MemoryFrontmatter): boolean {\n return fm.status === \"stale\" || fm.status === \"deprecated\" || fm.status === \"rejected\";\n}\n\n/**\n * Compute the demonstrated utility of a single memory from its frontmatter + usage.\n * Pure and deterministic given `now`.\n */\nexport function computeImpact(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n options: ImpactOptions = {},\n): ImpactScore {\n const now = options.now ?? new Date();\n const dormantDays = options.dormantDays ?? DEFAULT_DORMANT_DAYS;\n const signals: string[] = [];\n\n let raw = 0;\n\n // POSITIVE — reads (a memory that keeps getting surfaced has some pull). Log-scaled\n // and capped at 0.35 so reads alone can never reach \"high\": being surfaced is not\n // the same as being useful.\n if (usage.read_count > 0) {\n raw += Math.min(1, Math.log2(usage.read_count + 1) / Math.log2(READ_SATURATION + 1)) * 0.35;\n signals.push(`read ${usage.read_count}×`);\n }\n\n // POSITIVE — applied outcomes: the strongest signal. The agent/human confirmed it\n // changed what they did. 4 applications saturate this 0.60 component — enough to\n // reach \"high\" on its own, since a demonstrably-applied memory has earned it.\n if (usage.applied_count > 0) {\n raw += Math.min(1, usage.applied_count / 4) * 0.6;\n signals.push(`applied ${usage.applied_count}×`);\n }\n\n // POSITIVE — prevention events (OUTCOME): the memory's sensor fired on real diffs, intercepting a\n // documented mistake before it landed. The strongest demonstrated-value signal — 3 catches\n // saturate this 0.60 component (enough to reach \"high\" alone, like applied). Falls back to the\n // frontmatter `sensor.last_fired` flag for memories that fired before prevention counting existed.\n if (usage.prevented_count > 0) {\n raw += Math.min(1, usage.prevented_count / 3) * 0.6;\n signals.push(`prevented ${usage.prevented_count}×`);\n } else if (hasSensorFired(fm)) {\n raw += 0.25;\n signals.push(\"sensor fired\");\n }\n\n // NEGATIVE — rejections: explicit \"not useful\" feedback. Heavily weighted.\n if (usage.rejected_count > 0) {\n raw -= Math.min(0.6, usage.rejected_count * 0.25);\n signals.push(`rejected ${usage.rejected_count}×`);\n }\n\n let score = clamp01(raw);\n\n // Dead statuses collapse the score regardless of past reads.\n if (isDeadStatus(fm)) {\n score *= 0.2;\n signals.push(`status=${fm.status}`);\n }\n\n // Dormancy — no read and no application within the window. The clock starts at the\n // most recent activity (applied → read → created).\n const anchor = usage.last_applied_at ?? usage.last_read_at ?? fm.created_at;\n const ageDays = (now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY;\n const dormant =\n Number.isFinite(ageDays) && ageDays >= dormantDays && usage.applied_count === 0;\n if (dormant) {\n score *= 0.5;\n signals.push(`dormant ${Math.floor(ageDays)}d`);\n }\n\n const tier = deriveTier(score, dormant, usage);\n const pruneCandidate = isPruneCandidate(fm, usage, tier);\n\n return { score: round3(score), tier, signals, pruneCandidate };\n}\n\nfunction deriveTier(score: number, dormant: boolean, usage: MemoryUsage): ImpactTier {\n if (dormant && usage.read_count <= 1 && usage.applied_count === 0) return \"dormant\";\n if (score >= 0.55) return \"high\";\n if (score >= 0.2) return \"medium\";\n return \"low\";\n}\n\nfunction isPruneCandidate(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n tier: ImpactTier,\n): boolean {\n // A sensor or any applied outcome means the memory earns its keep.\n if (fm.sensor || usage.applied_count > 0) return false;\n if (isDeadStatus(fm)) return true;\n // More rejected than read = actively unhelpful.\n if (usage.rejected_count > 0 && usage.rejected_count >= usage.read_count) return true;\n // Never used and gone dormant = dead weight.\n if (tier === \"dormant\" && usage.read_count === 0) return true;\n return false;\n}\n\nfunction round3(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\n/** Sort comparator: highest impact first, prune candidates last on ties. */\nexport function compareImpact(a: ImpactScore, b: ImpactScore): number {\n if (b.score !== a.score) return b.score - a.score;\n if (a.pruneCandidate !== b.pruneCandidate) return a.pruneCandidate ? 1 : -1;\n return 0;\n}\n\nexport interface ImpactSummary {\n total: number;\n high: number;\n medium: number;\n low: number;\n dormant: number;\n prune_candidates: number;\n}\n\n/** Roll up a set of impact scores into tier counts. */\nexport function summarizeImpact(scores: ImpactScore[]): ImpactSummary {\n const summary: ImpactSummary = {\n total: scores.length,\n high: 0,\n medium: 0,\n low: 0,\n dormant: 0,\n prune_candidates: 0,\n };\n for (const s of scores) {\n summary[s.tier] += 1;\n if (s.pruneCandidate) summary.prune_candidates += 1;\n }\n return summary;\n}\n\nexport type FeedbackAdjustmentAction = \"none\" | \"downgrade-block-sensor\" | \"deprecate-memory\";\n\nexport interface FeedbackAdjustment {\n action: FeedbackAdjustmentAction;\n reason: string;\n}\n\nexport interface FeedbackAdjustmentOptions {\n /** Rejections needed before deprecating a memory with no positive outcomes. Defaults to 2. */\n rejectionThreshold?: number;\n}\n\n/**\n * Turn explicit human rejection (`mem_feedback outcome=rejected`) into a deterministic\n * noise-reduction action. Pure: callers decide whether to persist the returned change.\n */\nexport function recommendFeedbackAdjustment(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n options: FeedbackAdjustmentOptions = {},\n): FeedbackAdjustment {\n const rejectionThreshold = options.rejectionThreshold ?? 2;\n const hasPositiveOutcome = usage.applied_count > 0 || usage.prevented_count > 0;\n\n if (fm.sensor?.severity === \"block\" && usage.rejected_count >= 1) {\n return {\n action: \"downgrade-block-sensor\",\n reason: \"A human contested a blocking guardrail; downgrade it to warn so the gate stays helpful while the lesson is reviewed.\",\n };\n }\n\n if (!hasPositiveOutcome && usage.rejected_count >= rejectionThreshold) {\n return {\n action: \"deprecate-memory\",\n reason: `${usage.rejected_count} rejection(s) and no applied/prevented outcomes; deprecate until the lesson is refined.`,\n };\n }\n\n return { action: \"none\", reason: \"No automatic adjustment needed.\" };\n}\n\nexport function applyFeedbackAdjustment(\n fm: MemoryFrontmatter,\n adjustment: FeedbackAdjustment,\n now: Date = new Date(),\n): MemoryFrontmatter {\n if (adjustment.action === \"none\") return fm;\n const tags = [...new Set([...fm.tags, \"feedback-contested\"])];\n if (adjustment.action === \"downgrade-block-sensor\" && fm.sensor) {\n return {\n ...fm,\n tags,\n verified_at: now.toISOString(),\n sensor: { ...fm.sensor, severity: \"warn\" },\n };\n }\n if (adjustment.action === \"deprecate-memory\") {\n return {\n ...fm,\n tags,\n status: \"deprecated\",\n stale_reason: adjustment.reason,\n verified_at: now.toISOString(),\n };\n }\n return fm;\n}\n","/**\n * Prevention event log — the time-series behind hAIve's OUTCOME metric.\n *\n * `usage.json` keeps a cumulative `prevented_count` per memory (cheap, drives impact). This log\n * keeps one append-only record PER catch, with a timestamp, so we can answer questions a counter\n * can't: how is prevention trending over time, and which lessons keep getting re-introduced after\n * capture (recurrence). Lives in `.ai/.cache/` (gitignored telemetry) — never committed, never\n * churns a release.\n */\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { LoadedMemory } from \"./loader.js\";\nimport type { HaivePaths } from \"./paths.js\";\nimport {\n getUsage,\n loadUsageIndex,\n recordPrevention,\n saveUsageIndex,\n type UsageIndex,\n} from \"./usage.js\";\n\nexport type PreventionSource = \"sensor\" | \"anti-pattern\";\n\nexport interface PreventionEvent {\n /** ISO timestamp of the catch. */\n at: string;\n /** Memory id whose lesson fired. */\n id: string;\n /** Which gate path recorded it. */\n source: PreventionSource;\n}\n\nexport function preventionLogPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", \"prevention-log.jsonl\");\n}\n\n/** Append one catch to the log. Best-effort, creates the dir on demand. */\nexport async function appendPreventionEvent(paths: HaivePaths, event: PreventionEvent): Promise<void> {\n const file = preventionLogPath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n await appendFile(file, JSON.stringify(event) + \"\\n\", \"utf8\");\n}\n\n/**\n * THE single recorder for \"a documented lesson intercepted a real mistake\". Every gate path —\n * the installed git-hook gate (`enforce check`), the standalone `haive sensors check`, and the\n * `anti_patterns_check` MCP tool — funnels its fired memory ids through here so prevention is\n * recorded once and identically, not bolted onto each entry point (it used to leak: the git-hook\n * gate blocked but never recorded — see the harness-positioning gotcha).\n *\n * Bumps `prevented_count` in usage.json (debounced per memory via {@link recordPrevention}) AND\n * appends one timestamped event per NEW catch to the prevention log. Best-effort: a telemetry\n * write must never break a commit, so failures are swallowed. Returns the ids actually recorded\n * (i.e. not debounced), so callers can report \"caught for you\" without re-counting.\n */\nexport async function recordPreventionHits(\n paths: HaivePaths,\n firedIds: string[],\n source: PreventionSource,\n now: Date = new Date(),\n): Promise<string[]> {\n const unique = [...new Set(firedIds)].filter(Boolean);\n if (unique.length === 0) return [];\n const usage = await loadUsageIndex(paths).catch(() => null);\n if (!usage) return [];\n const recordedIds: string[] = [];\n for (const id of unique) {\n if (recordPrevention(usage, id, now.getTime())) recordedIds.push(id);\n }\n if (recordedIds.length === 0) return [];\n await saveUsageIndex(paths, usage).catch(() => { /* best-effort telemetry */ });\n const at = now.toISOString();\n for (const id of recordedIds) {\n await appendPreventionEvent(paths, { at, id, source }).catch(() => { /* best-effort */ });\n }\n return recordedIds;\n}\n\n/** Read all catch events (skips malformed lines). */\nexport async function loadPreventionEvents(paths: HaivePaths): Promise<PreventionEvent[]> {\n const file = preventionLogPath(paths);\n if (!existsSync(file)) return [];\n const raw = await readFile(file, \"utf8\").catch(() => \"\");\n const events: PreventionEvent[] = [];\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const e = JSON.parse(trimmed) as PreventionEvent;\n if (e && typeof e.at === \"string\" && typeof e.id === \"string\") events.push(e);\n } catch {\n // skip a corrupt line rather than fail the whole read\n }\n }\n return events;\n}\n\n// ── Pure analytics over the event log ───────────────────────────────────────\n\nexport interface PreventionTrend {\n /** Catches in the last 7 days. */\n last_7d: number;\n /** Catches in the last 30 days. */\n last_30d: number;\n /** Catch counts per ISO week, oldest → newest, for the last N weeks (default 6). */\n weekly: number[];\n}\n\nconst MS_PER_DAY = 86_400_000;\n\nexport function computePreventionTrend(\n events: PreventionEvent[],\n now: Date = new Date(),\n weeks = 6,\n): PreventionTrend {\n const nowMs = now.getTime();\n let last7 = 0;\n let last30 = 0;\n const weekly = new Array<number>(weeks).fill(0);\n for (const e of events) {\n const t = Date.parse(e.at);\n if (!Number.isFinite(t)) continue;\n const ageDays = (nowMs - t) / MS_PER_DAY;\n if (ageDays < 0) continue;\n if (ageDays <= 7) last7 += 1;\n if (ageDays <= 30) last30 += 1;\n const weekIdx = weeks - 1 - Math.floor(ageDays / 7);\n if (weekIdx >= 0 && weekIdx < weeks) weekly[weekIdx] = (weekly[weekIdx] ?? 0) + 1;\n }\n return { last_7d: last7, last_30d: last30, weekly };\n}\n\nexport interface RecurrenceRow {\n id: string;\n /** Total catches for this memory. */\n catches: number;\n /** Number of distinct UTC days the lesson fired — the recurrence signal. */\n distinct_days: number;\n last_at: string;\n}\n\nexport interface RecurrenceReport {\n /**\n * Memories whose lesson was caught on >= 2 distinct days — i.e. the mistake was RE-INTRODUCED\n * after it had already been captured and caught once. A high count means a recurring problem the\n * team keeps reintroducing (the guardrail is earning its keep, and the root cause may need a\n * stronger fix than a memory).\n */\n recurring_count: number;\n top: RecurrenceRow[];\n}\n\nexport function computeRecurrence(events: PreventionEvent[]): RecurrenceReport {\n const byId = new Map<string, { catches: number; days: Set<string>; last: string }>();\n for (const e of events) {\n const cur = byId.get(e.id) ?? { catches: 0, days: new Set<string>(), last: e.at };\n cur.catches += 1;\n cur.days.add(e.at.slice(0, 10));\n if (e.at > cur.last) cur.last = e.at;\n byId.set(e.id, cur);\n }\n const rows: RecurrenceRow[] = [];\n for (const [id, v] of byId) {\n if (v.days.size >= 2) {\n rows.push({ id, catches: v.catches, distinct_days: v.days.size, last_at: v.last });\n }\n }\n rows.sort((a, b) => b.distinct_days - a.distinct_days || b.catches - a.catches);\n return { recurring_count: rows.length, top: rows };\n}\n\nexport interface BriefingProofLineOptions {\n /** End of the reporting window. Defaults to now. */\n now?: Date;\n /** Window size in days. Defaults to 30 (\"this month\" in product copy). */\n days?: number;\n}\n\n/**\n * Coordination point for Lot C: turn prevention events into one compact proof line\n * suitable for get_briefing, without coupling this lot to the MCP tool.\n */\nexport function briefingProofLine(\n events: PreventionEvent[],\n options: BriefingProofLineOptions = {},\n): string | null {\n const now = options.now ?? new Date();\n const days = options.days ?? 30;\n const since = now.getTime() - days * MS_PER_DAY;\n let count = 0;\n for (const e of events) {\n const t = Date.parse(e.at);\n if (!Number.isFinite(t)) continue;\n if (t >= since && t <= now.getTime()) count += 1;\n }\n if (count === 0) return null;\n return `This harness prevented ${count} repeated mistake${count === 1 ? \"\" : \"s\"} in the last ${days} days.`;\n}\n\nexport interface CaughtForYouOptions {\n /** Only include events at or after this instant. */\n since?: string | Date;\n /** Only include events at or before this instant. Defaults to now. */\n now?: Date;\n /** Max rows in the summary. Defaults to 5. */\n limit?: number;\n}\n\nexport interface CaughtForYouRow {\n id: string;\n title: string;\n source: PreventionSource;\n catches: number;\n previous_count: number;\n current_count: number;\n last_at: string;\n}\n\nexport interface CaughtForYouSummary {\n total_catches: number;\n since: string | null;\n until: string;\n rows: CaughtForYouRow[];\n}\n\nfunction titleFromMemory(loaded: LoadedMemory | undefined): string {\n if (!loaded) return \"\";\n for (const line of loaded.memory.body.split(\"\\n\")) {\n const heading = /^#+\\s*(.+)$/.exec(line.trim());\n if (heading) return heading[1]!.trim().slice(0, 96);\n }\n for (const line of loaded.memory.body.split(\"\\n\")) {\n const t = line.trim();\n if (t) return t.replace(/^[-*]\\s*/, \"\").slice(0, 96);\n }\n return \"\";\n}\n\nfunction sourceRank(source: PreventionSource): number {\n return source === \"anti-pattern\" ? 0 : 1;\n}\n\n/** Build the end-of-session \"caught for you\" scene from prevention events. Pure. */\nexport function summarizeCaughtForYou(\n events: PreventionEvent[],\n memories: LoadedMemory[],\n usage: UsageIndex,\n options: CaughtForYouOptions = {},\n): CaughtForYouSummary {\n const until = options.now ?? new Date();\n const sinceMs =\n options.since === undefined\n ? null\n : options.since instanceof Date\n ? options.since.getTime()\n : Date.parse(options.since);\n const untilMs = until.getTime();\n const byIdSource = new Map<string, { id: string; source: PreventionSource; catches: number; last_at: string }>();\n\n for (const e of events) {\n const t = Date.parse(e.at);\n if (!Number.isFinite(t)) continue;\n if (sinceMs !== null && Number.isFinite(sinceMs) && t < sinceMs) continue;\n if (t > untilMs) continue;\n const key = `${e.id}\\0${e.source}`;\n const current = byIdSource.get(key) ?? { id: e.id, source: e.source, catches: 0, last_at: e.at };\n current.catches += 1;\n if (e.at > current.last_at) current.last_at = e.at;\n byIdSource.set(key, current);\n }\n\n const memoryById = new Map(memories.map((m) => [m.memory.frontmatter.id, m]));\n const rows = [...byIdSource.values()]\n .map((row): CaughtForYouRow => {\n const current = getUsage(usage, row.id).prevented_count;\n const previous = Math.max(0, current - row.catches);\n return {\n id: row.id,\n title: titleFromMemory(memoryById.get(row.id)) || row.id,\n source: row.source,\n catches: row.catches,\n previous_count: previous,\n current_count: current,\n last_at: row.last_at,\n };\n })\n .sort((a, b) => b.last_at.localeCompare(a.last_at) || sourceRank(a.source) - sourceRank(b.source))\n .slice(0, options.limit ?? 5);\n\n return {\n total_catches: [...byIdSource.values()].reduce((sum, row) => sum + row.catches, 0),\n since: sinceMs !== null && Number.isFinite(sinceMs) ? new Date(sinceMs).toISOString() : null,\n until: until.toISOString(),\n rows,\n };\n}\n\n/** Render a compact human-readable block for CLI/session recaps. */\nexport function renderCaughtForYou(summary: CaughtForYouSummary): string | null {\n if (summary.total_catches === 0 || summary.rows.length === 0) return null;\n const lines = [\n `Caught for you: ${summary.total_catches} prevented repeat${summary.total_catches === 1 ? \"\" : \"s\"} this session.`,\n ];\n for (const row of summary.rows) {\n const gate = row.source === \"anti-pattern\" ? \"Blocked\" : \"Caught\";\n lines.push(\n `- ${gate}: ${row.title} (${row.id}). Prevention ${row.previous_count}->${row.current_count}.`,\n );\n }\n return lines.join(\"\\n\");\n}\n","/**\n * Project-context emission throttle — a token saver for long sessions.\n *\n * `get_briefing` re-emits the full `.ai/project-context.md` on every call. Across a 10-call session\n * that re-sends the same ~1.5k tokens nine times for nothing. This records a tiny marker (content\n * hash + timestamp, in gitignored `.ai/.cache/`) so a briefing can skip re-emitting an UNCHANGED\n * context within a short window — the agent already has it from the earlier call.\n */\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\n/** How long an emitted project context is considered \"still fresh in the agent's context\". */\nexport const PROJECT_CONTEXT_THROTTLE_MS = 8 * 60 * 1000;\n\nfunction throttleMarkerPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", \"briefing-context.json\");\n}\n\nexport function hashProjectContext(content: string): string {\n return createHash(\"sha1\").update(content).digest(\"hex\").slice(0, 16);\n}\n\n/** True if an identical project-context body was already emitted within the throttle window. */\nexport async function projectContextRecentlyEmitted(\n paths: HaivePaths,\n hash: string,\n now: number = Date.now(),\n): Promise<boolean> {\n const file = throttleMarkerPath(paths);\n if (!existsSync(file)) return false;\n try {\n const m = JSON.parse(await readFile(file, \"utf8\")) as { hash?: string; at?: string };\n if (m.hash !== hash || !m.at) return false;\n return now - Date.parse(m.at) < PROJECT_CONTEXT_THROTTLE_MS;\n } catch {\n return false;\n }\n}\n\n/** Record that this exact project-context body was just emitted. Best-effort. */\nexport async function recordProjectContextEmission(\n paths: HaivePaths,\n hash: string,\n now: number = Date.now(),\n): Promise<void> {\n const file = throttleMarkerPath(paths);\n await mkdir(path.dirname(file), { recursive: true }).catch(() => { /* ignore */ });\n await writeFile(file, JSON.stringify({ hash, at: new Date(now).toISOString() }), \"utf8\").catch(() => { /* ignore */ });\n}\n","import type { LoadedMemory } from \"./loader.js\";\n\n/**\n * A rigorous, model-free, repeatable evaluation of hAIve's core promise: surfacing\n * the right knowledge and guardrails at the right moment. Unlike the agent benchmark\n * (which parses human-written reports), this is deterministic and CI-runnable — it\n * produces a numeric quality score from labeled cases, so a regression in ranking or\n * sensor coverage fails the build instead of silently degrading every agent session.\n *\n * Two case families:\n * - RETRIEVAL — given a task (+optional files/symbols), do the expected memories\n * surface in the briefing top-k? Measured by recall and mean reciprocal rank.\n * - SENSORS — given a known-bad diff, does the expected memory's sensor fire?\n * Measured by catch-rate.\n *\n * This module is pure: it defines the case/result types, the scoring math, and case\n * synthesis from a repo's own anchored memories. Orchestration (calling get_briefing\n * / anti_patterns_check) lives in the CLI, since core cannot depend on the MCP layer.\n */\n\nexport interface RetrievalCase {\n name: string;\n task: string;\n files?: string[];\n symbols?: string[];\n /** Memory ids that SHOULD surface in the briefing for this case. */\n expect_ids: string[];\n}\n\nexport interface SensorCase {\n name: string;\n /** Unified diff (or added-line text) the sensors run against. */\n diff: string;\n paths?: string[];\n /** Memory ids whose sensor SHOULD fire on this diff. */\n expect_fire_ids: string[];\n}\n\nexport interface EvalSpec {\n retrieval?: RetrievalCase[];\n sensors?: SensorCase[];\n}\n\nexport interface RetrievalCaseResult {\n name: string;\n expect_ids: string[];\n /** Surfaced memory ids, in ranked order, capped at k. */\n surfaced_ids: string[];\n hits: string[];\n misses: string[];\n precision: number;\n recall: number;\n /** 1-based rank of the first expected id among surfaced ids; null if none surfaced. */\n best_rank: number | null;\n}\n\nexport interface SensorCaseResult {\n name: string;\n expect_fire_ids: string[];\n fired_ids: string[];\n hits: string[];\n misses: string[];\n recall: number;\n}\n\nexport interface RetrievalAggregate {\n cases: RetrievalCaseResult[];\n /**\n * Top-k precision = expected hits ÷ surfaced results. Inherently LOW when only ~1 memory is\n * expected per case but k results are surfaced (e.g. 1/8 ≈ 0.12) — this is a top-k artifact, not\n * a quality defect. Retrieval quality is judged by `mean_recall` and `mrr`; precision is NOT part\n * of the headline eval score (see `scoreEval`). Reported for completeness only.\n */\n mean_precision: number;\n mean_recall: number;\n /** Mean reciprocal rank of the first expected hit — rewards ranking the right memory high. */\n mrr: number;\n}\n\nexport interface SensorAggregate {\n cases: SensorCaseResult[];\n catch_rate: number;\n}\n\nexport interface EvalReport {\n retrieval: RetrievalAggregate | null;\n sensors: SensorAggregate | null;\n /** Overall quality score 0..100. */\n score: number;\n}\n\nfunction round3(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\nfunction uniq(ids: string[]): string[] {\n return [...new Set(ids)];\n}\n\n/**\n * Score one retrieval case from the (ranked) ids the briefing surfaced.\n * `surfacedRanked` should already be capped to the top-k the caller cares about.\n */\nexport function scoreRetrievalCase(\n name: string,\n expectIds: string[],\n surfacedRanked: string[],\n): RetrievalCaseResult {\n const expect = uniq(expectIds);\n const surfaced = uniq(surfacedRanked);\n const surfacedSet = new Set(surfaced);\n const hits = expect.filter((id) => surfacedSet.has(id));\n const misses = expect.filter((id) => !surfacedSet.has(id));\n\n let bestRank: number | null = null;\n for (let i = 0; i < surfaced.length; i++) {\n if (expect.includes(surfaced[i]!)) {\n bestRank = i + 1;\n break;\n }\n }\n\n return {\n name,\n expect_ids: expect,\n surfaced_ids: surfaced,\n hits,\n misses,\n precision: surfaced.length === 0 ? 0 : round3(hits.length / surfaced.length),\n recall: expect.length === 0 ? 1 : round3(hits.length / expect.length),\n best_rank: bestRank,\n };\n}\n\nexport function aggregateRetrieval(cases: RetrievalCaseResult[]): RetrievalAggregate {\n const n = cases.length;\n const mean = (sel: (c: RetrievalCaseResult) => number): number =>\n n === 0 ? 0 : round3(cases.reduce((s, c) => s + sel(c), 0) / n);\n return {\n cases,\n mean_precision: mean((c) => c.precision),\n mean_recall: mean((c) => c.recall),\n mrr: mean((c) => (c.best_rank ? 1 / c.best_rank : 0)),\n };\n}\n\nexport function scoreSensorCase(\n name: string,\n expectFireIds: string[],\n firedIds: string[],\n): SensorCaseResult {\n const expect = uniq(expectFireIds);\n const fired = uniq(firedIds);\n const firedSet = new Set(fired);\n const hits = expect.filter((id) => firedSet.has(id));\n const misses = expect.filter((id) => !firedSet.has(id));\n return {\n name,\n expect_fire_ids: expect,\n fired_ids: fired,\n hits,\n misses,\n recall: expect.length === 0 ? 1 : round3(hits.length / expect.length),\n };\n}\n\nexport function aggregateSensors(cases: SensorCaseResult[]): SensorAggregate {\n const totalExpected = cases.reduce((s, c) => s + c.expect_fire_ids.length, 0);\n const totalHits = cases.reduce((s, c) => s + c.hits.length, 0);\n return {\n cases,\n catch_rate: totalExpected === 0 ? 1 : round3(totalHits / totalExpected),\n };\n}\n\n/** Combine retrieval + sensor aggregates into a single 0..100 quality score. */\nexport function overallScore(\n retrieval: RetrievalAggregate | null,\n sensors: SensorAggregate | null,\n): number {\n if (retrieval && sensors) {\n return Math.round((0.5 * retrieval.mean_recall + 0.2 * retrieval.mrr + 0.3 * sensors.catch_rate) * 100);\n }\n if (retrieval) {\n return Math.round((0.7 * retrieval.mean_recall + 0.3 * retrieval.mrr) * 100);\n }\n if (sensors) {\n return Math.round(sensors.catch_rate * 100);\n }\n return 0;\n}\n\nexport function buildReport(\n retrieval: RetrievalAggregate | null,\n sensors: SensorAggregate | null,\n): EvalReport {\n return { retrieval, sensors, score: overallScore(retrieval, sensors) };\n}\n\n/**\n * Baseline / compare — makes the \"hAIve improves retrieval by N%\" claim reproducible.\n *\n * `haive eval --baseline` snapshots a report; `--compare` re-runs and diffs against it,\n * so a ranking/sensor regression is a number, not a vibe. Pure math here; the CLI does I/O.\n */\nexport interface MetricDelta {\n baseline: number;\n current: number;\n /** current − baseline (positive = improvement for all these metrics). */\n delta: number;\n}\n\nexport interface EvalDelta {\n score: MetricDelta;\n mean_recall: MetricDelta | null;\n mrr: MetricDelta | null;\n catch_rate: MetricDelta | null;\n /** True when the overall score dropped vs the baseline. */\n regressed: boolean;\n /** True when the overall score rose vs the baseline. */\n improved: boolean;\n}\n\nfunction metricDelta(baseline: number, current: number): MetricDelta {\n return { baseline: round3(baseline), current: round3(current), delta: round3(current - baseline) };\n}\n\n/** Diff a current report against a baseline. Pure. */\nexport function compareEvalReports(baseline: EvalReport, current: EvalReport): EvalDelta {\n const recall =\n baseline.retrieval && current.retrieval\n ? metricDelta(baseline.retrieval.mean_recall, current.retrieval.mean_recall)\n : null;\n const mrr =\n baseline.retrieval && current.retrieval\n ? metricDelta(baseline.retrieval.mrr, current.retrieval.mrr)\n : null;\n const catchRate =\n baseline.sensors && current.sensors\n ? metricDelta(baseline.sensors.catch_rate, current.sensors.catch_rate)\n : null;\n return {\n score: metricDelta(baseline.score, current.score),\n mean_recall: recall,\n mrr,\n catch_rate: catchRate,\n regressed: current.score < baseline.score,\n improved: current.score > baseline.score,\n };\n}\n\n/** Extract a short task-like title from a memory body (first heading or first line). */\nexport function titleFromBody(body: string): string {\n const lines = body.split(\"\\n\");\n for (const line of lines) {\n const heading = /^#+\\s*(.+)$/.exec(line.trim());\n if (heading) return heading[1]!.trim().slice(0, 120);\n }\n for (const line of lines) {\n const t = line.trim();\n if (t) return t.replace(/^[-*]\\s*/, \"\").slice(0, 120);\n }\n return \"\";\n}\n\nexport interface SelfEvalOptions {\n /** Include each memory's anchor paths as the case files (tests anchored retrieval). */\n includeFiles?: boolean;\n /** Skip memories with these statuses (default: stale/deprecated/rejected). */\n skipStatuses?: string[];\n}\n\n/**\n * Synthesize retrieval cases from a repo's own anchored memories — zero-setup eval.\n * Each anchored, non-recap, non-dead memory becomes a case: \"when working on the\n * file(s) this memory anchors, with its title as the task, does hAIve surface it?\".\n * With `includeFiles: false` it becomes a harder semantic-only probe (title alone).\n */\nexport function synthesizeSelfEvalCases(\n memories: LoadedMemory[],\n options: SelfEvalOptions = {},\n): RetrievalCase[] {\n const includeFiles = options.includeFiles ?? true;\n const skip = new Set(options.skipStatuses ?? [\"stale\", \"deprecated\", \"rejected\"]);\n const cases: RetrievalCase[] = [];\n for (const { memory } of memories) {\n const fm = memory.frontmatter;\n if (fm.type === \"session_recap\") continue;\n if (skip.has(fm.status)) continue;\n const paths = fm.anchor.paths;\n if (paths.length === 0) continue;\n const task = titleFromBody(memory.body) || fm.id;\n cases.push({\n name: fm.id,\n task,\n ...(includeFiles ? { files: paths } : {}),\n expect_ids: [fm.id],\n });\n }\n return cases;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport type { MemoryUsage } from \"./usage.js\";\n\nexport type ConfidenceLevel =\n | \"unverified\"\n | \"low\"\n | \"trusted\"\n | \"authoritative\"\n | \"stale\";\n\nexport interface ConfidenceThresholds {\n trustedReads: number;\n authoritativeReads: number;\n /** Days without a read after which confidence drops one tier (authoritative → trusted). */\n decayDays: number;\n /** Days without a read after which confidence drops two tiers (e.g. authoritative → low). */\n hardDecayDays: number;\n}\n\nexport const DEFAULT_CONFIDENCE_THRESHOLDS: ConfidenceThresholds = {\n trustedReads: 3,\n authoritativeReads: 10,\n decayDays: 180,\n hardDecayDays: 365,\n};\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/**\n * Compute the trust level of a memory.\n *\n * Base tier is derived from `status + read_count`:\n * - draft → unverified\n * - proposed (low reads) → low\n * - proposed (3+ reads) → trusted\n * - validated (low reads) → trusted\n * - validated (10+ reads) → authoritative\n * - stale / deprecated / rejected → stale\n *\n * On top of the base tier, a TIME DECAY is applied: a memory that has not been\n * read in `decayDays` (default 180) drops one tier, and one not read in\n * `hardDecayDays` (default 365) drops two tiers. The clock starts at\n * `last_read_at` if any, otherwise `created_at` from the frontmatter.\n *\n * The decay never crosses into `stale` (we keep that signal reserved for the\n * verifier). The intent is to surface \"this used to be authoritative but\n * nobody has touched it in a year — verify before quoting it\" without\n * pretending the memory is wrong.\n */\nexport function deriveConfidence(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n thresholds: ConfidenceThresholds = DEFAULT_CONFIDENCE_THRESHOLDS,\n now: Date = new Date(),\n): ConfidenceLevel {\n if (fm.status === \"stale\" || fm.status === \"deprecated\" || fm.status === \"rejected\") return \"stale\";\n\n const baseLevel = baseConfidence(fm, usage, thresholds);\n\n // Apply decay only to tiers worth lowering.\n if (baseLevel !== \"authoritative\" && baseLevel !== \"trusted\") return baseLevel;\n\n const anchor = usage.last_read_at ?? fm.created_at;\n const ageDays = (now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY;\n if (Number.isNaN(ageDays) || ageDays <= 0) return baseLevel;\n\n if (ageDays >= thresholds.hardDecayDays) {\n // Two-tier drop. authoritative → low, trusted → low.\n return \"low\";\n }\n if (ageDays >= thresholds.decayDays) {\n if (baseLevel === \"authoritative\") return \"trusted\";\n if (baseLevel === \"trusted\") return \"low\";\n }\n return baseLevel;\n}\n\nfunction baseConfidence(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n thresholds: ConfidenceThresholds,\n): ConfidenceLevel {\n if (fm.status === \"validated\") {\n return usage.read_count >= thresholds.authoritativeReads\n ? \"authoritative\"\n : \"trusted\";\n }\n if (fm.status === \"proposed\") {\n return usage.read_count >= thresholds.trustedReads ? \"trusted\" : \"low\";\n }\n // draft\n return \"unverified\";\n}\n\nexport interface AutoPromoteRule {\n /** Minimum read_count to promote proposed → validated. */\n minReads: number;\n /** Maximum rejected_count tolerated (memories with more rejections never auto-promote). */\n maxRejections: number;\n}\n\nexport const DEFAULT_AUTO_PROMOTE_RULE: AutoPromoteRule = {\n minReads: 5,\n maxRejections: 0,\n};\n\nexport function isAutoPromoteEligible(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n rule: AutoPromoteRule = DEFAULT_AUTO_PROMOTE_RULE,\n): boolean {\n if (fm.status !== \"proposed\") return false;\n if (usage.rejected_count > rule.maxRejections) return false;\n return usage.read_count >= rule.minReads;\n}\n","/**\n * Distinctive-token corroboration for the anti-pattern gate.\n *\n * The pre-commit gate used to hard-block whenever a diff shared ANY ≥4-char token\n * with an anchored gotcha's body. That fires on ubiquitous domain words (\"memory\",\n * \"sensor\", \"scope\", \"input\", \"version\") and on version-bump diffs — blocking agents\n * for nothing. The fix: a `literal` overlap only corroborates a BLOCK when at least\n * one shared token is *distinctive* to that gotcha — i.e. rare across the gotcha\n * corpus (low document frequency), like `BigInt`, `open-in-view`, `rec_7`. Common\n * words can still surface the warning for review; they just can't hard-block.\n *\n * Pure module (no I/O), TF-IDF-style. Unit-tested in `test/distinctive.test.ts`.\n */\n\n/**\n * Language keywords + ubiquitous code words that would match almost any memory body\n * and so carry no distinguishing signal. Shared by the diff tokenizer and the\n * distinctiveness check so \"literal\" stays meaningful.\n */\nexport const CODE_STOPWORDS = new Set([\n \"import\", \"export\", \"function\", \"return\", \"const\", \"let\", \"var\", \"class\", \"public\",\n \"private\", \"protected\", \"static\", \"this\", \"true\", \"false\", \"null\", \"undefined\", \"void\",\n \"async\", \"await\", \"from\", \"type\", \"interface\", \"extends\", \"implements\", \"number\", \"string\",\n \"boolean\", \"value\", \"default\", \"case\", \"break\", \"continue\", \"throw\", \"catch\", \"finally\",\n \"else\", \"while\", \"for\", \"new\", \"super\", \"yield\", \"module\", \"require\", \"console\",\n]);\n\n/** Minimum token length kept for word-level matching (shorter tokens are too noisy). */\nexport const MIN_WORD_LEN = 4;\n\n/** Split text into lowercase word tokens (>= MIN_WORD_LEN, excluding code stopwords). */\nexport function tokenizeWords(text: string): string[] {\n return text\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length >= MIN_WORD_LEN && !CODE_STOPWORDS.has(t));\n}\n\nexport interface DocFrequency {\n /** token -> number of documents (memory bodies) it appears in */\n df: Map<string, number>;\n /** total number of documents */\n total: number;\n}\n\n/** Build per-token document frequency across a corpus of memory bodies. */\nexport function buildDocFrequency(bodies: string[]): DocFrequency {\n const df = new Map<string, number>();\n for (const body of bodies) {\n const unique = new Set(tokenizeWords(body));\n for (const tok of unique) df.set(tok, (df.get(tok) ?? 0) + 1);\n }\n return { df, total: bodies.length };\n}\n\n/**\n * Document-frequency cap at/below which a token counts as distinctive. Deliberately\n * strict — \"distinctive\" means *rare* (≈ the bottom 10% of the corpus), with a floor\n * of 1 so a token appearing in a single memory is always distinctive. Strictness is\n * intentional: blocking is the aggressive action, so we under-block rather than fire\n * on a word that several gotchas happen to share.\n */\nexport function distinctiveCap(total: number): number {\n return Math.max(1, Math.floor(0.1 * total));\n}\n\n/** True when `token` is distinctive (rare) within the corpus. */\nexport function isDistinctiveToken(token: string, freq: DocFrequency): boolean {\n const tok = token.toLowerCase();\n if (tok.length < MIN_WORD_LEN || CODE_STOPWORDS.has(tok)) return false;\n const df = freq.df.get(tok);\n if (df === undefined) return true; // not seen elsewhere in the corpus → distinctive\n return df <= distinctiveCap(freq.total);\n}\n\n/**\n * True when the added diff text shares at least one *distinctive* word token with the\n * memory body. This is the precise corroboration the block decision should require:\n * \"the change actually contains the specific thing this gotcha warns about\", not\n * \"the change happens to mention a common domain word\".\n */\nexport function diffHasDistinctiveOverlap(\n addedDiffText: string,\n memoryBody: string,\n freq: DocFrequency,\n): boolean {\n const memoryTokens = new Set(tokenizeWords(memoryBody));\n if (memoryTokens.size === 0) return false;\n for (const tok of new Set(tokenizeWords(addedDiffText))) {\n if (memoryTokens.has(tok) && isDistinctiveToken(tok, freq)) return true;\n }\n return false;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport { pathsOverlap } from \"./relevance.js\";\n\n/**\n * Progressive disclosure for `skill` memories.\n *\n * Skills are reusable playbooks. Surfacing all of them on every briefing wastes the\n * instruction budget and buries the relevant one. A skill with an `activation` block\n * is disclosed ONLY when it is relevant to the current task/files; a skill without\n * one keeps the legacy always-eligible behavior. This module is pure (no I/O).\n */\n\nexport interface ActivationContext {\n task?: string;\n files?: string[];\n}\n\nexport interface SkillActivation {\n applicable: boolean;\n activated: boolean;\n reasons: string[];\n}\n\nexport function isSkill(fm: Pick<MemoryFrontmatter, \"type\">): boolean {\n return fm.type === \"skill\";\n}\n\n/**\n * Decide whether a skill should be disclosed for the given context.\n * For non-skills, or skills with no `activation` block, returns `activated: true`\n * (never suppress them). Otherwise activates on `always`, a keyword substring match\n * against the task, or a glob match against the edited files.\n */\nexport function evaluateSkillActivation(\n fm: Pick<MemoryFrontmatter, \"type\" | \"activation\">,\n ctx: ActivationContext,\n): SkillActivation {\n if (!isSkill(fm)) return { applicable: false, activated: true, reasons: [] };\n const act = fm.activation;\n if (!act) return { applicable: false, activated: true, reasons: [\"no-activation\"] };\n\n const reasons: string[] = [];\n if (act.always) reasons.push(\"always\");\n\n const task = (ctx.task ?? \"\").toLowerCase();\n if (task) {\n for (const kw of act.keywords) {\n if (kw && task.includes(kw.toLowerCase())) {\n reasons.push(`keyword:${kw}`);\n break;\n }\n }\n }\n\n const files = ctx.files ?? [];\n if (files.length > 0) {\n outer: for (const glob of act.globs) {\n for (const f of files) {\n if (pathsOverlap(glob, f)) {\n reasons.push(`glob:${glob}`);\n break outer;\n }\n }\n }\n }\n\n return { applicable: true, activated: reasons.length > 0, reasons };\n}\n\n/** Convenience: true when a skill defines activation triggers that the context does NOT satisfy. */\nexport function isSkillSuppressed(\n fm: Pick<MemoryFrontmatter, \"type\" | \"activation\">,\n ctx: ActivationContext,\n): boolean {\n const result = evaluateSkillActivation(fm, ctx);\n return result.applicable && !result.activated;\n}\n","/**\n * Specificity (\"surprise\") scoring for memories.\n *\n * hAIve's measured value is preventing agents from reinventing — wrongly — the team's\n * NON-OBVIOUS, arbitrary decisions (e.g. \"public ids are internal id + 100000 prefixed AC-\",\n * \"the status field must be 'OK'/'KO'\"). A capable model already knows generic best practice\n * (\"use Decimal for money\", \"validate input\"), so surfacing that is pure token overhead.\n *\n * `specificityScore` is a cheap, deterministic heuristic that estimates how *unguessable* a\n * memory is: high when it contains concrete, arbitrary signal (string literals, code\n * identifiers, magic numbers, paths, ALLCAPS constants), low when it is generic prose.\n *\n * It is intentionally a heuristic, not a model call — used to (1) bias briefing ranking toward\n * unguessable knowledge, (2) keep a near-empty briefing cheap when nothing team-specific\n * matches, (3) lint low-value memories, and (4) filter auto-capture candidates.\n */\n\n/** Generic best-practice phrases a capable model already knows — low marginal value to surface. */\nconst GENERIC_PHRASES: readonly string[] = [\n \"validate input\", \"sanitize\", \"prepared statement\", \"parameterized quer\",\n \"never commit secret\", \"use environment variable\", \"handle error\", \"write test\",\n \"avoid sql injection\", \"escape html\", \"hash password\", \"use https\", \"least privilege\",\n \"do not hardcode\", \"don't hardcode\", \"single responsibility\", \"keep it dry\",\n \"follow best practice\", \"use meaningful names\", \"add error handling\", \"check for null\",\n \"use try/catch\", \"use async/await\", \"avoid magic number\", \"write clean code\",\n];\n\nconst STRING_LITERAL = /[\"'`][^\"'`\\n]{1,48}[\"'`]/g;\nconst BACKTICK_SPAN = /`[^`\\n]+`/g;\nconst CAMEL_CASE = /\\b[a-zA-Z_][a-zA-Z0-9_]*[a-z][A-Z][a-zA-Z0-9_]*\\b/g;\nconst SNAKE_CASE = /\\b[a-z][a-z0-9]*_[a-z0-9_]+\\b/g;\nconst DOTTED = /\\b\\w+\\.\\w+(?:\\.\\w+)*\\b/g;\nconst MAGIC_NUMBER = /\\b\\d{2,}\\b|\\b\\d+\\.\\d+\\b/g;\nconst FILE_PATH = /\\b[\\w./-]+\\.[a-z]{1,5}\\b/g;\nconst ALLCAPS_CONST = /\\b[A-Z]{2,}(?:_[A-Z0-9]+)+\\b|\\b[A-Z]{3,}\\b/g;\n\nfunction countMatches(text: string, re: RegExp): number {\n const m = text.match(re);\n return m ? m.length : 0;\n}\n\n/**\n * Estimate how unguessable / team-specific a memory body is, in [0, 1].\n * ~0 = generic advice a model already follows by default.\n * ~1 = arbitrary, repo-specific knowledge no model can infer.\n */\nexport function specificityScore(body: string): number {\n const text = (body ?? \"\").trim();\n if (text.length === 0) return 0;\n const lower = text.toLowerCase();\n const words = lower.split(/\\s+/).filter(Boolean).length || 1;\n\n let hits = 0;\n hits += countMatches(text, STRING_LITERAL) * 2;\n hits += countMatches(text, BACKTICK_SPAN) * 2;\n hits += countMatches(text, CAMEL_CASE);\n hits += countMatches(text, SNAKE_CASE);\n hits += countMatches(text, DOTTED);\n hits += countMatches(text, MAGIC_NUMBER);\n hits += countMatches(text, FILE_PATH);\n hits += countMatches(text, ALLCAPS_CONST);\n\n // Density of concrete signal. The denominator scales with length so a long generic\n // paragraph isn't rescued by a single identifier, while a short, dense rule scores high.\n let score = Math.min(1, hits / Math.max(6, words * 0.35));\n\n // A memory that reads like generic advice and carries little concrete signal is capped low.\n const generic = GENERIC_PHRASES.some((p) => lower.includes(p));\n if (generic && hits < 4) score = Math.min(score, 0.22);\n\n return score;\n}\n\n/**\n * True when a body uses generic best-practice phrasing a capable model already follows.\n * Used to SCOPE the LOW_VALUE lint: a low-density body is only \"guessable noise\" when it also\n * reads like generic advice. An arbitrary team *policy* can be prose-y yet unguessable (e.g.\n * \"UI text in English, user content in any language\") — that must NOT be flagged. Positive\n * evidence (a generic phrase) keeps the lint high-precision and kills that false positive.\n */\nexport function looksLikeGenericAdvice(body: string): boolean {\n const lower = (body ?? \"\").toLowerCase();\n return GENERIC_PHRASES.some((p) => lower.includes(p));\n}\n\n/** Default threshold below which a memory is considered likely-guessable (low marginal value). */\nexport const GUESSABLE_THRESHOLD = 0.3;\n\n/** True when a memory body looks like generic knowledge a capable model already has. */\nexport function isLikelyGuessable(body: string, threshold: number = GUESSABLE_THRESHOLD): boolean {\n return specificityScore(body) < threshold;\n}\n\n/**\n * Quality floor for SEEDED memories (stack packs, ingested findings) — the guard against shipping\n * low-value \"use const not var\" starter content. A seed earns its place only if it is either:\n * - ENFORCEABLE: it carries a hand-authored sensor (its value is the gate, not its prose), or\n * - SPECIFIC: it reads as a concrete framework/repo trap (specificity >= floor) and is NOT\n * generic best-practice prose a capable model already follows.\n * Used both at seed time (skip a memory that fails) and as a CI guard over the shipped pack library.\n *\n * The floor (0.2) is intentionally LOWER than {@link GUESSABLE_THRESHOLD} (0.3, used to lint claimed\n * team knowledge): a seed is explicitly background-priority framework REFERENCE, not a claim of\n * non-guessable team policy, so a concrete framework gotcha with a code example clears it — while\n * genuine garbage (\"use const\", \"write tests\") still scores ~0 and/or trips looksLikeGenericAdvice.\n */\nexport const SEED_QUALITY_FLOOR = 0.2;\n\nexport function meetsSeedQualityFloor(\n body: string,\n hasSensor: boolean,\n floor: number = SEED_QUALITY_FLOOR,\n): boolean {\n if (hasSensor) return true;\n if (looksLikeGenericAdvice(body)) return false;\n return specificityScore(body) >= floor;\n}\n","/**\n * Token budgeting helpers. We use the standard heuristic of ~4 chars per token,\n * which is conservative for English/code/markdown. Callers that need exact\n * counts should plug in a real tokenizer; this module only ever over-estimates,\n * so the user's hard limits are respected.\n */\n\nexport const CHARS_PER_TOKEN = 4;\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\nexport interface TruncateOptions {\n /** Maximum tokens allowed in the result (inclusive). */\n maxTokens: number;\n /** Marker inserted where content was dropped. */\n marker?: string;\n /** Where to keep characters from when truncating. Default: head. */\n mode?: \"head\" | \"tail\" | \"middle\";\n}\n\nexport interface TruncateResult {\n text: string;\n truncated: boolean;\n estimatedTokens: number;\n originalTokens: number;\n}\n\nconst DEFAULT_MARKER = \"\\n…[truncated]…\\n\";\n\nexport function truncateToTokens(\n input: string,\n options: TruncateOptions,\n): TruncateResult {\n const originalTokens = estimateTokens(input);\n const max = Math.max(0, options.maxTokens);\n if (originalTokens <= max) {\n return { text: input, truncated: false, estimatedTokens: originalTokens, originalTokens };\n }\n\n if (max === 0) {\n return { text: \"\", truncated: true, estimatedTokens: 0, originalTokens };\n }\n\n const marker = options.marker ?? DEFAULT_MARKER;\n const mode = options.mode ?? \"head\";\n const markerTokens = estimateTokens(marker);\n const budgetChars = Math.max(0, (max - markerTokens) * CHARS_PER_TOKEN);\n\n let result: string;\n if (budgetChars === 0) {\n result = \"\";\n } else if (mode === \"tail\") {\n result = marker + input.slice(input.length - budgetChars);\n } else if (mode === \"middle\") {\n const half = Math.floor(budgetChars / 2);\n result = input.slice(0, half) + marker + input.slice(input.length - half);\n } else {\n result = input.slice(0, budgetChars) + marker;\n }\n\n return {\n text: result,\n truncated: true,\n estimatedTokens: estimateTokens(result),\n originalTokens,\n };\n}\n\n/**\n * Allocate a global token budget across N parts with relative weights, then\n * truncate each part to its share. Returns parts in input order, paired with\n * truncate metadata.\n */\nexport interface BudgetPart {\n key: string;\n text: string;\n weight: number;\n mode?: TruncateOptions[\"mode\"];\n}\n\nexport interface BudgetSlice {\n key: string;\n text: string;\n truncated: boolean;\n estimatedTokens: number;\n originalTokens: number;\n allocatedTokens: number;\n}\n\nexport function allocateBudget(\n parts: BudgetPart[],\n maxTokens: number,\n): BudgetSlice[] {\n if (parts.length === 0) return [];\n const totalWeight = parts.reduce((s, p) => s + Math.max(0, p.weight), 0);\n if (totalWeight === 0) {\n return parts.map((p) => ({\n key: p.key,\n text: \"\",\n truncated: estimateTokens(p.text) > 0,\n estimatedTokens: 0,\n originalTokens: estimateTokens(p.text),\n allocatedTokens: 0,\n }));\n }\n\n // First pass: allocate by weight, but if a part's content fits in less than\n // its share, redistribute the surplus to others proportionally.\n const allocations = new Map<string, number>();\n let remaining = maxTokens;\n let remainingWeight = totalWeight;\n\n // Sort parts by share fit ascending so small ones consume their share first.\n const sortedByFit = [...parts]\n .map((p) => ({\n key: p.key,\n tokens: estimateTokens(p.text),\n share: (p.weight / totalWeight) * maxTokens,\n part: p,\n }))\n .sort((a, b) => a.tokens - b.tokens);\n\n for (const item of sortedByFit) {\n const myShare = remainingWeight > 0\n ? (item.part.weight / remainingWeight) * remaining\n : 0;\n const grant = Math.min(item.tokens, Math.floor(myShare));\n allocations.set(item.key, grant);\n remaining -= grant;\n remainingWeight -= item.part.weight;\n }\n\n return parts.map((p) => {\n const allocated = allocations.get(p.key) ?? 0;\n const truncated = truncateToTokens(p.text, {\n maxTokens: allocated,\n mode: p.mode ?? \"head\",\n });\n return {\n key: p.key,\n text: truncated.text,\n truncated: truncated.truncated,\n estimatedTokens: truncated.estimatedTokens,\n originalTokens: truncated.originalTokens,\n allocatedTokens: allocated,\n };\n });\n}\n","import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const CODE_MAP_FILE = \"code-map.json\";\n\nexport type CodeExportKind =\n | \"function\"\n | \"class\"\n | \"interface\"\n | \"type\"\n | \"const\"\n | \"enum\"\n | \"default\";\n\nexport interface CodeExport {\n name: string;\n kind: CodeExportKind;\n description?: string;\n line: number;\n}\n\nexport interface CodeFileEntry {\n summary?: string;\n exports: CodeExport[];\n loc: number;\n}\n\nexport interface CodeMap {\n version: 1;\n generated_at: string;\n root: string;\n files: Record<string, CodeFileEntry>;\n}\n\nexport interface BuildCodeMapOptions {\n includeExtensions?: string[];\n excludeDirs?: string[];\n /** Include untracked files that are not ignored by git. Default: false when the root is a git repo. */\n includeUntracked?: boolean;\n}\n\nconst DEFAULT_INCLUDE = [\n \".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\",\n \".java\", \".kt\",\n \".py\",\n \".go\",\n \".rb\",\n \".rs\",\n \".cs\",\n \".php\",\n];\nconst DEFAULT_EXCLUDE = [\n \"node_modules\",\n \"dist\",\n \"build\",\n \"out\",\n \".git\",\n \".next\",\n \".turbo\",\n \".vitest-cache\",\n \"coverage\",\n \"test\",\n \"tests\",\n \"__tests__\",\n \"__mocks__\",\n \"target\", // Maven/Gradle build output\n \".gradle\",\n \"__pycache__\",\n \".pytest_cache\",\n \"vendor\", // Go / PHP\n];\n\nconst TEST_FILE_RE = /\\.(test|spec)\\.[a-z]+$/i;\n\nexport function codeMapPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, CODE_MAP_FILE);\n}\n\nexport async function loadCodeMap(paths: HaivePaths): Promise<CodeMap | null> {\n const file = codeMapPath(paths);\n if (!existsSync(file)) return null;\n return JSON.parse(await readFile(file, \"utf8\")) as CodeMap;\n}\n\nexport async function saveCodeMap(paths: HaivePaths, map: CodeMap): Promise<void> {\n const file = codeMapPath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n await writeFile(file, JSON.stringify(map, null, 2), \"utf8\");\n}\n\nexport async function buildCodeMap(\n root: string,\n options: BuildCodeMapOptions = {},\n): Promise<CodeMap> {\n const include = new Set(options.includeExtensions ?? DEFAULT_INCLUDE);\n const exclude = new Set(options.excludeDirs ?? DEFAULT_EXCLUDE);\n const files: Record<string, CodeFileEntry> = {};\n\n for await (const abs of collectSourceFiles(root, include, exclude, options.includeUntracked)) {\n const rel = path.relative(root, abs).replace(/\\\\/g, \"/\");\n if (rel.startsWith(\".ai/\")) continue;\n const content = await readFile(abs, \"utf8\");\n const ext = path.extname(abs).toLowerCase();\n const entry = parseFile(content, ext);\n if (entry.exports.length > 0) files[rel] = entry;\n }\n\n return {\n version: 1,\n generated_at: new Date().toISOString(),\n root,\n files,\n };\n}\n\nasync function* collectSourceFiles(\n root: string,\n include: Set<string>,\n exclude: Set<string>,\n includeUntracked: boolean | undefined,\n): AsyncGenerator<string> {\n const gitFiles = gitSourceFiles(root, include, exclude, includeUntracked === true);\n if (gitFiles) {\n for (const rel of gitFiles) yield path.join(root, rel);\n return;\n }\n\n yield* walkSourceFiles(root, include, exclude);\n}\n\nfunction gitSourceFiles(\n root: string,\n include: Set<string>,\n exclude: Set<string>,\n includeUntracked: boolean,\n): string[] | null {\n const args = includeUntracked\n ? [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"]\n : [\"ls-files\", \"--cached\"];\n const result = spawnSync(\"git\", args, {\n cwd: root,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n if (result.status !== 0) return null;\n\n return result.stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .filter((rel) => isIncludedSourcePath(rel, include, exclude))\n .sort();\n}\n\nasync function* walkSourceFiles(\n dir: string,\n include: Set<string>,\n exclude: Set<string>,\n): AsyncGenerator<string> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") && entry.name !== \".github\") {\n // Skip hidden dirs except .github (workflows can be useful)\n if (entry.isDirectory()) continue;\n }\n if (exclude.has(entry.name)) continue;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n yield* walkSourceFiles(full, include, exclude);\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name).toLowerCase();\n if (include.has(ext) && !TEST_FILE_RE.test(entry.name)) yield full;\n }\n }\n}\n\nfunction isIncludedSourcePath(\n rel: string,\n include: Set<string>,\n exclude: Set<string>,\n): boolean {\n const normalized = rel.replace(/\\\\/g, \"/\");\n if (normalized.startsWith(\".ai/\")) return false;\n const parts = normalized.split(\"/\");\n if (parts.some((part) => exclude.has(part))) return false;\n const base = parts.at(-1) ?? \"\";\n const ext = path.extname(base).toLowerCase();\n return include.has(ext) && !TEST_FILE_RE.test(base);\n}\n\nconst EXPORT_RE =\n /^export\\s+(?:default\\s+)?(async\\s+)?(function|class|interface|type|const|let|var|enum)\\s+(\\*?)\\s*([A-Za-z_$][\\w$]*)/gm;\n\nconst NAMED_REEXPORT_RE = /^export\\s*\\{([^}]+)\\}/gm;\n\nconst FILE_HEADER_COMMENT_RE = /^\\/\\*\\*([\\s\\S]*?)\\*\\//;\n\n// Java / Kotlin: public/protected class, interface, enum, record, @interface, fun, @RestController etc.\nconst JAVA_DECL_RE =\n /^(?:[ \\t]*)(?:@\\w+\\s+)*(?:public|protected|private|internal)?\\s*(?:static\\s+|final\\s+|abstract\\s+|open\\s+|data\\s+|sealed\\s+)*(?:(class|interface|enum|record|@interface|object)\\s+([A-Z][A-Za-z0-9_$]*)|(fun|def|func|function)\\s+([a-z_][A-Za-z0-9_$]*))/gm;\n\n// Python: def / class at module level (not indented)\nconst PYTHON_DECL_RE = /^(def|class)\\s+([A-Za-z_][A-Za-z0-9_]*)/gm;\n\n// Go: func declarations\nconst GO_DECL_RE = /^func\\s+(?:\\(\\w+\\s+\\*?[A-Za-z_][\\w]*\\)\\s+)?([A-Za-z_][A-Za-z0-9_]*)/gm;\n\n// Rust: pub fn / pub struct / pub enum / pub trait\nconst RUST_DECL_RE =\n /^pub(?:\\([^)]*\\))?\\s+(fn|struct|enum|trait|type|const|impl|mod)\\s+([A-Za-z_][A-Za-z0-9_]*)/gm;\n\nfunction parseFile(source: string, ext: string): CodeFileEntry {\n if (ext === \".java\" || ext === \".kt\") return parseJvmFile(source);\n if (ext === \".py\") return parsePythonFile(source);\n if (ext === \".go\") return parseGoFile(source);\n if (ext === \".rs\") return parseRustFile(source);\n return parseJsFile(source);\n}\n\nfunction parseJsFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n\n let m: RegExpExecArray | null;\n EXPORT_RE.lastIndex = 0;\n while ((m = EXPORT_RE.exec(source))) {\n const kindRaw = m[2] ?? \"\";\n const name = m[4] ?? \"\";\n if (!name) continue;\n const kind: CodeExportKind =\n kindRaw === \"function\" ? \"function\" :\n kindRaw === \"class\" ? \"class\" :\n kindRaw === \"interface\" ? \"interface\" :\n kindRaw === \"type\" ? \"type\" :\n kindRaw === \"enum\" ? \"enum\" : \"const\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n\n NAMED_REEXPORT_RE.lastIndex = 0;\n while ((m = NAMED_REEXPORT_RE.exec(source))) {\n const inside = m[1] ?? \"\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n for (const part of inside.split(\",\")) {\n const cleaned = part.trim().split(/\\s+as\\s+/).pop()?.trim() ?? \"\";\n if (!cleaned || cleaned.startsWith(\"type \")) continue;\n if (exports.some((e) => e.name === cleaned)) continue;\n exports.push({ name: cleaned, kind: \"const\", line: lineIdx + 1 });\n }\n }\n\n const summary = extractFileSummary(source);\n return { ...(summary ? { summary } : {}), exports, loc: source.split(\"\\n\").length };\n}\n\nfunction parseJvmFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n JAVA_DECL_RE.lastIndex = 0;\n while ((m = JAVA_DECL_RE.exec(source))) {\n const kindRaw = m[1] ?? m[3] ?? \"\";\n const name = m[2] ?? m[4] ?? \"\";\n if (!name) continue;\n const kind: CodeExportKind =\n kindRaw === \"class\" || kindRaw === \"record\" || kindRaw === \"object\" ? \"class\" :\n kindRaw === \"interface\" || kindRaw === \"@interface\" ? \"interface\" :\n kindRaw === \"enum\" ? \"enum\" :\n kindRaw === \"fun\" || kindRaw === \"def\" || kindRaw === \"func\" || kindRaw === \"function\" ? \"function\" :\n \"const\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n const summary = extractJavaSummary(source);\n return { ...(summary ? { summary } : {}), exports, loc: lines.length };\n}\n\nfunction parsePythonFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n PYTHON_DECL_RE.lastIndex = 0;\n while ((m = PYTHON_DECL_RE.exec(source))) {\n const keyword = m[1] ?? \"\";\n const name = m[2] ?? \"\";\n if (!name || name.startsWith(\"_\")) continue;\n const kind: CodeExportKind = keyword === \"class\" ? \"class\" : \"function\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractPythonDocstring(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n const summary = extractPythonModuleDocstring(source);\n return { ...(summary ? { summary } : {}), exports, loc: lines.length };\n}\n\nfunction parseGoFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n GO_DECL_RE.lastIndex = 0;\n while ((m = GO_DECL_RE.exec(source))) {\n const name = m[1] ?? \"\";\n if (!name || !/^[A-Z]/.test(name)) continue; // Only exported (uppercase) in Go\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind: \"function\", ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n return { exports, loc: lines.length };\n}\n\nfunction parseRustFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n RUST_DECL_RE.lastIndex = 0;\n while ((m = RUST_DECL_RE.exec(source))) {\n const kindRaw = m[1] ?? \"\";\n const name = m[2] ?? \"\";\n if (!name) continue;\n const kind: CodeExportKind =\n kindRaw === \"struct\" || kindRaw === \"impl\" ? \"class\" :\n kindRaw === \"enum\" ? \"enum\" :\n kindRaw === \"trait\" ? \"interface\" :\n kindRaw === \"fn\" ? \"function\" :\n kindRaw === \"type\" ? \"type\" : \"const\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n return { exports, loc: lines.length };\n}\n\nfunction extractJavaSummary(source: string): string | undefined {\n // Java/Kotlin: file-level Javadoc before first class/interface\n const m = source.match(/^\\/\\*\\*([\\s\\S]*?)\\*\\//);\n if (!m) return undefined;\n const block = (m[1] ?? \"\")\n .split(\"\\n\")\n .map((l) => l.replace(/^\\s*\\*\\s?/, \"\").trim())\n .filter((l) => l && !l.startsWith(\"@\"))\n .join(\" \");\n return block ? firstSentence(block) : undefined;\n}\n\nfunction extractPythonDocstring(lines: string[], defLine: number): string | undefined {\n const next = lines[defLine + 1] ?? \"\";\n const stripped = next.trim();\n if (stripped.startsWith('\"\"\"') || stripped.startsWith(\"'''\")) {\n const inner = stripped.replace(/^[\"']{3}/, \"\").replace(/[\"']{3}.*$/, \"\").trim();\n return inner || undefined;\n }\n return undefined;\n}\n\nfunction extractPythonModuleDocstring(source: string): string | undefined {\n const m = source.match(/^[\"']{3}([\\s\\S]*?)[\"']{3}/);\n if (!m) return undefined;\n return firstSentence((m[1] ?? \"\").trim());\n}\n\nfunction computeLineOffsets(source: string): number[] {\n const out: number[] = [0];\n for (let i = 0; i < source.length; i++) {\n if (source[i] === \"\\n\") out.push(i + 1);\n }\n return out;\n}\n\nfunction byteToLine(byte: number, offsets: number[]): number {\n let lo = 0;\n let hi = offsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n const off = offsets[mid] ?? 0;\n if (off <= byte) lo = mid;\n else hi = mid - 1;\n }\n return lo;\n}\n\nfunction extractJSDocAbove(lines: string[], exportLine: number): string | undefined {\n let i = exportLine - 1;\n // Skip blank lines between JSDoc and export\n while (i >= 0 && (lines[i] ?? \"\").trim() === \"\") i--;\n if (i < 0) return undefined;\n const line = (lines[i] ?? \"\").trim();\n\n if (line.startsWith(\"//\")) {\n return line.replace(/^\\/\\/\\s*/, \"\").trim() || undefined;\n }\n\n // Single-line JSDoc: /** Adds two numbers. */\n const singleLine = line.match(/^\\/\\*\\*\\s*(.*?)\\s*\\*\\/\\s*$/);\n if (singleLine && singleLine[1]) {\n return firstSentence(singleLine[1]);\n }\n\n if (line.endsWith(\"*/\")) {\n // Walk up until /**\n const collected: string[] = [];\n // First piece: content of the line before */\n const firstPiece = line.replace(/\\*\\/\\s*$/, \"\").replace(/^\\*\\s?/, \"\").trim();\n if (firstPiece) collected.unshift(firstPiece);\n let j = i - 1;\n while (j >= 0) {\n const l = (lines[j] ?? \"\").trim();\n if (l.startsWith(\"/**\")) {\n const inner = l.replace(/^\\/\\*\\*/, \"\").trim();\n if (inner) collected.unshift(inner);\n break;\n }\n collected.unshift(l.replace(/^\\*\\s?/, \"\").trim());\n j--;\n }\n const joined = collected.join(\" \").trim();\n if (!joined) return undefined;\n return firstSentence(joined);\n }\n return undefined;\n}\n\nfunction firstSentence(text: string): string | undefined {\n const trimmed = text.trim();\n if (!trimmed) return undefined;\n return trimmed.split(/(?<=\\.)\\s+/)[0]?.trim();\n}\n\nfunction extractFileSummary(source: string): string | undefined {\n const m = source.match(FILE_HEADER_COMMENT_RE);\n if (!m) return undefined;\n const block = (m[1] ?? \"\")\n .split(\"\\n\")\n .map((l) => l.replace(/^\\s*\\*\\s?/, \"\").trim())\n .filter(Boolean)\n .join(\" \");\n if (!block) return undefined;\n const sentence = block.split(/(?<=\\.)\\s+/)[0]?.trim();\n return sentence;\n}\n\nexport interface CodeMapQueryOptions {\n file?: string;\n symbol?: string;\n}\n\nexport function queryCodeMap(map: CodeMap, options: CodeMapQueryOptions): {\n files: Array<{ path: string; entry: CodeFileEntry }>;\n} {\n const files: Array<{ path: string; entry: CodeFileEntry }> = [];\n for (const [filePath, entry] of Object.entries(map.files)) {\n if (options.file) {\n if (!filePath.includes(options.file)) continue;\n }\n if (options.symbol) {\n const sym = options.symbol.toLowerCase();\n if (!entry.exports.some((e) => e.name.toLowerCase().includes(sym))) continue;\n }\n files.push({ path: filePath, entry });\n }\n return { files };\n}\n","/**\n * hAIve project configuration — .ai/haive.config.json\n *\n * In autopilot mode, hAIve operates with zero human intervention:\n * - Memories go directly to `validated` (no approval cycle)\n * - `haive sync` auto-approves proposed memories after the delay\n * - The MCP server saves a session recap automatically on exit\n * - `get_briefing` auto-generates a minimal project context if none exists\n * - `haive sync` applies safe self-maintenance repairs (context version, headings,\n * needs_anchor tags, code-map refresh) without human intervention\n *\n * Multi-repo support:\n * - crossRepoSources: pull shared memories from other repos on haive sync\n * - contractFiles: watch API contract files for breaking changes\n * - hubPath: local path to a shared team-knowledge hub repo\n */\nimport { existsSync } from \"node:fs\";\nimport { readFileSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const CONFIG_FILE = \"haive.config.json\";\n\n/** A remote or local repo to pull shared memories from. */\nexport interface CrossRepoSource {\n /** Human-readable name for this source (used in imported memory tags). */\n name: string;\n /** Local filesystem path to the other project's root (relative or absolute). */\n path?: string;\n /** Git URL — clone/fetch performed automatically. */\n git?: string;\n /** Only import memories matching all of these filters. */\n filter?: {\n /** Only import memories with these tags. */\n tags?: string[];\n /** Only import memories of these types. */\n types?: string[];\n };\n}\n\n/** An API contract file to snapshot and monitor for breaking changes. */\nexport interface ContractFile {\n /** Human-readable name for this contract. */\n name: string;\n /** Path to the contract file, relative to the project root. */\n path: string;\n /** Format of the contract file. */\n format: \"openapi\" | \"graphql\" | \"proto\" | \"typescript\" | \"json-schema\";\n}\n\nexport interface HaiveConfig {\n /** Autopilot mode: maximum autonomy, minimum human intervention. Default: false. */\n autopilot?: boolean;\n\n /**\n * Adaptive briefing: when get_briefing finds no team-specific (unguessable) memory for the\n * task/files, trim the auto-generated project context so the call stays near-zero-cost.\n * A capable model needs nothing extra in that case. Curated context is never trimmed.\n * Default: true.\n */\n adaptiveBriefing?: boolean;\n\n /** Default scope for new memories. Default: \"personal\". Autopilot sets \"team\". */\n defaultScope?: \"personal\" | \"team\";\n\n /**\n * Default status for new memories saved via mem_save.\n * Autopilot sets \"validated\" — skips the approval cycle entirely.\n * Default: \"draft\".\n */\n defaultStatus?: \"draft\" | \"validated\";\n\n /** Auto-approve proposed memories after N hours without rejection. Default: null (disabled). */\n autoApproveDelayHours?: number | null;\n\n /**\n * Auto-promote proposed→validated after N reads (overrides DEFAULT_AUTO_PROMOTE_RULE).\n * Autopilot sets 1 (immediate on first use).\n */\n autoPromoteMinReads?: number;\n\n /** Auto-save session recap on MCP server exit. Default: true in autopilot, false otherwise. */\n autoSessionEnd?: boolean;\n\n /**\n * Auto-generate a minimal project context from code-map when project-context.md is still\n * the template. Default: true in autopilot, false otherwise.\n */\n autoContext?: boolean;\n\n /**\n * Safe self-maintenance performed automatically in autopilot mode.\n * These repairs are intentionally conservative: no guessed anchor is applied\n * without strong evidence, but headings/tags/indexes/context metadata can be\n * kept fresh by the tool itself.\n */\n autoRepair?: {\n /** Keep .ai/project-context.md version metadata aligned with package.json. */\n context?: boolean;\n /** Apply safe memory lint fixes: headings and `needs_anchor` tags. */\n corpus?: boolean;\n /** Refresh .ai/code-map.json during sync when needed. */\n codeMap?: boolean;\n /** Best-effort build of code-search embeddings when @hiveai/embeddings is available. */\n codeSearch?: boolean;\n };\n\n // ── Multi-repo support ──────────────────────────────────────────────────\n\n /**\n * Other repos to pull `shared`-scoped memories from during `haive sync`.\n * Each source must have either `path` (local) or `git` (remote URL).\n *\n * Example:\n * { \"name\": \"backend\", \"path\": \"../repo-backend\", \"filter\": { \"tags\": [\"api-contract\"] } }\n */\n crossRepoSources?: CrossRepoSource[];\n\n /**\n * API contract files to snapshot and watch for breaking changes.\n * `haive sync` compares the current file against `.ai/contracts/<name>.lock`\n * and creates a `gotcha` memory if a breaking change is detected.\n *\n * Example:\n * { \"name\": \"payment-api\", \"path\": \"docs/openapi.yaml\", \"format\": \"openapi\" }\n */\n contractFiles?: ContractFile[];\n\n /**\n * Local path to a shared team-knowledge hub repo.\n * Used by `haive hub pull` and `haive hub push`.\n * Can be relative (resolved from project root) or absolute.\n */\n hubPath?: string;\n\n /**\n * Lock file paths to watch for dependency version changes.\n * Auto-detected if not specified (package.json, pom.xml, go.mod, etc.).\n * Set to [] to disable dependency tracking entirely.\n */\n dependencyFiles?: string[];\n\n /**\n * Agent-enforcement settings. Enabled by default so initialized projects\n * treat hAIve as infrastructure, not an optional convention.\n */\n enforcement?: {\n /** Enforcement posture: advisory reports only, warn in hooks, or block workflow gates. */\n mode?: \"off\" | \"advisory\" | \"strict\";\n /** Require get_briefing / mem_relevant_to before state-changing MCP tools. */\n requireBriefingFirst?: boolean;\n /**\n * Pre-edit (PreToolUse) behaviour when a file's anchored policy was not yet surfaced:\n * - \"advise\" (default): inject the relevant memory content into the agent's context and record\n * it in the briefing marker, then ALLOW the edit — no round-trip, no separate briefing command.\n * - \"block\": hard-block the edit until a briefing covers the file (the legacy strict behaviour).\n * The commit-time decision-coverage gate and CI enforcement remain the hard backstops either way.\n */\n preEditGate?: \"advise\" | \"block\";\n /** Require a session recap before pre-push / CI gates pass. */\n requireSessionRecap?: boolean;\n /** Require memory anchor verification before pre-commit / CI gates pass. */\n requireMemoryVerify?: boolean;\n /** Block changes when anchored decisions/gotchas have become stale. */\n blockStaleDecisionChanges?: boolean;\n /** Require changed files to be covered by relevant surfaced decisions/policies. */\n requireDecisionCoverage?: boolean;\n /**\n * How hard the pre-commit anti-pattern gate blocks a matching attempt/gotcha:\n * - off: never block on anti-patterns (report only)\n * - review: block only on a very strong semantic match (score ≥ 0.75) — soft, legacy default\n * - anchored: ALSO block when a high-confidence anti-pattern is anchored to a touched file\n * and corroborated by the diff (literal token or semantic ≥ 0.45). High precision.\n * - strict: block on any high-confidence anti-pattern match (anchor, literal, or semantic)\n * Config/docs-only commits are always downgraded regardless of this setting.\n * Default: \"anchored\" — makes \"known bad approaches are blocked\" true for the precise case.\n */\n antiPatternGate?: \"off\" | \"review\" | \"anchored\" | \"strict\";\n /**\n * Pre-commit/pre-push decision-coverage behaviour. When true (default), the gate SURFACES the\n * relevant anchored decisions/policies itself and records them in the session marker at commit\n * time — no separate `haive briefing` step required. Set false for the strict legacy behaviour\n * where the commit is blocked until a prior briefing covered those decisions.\n */\n autoBrief?: boolean;\n /**\n * Execute `kind: \"shell\" | \"test\"` memory sensors during `haive sensors check`.\n * These run arbitrary repo-authored commands, so they are OFF by default; turn on per repo\n * (or pass `--commands`) once the team trusts the sensors. Regex sensors always run. Default false.\n */\n runCommandSensors?: boolean;\n /**\n * How `haive enforce finish` reacts to hard failures observed this session that were never\n * captured as a lesson (`mem_tried`):\n * - off: ignore\n * - warn: surface them as an info finding (default — failure detection has false positives)\n * - block: hard-block finish until each is captured\n * Default: \"warn\".\n */\n failureCaptureGate?: \"off\" | \"warn\" | \"block\";\n /**\n * How `haive eval --ci` reacts to a harness-quality regression vs the recorded baseline:\n * - off: never block\n * - warn: report the drop (default)\n * - block: exit non-zero on any score drop\n * Default: \"warn\".\n */\n evalRegressionGate?: \"off\" | \"warn\" | \"block\";\n /**\n * Default unread-age window (in days) for `haive memory archive` corpus decay.\n * A noisy or stale corpus is actively harmful — it makes the agent follow outdated policy.\n * Default: 180.\n */\n decayAfterDays?: number;\n /** Minimum score required for strict enforcement gates. */\n scoreThreshold?: number;\n /** Remove generated hAIve runtime/cache files during cleanup gates. */\n cleanupGeneratedArtifacts?: boolean;\n /**\n * MCP tool surface:\n * - enforcement: compact default harness for coding agents\n * - maintenance: corpus/admin tools for humans and team stewards\n * - experimental: research/diagnostic tools that are not core product surface\n * - full: legacy alias for experimental\n */\n toolProfile?: \"enforcement\" | \"maintenance\" | \"experimental\" | \"full\";\n /** Named memory/policy families enabled for this project. */\n policyPacks?: string[];\n /**\n * Branch on which `enforce finish` enforces the release discipline (lockstep version bump +\n * matching pushed tag) as a HARD gate. On any other branch — feature/* or an integration branch\n * like `develop` — those same checks are advisory (warn), since the version/tag are produced when\n * releasing from this branch, not on every integration commit. Default: \"main\".\n */\n releaseBranch?: string;\n };\n}\n\nexport const DEFAULT_CONFIG: HaiveConfig = {\n autopilot: false,\n defaultScope: \"personal\",\n defaultStatus: \"draft\",\n autoApproveDelayHours: null,\n autoPromoteMinReads: 5,\n autoSessionEnd: false,\n autoContext: false,\n autoRepair: {\n context: false,\n corpus: false,\n codeMap: false,\n codeSearch: false,\n },\n enforcement: {\n mode: \"strict\",\n requireBriefingFirst: true,\n requireSessionRecap: true,\n requireMemoryVerify: true,\n blockStaleDecisionChanges: true,\n requireDecisionCoverage: true,\n antiPatternGate: \"anchored\",\n scoreThreshold: 80,\n cleanupGeneratedArtifacts: true,\n toolProfile: \"enforcement\",\n policyPacks: [\"architecture\", \"gotchas\", \"security\", \"domain\", \"release\"],\n releaseBranch: \"main\",\n },\n};\n\nexport const AUTOPILOT_DEFAULTS: HaiveConfig = {\n autopilot: true,\n defaultScope: \"team\",\n defaultStatus: \"validated\",\n autoApproveDelayHours: 72,\n autoPromoteMinReads: 1,\n autoSessionEnd: true,\n autoContext: true,\n autoRepair: {\n context: true,\n corpus: true,\n codeMap: true,\n codeSearch: true,\n },\n enforcement: {\n mode: \"strict\",\n requireBriefingFirst: true,\n requireSessionRecap: true,\n requireMemoryVerify: true,\n blockStaleDecisionChanges: true,\n requireDecisionCoverage: true,\n antiPatternGate: \"anchored\",\n scoreThreshold: 85,\n cleanupGeneratedArtifacts: true,\n toolProfile: \"enforcement\",\n policyPacks: [\"architecture\", \"gotchas\", \"security\", \"domain\", \"release\"],\n releaseBranch: \"main\",\n },\n};\n\n/** The pre-commit anti-pattern gate hardness levels. */\nexport type AntiPatternGate = \"off\" | \"review\" | \"anchored\" | \"strict\";\n\n/**\n * Single source of truth mapping a configured `antiPatternGate` to the\n * `pre_commit_check` parameters that implement it. Both the git-hook path\n * (`haive enforce check`) and the standalone `haive precommit` command derive\n * their behavior from this so the two surfaces can never drift apart.\n */\nexport function antiPatternGateParams(\n gate: AntiPatternGate,\n): { block_on: \"any\" | \"high-confidence\" | \"never\"; anchored_blocks: boolean } {\n switch (gate) {\n case \"off\":\n return { block_on: \"never\", anchored_blocks: false };\n case \"review\":\n return { block_on: \"high-confidence\", anchored_blocks: false };\n case \"strict\":\n return { block_on: \"any\", anchored_blocks: true };\n case \"anchored\":\n default:\n return { block_on: \"high-confidence\", anchored_blocks: true };\n }\n}\n\nexport function configPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, CONFIG_FILE);\n}\n\nexport async function loadConfig(paths: HaivePaths): Promise<HaiveConfig> {\n const file = configPath(paths);\n if (!existsSync(file)) return { ...DEFAULT_CONFIG };\n try {\n const raw = await readFile(file, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<HaiveConfig>;\n const merged = mergeConfig(DEFAULT_CONFIG, parsed);\n // In autopilot mode, apply autopilot defaults for any field not explicitly set\n if (merged.autopilot) {\n return mergeConfig(AUTOPILOT_DEFAULTS, parsed);\n }\n return merged;\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport function loadConfigSync(paths: HaivePaths): HaiveConfig {\n const file = configPath(paths);\n if (!existsSync(file)) return { ...DEFAULT_CONFIG };\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as Partial<HaiveConfig>;\n const merged = mergeConfig(DEFAULT_CONFIG, parsed);\n return merged.autopilot\n ? mergeConfig(AUTOPILOT_DEFAULTS, parsed)\n : merged;\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport async function saveConfig(paths: HaivePaths, config: HaiveConfig): Promise<void> {\n await writeFile(configPath(paths), JSON.stringify(config, null, 2) + \"\\n\", \"utf8\");\n}\n\nfunction mergeConfig(base: HaiveConfig, override: Partial<HaiveConfig>): HaiveConfig {\n return {\n ...base,\n ...override,\n autoRepair: {\n ...base.autoRepair,\n ...override.autoRepair,\n },\n enforcement: {\n ...base.enforcement,\n ...override.enforcement,\n },\n };\n}\n","/**\n * Cross-repo memory import — pulls `shared`-scoped memories from other projects.\n *\n * Strategy:\n * 1. For each CrossRepoSource in haive.config.json, resolve the source root.\n * 2. Load memories from <source>/.ai/memories/ where scope=shared (+ optional filter).\n * 3. Track imports via .ai/.cache/cross-repo/<name>/import-map.json\n * (sourceId → localFilePath).\n * 4. Write new/updated memories to .ai/memories/shared/<source-name>/.\n * 5. Return a report: { imported, updated, skipped, errors }.\n *\n * Imported memories are tagged with `cross-repo:<source-name>` so they are\n * identifiable and excluded from cross-repo-push to prevent echo loops.\n */\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport {\n buildFrontmatter,\n loadMemoriesFromDir,\n resolveHaivePaths,\n serializeMemory,\n} from \"./index.js\";\nimport type { CrossRepoSource, HaiveConfig } from \"./config.js\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport interface CrossRepoReport {\n source: string;\n imported: string[];\n updated: string[];\n skipped: string[];\n errors: string[];\n}\n\ntype ImportMap = Record<string, string>; // sourceId → local absolute filePath\n\nasync function loadImportMap(cacheDir: string): Promise<ImportMap> {\n const mapPath = path.join(cacheDir, \"import-map.json\");\n if (!existsSync(mapPath)) return {};\n try {\n return JSON.parse(await readFile(mapPath, \"utf8\")) as ImportMap;\n } catch {\n return {};\n }\n}\n\nasync function saveImportMap(cacheDir: string, map: ImportMap): Promise<void> {\n await writeFile(path.join(cacheDir, \"import-map.json\"), JSON.stringify(map, null, 2) + \"\\n\", \"utf8\");\n}\n\n/**\n * Pull shared memories from all configured cross-repo sources.\n * Returns one report per source.\n */\nexport async function pullCrossRepoSources(\n paths: HaivePaths,\n config: HaiveConfig,\n projectRoot: string,\n): Promise<CrossRepoReport[]> {\n const sources = config.crossRepoSources ?? [];\n if (sources.length === 0) return [];\n\n const reports: CrossRepoReport[] = [];\n for (const source of sources) {\n reports.push(await pullFromSource(paths, source, projectRoot));\n }\n return reports;\n}\n\nasync function pullFromSource(\n paths: HaivePaths,\n source: CrossRepoSource,\n projectRoot: string,\n): Promise<CrossRepoReport> {\n const report: CrossRepoReport = {\n source: source.name,\n imported: [],\n updated: [],\n skipped: [],\n errors: [],\n };\n\n // Resolve source root\n let sourceRoot: string | null = null;\n if (source.path) {\n const resolved = path.resolve(projectRoot, source.path);\n if (!existsSync(resolved)) {\n report.errors.push(`Path not found: ${resolved}`);\n return report;\n }\n sourceRoot = resolved;\n } else if (source.git) {\n sourceRoot = await cloneOrFetchGitSource(source, paths, report);\n if (!sourceRoot) return report;\n } else {\n report.errors.push(`Source \"${source.name}\" has neither path nor git — skipping.`);\n return report;\n }\n\n const sourcePaths = resolveHaivePaths(sourceRoot);\n if (!existsSync(sourcePaths.memoriesDir)) {\n report.errors.push(`No .ai/memories/ found at ${sourceRoot}`);\n return report;\n }\n\n // Load source memories filtered to scope=shared\n const sourceMemories = (await loadMemoriesFromDir(sourcePaths.memoriesDir)).filter(\n ({ memory }) => {\n const fm = memory.frontmatter;\n if (fm.scope !== \"shared\") return false;\n if (fm.status === \"rejected\" || fm.status === \"deprecated\") return false;\n if (source.filter?.tags && source.filter.tags.length > 0) {\n const hasTag = source.filter.tags.some((t) => fm.tags.includes(t));\n if (!hasTag) return false;\n }\n if (source.filter?.types && source.filter.types.length > 0) {\n if (!source.filter.types.includes(fm.type)) return false;\n }\n return true;\n },\n );\n\n if (sourceMemories.length === 0) {\n report.skipped.push(\"no shared memories found in source\");\n return report;\n }\n\n // Destination: .ai/memories/shared/<source-name>/\n const destDir = path.join(paths.memoriesDir, \"shared\", source.name);\n await mkdir(destDir, { recursive: true });\n\n // Cache dir for import tracking\n const cacheDir = path.join(paths.haiveDir, \".cache\", \"cross-repo\", source.name);\n await mkdir(cacheDir, { recursive: true });\n const importMap = await loadImportMap(cacheDir);\n const mapDirty = false;\n let dirty = mapDirty;\n\n for (const { memory } of sourceMemories) {\n const fm = memory.frontmatter;\n const sourceId = fm.id;\n const importTag = `cross-repo:${source.name}`;\n const tags = [...new Set([...fm.tags, importTag])];\n\n const importedBodyPrefix =\n `> **Imported from \\`${source.name}\\`** (original id: \\`${sourceId}\\`) \\n` +\n `> Imported at: ${new Date().toISOString()}\\n\\n`;\n\n const existingLocalPath = importMap[sourceId];\n\n if (existingLocalPath && existsSync(existingLocalPath)) {\n // Already imported — check if body changed in source\n const existingFiles = await loadMemoriesFromDir(destDir);\n const existingEntry = existingFiles.find(({ filePath }) => filePath === existingLocalPath);\n const sourceBodyStripped = memory.body.trim();\n const existingBodyStripped = (existingEntry?.memory.body ?? \"\")\n .replace(/^>.*\\n>.*\\n\\n/m, \"\")\n .trim();\n\n if (existingBodyStripped === sourceBodyStripped) {\n report.skipped.push(sourceId);\n continue;\n }\n\n // Body changed — update\n const updatedBody = importedBodyPrefix + memory.body;\n if (existingEntry) {\n await writeFile(\n existingLocalPath,\n serializeMemory({ frontmatter: existingEntry.memory.frontmatter, body: updatedBody }),\n \"utf8\",\n );\n }\n report.updated.push(sourceId);\n } else {\n // New import\n const slug = `${source.name}-${fm.id.slice(0, 40)}`;\n const newFm = buildFrontmatter({\n type: fm.type,\n slug,\n scope: \"team\" as const,\n module: undefined,\n status: \"validated\",\n tags,\n domain: fm.domain,\n author: fm.author,\n paths: fm.anchor.paths,\n symbols: fm.anchor.symbols,\n commit: fm.anchor.commit,\n topic: fm.topic ? `${source.name}:${fm.topic}` : undefined,\n });\n\n const body = importedBodyPrefix + memory.body;\n const destPath = path.join(destDir, `${newFm.id}.md`);\n await writeFile(destPath, serializeMemory({ frontmatter: newFm, body }), \"utf8\");\n importMap[sourceId] = destPath;\n dirty = true;\n report.imported.push(sourceId);\n }\n }\n\n if (dirty) await saveImportMap(cacheDir, importMap);\n return report;\n}\n\n/**\n * Clone or fetch a git source into .ai/.cache/cross-repo/<name>/.\n * Returns the resolved local path, or null on error.\n */\nasync function cloneOrFetchGitSource(\n source: CrossRepoSource,\n paths: HaivePaths,\n report: CrossRepoReport,\n): Promise<string | null> {\n const cacheDir = path.join(paths.haiveDir, \".cache\", \"cross-repo\", source.name);\n await mkdir(cacheDir, { recursive: true });\n\n if (existsSync(path.join(cacheDir, \".git\"))) {\n const result = spawnSync(\"git\", [\"fetch\", \"--depth=1\", \"origin\"], {\n cwd: cacheDir,\n encoding: \"utf8\",\n });\n if (result.status !== 0) {\n report.errors.push(`git fetch failed for ${source.name}: ${result.stderr}`);\n return null;\n }\n spawnSync(\"git\", [\"reset\", \"--hard\", \"FETCH_HEAD\"], { cwd: cacheDir });\n } else {\n const result = spawnSync(\n \"git\",\n [\"clone\", \"--depth=1\", source.git!, \".\"],\n { cwd: cacheDir, encoding: \"utf8\" },\n );\n if (result.status !== 0) {\n report.errors.push(`git clone failed for ${source.name}: ${result.stderr}`);\n return null;\n }\n }\n\n return cacheDir;\n}\n","/**\n * Dependency version tracker.\n *\n * During `haive sync`, parse the project's dependency manifest files\n * (package.json, pom.xml, go.mod, Cargo.toml, requirements.txt, etc.),\n * compare against a snapshot stored at `.ai/contracts/deps-<name>.lock`,\n * and return memories that should be marked stale because a dependency\n * they reference has changed version (major bump = breaking change risk).\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport interface DependencySnapshot {\n file: string;\n format: string;\n captured_at: string;\n deps: Record<string, string>; // name → version\n}\n\nexport interface DepChange {\n name: string;\n from: string;\n to: string;\n /** true if the major version number changed */\n isMajorBump: boolean;\n}\n\nexport interface DepTrackResult {\n file: string;\n changes: DepChange[];\n}\n\n// ── Manifest parsers ───────────────────────────────────────────────────────\n\n/** Parse package.json (npm/pnpm/yarn) — returns name→version map */\nfunction parsePackageJson(content: string): Record<string, string> {\n try {\n const pkg = JSON.parse(content) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n };\n return {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n } catch {\n return {};\n }\n}\n\n/** Parse go.mod — returns module→version map */\nfunction parseGoMod(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(\"\\n\")) {\n const m = line.trim().match(/^(\\S+)\\s+(v[\\d.]+)/);\n if (m?.[1] && m[2]) result[m[1]] = m[2];\n }\n return result;\n}\n\n/** Parse requirements.txt (Python) — returns package→version map */\nfunction parseRequirementsTxt(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(\"\\n\")) {\n const clean = (line.split(\"#\")[0] ?? \"\").trim();\n const m = clean.match(/^([A-Za-z0-9_.-]+)[=><~!]+(.+)$/);\n if (m?.[1] && m[2]) result[m[1].toLowerCase()] = m[2].trim();\n }\n return result;\n}\n\n/** Parse Cargo.toml (Rust) — returns crate→version map */\nfunction parseCargotoml(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n let inDeps = false;\n for (const line of content.split(\"\\n\")) {\n if (/^\\[(dependencies|dev-dependencies|build-dependencies)\\]/.test(line.trim())) {\n inDeps = true;\n continue;\n }\n if (line.startsWith(\"[\") && !line.includes(\"dependencies\")) {\n inDeps = false;\n continue;\n }\n if (!inDeps) continue;\n const simple = line.match(/^(\\w[\\w-]*)\\s*=\\s*\"([^\"]+)\"/);\n if (simple?.[1] && simple[2]) { result[simple[1]] = simple[2]; continue; }\n const table = line.match(/^(\\w[\\w-]*)\\s*=\\s*\\{[^}]*version\\s*=\\s*\"([^\"]+)\"/);\n if (table?.[1] && table[2]) result[table[1]] = table[2];\n }\n return result;\n}\n\n/** Parse pom.xml (Maven) — returns groupId:artifactId→version map */\nfunction parsePomXml(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n const depRe = /<dependency>[\\s\\S]*?<groupId>([^<]+)<\\/groupId>[\\s\\S]*?<artifactId>([^<]+)<\\/artifactId>[\\s\\S]*?<version>([^<]+)<\\/version>[\\s\\S]*?<\\/dependency>/g;\n let m: RegExpExecArray | null;\n while ((m = depRe.exec(content)) !== null) {\n if (m[1] && m[2] && m[3]) {\n result[`${m[1].trim()}:${m[2].trim()}`] = m[3].trim();\n }\n }\n return result;\n}\n\n// ── Auto-detection of manifest files ──────────────────────────────────────\n\nconst KNOWN_MANIFESTS: Array<{ name: string; parser: (c: string) => Record<string, string> }> = [\n { name: \"package.json\", parser: parsePackageJson },\n { name: \"go.mod\", parser: parseGoMod },\n { name: \"requirements.txt\", parser: parseRequirementsTxt },\n { name: \"Cargo.toml\", parser: parseCargotoml },\n { name: \"pom.xml\", parser: parsePomXml },\n];\n\nfunction getParser(file: string): ((c: string) => Record<string, string>) | null {\n const base = path.basename(file);\n return KNOWN_MANIFESTS.find((m) => m.name === base)?.parser ?? null;\n}\n\n// ── Version comparison ─────────────────────────────────────────────────────\n\nfunction extractMajor(version: string): number | null {\n const clean = version.replace(/^[^0-9]*/, \"\"); // strip ^, ~, >=, v, etc.\n const firstPart = clean.split(\".\")[0];\n if (!firstPart) return null;\n const n = parseInt(firstPart, 10);\n return isNaN(n) ? null : n;\n}\n\nfunction isMajorBump(from: string, to: string): boolean {\n const fromMajor = extractMajor(from);\n const toMajor = extractMajor(to);\n if (fromMajor === null || toMajor === null) return false;\n return toMajor > fromMajor;\n}\n\n// ── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Resolve which manifest files to track.\n * Uses config.dependencyFiles if set, otherwise auto-detects from KNOWN_MANIFESTS.\n */\nexport function resolveManifestFiles(\n projectRoot: string,\n configuredFiles?: string[],\n): string[] {\n if (configuredFiles !== undefined) {\n // Explicitly configured (can be [] to disable)\n return configuredFiles.map((f) => path.resolve(projectRoot, f)).filter(existsSync);\n }\n return KNOWN_MANIFESTS\n .map(({ name }) => path.join(projectRoot, name))\n .filter(existsSync);\n}\n\n/**\n * Check all manifest files for version changes since last snapshot.\n * Returns one result per file that has changes.\n */\nexport async function trackDependencies(\n projectRoot: string,\n haiveDir: string,\n manifestFiles: string[],\n): Promise<DepTrackResult[]> {\n const contractsDir = path.join(haiveDir, \"contracts\");\n await mkdir(contractsDir, { recursive: true });\n\n const results: DepTrackResult[] = [];\n\n for (const manifestPath of manifestFiles) {\n const parser = getParser(manifestPath);\n if (!parser) continue;\n\n const content = await readFile(manifestPath, \"utf8\");\n const currentDeps = parser(content);\n const lockName = `deps-${path.basename(manifestPath)}.lock`;\n const lockPath = path.join(contractsDir, lockName);\n\n if (!existsSync(lockPath)) {\n // First run — save snapshot, no changes to report\n const snapshot: DependencySnapshot = {\n file: path.relative(projectRoot, manifestPath),\n format: path.basename(manifestPath),\n captured_at: new Date().toISOString(),\n deps: currentDeps,\n };\n await writeFile(lockPath, JSON.stringify(snapshot, null, 2) + \"\\n\", \"utf8\");\n continue;\n }\n\n const snapshot = JSON.parse(await readFile(lockPath, \"utf8\")) as DependencySnapshot;\n const changes: DepChange[] = [];\n\n for (const [name, currentVer] of Object.entries(currentDeps)) {\n const prevVer = snapshot.deps[name];\n if (prevVer && prevVer !== currentVer) {\n changes.push({\n name,\n from: prevVer,\n to: currentVer,\n isMajorBump: isMajorBump(prevVer, currentVer),\n });\n }\n }\n\n if (changes.length > 0) {\n results.push({ file: path.relative(projectRoot, manifestPath), changes });\n // Update snapshot\n const updated: DependencySnapshot = {\n ...snapshot,\n captured_at: new Date().toISOString(),\n deps: currentDeps,\n };\n await writeFile(lockPath, JSON.stringify(updated, null, 2) + \"\\n\", \"utf8\");\n }\n }\n\n return results;\n}\n","/**\n * Contract snapshot and diff watcher.\n *\n * Supports:\n * - OpenAPI/Swagger (JSON or YAML)\n * - GraphQL schema\n * - Protocol Buffers (.proto)\n * - TypeScript declaration files (.d.ts)\n * - JSON Schema\n *\n * `haive snapshot --contract <file>` saves a snapshot to .ai/contracts/<name>.lock\n * `haive sync` compares current file against snapshot and returns BreakingChange[].\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type { ContractFile } from \"./config.js\";\n\nexport interface ContractSnapshot {\n name: string;\n path: string;\n format: string;\n captured_at: string;\n hash: string; // SHA-256 of file content\n endpoints?: string[]; // OpenAPI: list of \"METHOD /path\"\n types?: string[]; // GraphQL/TS: list of type/interface/message names\n fields?: Record<string, string[]>; // type → list of field names\n raw_lines?: string[]; // fallback: full file lines for line-by-line diff\n}\n\nexport interface BreakingChange {\n kind:\n | \"endpoint_removed\"\n | \"endpoint_added\"\n | \"type_removed\"\n | \"type_added\"\n | \"field_removed\"\n | \"field_added\"\n | \"content_changed\";\n description: string;\n severity: \"breaking\" | \"additive\" | \"unknown\";\n}\n\nexport interface ContractDiffResult {\n contract: string;\n file: string;\n changes: BreakingChange[];\n unchanged: boolean;\n}\n\n// ── Parsers ────────────────────────────────────────────────────────────────\n\nfunction sha256(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/** Parse OpenAPI/Swagger — extract endpoint list and schemas */\nfunction parseOpenApi(content: string, file: string): Partial<ContractSnapshot> {\n try {\n let doc: Record<string, unknown>;\n if (file.endsWith(\".yaml\") || file.endsWith(\".yml\")) {\n // Simple YAML line-based extraction (no full YAML parser dep)\n doc = parseYamlPaths(content);\n } else {\n doc = JSON.parse(content) as Record<string, unknown>;\n }\n const paths = (doc.paths ?? {}) as Record<string, Record<string, unknown>>;\n const endpoints: string[] = [];\n for (const [routePath, methods] of Object.entries(paths)) {\n for (const method of Object.keys(methods)) {\n if ([\"get\",\"post\",\"put\",\"patch\",\"delete\",\"head\",\"options\"].includes(method)) {\n endpoints.push(`${method.toUpperCase()} ${routePath}`);\n }\n }\n }\n // Extract schema/component names\n const schemas = (\n (doc.components as Record<string, unknown> | undefined)?.schemas ??\n (doc.definitions as Record<string, unknown> | undefined) ??\n {}\n ) as Record<string, Record<string, unknown>>;\n const types = Object.keys(schemas);\n const fields: Record<string, string[]> = {};\n for (const [typeName, schema] of Object.entries(schemas)) {\n const props = (schema.properties ?? {}) as Record<string, unknown>;\n fields[typeName] = Object.keys(props);\n }\n return { endpoints, types, fields };\n } catch {\n return {};\n }\n}\n\n/** Naive YAML paths extractor — avoids needing js-yaml dep */\nfunction parseYamlPaths(content: string): Record<string, unknown> {\n const result: Record<string, Record<string, boolean>> = {};\n let currentPath = \"\";\n for (const line of content.split(\"\\n\")) {\n const pathMatch = line.match(/^ (\\/[^\\s:]+):/);\n if (pathMatch?.[1]) {\n currentPath = pathMatch[1];\n result[currentPath] = {};\n continue;\n }\n if (currentPath) {\n const methodMatch = line.match(/^ (get|post|put|patch|delete|head|options):/);\n if (methodMatch?.[1]) (result[currentPath] ??= {})[methodMatch[1]] = true;\n }\n }\n return { paths: result };\n}\n\n/** Parse GraphQL schema — extract type/interface/union/enum names */\nfunction parseGraphQL(content: string): Partial<ContractSnapshot> {\n const types: string[] = [];\n const fields: Record<string, string[]> = {};\n let currentType = \"\";\n\n for (const line of content.split(\"\\n\")) {\n const typeMatch = line.match(/^(?:type|interface|union|enum|input)\\s+(\\w+)/);\n if (typeMatch?.[1]) {\n currentType = typeMatch[1];\n types.push(currentType);\n fields[currentType] = [];\n continue;\n }\n if (currentType && line.trim().startsWith(\"}\")) {\n currentType = \"\";\n continue;\n }\n if (currentType) {\n const fieldMatch = line.match(/^\\s+(\\w+)\\s*[:(]/);\n if (fieldMatch?.[1]) (fields[currentType] ??= []).push(fieldMatch[1]);\n }\n }\n return { types, fields };\n}\n\n/** Parse .proto (Protocol Buffers) — extract message/service names */\nfunction parseProto(content: string): Partial<ContractSnapshot> {\n const types: string[] = [];\n const fields: Record<string, string[]> = {};\n let currentMsg = \"\";\n\n for (const line of content.split(\"\\n\")) {\n const msgMatch = line.match(/^(?:message|service|enum)\\s+(\\w+)/);\n if (msgMatch?.[1]) {\n currentMsg = msgMatch[1];\n types.push(currentMsg);\n fields[currentMsg] = [];\n continue;\n }\n if (currentMsg && line.trim() === \"}\") {\n currentMsg = \"\";\n continue;\n }\n if (currentMsg) {\n const fieldMatch = line.match(/^\\s+(?:optional|required|repeated)?\\s*\\w+\\s+(\\w+)\\s*=/);\n if (fieldMatch?.[1]) (fields[currentMsg] ??= []).push(fieldMatch[1]);\n const rpcMatch = line.match(/^\\s+rpc\\s+(\\w+)/);\n if (rpcMatch?.[1]) (fields[currentMsg] ??= []).push(`rpc:${rpcMatch[1]}`);\n }\n }\n return { types, fields };\n}\n\n/** Parse TypeScript .d.ts — extract exported interface/class/type names */\nfunction parseTypescript(content: string): Partial<ContractSnapshot> {\n const types: string[] = [];\n const fields: Record<string, string[]> = {};\n let currentType = \"\";\n let braceDepth = 0;\n\n for (const line of content.split(\"\\n\")) {\n const exportMatch = line.match(/^export\\s+(?:declare\\s+)?(?:interface|class|type|enum)\\s+(\\w+)/);\n if (exportMatch?.[1]) {\n currentType = exportMatch[1];\n types.push(currentType);\n fields[currentType] = [];\n }\n if (currentType) {\n braceDepth += (line.match(/{/g) ?? []).length;\n braceDepth -= (line.match(/}/g) ?? []).length;\n if (braceDepth <= 0 && line.includes(\"}\")) { currentType = \"\"; braceDepth = 0; continue; }\n const memberMatch = line.match(/^\\s+(?:readonly\\s+)?(\\w+)\\s*[?:(!]/);\n if (memberMatch?.[1] && currentType) (fields[currentType] ??= []).push(memberMatch[1]);\n }\n }\n return { types, fields };\n}\n\nfunction parseByFormat(\n content: string,\n format: ContractFile[\"format\"],\n filePath: string,\n): Partial<ContractSnapshot> {\n switch (format) {\n case \"openapi\": return parseOpenApi(content, filePath);\n case \"graphql\": return parseGraphQL(content);\n case \"proto\": return parseProto(content);\n case \"typescript\": return parseTypescript(content);\n case \"json-schema\": {\n try {\n const schema = JSON.parse(content) as Record<string, Record<string, unknown>>;\n const types = Object.keys((schema.definitions ?? schema.properties ?? {}) as Record<string, unknown>);\n return { types };\n } catch { return {}; }\n }\n default: return {};\n }\n}\n\n// ── Diff logic ─────────────────────────────────────────────────────────────\n\nfunction diffLists(before: string[], after: string[], kind: string): BreakingChange[] {\n const changes: BreakingChange[] = [];\n const beforeSet = new Set(before);\n const afterSet = new Set(after);\n for (const item of beforeSet) {\n if (!afterSet.has(item)) {\n const isBreaking = kind === \"endpoint\" || kind === \"field\" || kind === \"type\";\n changes.push({\n kind: `${kind}_removed` as BreakingChange[\"kind\"],\n description: `${kind} removed: ${item}`,\n severity: isBreaking ? \"breaking\" : \"unknown\",\n });\n }\n }\n for (const item of afterSet) {\n if (!beforeSet.has(item)) {\n changes.push({\n kind: `${kind}_added` as BreakingChange[\"kind\"],\n description: `${kind} added: ${item}`,\n severity: \"additive\",\n });\n }\n }\n return changes;\n}\n\nfunction diffSnapshots(before: ContractSnapshot, after: ContractSnapshot): BreakingChange[] {\n if (before.hash === after.hash) return [];\n\n const changes: BreakingChange[] = [];\n\n // Endpoint diff (OpenAPI)\n if (before.endpoints && after.endpoints) {\n changes.push(...diffLists(before.endpoints, after.endpoints, \"endpoint\"));\n }\n\n // Type diff (all formats)\n if (before.types && after.types) {\n changes.push(...diffLists(before.types, after.types, \"type\"));\n }\n\n // Field diff per type\n if (before.fields && after.fields) {\n const allTypes = new Set([...Object.keys(before.fields), ...Object.keys(after.fields)]);\n for (const typeName of allTypes) {\n const beforeFields = before.fields[typeName] ?? [];\n const afterFields = after.fields[typeName] ?? [];\n const fieldChanges = diffLists(beforeFields, afterFields, \"field\");\n for (const fc of fieldChanges) {\n changes.push({ ...fc, description: `${typeName}.${fc.description}` });\n }\n }\n }\n\n // Fallback: file changed but no structured diff\n if (changes.length === 0) {\n changes.push({\n kind: \"content_changed\",\n description: \"Contract file content changed (no structured diff available)\",\n severity: \"unknown\",\n });\n }\n\n return changes;\n}\n\n// ── Public API ─────────────────────────────────────────────────────────────\n\nexport function contractLockPath(haiveDir: string, name: string): string {\n return path.join(haiveDir, \"contracts\", `${name}.lock`);\n}\n\n/**\n * Take a snapshot of a contract file and save it to .ai/contracts/<name>.lock.\n * Returns the snapshot.\n */\nexport async function snapshotContract(\n projectRoot: string,\n haiveDir: string,\n contract: ContractFile,\n): Promise<ContractSnapshot> {\n const filePath = path.resolve(projectRoot, contract.path);\n if (!existsSync(filePath)) {\n throw new Error(`Contract file not found: ${filePath}`);\n }\n const content = await readFile(filePath, \"utf8\");\n const parsed = parseByFormat(content, contract.format, filePath);\n const snapshot: ContractSnapshot = {\n name: contract.name,\n path: contract.path,\n format: contract.format,\n captured_at: new Date().toISOString(),\n hash: sha256(content),\n ...parsed,\n };\n const contractsDir = path.join(haiveDir, \"contracts\");\n await mkdir(contractsDir, { recursive: true });\n await writeFile(contractLockPath(haiveDir, contract.name), JSON.stringify(snapshot, null, 2) + \"\\n\", \"utf8\");\n return snapshot;\n}\n\n/**\n * Compare a contract file against its stored snapshot.\n * Returns the diff result. If no snapshot exists, creates one and returns unchanged.\n */\nexport async function diffContract(\n projectRoot: string,\n haiveDir: string,\n contract: ContractFile,\n): Promise<ContractDiffResult> {\n const filePath = path.resolve(projectRoot, contract.path);\n if (!existsSync(filePath)) {\n return { contract: contract.name, file: contract.path, changes: [], unchanged: true };\n }\n\n const lockPath = contractLockPath(haiveDir, contract.name);\n\n if (!existsSync(lockPath)) {\n // First time — save snapshot\n await snapshotContract(projectRoot, haiveDir, contract);\n return { contract: contract.name, file: contract.path, changes: [], unchanged: true };\n }\n\n const content = await readFile(filePath, \"utf8\");\n const beforeSnapshot = JSON.parse(await readFile(lockPath, \"utf8\")) as ContractSnapshot;\n const afterParsed = parseByFormat(content, contract.format, filePath);\n const afterSnapshot: ContractSnapshot = {\n ...beforeSnapshot,\n hash: sha256(content),\n captured_at: new Date().toISOString(),\n ...afterParsed,\n };\n\n const changes = diffSnapshots(beforeSnapshot, afterSnapshot);\n\n if (changes.length > 0) {\n // Update snapshot to current state\n await writeFile(lockPath, JSON.stringify(afterSnapshot, null, 2) + \"\\n\", \"utf8\");\n }\n\n return {\n contract: contract.name,\n file: contract.path,\n changes,\n unchanged: changes.length === 0,\n };\n}\n\n/**\n * Check all configured contract files for changes.\n */\nexport async function watchContracts(\n projectRoot: string,\n haiveDir: string,\n contractFiles: ContractFile[],\n): Promise<ContractDiffResult[]> {\n const results: ContractDiffResult[] = [];\n for (const contract of contractFiles) {\n results.push(await diffContract(projectRoot, haiveDir, contract));\n }\n return results.filter((r) => !r.unchanged);\n}\n","import { appendFile, mkdir, readFile, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const USAGE_LOG_FILE = \"tool-usage.jsonl\";\nexport const USAGE_LOG_DIR = \".usage\";\n\nexport interface UsageEvent {\n /** ISO timestamp */\n at: string;\n /** Tool name (MCP tool or CLI command) */\n tool: string;\n /** Truncated, non-sensitive snapshot of the input */\n summary?: string;\n}\n\nexport function usageLogPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, USAGE_LOG_DIR, USAGE_LOG_FILE);\n}\n\n/**\n * Append a single usage event to the rolling log. Best-effort: failures are\n * swallowed since logging must never block tool execution.\n */\nexport async function appendUsageEvent(paths: HaivePaths, event: UsageEvent): Promise<void> {\n try {\n const file = usageLogPath(paths);\n const dir = path.dirname(file);\n if (!existsSync(dir)) await mkdir(dir, { recursive: true });\n await appendFile(file, JSON.stringify(event) + \"\\n\", \"utf8\");\n } catch {\n // Logging is best-effort.\n }\n}\n\n/**\n * Read all usage events from disk. Skips malformed lines silently.\n * For very large logs (>50k lines), prefer `streamUsageEvents` (not implemented yet).\n */\nexport async function readUsageEvents(paths: HaivePaths): Promise<UsageEvent[]> {\n const file = usageLogPath(paths);\n if (!existsSync(file)) return [];\n const raw = await readFile(file, \"utf8\");\n const out: UsageEvent[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line) continue;\n try {\n const parsed = JSON.parse(line) as UsageEvent;\n if (parsed.tool && parsed.at) out.push(parsed);\n } catch {\n // skip malformed lines\n }\n }\n return out;\n}\n\nexport interface UsageAggregate {\n total: number;\n by_tool: Array<{ tool: string; count: number; last_used: string }>;\n /** Most-frequently called tools first */\n top: Array<{ tool: string; count: number }>;\n window_start: string | null;\n window_end: string | null;\n}\n\n/**\n * Bucket events by tool, optionally filtered by a since cutoff (ISO date or relative like '7d').\n */\nexport function aggregateUsage(events: UsageEvent[], since?: Date): UsageAggregate {\n const cutoff = since ? since.getTime() : 0;\n const filtered = cutoff > 0\n ? events.filter((e) => Date.parse(e.at) >= cutoff)\n : events;\n\n const counts = new Map<string, { count: number; last: string }>();\n for (const e of filtered) {\n const prior = counts.get(e.tool);\n if (!prior) counts.set(e.tool, { count: 1, last: e.at });\n else {\n prior.count++;\n if (e.at > prior.last) prior.last = e.at;\n }\n }\n\n const by_tool = [...counts.entries()]\n .map(([tool, { count, last }]) => ({ tool, count, last_used: last }))\n .sort((a, b) => b.count - a.count);\n\n const sorted = filtered.slice().sort((a, b) => a.at.localeCompare(b.at));\n\n return {\n total: filtered.length,\n by_tool,\n top: by_tool.slice(0, 10).map(({ tool, count }) => ({ tool, count })),\n window_start: sorted[0]?.at ?? null,\n window_end: sorted[sorted.length - 1]?.at ?? null,\n };\n}\n\n/**\n * Parse a since string: ISO date, or relative like '7d', '24h', '30m'.\n * Returns null when input is empty/undefined.\n */\nexport function parseSince(input: string | undefined): Date | null {\n if (!input) return null;\n const m = input.match(/^(\\d+)([dhm])$/);\n if (m) {\n const n = parseInt(m[1] ?? \"0\", 10);\n const unit = m[2] ?? \"d\";\n const ms = unit === \"d\" ? n * 86400_000 : unit === \"h\" ? n * 3600_000 : n * 60_000;\n return new Date(Date.now() - ms);\n }\n const parsed = new Date(input);\n if (Number.isNaN(parsed.getTime())) return null;\n return parsed;\n}\n\nexport async function usageLogSize(paths: HaivePaths): Promise<{ exists: boolean; size_bytes: number; lines: number }> {\n const file = usageLogPath(paths);\n if (!existsSync(file)) return { exists: false, size_bytes: 0, lines: 0 };\n const st = await stat(file);\n const raw = await readFile(file, \"utf8\");\n return { exists: true, size_bytes: st.size, lines: raw.split(\"\\n\").filter((l) => l).length };\n}\n","/**\n * Named budgets for get_briefing so agents choose quality vs token cost intentionally.\n */\n\nexport type BriefingBudgetPreset = \"quick\" | \"balanced\" | \"deep\";\n\nexport interface BriefingBudgetNumbers {\n max_tokens: number;\n max_memories: number;\n include_module_contexts: boolean;\n}\n\nexport const BRIEFING_PRESET_DEFAULTS: Record<BriefingBudgetPreset, BriefingBudgetNumbers> = {\n /** Fast session start — minimal tokens, skip module CONTEXT.md slices */\n quick: { max_tokens: 2500, max_memories: 5, include_module_contexts: false },\n /** Historical defaults for get_briefing */\n balanced: { max_tokens: 8000, max_memories: 8, include_module_contexts: true },\n /** Deep refactor / onboarding — richer memory surface */\n deep: { max_tokens: 16_000, max_memories: 14, include_module_contexts: true },\n};\n\n/**\n * Merge preset-derived numbers with caller overrides when no preset was selected.\n */\nexport function resolveBriefingBudget(\n preset: BriefingBudgetPreset | undefined,\n overrides: BriefingBudgetNumbers,\n): BriefingBudgetNumbers {\n if (!preset) return { ...overrides };\n const p = BRIEFING_PRESET_DEFAULTS[preset];\n return {\n max_tokens: p.max_tokens,\n max_memories: p.max_memories,\n include_module_contexts: p.include_module_contexts,\n };\n}\n","/**\n * Strip memory markdown down to actionable bullet lines — cheaper for briefing payloads.\n */\n\nconst MAX_DEFAULT_CHARS = 1200;\n\n/**\n * Prefer markdown list lines; fall back to the first substantive paragraph block.\n */\nexport function extractActionsBriefBody(markdown: string, maxChars = MAX_DEFAULT_CHARS): string {\n const stripped = markdown.replace(/\\r/g, \"\").trim();\n if (!stripped) return \"\";\n\n const lines = stripped.split(\"\\n\");\n const bullets: string[] = [];\n for (const line of lines) {\n const m = line.match(/^\\s*[-*+]\\s+(.+)/);\n if (m?.[1]) {\n bullets.push(`- ${m[1].trim()}`);\n if (bullets.join(\"\\n\").length >= maxChars) break;\n }\n }\n if (bullets.length >= 2) {\n let text = bullets.join(\"\\n\");\n if (text.length > maxChars) text = text.slice(0, maxChars).trimEnd() + \"…\";\n return text;\n }\n\n // Single bullet or none — take contiguous non-empty paragraphs (skip headings)\n const paragraphs: string[] = [];\n let buf: string[] = [];\n for (const line of lines) {\n const t = line.trim();\n if (!t) {\n if (buf.length) {\n paragraphs.push(buf.join(\" \").trim());\n buf = [];\n }\n continue;\n }\n if (t.startsWith(\"#\") || t.startsWith(\"```\")) {\n if (buf.length) {\n paragraphs.push(buf.join(\" \").trim());\n buf = [];\n }\n continue;\n }\n buf.push(t);\n }\n if (buf.length) paragraphs.push(buf.join(\" \").trim());\n\n let out = paragraphs[0] ?? stripped.slice(0, maxChars);\n if (!out.trim()) out = stripped.slice(0, maxChars);\n if (out.length > maxChars) out = out.slice(0, maxChars).trimEnd() + \"…\";\n return out;\n}\n","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { findProjectRoot, resolveHaivePaths } from \"./paths.js\";\n\nconst ROOT_MARKERS = [\".ai\", \".git\", \"package.json\"] as const;\n\nexport interface ResolveProjectInfo {\n cwd: string;\n resolved_root: string;\n haive_project_root_env: string | null;\n explicit_root: boolean;\n haive_dir_exists: boolean;\n memories_dir_exists: boolean;\n runtime_dir: string;\n /** Which of `.ai`, `.git`, `package.json` exist at `resolved_root`. */\n markers_found: string[];\n}\n\nfunction markersAtRoot(root: string): string[] {\n const found: string[] = [];\n for (const m of ROOT_MARKERS) {\n if (existsSync(path.join(root, m))) found.push(m);\n }\n return found;\n}\n\n/**\n * Resolve the hAIve project root for diagnostics (MCP / CLI). Never throws.\n */\nexport function resolveProjectInfo(opts: {\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n} = {}): ResolveProjectInfo {\n const env = opts.env ?? process.env;\n const cwd = path.resolve(opts.cwd ?? process.cwd());\n const raw = env.HAIVE_PROJECT_ROOT;\n const explicit =\n raw !== undefined && raw !== \"\" ? path.resolve(raw) : null;\n const resolvedRoot = explicit ?? findProjectRoot(cwd);\n const paths = resolveHaivePaths(resolvedRoot);\n return {\n cwd,\n resolved_root: resolvedRoot,\n haive_project_root_env: explicit,\n explicit_root: explicit != null,\n haive_dir_exists: existsSync(paths.haiveDir),\n memories_dir_exists: existsSync(paths.memoriesDir),\n runtime_dir: paths.runtimeDir,\n markers_found: markersAtRoot(resolvedRoot),\n };\n}\n","import type { MemoryType } from \"./types.js\";\n\nconst TYPE_TO_FAMILY: Partial<Record<MemoryType, string>> = {\n architecture: \"architecture\",\n convention: \"pattern\",\n decision: \"decision\",\n gotcha: \"bug\",\n attempt: \"bug\",\n glossary: \"discovery\",\n skill: \"skill\",\n session_recap: \"session\",\n};\n\nfunction slugifyTitle(title: string): string {\n const s = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return s.length > 0 ? s.slice(0, 60) : \"untitled\";\n}\n\n/**\n * Suggest a stable `topic` frontmatter key (topic-upsert) from type + title.\n */\nexport function suggestTopicKey(\n type: string,\n titleOrPhrase: string,\n): { topic_key: string; family: string } {\n const family = TYPE_TO_FAMILY[type as MemoryType] ?? \"discovery\";\n const slug = slugifyTitle(titleOrPhrase);\n return { topic_key: `${family}/${slug}`, family };\n}\n","import type { LoadedMemory } from \"./loader.js\";\n\nfunction tokenizeDoc(text: string): string[] {\n return text\n .toLowerCase()\n .split(/[^a-z0-9_]+/)\n .map((w) => w.trim())\n .filter((w) => w.length >= 2);\n}\n\nfunction memorySearchText(loaded: LoadedMemory): string {\n const fm = loaded.memory.frontmatter;\n return [\n fm.id,\n fm.type,\n fm.tags.join(\" \"),\n loaded.memory.body,\n fm.module ?? \"\",\n fm.topic ?? \"\",\n ...fm.anchor.paths,\n ...fm.anchor.symbols,\n ].join(\" \");\n}\n\nexport interface LexicalRankResult {\n ranked: LoadedMemory[];\n scores: number[];\n}\n\n/**\n * Okapi-BM25–style ranking over a small in-memory corpus (no extra index file).\n */\nexport function rankMemoriesLexical(\n loadedMemories: LoadedMemory[],\n query: string,\n limit: number,\n): LexicalRankResult {\n const qTokens = tokenizeDoc(query);\n if (qTokens.length === 0 || loadedMemories.length === 0) {\n return { ranked: [], scores: [] };\n }\n\n const docs = loadedMemories.map((loaded) => ({\n loaded,\n tokens: tokenizeDoc(memorySearchText(loaded)),\n }));\n\n const N = docs.length;\n const df = new Map<string, number>();\n for (const { tokens } of docs) {\n const seen = new Set(tokens);\n for (const t of seen) {\n df.set(t, (df.get(t) ?? 0) + 1);\n }\n }\n\n const avgdl =\n docs.reduce((s, d) => s + d.tokens.length, 0) / Math.max(N, 1);\n const k1 = 1.2;\n const b = 0.75;\n\n function scoreDoc(tokens: string[]): number {\n if (tokens.length === 0) return 0;\n let score = 0;\n const len = tokens.length;\n const tfCounts = new Map<string, number>();\n for (const t of tokens) {\n tfCounts.set(t, (tfCounts.get(t) ?? 0) + 1);\n }\n\n for (const qt of qTokens) {\n const tf = tfCounts.get(qt) ?? 0;\n if (tf === 0) continue;\n const dfi = df.get(qt) ?? 0;\n const idf = Math.log(1 + (N - dfi + 0.5) / (dfi + 0.5));\n const denom = tf + k1 * (1 - b + (b * len) / avgdl);\n const okapiTf = (tf * (k1 + 1)) / denom;\n score += idf * okapiTf;\n }\n return score;\n }\n\n const scored = docs\n .map(({ loaded, tokens }) => ({ loaded, score: scoreDoc(tokens) }))\n .filter((x) => x.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, limit);\n\n return {\n ranked: scored.map((x) => x.loaded),\n scores: scored.map((x) => x.score),\n };\n}\n","import type { LoadedMemory } from \"./loader.js\";\nimport { pathsOverlap } from \"./relevance.js\";\n\nfunction anchorPathsOverlap(\n fmA: LoadedMemory[\"memory\"][\"frontmatter\"],\n fmB: LoadedMemory[\"memory\"][\"frontmatter\"],\n): boolean {\n for (const a of fmA.anchor.paths) {\n for (const b of fmB.anchor.paths) {\n if (pathsOverlap(a, b)) return true;\n }\n }\n return false;\n}\n\nexport function firstMemoryOneLine(body: string): string {\n const heading = body.match(/^\\s*#\\s+(.+)$/m)?.[1]?.trim();\n const line =\n heading ??\n body\n .split(\"\\n\")\n .map((l) => l.trim())\n .find((l) => l.length > 0);\n return (line ?? \"\").slice(0, 280);\n}\n\nexport interface TimelineEntry {\n id: string;\n type: string;\n scope: string;\n created_at: string;\n one_line: string;\n topic?: string;\n}\n\nexport interface CollectTimelineOpts {\n memoryId?: string;\n topic?: string;\n limit: number;\n}\n\n/**\n * Memories related by id seed (related_ids, shared topic, anchor overlap) or by topic alone.\n */\nexport function collectTimelineEntries(\n all: LoadedMemory[],\n opts: CollectTimelineOpts,\n): { entries: TimelineEntry[]; notice?: string } {\n if (!opts.memoryId && !opts.topic) {\n return { entries: [], notice: \"Provide memory_id and/or topic\" };\n }\n\n const byId = new Map(all.map((l) => [l.memory.frontmatter.id, l]));\n\n if (opts.topic && !opts.memoryId) {\n const matches = all.filter((l) => l.memory.frontmatter.topic === opts.topic);\n matches.sort((a, b) =>\n a.memory.frontmatter.created_at.localeCompare(b.memory.frontmatter.created_at),\n );\n return {\n entries: matches.slice(0, opts.limit).map((l) => toEntry(l)),\n };\n }\n\n const seed = byId.get(opts.memoryId!);\n if (!seed) {\n return { entries: [], notice: `No memory with id \"${opts.memoryId}\"` };\n }\n\n const collected = new Set<string>();\n const add = (id: string) => {\n if (byId.has(id)) collected.add(id);\n };\n\n add(seed.memory.frontmatter.id);\n for (const rid of seed.memory.frontmatter.related_ids) add(rid);\n\n const seedTopic = seed.memory.frontmatter.topic;\n if (seedTopic) {\n for (const l of all) {\n if (l.memory.frontmatter.topic === seedTopic) add(l.memory.frontmatter.id);\n }\n }\n\n for (const l of all) {\n if (anchorPathsOverlap(seed.memory.frontmatter, l.memory.frontmatter)) {\n add(l.memory.frontmatter.id);\n }\n }\n\n const firstHop = [...collected];\n for (const id of firstHop) {\n const m = byId.get(id);\n if (!m) continue;\n for (const rid of m.memory.frontmatter.related_ids) add(rid);\n }\n\n let sorted = [...collected]\n .map((id) => byId.get(id)!)\n .filter(Boolean)\n .sort((a, b) =>\n a.memory.frontmatter.created_at.localeCompare(b.memory.frontmatter.created_at),\n );\n\n if (opts.topic) {\n sorted = sorted.filter((l) => l.memory.frontmatter.topic === opts.topic);\n }\n\n return {\n entries: sorted.slice(0, opts.limit).map((l) => toEntry(l)),\n };\n}\n\nfunction toEntry(l: LoadedMemory): TimelineEntry {\n const fm = l.memory.frontmatter;\n const base: TimelineEntry = {\n id: fm.id,\n type: fm.type,\n scope: fm.scope,\n created_at: fm.created_at,\n one_line: firstMemoryOneLine(l.memory.body),\n };\n if (fm.topic !== undefined && fm.topic !== \"\") {\n return { ...base, topic: fm.topic };\n }\n return base;\n}\n","import type { LoadedMemory } from \"./loader.js\";\n\nfunction tokenSetForConflict(loaded: LoadedMemory): Set<string> {\n const fm = loaded.memory.frontmatter;\n const heading = loaded.memory.body.match(/^\\s*#\\s+(.+)$/m)?.[1] ?? \"\";\n const blob = `${fm.id} ${heading} ${loaded.memory.body.slice(0, 2000)}`;\n const tokens = blob\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .map((w) => w.trim())\n .filter((w) => w.length >= 3);\n return new Set(tokens);\n}\n\nfunction jaccard(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 || b.size === 0) return 0;\n let inter = 0;\n for (const x of a) {\n if (b.has(x)) inter++;\n }\n const uni = a.size + b.size - inter;\n return uni === 0 ? 0 : inter / uni;\n}\n\nexport interface ConflictCandidatesOpts {\n sinceDays: number;\n types: string[];\n minJaccard: number;\n maxPairs: number;\n /** Hard cap on memories considered ( avoids O(n²) explosions). */\n maxScan: number;\n}\n\nexport interface ConflictCandidatePair {\n id_a: string;\n id_b: string;\n jaccard: number;\n}\n\nexport interface TopicStatusPair {\n id_a: string;\n id_b: string;\n topic: string;\n status_a: string;\n status_b: string;\n}\n\n/**\n * Same `topic` key with opposed trust (validated vs rejected) — advisory; use `mem_conflicts_with` per id next.\n */\nexport function findTopicStatusConflictPairs(\n memories: LoadedMemory[],\n maxPairs: number,\n): TopicStatusPair[] {\n const byTopic = new Map<string, LoadedMemory[]>();\n for (const l of memories) {\n const topic = l.memory.frontmatter.topic;\n if (!topic || topic.trim() === \"\") continue;\n const g = byTopic.get(topic);\n if (g) g.push(l);\n else byTopic.set(topic, [l]);\n }\n const out: TopicStatusPair[] = [];\n for (const [topic, group] of byTopic) {\n if (group.length < 2) continue;\n for (let i = 0; i < group.length && out.length < maxPairs; i++) {\n for (let j = i + 1; j < group.length && out.length < maxPairs; j++) {\n const sa = group[i]!.memory.frontmatter.status;\n const sb = group[j]!.memory.frontmatter.status;\n if (\n (sa === \"validated\" && sb === \"rejected\") ||\n (sa === \"rejected\" && sb === \"validated\")\n ) {\n out.push({\n id_a: group[i]!.memory.frontmatter.id,\n id_b: group[j]!.memory.frontmatter.id,\n topic,\n status_a: sa,\n status_b: sb,\n });\n }\n }\n }\n }\n return out;\n}\n\n/**\n * Bulk heuristic: lexical similarity pairs for human review → often followed by `mem_conflicts_with`.\n */\nexport function findLexicalConflictPairs(\n memories: LoadedMemory[],\n opts: ConflictCandidatesOpts,\n): { pairs: ConflictCandidatePair[]; scanned: number; truncated: boolean } {\n const cutoff = Date.now() - opts.sinceDays * 86_400_000;\n let pool = memories.filter((l) => {\n const fm = l.memory.frontmatter;\n if (!opts.types.includes(fm.type)) return false;\n const t = Date.parse(fm.created_at);\n return !Number.isNaN(t) && t >= cutoff;\n });\n pool.sort((a, b) =>\n b.memory.frontmatter.created_at.localeCompare(a.memory.frontmatter.created_at),\n );\n let truncated = false;\n if (pool.length > opts.maxScan) {\n pool = pool.slice(0, opts.maxScan);\n truncated = true;\n }\n const sets = pool.map((l) => ({\n id: l.memory.frontmatter.id,\n set: tokenSetForConflict(l),\n }));\n\n const pairs: ConflictCandidatePair[] = [];\n for (let i = 0; i < sets.length; i++) {\n for (let j = i + 1; j < sets.length; j++) {\n const jac = jaccard(sets[i]!.set, sets[j]!.set);\n if (jac >= opts.minJaccard) {\n pairs.push({ id_a: sets[i]!.id, id_b: sets[j]!.id, jaccard: jac });\n }\n }\n }\n pairs.sort((a, b) => b.jaccard - a.jaccard);\n return {\n pairs: pairs.slice(0, opts.maxPairs),\n scanned: pool.length,\n truncated,\n };\n}\n","import { mkdir, readFile, appendFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const RUNTIME_JOURNAL_FILENAME = \"session-journal.ndjson\";\n\nexport interface RuntimeJournalEntry {\n ts: string;\n kind: \"note\" | \"session_end\" | \"mcp\";\n /** Short human or agent message */\n message: string;\n /** Optional MCP tool name for kind=mcp */\n tool?: string;\n /** Arbitrary JSON-serializable metadata */\n meta?: Record<string, unknown>;\n}\n\nexport function runtimeJournalPath(paths: HaivePaths): string {\n return path.join(paths.runtimeDir, RUNTIME_JOURNAL_FILENAME);\n}\n\n/**\n * Append one NDJSON line under `.ai/.runtime/` (untracked by default).\n * Never throws to callers of shutdown hooks — wraps internally.\n */\nexport async function appendRuntimeJournalEntry(\n paths: HaivePaths,\n entry: Omit<RuntimeJournalEntry, \"ts\"> & { ts?: string },\n): Promise<void> {\n try {\n await mkdir(paths.runtimeDir, { recursive: true });\n const line: RuntimeJournalEntry = {\n ts: entry.ts ?? new Date().toISOString(),\n kind: entry.kind,\n message: entry.message,\n ...(entry.tool !== undefined ? { tool: entry.tool } : {}),\n ...(entry.meta !== undefined ? { meta: entry.meta } : {}),\n };\n await appendFile(\n runtimeJournalPath(paths),\n JSON.stringify(line) + \"\\n\",\n \"utf8\",\n );\n } catch {\n // non-fatal — runtime layer must not break tools\n }\n}\n\n/** Read last N valid JSON lines (oldest-first in returned array). */\nexport async function readRuntimeJournalTail(\n paths: HaivePaths,\n limit: number,\n): Promise<RuntimeJournalEntry[]> {\n const file = runtimeJournalPath(paths);\n if (!existsSync(file) || limit <= 0) return [];\n try {\n const raw = await readFile(file, \"utf8\");\n const lines = raw.trim().split(\"\\n\").filter(Boolean);\n const parsed: RuntimeJournalEntry[] = [];\n for (const line of lines.slice(-limit)) {\n try {\n parsed.push(JSON.parse(line) as RuntimeJournalEntry);\n } catch {\n /* skip corrupt line */\n }\n }\n return parsed;\n } catch {\n return [];\n }\n}\n","import { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const BRIEFING_MARKER_TTL_MS = 12 * 60 * 60 * 1000;\nexport const SESSION_RECAP_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\nexport interface BriefingMarker {\n session_id: string;\n task?: string;\n source: string;\n created_at: string;\n root: string;\n memory_ids?: string[];\n files?: string[];\n}\n\nexport function enforcementDir(paths: HaivePaths): string {\n return path.join(paths.runtimeDir, \"enforcement\");\n}\n\nexport function briefingMarkersDir(paths: HaivePaths): string {\n return path.join(enforcementDir(paths), \"briefings\");\n}\n\nexport function normalizeSessionId(sessionId?: string): string {\n return (sessionId?.trim() || \"default\").replace(/[^a-zA-Z0-9_.-]+/g, \"-\").slice(0, 120);\n}\n\nexport function briefingMarkerPath(paths: HaivePaths, sessionId?: string): string {\n return path.join(briefingMarkersDir(paths), `${normalizeSessionId(sessionId)}.json`);\n}\n\nexport async function writeBriefingMarker(\n paths: HaivePaths,\n input: {\n sessionId?: string;\n task?: string;\n source: string;\n memoryIds?: string[];\n files?: string[];\n /**\n * Accumulate memory_ids/files with the existing fresh marker for THIS session instead of\n * overwriting (default true). This is what lets decision-coverage build up as the agent works:\n * every get_briefing call, every pre-edit injection, every `haive briefing` ADDS to the\n * session's consulted set — so a broad commit no longer requires one giant briefing covering\n * every relevant decision at once. Pass false to replace (e.g. starting a brand-new session).\n */\n accumulate?: boolean;\n },\n): Promise<BriefingMarker> {\n const sessionId = normalizeSessionId(input.sessionId);\n const accumulate = input.accumulate ?? true;\n\n // Union with the existing fresh marker for the same session, so consulted memories accrue.\n let priorIds: string[] = [];\n let priorFiles: string[] = [];\n if (accumulate) {\n const existing = await readSessionBriefingMarker(paths, sessionId);\n if (existing) {\n priorIds = existing.memory_ids ?? [];\n priorFiles = existing.files ?? [];\n }\n }\n\n const mergedIds = [...new Set([...priorIds, ...(input.memoryIds ?? [])])];\n const mergedFiles = [...new Set([...priorFiles, ...(input.files ?? [])])];\n\n const marker: BriefingMarker = {\n session_id: sessionId,\n ...(input.task?.trim() ? { task: input.task.trim() } : {}),\n ...(mergedIds.length > 0 ? { memory_ids: mergedIds } : {}),\n ...(mergedFiles.length > 0 ? { files: mergedFiles } : {}),\n source: input.source,\n created_at: new Date().toISOString(),\n root: paths.root,\n };\n await mkdir(briefingMarkersDir(paths), { recursive: true });\n await writeFile(\n briefingMarkerPath(paths, marker.session_id),\n JSON.stringify(marker, null, 2) + \"\\n\",\n \"utf8\",\n );\n return marker;\n}\n\n/** Read THIS session's marker if it exists and is still fresh (within TTL). Null otherwise. */\nasync function readSessionBriefingMarker(\n paths: HaivePaths,\n sessionId: string,\n ttlMs = BRIEFING_MARKER_TTL_MS,\n): Promise<BriefingMarker | null> {\n const file = briefingMarkerPath(paths, sessionId);\n if (!existsSync(file)) return null;\n try {\n const marker = JSON.parse(await readFile(file, \"utf8\")) as BriefingMarker;\n const created = Date.parse(marker.created_at);\n if (!Number.isFinite(created) || Date.now() - created > ttlMs) return null;\n return marker;\n } catch {\n return null;\n }\n}\n\nexport async function hasRecentBriefingMarker(\n paths: HaivePaths,\n sessionId?: string,\n ttlMs = BRIEFING_MARKER_TTL_MS,\n): Promise<boolean> {\n const now = Date.now();\n const candidates: string[] = [];\n const exact = briefingMarkerPath(paths, sessionId);\n if (existsSync(exact)) candidates.push(exact);\n try {\n const dir = briefingMarkersDir(paths);\n const files = await readdir(dir);\n for (const file of files) {\n if (file.endsWith(\".json\")) candidates.push(path.join(dir, file));\n }\n } catch {\n // no marker directory yet\n }\n\n for (const file of new Set(candidates)) {\n try {\n const marker = JSON.parse(await readFile(file, \"utf8\")) as BriefingMarker;\n const created = Date.parse(marker.created_at);\n if (Number.isFinite(created) && now - created <= ttlMs) return true;\n } catch {\n // ignore corrupt markers\n }\n }\n return false;\n}\n\nexport async function readRecentBriefingMarker(\n paths: HaivePaths,\n sessionId?: string,\n ttlMs = BRIEFING_MARKER_TTL_MS,\n): Promise<BriefingMarker | null> {\n const now = Date.now();\n const candidates: string[] = [];\n const exact = briefingMarkerPath(paths, sessionId);\n if (existsSync(exact)) candidates.push(exact);\n try {\n const dir = briefingMarkersDir(paths);\n const files = await readdir(dir);\n for (const file of files) {\n if (file.endsWith(\".json\")) candidates.push(path.join(dir, file));\n }\n } catch {\n // no marker directory yet\n }\n\n let freshest: BriefingMarker | null = null;\n let freshestTs = 0;\n for (const file of new Set(candidates)) {\n try {\n const marker = JSON.parse(await readFile(file, \"utf8\")) as BriefingMarker;\n const created = Date.parse(marker.created_at);\n if (!Number.isFinite(created) || now - created > ttlMs) continue;\n if (created > freshestTs) {\n freshest = marker;\n freshestTs = created;\n }\n } catch {\n // ignore corrupt markers\n }\n }\n return freshest;\n}\n\nexport function isFreshIsoDate(value: string | Date, ttlMs: number, now = Date.now()): boolean {\n const ts = value instanceof Date ? value.getTime() : Date.parse(value);\n return Number.isFinite(ts) && now - ts <= ttlMs;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\n\nexport interface RetirementSignal {\n retired: boolean;\n reason?: string;\n}\n\nconst RETIRED_TAGS = new Set([\"superseded\", \"obsolete\", \"archived\"]);\n\nconst RETIRED_BODY_PATTERNS: Array<{ re: RegExp; reason: string }> = [\n { re: /\\bfixed\\s+in\\b[\\s\\S]{0,160}\\b(audit|history|historical|obsolete|no longer applies)\\b/i, reason: \"body says this fixed record is audit/history only\" },\n { re: /\\bresolved\\s+in\\b/i, reason: \"body says this was resolved\" },\n { re: /\\bsuperseded\\s+by\\b/i, reason: \"body says this was superseded\" },\n { re: /\\bno\\s+longer\\s+(applies|true|valid)\\b/i, reason: \"body says this no longer applies\" },\n { re: /\\bobsolete\\b/i, reason: \"body says this is obsolete\" },\n];\n\n/**\n * Explicit lifecycle gate for records that should not be fed back to agents as active policy.\n *\n * `status=deprecated/rejected/stale` is already the hard lifecycle signal. This helper covers\n * softer signals that teams naturally write while curating a corpus: an `expires_when` date,\n * a `superseded`/`obsolete` tag, or a short body note saying the attempt is now obsolete.\n *\n * Note: a plain `fixed` tag is intentionally NOT retired by itself. Many teams keep fixed\n * gotchas active as regression guards. To retire one, mark it deprecated, set expires_when,\n * use `obsolete`/`superseded`, or write that the fixed record is kept for audit/history only.\n */\nexport function retirementSignal(\n fm: MemoryFrontmatter,\n body = \"\",\n now: Date = new Date(),\n): RetirementSignal {\n if (fm.status === \"deprecated\" || fm.status === \"rejected\" || fm.status === \"stale\") {\n return { retired: true, reason: `status=${fm.status}` };\n }\n\n if (fm.expires_when) {\n const expiresAt = Date.parse(fm.expires_when);\n if (Number.isFinite(expiresAt) && expiresAt <= now.getTime()) {\n return { retired: true, reason: `expired on ${fm.expires_when.slice(0, 10)}` };\n }\n }\n\n const retiredTag = fm.tags.find((tag) => RETIRED_TAGS.has(tag.toLowerCase()));\n if (retiredTag) {\n return { retired: true, reason: `tagged ${retiredTag}` };\n }\n\n for (const pattern of RETIRED_BODY_PATTERNS) {\n if (pattern.re.test(body)) return { retired: true, reason: pattern.reason };\n }\n\n return { retired: false };\n}\n\nexport function isRetiredMemory(\n fm: MemoryFrontmatter,\n body = \"\",\n now: Date = new Date(),\n): boolean {\n return retirementSignal(fm, body, now).retired;\n}\n","import type { Memory, Sensor } from \"./types.js\";\n\n/**\n * Sensors — the feedback *computational* layer of the harness.\n *\n * A memory's `sensor` turns a documented lesson (gotcha/attempt) into a deterministic\n * check. Unlike semantic anti-pattern matching (probabilistic, warmup-sensitive), a\n * regex sensor fires the same way every time, so a known mistake becomes a permanent\n * guardrail. Phase 1 supports `kind: \"regex\"` only — pure, no I/O. `shell`/`test`\n * sensors are recognized but not executed here (they must run from the CLI).\n */\n\nexport interface SensorHit {\n /** The memory id whose sensor matched. */\n memory_id: string;\n /** The sensor that matched. */\n sensor: Sensor;\n /** Project-relative file the match was found in (when known). */\n file?: string;\n /** The matched line (trimmed, capped) — useful for review output. */\n matched_line?: string;\n /** LLM-facing self-correction message carried from the sensor. */\n message: string;\n severity: Sensor[\"severity\"];\n}\n\n/** A unit of code to scan: a file path plus the text to match against. */\nexport interface SensorTarget {\n /** Project-relative path (used for path scoping and reporting). */\n path: string;\n /**\n * Text to scan. For a diff, pass only the added lines (callers should pre-filter)\n * so a sensor fires on \"you introduced the bad pattern\", not \"you touched a file\n * that merely mentions it\".\n */\n content: string;\n}\n\nfunction normalizeProjectPath(value: string): string {\n return value\n .replace(/\\\\/g, \"/\")\n .replace(/^\\.\\//, \"\")\n .replace(/^[ab]\\//, \"\")\n .replace(/\\/+$/g, \"\");\n}\n\n/**\n * Does this sensor apply to `path`? A sensor with no explicit `paths` (and whose\n * memory has no anchor paths) applies everywhere. Otherwise it applies only to the\n * exact file or directory prefix. Use an explicit directory path (`src/foo/`) when a\n * sensor should cover a whole subtree.\n */\nexport function sensorAppliesToPath(\n sensor: Sensor,\n anchorPaths: string[],\n path: string,\n): boolean {\n const scopes = sensor.paths.length > 0 ? sensor.paths : anchorPaths;\n if (scopes.length === 0) return true;\n const target = normalizeProjectPath(path);\n return scopes.some((rawScope) => {\n const scope = normalizeProjectPath(rawScope);\n if (!scope) return false;\n return target === scope || target.startsWith(`${scope}/`);\n });\n}\n\n/**\n * Compile a regex sensor. Returns null when the sensor is not a runnable regex\n * (wrong kind, missing/invalid pattern) so callers can skip it safely.\n */\nexport function compileRegexSensor(sensor: Sensor): RegExp | null {\n if (sensor.kind !== \"regex\" || !sensor.pattern) return null;\n try {\n // Always multiline so `^`/`$` work per added line; merge with caller flags.\n const flags = new Set([\"m\", ...(sensor.flags ?? \"\").split(\"\")].filter(Boolean));\n return new RegExp(sensor.pattern, [...flags].join(\"\"));\n } catch {\n return null;\n }\n}\n\n/**\n * Run a single regex sensor over one target. Returns the first matching line as a hit,\n * or null. Deterministic and side-effect-free.\n */\nexport function runRegexSensor(\n memoryId: string,\n sensor: Sensor,\n target: SensorTarget,\n): SensorHit | null {\n const re = compileRegexSensor(sensor);\n if (!re) return null;\n for (const rawLine of target.content.split(\"\\n\")) {\n // Fresh lastIndex each line (no global flag is forced, but be defensive).\n re.lastIndex = 0;\n if (re.test(rawLine)) {\n return {\n memory_id: memoryId,\n sensor,\n file: target.path,\n matched_line: rawLine.trim().slice(0, 200),\n message: sensor.message,\n severity: sensor.severity,\n };\n }\n }\n return null;\n}\n\n/**\n * Run every memory's regex sensor against every applicable target.\n *\n * Memories without a sensor, or with a non-regex sensor, are skipped (non-regex kinds\n * are the CLI's responsibility). At most one hit per (memory, file) pair is returned.\n */\nexport function runSensors(\n memories: Memory[],\n targets: SensorTarget[],\n): SensorHit[] {\n const hits: SensorHit[] = [];\n for (const memory of memories) {\n const sensor = memory.frontmatter.sensor;\n if (!sensor || sensor.kind !== \"regex\") continue;\n const anchorPaths = memory.frontmatter.anchor.paths;\n for (const target of targets) {\n if (!sensorAppliesToPath(sensor, anchorPaths, target.path)) continue;\n const hit = runRegexSensor(memory.frontmatter.id, sensor, target);\n if (hit) hits.push(hit);\n }\n }\n return hits;\n}\n\n/**\n * A shell/test sensor selected for execution — the feedback *computational* layer that a regex\n * can't express. The schema reserves `kind: \"shell\" | \"test\"`; this picks the ones whose memory\n * applies to the changed paths so the CLI can run `command` (core stays pure — it never executes).\n */\nexport interface CommandSensorSpec {\n memory_id: string;\n /** Command to execute (shell or test runner invocation). */\n command: string;\n kind: \"shell\" | \"test\";\n severity: Sensor[\"severity\"];\n /** LLM-facing self-correction message carried from the sensor. */\n message: string;\n /** Anchor/scoped paths this sensor cares about (for reporting). */\n paths: string[];\n}\n\n/**\n * Select the shell/test sensors that apply to `changedPaths`. With no changed paths (or a sensor\n * scoped to everywhere) the sensor is selected unconditionally. Pure: the caller executes commands.\n */\nexport function selectCommandSensors(\n memories: Memory[],\n changedPaths: string[],\n): CommandSensorSpec[] {\n const specs: CommandSensorSpec[] = [];\n for (const memory of memories) {\n const sensor = memory.frontmatter.sensor;\n if (!sensor) continue;\n if (sensor.kind !== \"shell\" && sensor.kind !== \"test\") continue;\n const command = sensor.command?.trim();\n if (!command) continue;\n const anchorPaths = memory.frontmatter.anchor.paths;\n const applies =\n changedPaths.length === 0\n ? true\n : changedPaths.some((p) => sensorAppliesToPath(sensor, anchorPaths, p));\n if (!applies) continue;\n specs.push({\n memory_id: memory.frontmatter.id,\n command,\n kind: sensor.kind,\n severity: sensor.severity,\n message: sensor.message,\n paths: sensor.paths.length > 0 ? sensor.paths : anchorPaths,\n });\n }\n return specs;\n}\n\n/** Split a unified diff into per-file targets containing only added lines. */\nexport function sensorTargetsFromDiff(diff: string): SensorTarget[] {\n const targets: SensorTarget[] = [];\n let currentPath: string | null = null;\n let added: string[] = [];\n\n const flush = (): void => {\n if (!currentPath || added.length === 0) return;\n targets.push({ path: currentPath, content: added.join(\"\\n\") });\n added = [];\n };\n\n for (const line of diff.split(\"\\n\")) {\n if (line.startsWith(\"diff --git \")) {\n flush();\n currentPath = null;\n continue;\n }\n\n if (line.startsWith(\"+++ \")) {\n flush();\n const raw = line.slice(4).trim();\n currentPath = raw === \"/dev/null\" ? null : normalizeProjectPath(raw);\n continue;\n }\n\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n if (!currentPath) currentPath = \"\";\n added.push(line.slice(1));\n }\n }\n flush();\n return targets;\n}\n\n/**\n * Extract the added lines from a unified diff (lines starting with a single `+`,\n * excluding the `+++` file header). Mirrors the diff-handling already used by the\n * anti-pattern tokenizer so sensors fire on introductions, not mere mentions.\n */\nexport function addedLinesFromDiff(diff: string): string {\n const targets = sensorTargetsFromDiff(diff);\n if (targets.length > 0) return targets.map((target) => target.content).join(\"\\n\");\n return diff\n .split(\"\\n\")\n .filter((l) => l.startsWith(\"+\") && !l.startsWith(\"+++\"))\n .map((l) => l.slice(1))\n .join(\"\\n\");\n}\n","import type { Sensor } from \"./types.js\";\n\nconst CODE_TOKEN_RE = /`([^`\\n]{3,80})`|[\"']([A-Za-z0-9_.:-]{3,80})[\"']|\\b([A-Za-z][A-Za-z0-9_.:-]{2,79})\\b/g;\n\nconst SENSOR_STOPWORDS = new Set([\n \"about\", \"after\", \"again\", \"agent\", \"always\", \"anchor\", \"approach\", \"because\",\n \"before\", \"break\", \"broken\", \"cannot\", \"change\", \"code\", \"commit\", \"correct\",\n \"could\", \"default\", \"detect\", \"direct\", \"directory\", \"does\", \"error\", \"failed\",\n \"fails\", \"file\", \"files\", \"future\", \"instead\", \"memory\", \"never\", \"project\",\n \"recorded\", \"repo\", \"return\", \"should\", \"source\", \"string\", \"this\",\n \"tried\", \"true\", \"type\", \"undefined\", \"value\", \"when\", \"where\", \"which\", \"with\",\n \"without\",\n]);\n\nexport interface SensorSuggestionOptions {\n /** Extra paths to put on the sensor. Defaults to the memory anchor paths. */\n paths?: string[];\n}\n\n/**\n * Conservatively suggest a regex sensor from a gotcha/attempt body.\n *\n * This helper intentionally returns null more often than it guesses. Autogenerated\n * sensors start as `warn`, never `block`; humans can promote them after seeing them fire.\n */\nexport function suggestSensorFromMemory(\n body: string,\n anchorPaths: string[],\n options: SensorSuggestionOptions = {},\n): Sensor | null {\n const paths = options.paths ?? anchorPaths;\n if (paths.length === 0) return null;\n\n const negativeText = body.split(/\\*\\*Instead,\\s*use:\\*\\*|^##\\s+Instead\\b/im)[0] ?? body;\n const assignment = pickAssignmentPattern(negativeText);\n const lowercaseValue = assignment ? null : pickLowercaseValuePattern(negativeText);\n const token = assignment?.label ?? lowercaseValue?.label ?? pickDistinctiveToken(negativeText);\n if (!token) return null;\n\n return {\n kind: \"regex\",\n pattern: assignment?.pattern ?? lowercaseValue?.pattern ?? escapeRegExp(token),\n paths,\n message: sensorMessageFromBody(body, token),\n severity: \"warn\",\n autogen: true,\n last_fired: null,\n };\n}\n\nfunction pickLowercaseValuePattern(text: string): { label: string; pattern: string; score: number } | null {\n const candidates: Array<{ label: string; pattern: string; score: number }> = [];\n for (const match of text.matchAll(/\\blowercase\\s+([A-Za-z][A-Za-z0-9_.:-]{2,79})\\s+([a-z][a-z0-9_.:-]{1,40})\\b/g)) {\n const key = match[1] ?? \"\";\n const value = match[2] ?? \"\";\n if (!isDistinctiveToken(key, true) || isBoringValue(value)) continue;\n candidates.push({\n label: `${key}=${value}`,\n pattern: `${escapeRegExp(key)}\\\\s*[:=]\\\\s*[\"']?${escapeRegExp(value)}[\"']?`,\n score: key.length + value.length + 35,\n });\n }\n return candidates.sort((a, b) => b.score - a.score)[0] ?? null;\n}\n\nfunction pickAssignmentPattern(text: string): { label: string; pattern: string; score: number } | null {\n const candidates: Array<{ label: string; pattern: string; score: number }> = [];\n for (const source of assignmentSources(text)) {\n for (const match of source.matchAll(/\\b([A-Za-z][A-Za-z0-9_.:-]{2,79})\\b\\s*(=|:)\\s*[\"']?([A-Za-z0-9_.:-]{2,80})[\"']?/g)) {\n const key = match[1] ?? \"\";\n const operator = match[2] ?? \"\";\n const value = match[3] ?? \"\";\n if (!isDistinctiveToken(key, true) || isBoringValue(value)) continue;\n const label = `${key}${operator}${value}`;\n candidates.push({\n label,\n pattern: `${escapeRegExp(key)}\\\\s*${escapeRegExp(operator)}\\\\s*[\"']?${escapeRegExp(value)}[\"']?`,\n score: label.length + assignmentContextScore(source, match.index ?? 0, match[0].length),\n });\n }\n }\n return candidates.sort((a, b) => b.score - a.score)[0] ?? null;\n}\n\nfunction assignmentContextScore(source: string, index: number, length: number): number {\n const before = source.slice(Math.max(0, index - 50), index).toLowerCase();\n const after = source.slice(index + length, Math.min(source.length, index + length + 50)).toLowerCase();\n const window = `${before} ${after}`;\n let score = 0;\n if (/\\b(bad|failed|fails|broke|broken|wrong|avoid|forbid|forbidden|leaks?)\\b/.test(after)) score += 50;\n if (/do\\s+not|don't|never|should\\s+not|must\\s+not/.test(window)) score += 40;\n if (/\\b(keep|instead|correct|right|use|prefer|allowed)\\b/.test(before)) score -= 60;\n if (/\\b(keep|instead|correct|right|use|prefer|allowed)\\b/.test(after)) score -= 25;\n return score;\n}\n\nfunction assignmentSources(text: string): string[] {\n return [text];\n}\n\nfunction pickDistinctiveToken(text: string): string | null {\n const candidates = new Map<string, { raw: string; score: number }>();\n for (const match of text.matchAll(CODE_TOKEN_RE)) {\n const raw = (match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n const token = raw.replace(/^[^\\w.-]+|[^\\w.-]+$/g, \"\");\n const isCodeLike = Boolean(match[1] ?? match[2]);\n if (!isDistinctiveToken(token, isCodeLike)) continue;\n const key = token.toLowerCase();\n const codeSpanBonus = match[1] ? 20 : match[2] ? 8 : 0;\n const shapeBonus =\n /[-_.:]/.test(token) ? 3 :\n /[A-Z]/.test(token.slice(1)) ? 2 :\n /\\d/.test(token) ? 1 : 0;\n const score = token.length + codeSpanBonus + shapeBonus;\n const existing = candidates.get(key);\n if (!existing || score > existing.score) candidates.set(key, { raw: token, score });\n }\n const best = [...candidates.values()].sort((a, b) => b.score - a.score)[0];\n return best?.raw ?? null;\n}\n\n/**\n * Reject tokens that produce nonsensical sensors: pure numbers, number ranges / line refs\n * (`1131-1186`), version-ish strings, and bare filenames (`enforce.ts`). A sensor built from these\n * fires on noise and trains agents to ignore the gate — the false-positive failure mode the harness\n * must avoid. (Real reproduced miss: a gotcha body referencing `enforce.ts:1131-1186` produced the\n * regex `enforce\\.ts\\s*:\\s*1131-1186`.)\n */\nconst FILE_EXT_REF = /\\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|rb|php|cs|cpp|c|h|md|json|ya?ml|toml|lock)\\b/i;\nfunction isDegenerateToken(token: string): boolean {\n if (/^[\\d.\\-:_]+$/.test(token)) return true; // pure number / range / line ref like 1131-1186\n if (/\\d+\\s*-\\s*\\d+/.test(token)) return true; // a numeric / line range embedded anywhere (e.g. 1131-1186)\n if (FILE_EXT_REF.test(token)) return true; // contains a filename reference (e.g. enforce.ts, enforce.ts:1131)\n // mostly digits (e.g. a version or id with a stray letter): <=1 letter among many digits\n const letters = (token.match(/[A-Za-z]/g) ?? []).length;\n const digits = (token.match(/\\d/g) ?? []).length;\n if (digits >= 3 && letters <= 1) return true;\n return false;\n}\n\nfunction isDistinctiveToken(token: string, isCodeLike: boolean): boolean {\n if (token.length < 4 || token.length > 80) return false;\n if (/^https?:\\/\\//i.test(token)) return false;\n if (/^\\d+$/.test(token)) return false;\n if (isDegenerateToken(token)) return false;\n const lower = token.toLowerCase();\n if (SENSOR_STOPWORDS.has(lower)) return false;\n if (!/[A-Za-z]/.test(token)) return false;\n const shaped = /[-_.:\\d]/.test(token) || /[A-Z]/.test(token.slice(1));\n return shaped || isCodeLike;\n}\n\nfunction isBoringValue(value: string): boolean {\n if (!value || value.length > 80) return true;\n const lower = value.toLowerCase();\n if (lower === \"true\" || lower === \"false\") return false;\n if (isDegenerateToken(value)) return true; // numbers / ranges / line refs / filenames are not real values\n return SENSOR_STOPWORDS.has(lower);\n}\n\nfunction sensorMessageFromBody(body: string, token: string): string {\n const instead = body.match(/\\*\\*Instead,\\s*use:\\*\\*\\s*([^\\n]+)/i)?.[1]?.trim();\n if (instead) return `Avoid ${token}; ${instead}`;\n const firstGuidance = body\n .split(\"\\n\")\n .map((line) => line.replace(/^#+\\s*/, \"\").trim())\n .find((line) => line.length > 0 && !line.startsWith(\"---\"));\n return firstGuidance?.slice(0, 180) || `Avoid ${token}; this matched an autogenerated hAIve sensor.`;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport { buildFrontmatter } from \"./parser.js\";\nimport { suggestSensorFromMemory } from \"./sensor-suggest.js\";\n\n/**\n * Findings ingestion — the self-feeding half of the sensors story (feature B).\n *\n * Phase 1/2 turned a documented mistake into an executable `sensor`. But someone still has\n * to *document* the mistake. Findings ingestion closes the review↔memory loop: a real defect\n * reported by a scanner (SonarQube, or any SARIF-emitting tool like ESLint/Semgrep/CodeQL)\n * becomes an anchored `gotcha`/`convention` memory, pre-filled with a conservative autogen\n * sensor, so the *next* agent is steered away from it before it writes the same code.\n *\n * This module is pure: parsers + draft synthesis, no I/O. The CLI (`haive ingest`) and the\n * MCP tool (`ingest_findings`) read files / write memories around these functions.\n *\n * Safety: every draft is `status: proposed` and every suggested sensor is `severity: warn`\n * + `autogen: true`. Ingestion never auto-validates and never auto-blocks (safety rules +\n * `2026-05-07-attempt-strict-precommit-gate-on-haive`). A human promotes both.\n */\n\nexport type FindingSeverity = \"info\" | \"minor\" | \"major\" | \"critical\" | \"blocker\";\n\nexport interface Finding {\n /** Source tool, e.g. \"sonar\", \"eslint\", \"semgrep\". */\n tool: string;\n /** Rule key, e.g. \"typescript:S1234\" or \"no-unused-vars\". */\n ruleId: string;\n /** Human-readable description of the problem. */\n message: string;\n severity: FindingSeverity;\n /** Project-relative file path. */\n path: string;\n /** 1-based line number, when known. */\n line?: number;\n /** Offending source snippet, when the report provides one. */\n snippet?: string;\n /**\n * Stable dedup key: `tool:ruleId:path`. Deliberately excludes the line so re-running a\n * scan after unrelated edits (which shift line numbers) does not re-propose the same memory.\n */\n key: string;\n}\n\nexport interface MemoryDraft {\n key: string;\n /** `ingest:<key>` — used as the memory `topic` so re-ingestion upserts instead of duplicating. */\n topic: string;\n frontmatter: MemoryFrontmatter;\n body: string;\n finding: Finding;\n /** True when a conservative sensor could be derived from the finding. */\n has_sensor: boolean;\n}\n\nexport interface DraftOptions {\n /** Memory type for the draft. Default \"gotcha\". */\n type?: \"gotcha\" | \"convention\";\n /** Scope for the draft. Default \"team\". */\n scope?: \"personal\" | \"team\" | \"module\";\n module?: string;\n author?: string;\n}\n\nexport interface DraftsOptions extends DraftOptions {\n /** Cap on number of drafts produced (after in-batch dedup). */\n limit?: number;\n /** Only ingest findings at or above this severity. Default: none (all). */\n minSeverity?: FindingSeverity;\n}\n\nconst SEVERITY_RANK: Record<FindingSeverity, number> = {\n info: 0,\n minor: 1,\n major: 2,\n critical: 3,\n blocker: 4,\n};\n\n/** Normalize a tool-specific severity string to the shared scale. */\nexport function normalizeFindingSeverity(raw: string | undefined | null): FindingSeverity {\n const v = (raw ?? \"\").toString().trim().toLowerCase();\n switch (v) {\n case \"blocker\":\n return \"blocker\";\n case \"critical\":\n case \"error\":\n case \"fatal\":\n return \"critical\";\n case \"major\":\n case \"warning\":\n case \"warn\":\n return \"major\";\n case \"minor\":\n case \"note\":\n case \"info\":\n case \"information\":\n case \"informational\":\n return v === \"minor\" ? \"minor\" : \"info\";\n default:\n return \"info\";\n }\n}\n\nfunction findingKey(tool: string, ruleId: string, path: string): string {\n return `${tool}:${ruleId}:${path}`;\n}\n\nfunction coerceJson(input: string | unknown): unknown {\n if (typeof input === \"string\") {\n try {\n return JSON.parse(input);\n } catch (err) {\n throw new Error(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n return input;\n}\n\nfunction asArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n}\n\n/**\n * Parse SARIF 2.1.0 (`runs[].results[]`). Works for any SARIF emitter (ESLint, Semgrep,\n * CodeQL, etc.). The tool name comes from `runs[].tool.driver.name`.\n */\nexport function parseSarif(input: string | unknown): Finding[] {\n const doc = asRecord(coerceJson(input));\n const findings: Finding[] = [];\n for (const runRaw of asArray(doc.runs)) {\n const run = asRecord(runRaw);\n const driver = asRecord(asRecord(run.tool).driver);\n const tool = (typeof driver.name === \"string\" ? driver.name : \"sarif\").toLowerCase();\n for (const resultRaw of asArray(run.results)) {\n const result = asRecord(resultRaw);\n const ruleId =\n (typeof result.ruleId === \"string\" && result.ruleId) ||\n (typeof asRecord(result.rule).id === \"string\" ? (asRecord(result.rule).id as string) : \"\") ||\n \"unknown-rule\";\n const message =\n (typeof asRecord(result.message).text === \"string\"\n ? (asRecord(result.message).text as string)\n : \"\") || ruleId;\n const severity = normalizeFindingSeverity(typeof result.level === \"string\" ? result.level : \"warning\");\n const location = asRecord(asArray(result.locations)[0]);\n const physical = asRecord(location.physicalLocation);\n const artifact = asRecord(physical.artifactLocation);\n const region = asRecord(physical.region);\n const path = typeof artifact.uri === \"string\" ? normalizeUri(artifact.uri) : \"\";\n if (!path) continue;\n const line = typeof region.startLine === \"number\" ? region.startLine : undefined;\n const snippet =\n typeof asRecord(region.snippet).text === \"string\"\n ? (asRecord(region.snippet).text as string).trim()\n : undefined;\n findings.push({\n tool,\n ruleId,\n message: message.trim(),\n severity,\n path,\n ...(line !== undefined ? { line } : {}),\n ...(snippet ? { snippet } : {}),\n key: findingKey(tool, ruleId, path),\n });\n }\n }\n return findings;\n}\n\n/**\n * Parse the SonarQube issues payload (`issues[]` from `/api/issues/search`). The file path\n * lives in `component` as `projectKey:relative/path`; we strip the project key.\n */\nexport function parseSonar(input: string | unknown): Finding[] {\n const doc = asRecord(coerceJson(input));\n const findings: Finding[] = [];\n for (const issueRaw of asArray(doc.issues)) {\n const issue = asRecord(issueRaw);\n const ruleId = typeof issue.rule === \"string\" ? issue.rule : \"unknown-rule\";\n const message = typeof issue.message === \"string\" ? issue.message.trim() : ruleId;\n // Sonar exposes either `severity` (legacy) or `impacts[].severity` (MQR mode).\n const impacts = asArray(issue.impacts);\n const impactSeverity =\n impacts.length > 0 && typeof asRecord(impacts[0]).severity === \"string\"\n ? (asRecord(impacts[0]).severity as string)\n : undefined;\n const severity = normalizeFindingSeverity(\n (typeof issue.severity === \"string\" ? issue.severity : undefined) ?? impactSeverity,\n );\n const component = typeof issue.component === \"string\" ? issue.component : \"\";\n const path = componentToPath(component);\n if (!path) continue;\n const line = typeof issue.line === \"number\" ? issue.line : undefined;\n findings.push({\n tool: \"sonar\",\n ruleId,\n message,\n severity,\n path,\n ...(line !== undefined ? { line } : {}),\n key: findingKey(\"sonar\", ruleId, path),\n });\n }\n return findings;\n}\n\n/**\n * Parse the ESLint JSON formatter output (`eslint --format json`): an array of\n * `{ filePath, messages: [{ ruleId, severity, message, line }] }`. No SARIF formatter\n * package needed — this is ESLint's built-in format. `severity` is 2=error, 1=warning.\n * `opts.cwd`, when given, makes absolute `filePath`s project-relative so anchoring works.\n */\nexport function parseEslintJson(input: string | unknown, opts: { cwd?: string } = {}): Finding[] {\n const docs = asArray(coerceJson(input));\n const findings: Finding[] = [];\n const cwd = opts.cwd ? opts.cwd.replace(/\\/+$/, \"\") + \"/\" : \"\";\n for (const fileRaw of docs) {\n const file = asRecord(fileRaw);\n const rawPath = typeof file.filePath === \"string\" ? file.filePath : \"\";\n if (!rawPath) continue;\n const path = cwd && rawPath.startsWith(cwd) ? rawPath.slice(cwd.length) : rawPath;\n for (const msgRaw of asArray(file.messages)) {\n const msg = asRecord(msgRaw);\n const ruleId = typeof msg.ruleId === \"string\" && msg.ruleId ? msg.ruleId : \"parse-error\";\n const message = typeof msg.message === \"string\" ? msg.message.trim() : ruleId;\n const severity = normalizeFindingSeverity(msg.severity === 2 ? \"error\" : \"warning\");\n const line = typeof msg.line === \"number\" ? msg.line : undefined;\n findings.push({\n tool: \"eslint\",\n ruleId,\n message,\n severity,\n path,\n ...(line !== undefined ? { line } : {}),\n key: findingKey(\"eslint\", ruleId, path),\n });\n }\n }\n return findings;\n}\n\nconst NPM_AUDIT_SEVERITY: Record<string, FindingSeverity> = {\n critical: \"blocker\",\n high: \"critical\",\n moderate: \"major\",\n low: \"minor\",\n info: \"info\",\n};\n\n/**\n * Parse `npm audit --json` output (`vulnerabilities` map). Each vulnerable package becomes one\n * finding anchored to `package.json` (vulnerabilities are dependency-level, not file-level), so\n * the next agent is warned before re-introducing or ignoring the advisory.\n */\nexport function parseNpmAudit(input: string | unknown): Finding[] {\n const doc = asRecord(coerceJson(input));\n const vulns = asRecord(doc.vulnerabilities);\n const findings: Finding[] = [];\n for (const [name, vulnRaw] of Object.entries(vulns)) {\n const vuln = asRecord(vulnRaw);\n const sev = typeof vuln.severity === \"string\" ? vuln.severity.toLowerCase() : \"info\";\n const severity = NPM_AUDIT_SEVERITY[sev] ?? \"info\";\n const via = asArray(vuln.via);\n const firstAdvisory = via.map(asRecord).find((v) => typeof v.title === \"string\");\n const title =\n firstAdvisory && typeof firstAdvisory.title === \"string\"\n ? (firstAdvisory.title as string)\n : `Vulnerable dependency: ${name}`;\n const range = typeof vuln.range === \"string\" ? ` (affected range: ${vuln.range})` : \"\";\n findings.push({\n tool: \"npm-audit\",\n ruleId: name,\n message: `${title}${range}`,\n severity,\n path: \"package.json\",\n key: findingKey(\"npm-audit\", name, \"package.json\"),\n });\n }\n return findings;\n}\n\nexport type FindingFormat = \"sarif\" | \"sonar\" | \"eslint\" | \"npm-audit\";\n\n/** Dispatch to the right parser by declared format. */\nexport function parseFindings(\n format: FindingFormat,\n input: string | unknown,\n opts: { cwd?: string } = {},\n): Finding[] {\n switch (format) {\n case \"sonar\":\n return parseSonar(input);\n case \"eslint\":\n return parseEslintJson(input, opts);\n case \"npm-audit\":\n return parseNpmAudit(input);\n default:\n return parseSarif(input);\n }\n}\n\nfunction normalizeUri(uri: string): string {\n return uri.replace(/^file:\\/\\//, \"\").replace(/^\\.\\//, \"\");\n}\n\nfunction componentToPath(component: string): string {\n const idx = component.indexOf(\":\");\n return idx === -1 ? component : component.slice(idx + 1);\n}\n\nfunction sanitize(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 40);\n}\n\nfunction basename(p: string): string {\n const parts = p.split(\"/\");\n return parts[parts.length - 1] || p;\n}\n\n/** Build the markdown body for a finding-derived memory. */\nexport function findingBody(finding: Finding): string {\n const lines: string[] = [\n `# ${finding.ruleId} in ${finding.path}`,\n \"\",\n `**Source:** ${finding.tool} finding (severity: ${finding.severity})`,\n \"\",\n finding.message,\n \"\",\n `**Location:** ${finding.path}${finding.line !== undefined ? `:${finding.line}` : \"\"}`,\n ];\n if (finding.snippet) {\n lines.push(\"\", \"**Offending code:**\", \"```\", finding.snippet, \"```\");\n }\n lines.push(\"\", `**Instead, use:** Resolve the ${finding.tool} finding — ${finding.message}`);\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/** Convert one finding into a proposed memory draft (with a conservative sensor when derivable). */\nexport function findingToDraft(finding: Finding, options: DraftOptions = {}): MemoryDraft {\n const type = options.type ?? \"gotcha\";\n const scope = options.scope ?? \"team\";\n const topic = `ingest:${finding.key}`;\n const slug = `${sanitize(finding.tool)}-${sanitize(finding.ruleId)}-${sanitize(basename(finding.path))}`;\n const body = findingBody(finding);\n\n const frontmatter = buildFrontmatter({\n type,\n slug,\n scope,\n module: options.module,\n author: options.author,\n paths: [finding.path],\n tags: [\"ingested\", finding.tool, finding.severity],\n topic,\n status: \"proposed\",\n });\n\n const sensor = suggestSensorFromMemory(body, [finding.path]);\n if (sensor) frontmatter.sensor = sensor;\n\n return { key: finding.key, topic, frontmatter, body, finding, has_sensor: Boolean(sensor) };\n}\n\n/** Convert a batch of findings into drafts, deduped within the batch and capped/filtered. */\nexport function draftsFromFindings(findings: Finding[], options: DraftsOptions = {}): MemoryDraft[] {\n const minRank = options.minSeverity ? SEVERITY_RANK[options.minSeverity] : -1;\n const seen = new Set<string>();\n const drafts: MemoryDraft[] = [];\n for (const finding of findings) {\n if (SEVERITY_RANK[finding.severity] < minRank) continue;\n if (seen.has(finding.key)) continue;\n seen.add(finding.key);\n drafts.push(findingToDraft(finding, options));\n if (options.limit !== undefined && drafts.length >= options.limit) break;\n }\n return drafts;\n}\n\n/** Drop drafts whose topic already exists in the corpus (cross-run dedup). */\nexport function filterNewDrafts(drafts: MemoryDraft[], existingTopics: Iterable<string>): MemoryDraft[] {\n const existing = new Set(existingTopics);\n return drafts.filter((d) => !existing.has(d.topic));\n}\n","/**\n * Gate signal-quality — is the inferential (anti-pattern) gate earning trust or crying wolf?\n *\n * hAIve's anti-pattern gate is probabilistic and warmup-sensitive, so it is deliberately calibrated\n * NOT to hard-block on weak matches. But a team needs to SEE whether the gate's signal is precise:\n * are its catches turning out to be real (prevented mistakes, applied lessons) or noise (rejected by\n * humans via `mem_feedback`)? This module turns the signals hAIve already records — prevention events\n * (by source) and per-memory rejection counts — into a precision indicator and an actionable tuning\n * suggestion for `enforcement.antiPatternGate`. Pure: no I/O.\n */\nimport type { PreventionEvent } from \"./prevention.js\";\nimport type { UsageIndex } from \"./usage.js\";\nimport type { AntiPatternGate } from \"./config.js\";\n\nexport interface GatePrecision {\n /** Catches recorded by deterministic regex/command sensors. */\n sensor_catches: number;\n /** Catches recorded by the inferential anti-pattern gate. */\n anti_pattern_catches: number;\n /** Total \"useful\" outcomes (catches + human-applied lessons). */\n useful: number;\n /** Total human rejections (mem_feedback \"not useful\"). Proxy for false positives. */\n rejections: number;\n /** useful / (useful + rejections), 0..1. Null when there is no signal yet. */\n precision: number | null;\n /** A tuning recommendation for enforcement.antiPatternGate, or null when current looks right. */\n suggestion: GateTuningSuggestion | null;\n}\n\nexport interface GateTuningSuggestion {\n recommended: AntiPatternGate;\n reason: string;\n}\n\nexport interface GatePrecisionMetricDelta {\n baseline: number | null;\n current: number | null;\n delta: number | null;\n}\n\nexport interface GatePrecisionDelta {\n precision: GatePrecisionMetricDelta;\n rejections: GatePrecisionMetricDelta;\n /** True when humans rejected more gate output than the baseline run. */\n false_positives_increased: boolean;\n /** True when precision is known on both sides and dropped. */\n precision_regressed: boolean;\n /** CI-friendly rollup: either more false positives or lower known precision. */\n regressed: boolean;\n}\n\nfunction round3(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\n/**\n * Compute the gate's signal quality from prevention events + usage.\n * @param currentGate the configured antiPatternGate, used to decide whether to suggest a change.\n */\nexport function computeGatePrecision(\n events: PreventionEvent[],\n usage: UsageIndex,\n currentGate: AntiPatternGate = \"anchored\",\n): GatePrecision {\n let sensorCatches = 0;\n let antiPatternCatches = 0;\n for (const e of events) {\n if (e.source === \"sensor\") sensorCatches += 1;\n else if (e.source === \"anti-pattern\") antiPatternCatches += 1;\n }\n\n let applied = 0;\n let rejections = 0;\n for (const mem of Object.values(usage.by_id ?? {})) {\n applied += mem.applied_count ?? 0;\n rejections += mem.rejected_count ?? 0;\n }\n\n const useful = sensorCatches + antiPatternCatches + applied;\n const denom = useful + rejections;\n const precision = denom === 0 ? null : round3(useful / denom);\n\n return {\n sensor_catches: sensorCatches,\n anti_pattern_catches: antiPatternCatches,\n useful,\n rejections,\n precision,\n suggestion: suggestGate(precision, rejections, currentGate),\n };\n}\n\n/**\n * Suggest loosening the gate when it is noisy (low precision with real rejection volume), or\n * tightening it when it is precise but currently soft. Returns null when current looks right or\n * there isn't enough signal to act on.\n */\nexport function suggestGate(\n precision: number | null,\n rejections: number,\n currentGate: AntiPatternGate,\n): GateTuningSuggestion | null {\n // Need a meaningful sample before recommending a change.\n if (precision === null || rejections < 3) return null;\n\n if (precision < 0.5 && (currentGate === \"anchored\" || currentGate === \"strict\")) {\n return {\n recommended: \"review\",\n reason: `Gate precision ${precision} with ${rejections} rejection(s) — the gate is crying wolf. Loosen to \"review\" (surface, don't hard-block) until the corpus is cleaner.`,\n };\n }\n if (precision >= 0.85 && currentGate === \"review\") {\n return {\n recommended: \"anchored\",\n reason: `Gate precision ${precision} — catches are reliably real. Tighten to \"anchored\" so corroborated anti-patterns hard-block.`,\n };\n }\n return null;\n}\n\nfunction nullableMetricDelta(baseline: number | null, current: number | null): GatePrecisionMetricDelta {\n if (baseline === null || current === null) return { baseline, current, delta: null };\n return { baseline: round3(baseline), current: round3(current), delta: round3(current - baseline) };\n}\n\n/** Compare gate signal quality against a baseline for CI regression gates. Pure. */\nexport function compareGatePrecision(\n baseline: GatePrecision,\n current: GatePrecision,\n): GatePrecisionDelta {\n const precision = nullableMetricDelta(baseline.precision, current.precision);\n const rejections = nullableMetricDelta(baseline.rejections, current.rejections);\n const falsePositivesIncreased = current.rejections > baseline.rejections;\n const precisionRegressed = precision.delta !== null && precision.delta < 0;\n return {\n precision,\n rejections,\n false_positives_increased: falsePositivesIncreased,\n precision_regressed: precisionRegressed,\n regressed: falsePositivesIncreased || precisionRegressed,\n };\n}\n","import type { LoadedMemory } from \"./loader.js\";\nimport type { MemoryFrontmatter } from \"./types.js\";\nimport { computeImpact, compareImpact, summarizeImpact, type ImpactSummary, type ImpactScore } from \"./impact.js\";\nimport { isRetiredMemory } from \"./memory-lifecycle.js\";\nimport { DECAY_DAYS, getUsage, isDecaying, type UsageIndex } from \"./usage.js\";\nimport {\n computePreventionTrend,\n computeRecurrence,\n type PreventionEvent,\n type PreventionTrend,\n type RecurrenceReport,\n} from \"./prevention.js\";\nimport { computeGatePrecision, type GatePrecision } from \"./gate-precision.js\";\nimport type { AntiPatternGate } from \"./config.js\";\n\n/**\n * Observability rollup — the \"is the corpus healthy and earning its keep?\" view.\n *\n * hAIve already has the pieces (impact scoring, usage tracking, sensors, retirement,\n * decay) but no single non-interactive snapshot that an agent, a CI job, or a human\n * can read in one shot. `haive tui` exists but needs a TTY; `haive stats` only covers\n * tool-call volume. This module aggregates the full picture deterministically so the\n * CLI can print it (or emit JSON). Pure: no I/O, unit-tested in `test/dashboard.test.ts`.\n */\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\nexport interface DashboardOptions {\n /** How many rows to include in each \"top\" list. Default 10. */\n top?: number;\n /** Dormancy window for impact scoring. Defaults to impact's own default. */\n dormantDays?: number;\n now?: Date;\n /** Prevention event log (from `loadPreventionEvents`) — powers the trend + recurrence rollups. */\n preventionEvents?: PreventionEvent[];\n /** Configured anti-pattern gate — lets the gate-precision rollup suggest tightening/loosening. */\n antiPatternGate?: AntiPatternGate;\n}\n\nexport interface ImpactRow {\n id: string;\n score: number;\n tier: ImpactScore[\"tier\"];\n signals: string[];\n prune_candidate: boolean;\n}\n\nexport interface SensorRow {\n id: string;\n severity: \"warn\" | \"block\";\n last_fired: string;\n}\n\nexport interface DormantRow {\n id: string;\n last_read_at: string | null;\n age_days: number;\n}\n\nexport interface PreventionRow {\n id: string;\n type: string;\n prevented_count: number;\n last_prevented_at: string | null;\n}\n\nexport interface DashboardReport {\n generated_at: string;\n inventory: {\n /** Policy corpus size (excludes session_recap). */\n total: number;\n session_recaps: number;\n active: number;\n retired: number;\n by_scope: Record<string, number>;\n by_type: Record<string, number>;\n by_status: Record<string, number>;\n };\n /** OUTCOME measurement: prevention events = times a memory's sensor/anti-pattern fired on a real\n * diff, intercepting a known mistake. Distinct from retrieval (reads) — demonstrated value. */\n prevention: {\n total_events: number;\n memories_with_catches: number;\n top: PreventionRow[];\n /** Catch volume over time (from the prevention event log). */\n trend: PreventionTrend;\n /** Lessons re-introduced after capture (caught on >= 2 distinct days). */\n recurrence: RecurrenceReport;\n };\n /** Inferential-gate signal quality: are catches real (useful) or noise (rejected)? + tuning hint. */\n gate_precision: GatePrecision;\n impact: ImpactSummary & { top: ImpactRow[] };\n sensors: {\n total: number;\n warn: number;\n block: number;\n autogen: number;\n fired: number;\n recently_fired: SensorRow[];\n };\n health: {\n stale: number;\n retired: number;\n /** Validated decision/gotcha/architecture memories with no anchor paths or symbols. */\n anchorless: number;\n /** Memories awaiting review (draft/proposed). */\n pending: number;\n prune_candidates: number;\n };\n decay: {\n decay_days: number;\n decaying: number;\n top_dormant: DormantRow[];\n };\n corpus: {\n /** Number of memory files (policy corpus, excludes session_recap). */\n memory_files: number;\n body_chars: number;\n /** Rough token estimate (~chars/4) — how heavy the corpus is to inject. */\n est_tokens: number;\n };\n}\n\nfunction isAnchorless(fm: MemoryFrontmatter): boolean {\n if (![\"decision\", \"gotcha\", \"architecture\"].includes(fm.type)) return false;\n if (fm.status !== \"validated\") return false;\n return fm.anchor.paths.length === 0 && fm.anchor.symbols.length === 0;\n}\n\nfunction inc(map: Record<string, number>, key: string): void {\n map[key] = (map[key] ?? 0) + 1;\n}\n\n/** Build the full observability rollup from the loaded corpus + usage index. Pure. */\nexport function buildDashboard(\n memories: LoadedMemory[],\n usage: UsageIndex,\n options: DashboardOptions = {},\n): DashboardReport {\n const now = options.now ?? new Date();\n const top = options.top ?? 10;\n\n const inventory = {\n total: 0,\n session_recaps: 0,\n active: 0,\n retired: 0,\n by_scope: {} as Record<string, number>,\n by_type: {} as Record<string, number>,\n by_status: {} as Record<string, number>,\n };\n\n const impactScores: ImpactScore[] = [];\n const impactRows: ImpactRow[] = [];\n const sensorRows: SensorRow[] = [];\n let sensorTotal = 0;\n let sensorWarn = 0;\n let sensorBlock = 0;\n let sensorAutogen = 0;\n let sensorFired = 0;\n let stale = 0;\n let retired = 0;\n let anchorless = 0;\n let pending = 0;\n let decaying = 0;\n let bodyChars = 0;\n const dormantRows: DormantRow[] = [];\n let preventionEvents = 0;\n const preventionRows: PreventionRow[] = [];\n\n for (const { memory } of memories) {\n const fm = memory.frontmatter;\n\n if (fm.type === \"session_recap\") {\n inventory.session_recaps += 1;\n continue;\n }\n\n inventory.total += 1;\n inc(inventory.by_scope, fm.scope);\n inc(inventory.by_type, fm.type);\n inc(inventory.by_status, fm.status);\n bodyChars += memory.body.length;\n\n const isRetired = isRetiredMemory(fm, memory.body, now);\n if (isRetired) {\n inventory.retired += 1;\n retired += 1;\n } else {\n inventory.active += 1;\n }\n if (fm.status === \"stale\") stale += 1;\n if (isAnchorless(fm)) anchorless += 1;\n if (fm.status === \"draft\" || fm.status === \"proposed\") pending += 1;\n\n // ── Sensors ──\n if (fm.sensor) {\n sensorTotal += 1;\n if (fm.sensor.severity === \"block\") sensorBlock += 1;\n else sensorWarn += 1;\n if (fm.sensor.autogen) sensorAutogen += 1;\n if (fm.sensor.last_fired) {\n sensorFired += 1;\n sensorRows.push({ id: fm.id, severity: fm.sensor.severity, last_fired: fm.sensor.last_fired });\n }\n }\n\n // ── Impact ──\n const memUsage = getUsage(usage, fm.id);\n const impact = computeImpact(fm, memUsage, {\n now,\n ...(options.dormantDays !== undefined ? { dormantDays: options.dormantDays } : {}),\n });\n impactScores.push(impact);\n impactRows.push({\n id: fm.id,\n score: impact.score,\n tier: impact.tier,\n signals: impact.signals,\n prune_candidate: impact.pruneCandidate,\n });\n\n // ── Prevention (outcome) ──\n if (memUsage.prevented_count > 0) {\n preventionEvents += memUsage.prevented_count;\n preventionRows.push({\n id: fm.id,\n type: fm.type,\n prevented_count: memUsage.prevented_count,\n last_prevented_at: memUsage.last_prevented_at,\n });\n }\n\n // ── Decay ──\n if (isDecaying(memUsage, fm.created_at)) decaying += 1;\n if (impact.tier === \"dormant\") {\n const anchor = memUsage.last_read_at ?? fm.created_at;\n const ageDays = Math.floor((now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY);\n dormantRows.push({ id: fm.id, last_read_at: memUsage.last_read_at, age_days: ageDays });\n }\n }\n\n impactRows.sort((a, b) =>\n compareImpact(\n { score: a.score, tier: a.tier, signals: a.signals, pruneCandidate: a.prune_candidate },\n { score: b.score, tier: b.tier, signals: b.signals, pruneCandidate: b.prune_candidate },\n ),\n );\n sensorRows.sort((a, b) => b.last_fired.localeCompare(a.last_fired));\n dormantRows.sort((a, b) => b.age_days - a.age_days);\n const eventLog = options.preventionEvents ?? [];\n const recurrence = computeRecurrence(eventLog);\n\n return {\n generated_at: now.toISOString(),\n inventory,\n prevention: {\n total_events: preventionEvents,\n memories_with_catches: preventionRows.length,\n top: preventionRows\n .sort((a, b) => b.prevented_count - a.prevented_count)\n .slice(0, top),\n trend: computePreventionTrend(eventLog, now),\n recurrence: {\n ...recurrence,\n top: recurrence.top.slice(0, top),\n },\n },\n gate_precision: computeGatePrecision(\n eventLog,\n usage,\n options.antiPatternGate ?? \"anchored\",\n ),\n impact: { ...summarizeImpact(impactScores), top: impactRows.slice(0, top) },\n sensors: {\n total: sensorTotal,\n warn: sensorWarn,\n block: sensorBlock,\n autogen: sensorAutogen,\n fired: sensorFired,\n recently_fired: sensorRows.slice(0, top),\n },\n health: {\n stale,\n retired,\n anchorless,\n pending,\n prune_candidates: impactScores.filter((s) => s.pruneCandidate).length,\n },\n decay: {\n decay_days: DECAY_DAYS,\n decaying,\n top_dormant: dormantRows.slice(0, top),\n },\n corpus: {\n memory_files: inventory.total,\n body_chars: bodyChars,\n est_tokens: Math.round(bodyChars / 4),\n },\n };\n}\n","/**\n * Failure-capture coverage — the gate behind hAIve's \"never silently fix the same mistake\" loop.\n *\n * `haive observe` (the PostToolUse hook) appends an observation per tool call to\n * `.ai/.cache/observations.jsonl`, tagging hard failures with `failure_hint: true`\n * (non-zero Bash exit, `error TSxxxx`, ENOENT, …). Those failures are exactly the\n * `mem_tried` candidates the harness wants captured — otherwise the next session repeats them.\n *\n * This module is the pure decision layer: given the failure observations and the corpus's\n * `attempt`/`gotcha` memories, which failures look UNCAPTURED (no lesson recorded after them)?\n * The CLI reads the files and turns the result into an `enforce finish` finding. No I/O here.\n */\n\nexport interface FailureObservation {\n /** ISO timestamp of the observation. */\n ts: string;\n /** Tool that failed (Bash / Edit / …). */\n tool: string;\n /** Short human-readable summary of what was attempted. */\n summary: string;\n}\n\nexport interface UncapturedFailure {\n ts: string;\n tool: string;\n summary: string;\n}\n\nexport interface FailureCoverageOptions {\n /** Only consider failures newer than this many hours (avoid stale observations blocking forever). Default 24. */\n windowHours?: number;\n /** Collapse near-identical failures (same normalized summary) to one row. Default true. */\n dedupe?: boolean;\n now?: Date;\n}\n\nconst MS_PER_HOUR = 3_600_000;\n\nfunction normalizeSummary(summary: string): string {\n return summary.toLowerCase().replace(/\\s+/g, \" \").trim().slice(0, 160);\n}\n\n/**\n * A failure is CAPTURED when an `attempt`/`gotcha` lesson was recorded at or after it\n * (within the window) — the agent stopped and wrote the lesson down. Failures that pre-date\n * every recent capture are uncaptured: the gate should nudge (or block) on those.\n *\n * @param failures failure-tagged observations (any order)\n * @param captureTimes ISO created_at of every attempt/gotcha memory in the corpus\n */\nexport function findUncapturedFailures(\n failures: FailureObservation[],\n captureTimes: string[],\n options: FailureCoverageOptions = {},\n): UncapturedFailure[] {\n const now = (options.now ?? new Date()).getTime();\n const windowMs = (options.windowHours ?? 24) * MS_PER_HOUR;\n const dedupe = options.dedupe ?? true;\n\n // The freshest capture timestamp within the window — a lesson recorded after a failure covers it.\n let latestCapture = 0;\n for (const iso of captureTimes) {\n const t = Date.parse(iso);\n if (Number.isFinite(t) && now - t <= windowMs && t > latestCapture) latestCapture = t;\n }\n\n const seen = new Set<string>();\n const out: UncapturedFailure[] = [];\n for (const f of failures) {\n const t = Date.parse(f.ts);\n if (!Number.isFinite(t)) continue;\n if (now - t > windowMs) continue; // too old to act on\n if (t <= latestCapture) continue; // a capture happened after this failure → covered\n if (dedupe) {\n const key = normalizeSummary(f.summary);\n if (seen.has(key)) continue;\n seen.add(key);\n }\n out.push({ ts: f.ts, tool: f.tool, summary: f.summary });\n }\n out.sort((a, b) => a.ts.localeCompare(b.ts));\n return out;\n}\n","/**\n * Harness coverage-gap detection — \"which churny files have NO team knowledge on them?\".\n *\n * hAIve's `eval` synthesizes cases from the memories that EXIST (does the corpus surface\n * correctly?). It cannot tell you what knowledge is MISSING. This module answers the inverse,\n * proactive question Fowler frames as an open challenge: of the files the team edits most, which\n * carry no covering decision/convention/gotcha/architecture memory? Those are the blind spots\n * where a confident agent is most likely to violate an unwritten rule.\n *\n * Pure: the caller supplies hot files (from git history / briefing-radar) and the loaded corpus.\n */\nimport type { LoadedMemory } from \"./loader.js\";\n\n/** Where a file's \"heat\" came from: committed git churn, agent edits this/recent sessions, or both. */\nexport type HotFileSource = \"git\" | \"agent\" | \"both\";\n\nexport interface HotFile {\n path: string;\n /** Number of times the file changed in the lookback window (the \"heat\"). */\n changes: number;\n /** Provenance of the heat. Optional for back-compat with git-only callers. */\n source?: HotFileSource;\n}\n\nexport interface CoverageGap {\n path: string;\n changes: number;\n /** Provenance of the heat that made this file a blind spot. */\n source?: HotFileSource;\n}\n\nexport interface CoverageOptions {\n /** Only flag files with at least this many changes. Default 3. */\n minChanges?: number;\n /** Memory types that count as \"covering\" a file. Default decision/convention/gotcha/architecture. */\n coveringTypes?: string[];\n /** Cap on returned gaps. Default 20. */\n limit?: number;\n}\n\nconst DEFAULT_COVERING_TYPES = [\"decision\", \"convention\", \"gotcha\", \"architecture\"];\n\nfunction normalizePath(value: string): string {\n return value.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/g, \"\");\n}\n\n/**\n * Build the set of path prefixes the corpus covers: every anchor path of a non-dead,\n * non-recap covering memory. A file is covered if it equals, or sits under, one of them.\n */\nexport function buildCoverageIndex(\n memories: LoadedMemory[],\n coveringTypes: string[] = DEFAULT_COVERING_TYPES,\n): Set<string> {\n const types = new Set(coveringTypes);\n const covered = new Set<string>();\n for (const { memory } of memories) {\n const fm = memory.frontmatter;\n if (!types.has(fm.type)) continue;\n if (fm.status === \"stale\" || fm.status === \"deprecated\" || fm.status === \"rejected\") continue;\n for (const p of fm.anchor.paths) {\n const norm = normalizePath(p);\n if (norm) covered.add(norm);\n }\n }\n return covered;\n}\n\n/** True when `file` equals or is nested under any covered path prefix. */\nexport function isCovered(file: string, coverage: Set<string>): boolean {\n const target = normalizePath(file);\n if (coverage.has(target)) return true;\n for (const scope of coverage) {\n if (target === scope || target.startsWith(`${scope}/`)) return true;\n }\n return false;\n}\n\n/**\n * Cross hot files with the coverage index → the uncovered, frequently-edited files.\n * Highest heat first. These are the highest-value places to add a memory or sensor.\n */\nexport function findCoverageGaps(\n hotFiles: HotFile[],\n memories: LoadedMemory[],\n options: CoverageOptions = {},\n): CoverageGap[] {\n const minChanges = options.minChanges ?? 3;\n const limit = options.limit ?? 20;\n const coverage = buildCoverageIndex(memories, options.coveringTypes);\n\n const gaps: CoverageGap[] = [];\n for (const hot of hotFiles) {\n if (hot.changes < minChanges) continue;\n if (isCovered(hot.path, coverage)) continue;\n gaps.push({ path: normalizePath(hot.path), changes: hot.changes, ...(hot.source ? { source: hot.source } : {}) });\n }\n gaps.sort((a, b) => b.changes - a.changes);\n return gaps.slice(0, limit);\n}\n\n/**\n * Tally a flat list of edited file paths into HotFiles — the agent-edit heat signal from the\n * PostToolUse observation log (files agents actually touch), complementary to committed git churn.\n * Pure: the caller reads/normalizes the observation paths.\n */\nexport function tallyHotFiles(paths: string[], source: HotFileSource = \"agent\"): HotFile[] {\n const counts = new Map<string, number>();\n for (const raw of paths) {\n const norm = normalizePath(raw);\n if (!norm) continue;\n counts.set(norm, (counts.get(norm) ?? 0) + 1);\n }\n return [...counts.entries()]\n .map(([path, changes]) => ({ path, changes, source }))\n .sort((a, b) => b.changes - a.changes);\n}\n\n/**\n * Merge two HotFile lists, summing heat per path. A file hot in both lists is tagged `both` so the\n * report can show that agents AND git churn both point at the same uncovered file (the strongest gap).\n */\nexport function mergeHotFiles(a: HotFile[], b: HotFile[]): HotFile[] {\n const merged = new Map<string, HotFile>();\n for (const hot of [...a, ...b]) {\n const norm = normalizePath(hot.path);\n if (!norm) continue;\n const existing = merged.get(norm);\n if (!existing) {\n merged.set(norm, { path: norm, changes: hot.changes, ...(hot.source ? { source: hot.source } : {}) });\n continue;\n }\n existing.changes += hot.changes;\n if (hot.source && existing.source && hot.source !== existing.source) existing.source = \"both\";\n else existing.source = existing.source ?? hot.source;\n }\n return [...merged.values()].sort((x, y) => y.changes - x.changes);\n}\n","/**\n * Eval-score history — makes harness QUALITY a trended number, not a one-off.\n *\n * `eval.ts` produces a 0..100 score (retrieval recall/MRR + sensor catch-rate). A single score\n * answers \"is the harness good right now?\"; this append-only log answers \"is it getting better or\n * regressing over releases?\" — the question Fowler flags as an open challenge (\"evaluating harness\n * coverage as it grows\"). Mirrors `prevention.ts`: one JSONL line per run in `.ai/.cache/` so it\n * never churns a release, plus pure trend math the CLI/dashboard can render.\n */\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport interface EvalHistoryEntry {\n /** ISO timestamp of the eval run. */\n at: string;\n /** Overall 0..100 score. */\n score: number;\n /** Optional component metrics for richer trend views. */\n mean_recall?: number;\n mrr?: number;\n catch_rate?: number;\n /** Optional version/commit the run was taken at. */\n ref?: string;\n}\n\nexport function evalHistoryPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", \"eval-history.jsonl\");\n}\n\n/** Append one eval run to the history. Best-effort, creates the dir on demand. */\nexport async function appendEvalHistory(paths: HaivePaths, entry: EvalHistoryEntry): Promise<void> {\n const file = evalHistoryPath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n await appendFile(file, JSON.stringify(entry) + \"\\n\", \"utf8\");\n}\n\n/** Read all eval runs (skips malformed lines). */\nexport async function loadEvalHistory(paths: HaivePaths): Promise<EvalHistoryEntry[]> {\n const file = evalHistoryPath(paths);\n if (!existsSync(file)) return [];\n const raw = await readFile(file, \"utf8\").catch(() => \"\");\n const out: EvalHistoryEntry[] = [];\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const e = JSON.parse(trimmed) as EvalHistoryEntry;\n if (e && typeof e.at === \"string\" && typeof e.score === \"number\") out.push(e);\n } catch {\n // skip a corrupt line\n }\n }\n return out;\n}\n\nexport interface EvalTrend {\n /** Most recent score, or null when there is no history. */\n latest: number | null;\n /** Score before the latest, or null. */\n previous: number | null;\n /** latest − previous (positive = improving). */\n delta: number | null;\n /** Best score ever recorded. */\n best: number | null;\n /** Number of runs recorded. */\n runs: number;\n /** Last N scores oldest → newest for a sparkline. */\n recent: number[];\n /** True when the latest run dropped vs the previous one. */\n regressed: boolean;\n}\n\n/** Pure trend over the history (chronological order is enforced internally). */\nexport function computeEvalTrend(entries: EvalHistoryEntry[], recentN = 10): EvalTrend {\n const sorted = [...entries].sort((a, b) => a.at.localeCompare(b.at));\n const scores = sorted.map((e) => e.score);\n const latest = scores.length > 0 ? scores[scores.length - 1]! : null;\n const previous = scores.length > 1 ? scores[scores.length - 2]! : null;\n const delta = latest !== null && previous !== null ? Math.round((latest - previous) * 1000) / 1000 : null;\n const best = scores.length > 0 ? Math.max(...scores) : null;\n return {\n latest,\n previous,\n delta,\n best,\n runs: scores.length,\n recent: scores.slice(-recentN),\n regressed: delta !== null && delta < 0,\n };\n}\n","/**\n * Contradiction resolution planning — turns \"two memories conflict\" into \"do THIS\".\n *\n * `conflict-candidates.ts` surfaces pairs (same topic with opposed status, or lexically near-\n * duplicate). That's detection, not resolution — and Fowler lists incoherence-at-scale (a harness\n * full of contradictory guides) as a core open challenge. This module decides, deterministically,\n * which memory of a pair should WIN and which should be superseded (deprecated), so the CLI can\n * apply it. Pure: no I/O, unit-tested.\n *\n * Decision order (strongest signal first):\n * 1. status — a `validated` memory beats a `rejected`/`deprecated`/`stale` one.\n * 2. revision — higher `revision_count` (more refined via topic-upsert) wins.\n * 3. recency — newer `created_at` wins (the team's latest word).\n */\nimport type { LoadedMemory } from \"./loader.js\";\nimport type { MemoryFrontmatter } from \"./types.js\";\n\nexport interface ConflictResolution {\n /** Memory id to keep authoritative. */\n keep_id: string;\n /** Memory id to deprecate (superseded). */\n supersede_id: string;\n /** Human-readable reason the winner was chosen. */\n reason: string;\n /** stale_reason to stamp on the superseded memory. */\n stale_reason: string;\n}\n\nconst STATUS_RANK: Record<string, number> = {\n validated: 4,\n proposed: 3,\n draft: 2,\n stale: 1,\n deprecated: 0,\n rejected: 0,\n};\n\nfunction statusRank(fm: MemoryFrontmatter): number {\n return STATUS_RANK[fm.status] ?? 2;\n}\n\n/** Compare two memories; returns the one that should WIN plus the reason. Pure. */\nexport function planConflictResolution(\n a: LoadedMemory,\n b: LoadedMemory,\n): ConflictResolution {\n const fa = a.memory.frontmatter;\n const fb = b.memory.frontmatter;\n\n const ra = statusRank(fa);\n const rb = statusRank(fb);\n let winner: LoadedMemory;\n let loser: LoadedMemory;\n let reason: string;\n\n if (ra !== rb) {\n [winner, loser] = ra > rb ? [a, b] : [b, a];\n reason = `status (${winner.memory.frontmatter.status} beats ${loser.memory.frontmatter.status})`;\n } else if (fa.revision_count !== fb.revision_count) {\n [winner, loser] = fa.revision_count > fb.revision_count ? [a, b] : [b, a];\n reason = `revision_count (${winner.memory.frontmatter.revision_count} > ${loser.memory.frontmatter.revision_count})`;\n } else {\n const cmp = fa.created_at.localeCompare(fb.created_at);\n [winner, loser] = cmp >= 0 ? [a, b] : [b, a];\n reason = `recency (${winner.memory.frontmatter.created_at} is newer)`;\n }\n\n const keepId = winner.memory.frontmatter.id;\n const supersedeId = loser.memory.frontmatter.id;\n return {\n keep_id: keepId,\n supersede_id: supersedeId,\n reason,\n stale_reason: `Superseded by ${keepId} (conflict resolved on ${reason}).`,\n };\n}\n\nexport interface AppliedConflictResolution {\n /** Updated frontmatter for the memory to keep (promoted). */\n winner: MemoryFrontmatter;\n /** Updated frontmatter for the memory to supersede (deprecated). */\n loser: MemoryFrontmatter;\n /** Topic the winner now carries — the consolidation target for future `mem_save` upserts. Null when neither carried one. */\n topic: string | null;\n /** True when the winner adopted the loser's topic because it had none. */\n topic_adopted: boolean;\n}\n\n/**\n * Turn a {@link ConflictResolution} plan into the two concrete frontmatter updates — the guided\n * supersede the backlog called for, wired into topic-upsert/revision_count:\n * - loser → deprecated, stamped with stale_reason + a related_ids link to the winner.\n * - winner → revision_count++ (it absorbed a contradiction), verified now, linked to the loser,\n * and it ADOPTS the loser's topic when it had none — so the next `mem_save` on this subject\n * upserts into the winner instead of spawning a third conflicting memory. An existing winner\n * topic is never overwritten. Pure: the caller persists both.\n */\nexport function applyConflictResolution(\n winner: LoadedMemory,\n loser: LoadedMemory,\n plan: ConflictResolution,\n now: Date = new Date(),\n): AppliedConflictResolution {\n const ts = now.toISOString();\n const wf = winner.memory.frontmatter;\n const lf = loser.memory.frontmatter;\n\n const winnerHasTopic = Boolean(wf.topic && wf.topic.trim() !== \"\");\n const loserHasTopic = Boolean(lf.topic && lf.topic.trim() !== \"\");\n const topicAdopted = !winnerHasTopic && loserHasTopic;\n const topic = winnerHasTopic ? wf.topic! : topicAdopted ? lf.topic! : null;\n\n const winnerFm: MemoryFrontmatter = {\n ...wf,\n revision_count: wf.revision_count + 1,\n verified_at: ts,\n related_ids: [...new Set([...wf.related_ids, plan.supersede_id])],\n ...(topic ? { topic } : {}),\n };\n\n const loserFm: MemoryFrontmatter = {\n ...lf,\n status: \"deprecated\",\n stale_reason: plan.stale_reason,\n verified_at: ts,\n related_ids: [...new Set([...lf.related_ids, plan.keep_id])],\n };\n\n return { winner: winnerFm, loser: loserFm, topic, topic_adopted: topicAdopted };\n}\n","/**\n * Cold-start seeding from git history — the harness has value only once the corpus is populated,\n * and a fresh repo starts empty (Fowler's \"harnessability\": greenfield is easy, legacy is hard).\n *\n * Reverts and fixups are the cheapest signal of a real, repo-specific mistake: a commit that had to\n * be undone or hot-fixed encodes a lesson the team already paid for. This module parses a list of\n * commits (the CLI runs `git log`) and proposes DRAFT `attempt` seeds — never validated, always\n * human-reviewed. Pure: the caller does the git I/O and the memory writes.\n */\n\nexport interface GitCommit {\n sha: string;\n subject: string;\n /** Files touched by the commit (optional — improves anchoring). */\n files?: string[];\n}\n\nexport interface SeedProposal {\n /** Kebab-ish slug derived from the reverted subject. */\n slug: string;\n /** What was tried (the thing that had to be reverted/fixed). */\n what: string;\n /** Why it failed (inferred from the revert/fixup). */\n why_failed: string;\n /** Suggested anchor paths (from the commit's files). */\n paths: string[];\n /** The source commit, for provenance. */\n source_sha: string;\n /** Detected signal kind. */\n kind: \"revert\" | \"fixup\" | \"workaround\";\n}\n\nconst REVERT_RE = /^Revert\\s+\"(.+)\"\\s*$/i;\nconst FIXUP_RE = /^(?:fixup!|hotfix[:!]|fix[:!]\\s*revert|revert\\s+revert)/i;\nconst URGENT_FIX_RE = /\\b(hotfix|urgent fix|emergency fix|critical fix|broke production|broken build)\\b/i;\n// A commit that admits a stop-gap encodes a known trap: the \"right\" fix is still owed.\n// The leading `(?<![\\w-])` stops compound *nouns* (a feature literally named \"env-workaround\",\n// \"X-workaround\") from being mistaken for an admission of bricolage — that produced a meaningless\n// seed for `chore: apply env-workaround down-rank to corpus`. FIXME/XXX are deliberately excluded:\n// they belong in code, not commit subjects, where they were pure noise.\nconst WORKAROUND_RE = /(?<![\\w-])(?:work[\\s-]?around|band[\\s-]?aid|temporary fix|temp fix|quick[\\s-]?fix|kludge|monkey[\\s-]?patch|stop[\\s-]?gap)(?![\\w-])|\\bhack(?:y|ish)?\\b/i;\n\nfunction slugify(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60) || \"reverted-change\"\n );\n}\n\n/**\n * Turn commits into seed proposals. A `Revert \"X\"` commit proposes an attempt about X; an obvious\n * hotfix/fixup commit proposes an attempt about the fixed area. Deduped by slug. Pure.\n */\nexport function proposeSeedsFromCommits(\n commits: GitCommit[],\n limit = 20,\n): SeedProposal[] {\n const out: SeedProposal[] = [];\n const seen = new Set<string>();\n\n for (const commit of commits) {\n const subject = commit.subject.trim();\n let what: string | null = null;\n let kind: SeedProposal[\"kind\"] | null = null;\n\n const revert = subject.match(REVERT_RE);\n if (revert) {\n what = revert[1]!.trim();\n kind = \"revert\";\n } else if (FIXUP_RE.test(subject) || URGENT_FIX_RE.test(subject)) {\n what = subject.replace(FIXUP_RE, \"\").trim() || subject;\n kind = \"fixup\";\n } else if (WORKAROUND_RE.test(subject)) {\n what = subject;\n kind = \"workaround\";\n }\n\n if (!what || !kind) continue;\n const slug = slugify(what);\n if (seen.has(slug)) continue;\n seen.add(slug);\n\n out.push({\n slug,\n what,\n why_failed:\n kind === \"revert\"\n ? `This change was reverted in commit ${commit.sha} — it caused a regression and was backed out. Verify the root cause before re-attempting.`\n : kind === \"workaround\"\n ? `This area carries a known workaround/stop-gap (commit ${commit.sha}: \"${subject}\") — the proper fix is still owed. Understand why the workaround exists before changing it.`\n : `This area required an urgent fix (commit ${commit.sha}: \"${subject}\") — it shipped broken once. Treat changes here with extra care.`,\n paths: (commit.files ?? []).slice(0, 8),\n source_sha: commit.sha,\n kind,\n });\n if (out.length >= limit) break;\n }\n\n return out;\n}\n","/**\n * Pure stack-detection helpers for cold-start seeding.\n *\n * Multi-language: reads package.json deps (JS/TS), requirements.txt (Python),\n * go.mod (Go), and pom.xml (Java/Spring) to produce the list of detected stacks.\n * No I/O — the caller reads the files and passes contents in, making this fully testable.\n */\n\nexport interface DetectStacksInput {\n /** Merged deps from package.json (dependencies + devDependencies). */\n packageJsonDeps?: Record<string, string>;\n /** Raw text of requirements.txt (or any requirements file). */\n requirementsTxt?: string;\n /** Raw text of go.mod. */\n goMod?: string;\n /** Raw text of pom.xml. */\n pomXml?: string;\n /** Raw text of composer.json (PHP). */\n composerJson?: string;\n /** Raw text of Gemfile (Ruby). */\n gemfile?: string;\n /** True when at least one .csproj/.sln file is present (.NET). */\n hasCsproj?: boolean;\n /** True when a Dockerfile is present. */\n hasDockerfile?: boolean;\n /** True when turbo.json is present (Turborepo). */\n hasTurboJson?: boolean;\n /** True when nx.json is present (Nx). */\n hasNxJson?: boolean;\n}\n\nexport type DetectableStack =\n | \"nestjs\" | \"nextjs\" | \"remix\" | \"react\" | \"express\" | \"fastify\"\n | \"prisma\" | \"drizzle\" | \"zustand\" | \"redux\" | \"reactquery\" | \"trpc\"\n | \"mongoose\" | \"graphql\" | \"vue\"\n | \"tailwind\" | \"vite\" | \"sveltekit\" | \"astro\" | \"typescript\" | \"monorepo\"\n | \"fastapi\" | \"django\" | \"flask\"\n | \"go\"\n | \"spring\"\n | \"laravel\" | \"rails\" | \"dotnet\" | \"docker\";\n\nconst JS_DETECTORS: [DetectableStack, string[]][] = [\n [\"nestjs\", [\"@nestjs/core\"]],\n [\"nextjs\", [\"next\"]],\n [\"remix\", [\"@remix-run/react\", \"@remix-run/node\"]],\n [\"react\", [\"react\"]],\n [\"express\", [\"express\"]],\n [\"fastify\", [\"fastify\"]],\n [\"prisma\", [\"@prisma/client\", \"prisma\"]],\n [\"drizzle\", [\"drizzle-orm\"]],\n [\"zustand\", [\"zustand\"]],\n [\"redux\", [\"@reduxjs/toolkit\", \"redux\"]],\n [\"reactquery\", [\"@tanstack/react-query\", \"react-query\"]],\n [\"trpc\", [\"@trpc/server\", \"@trpc/client\"]],\n [\"mongoose\", [\"mongoose\"]],\n [\"graphql\", [\"@apollo/client\", \"@apollo/server\", \"apollo-server\", \"graphql\"]],\n [\"vue\", [\"vue\", \"@vue/core\"]],\n [\"tailwind\", [\"tailwindcss\"]],\n [\"vite\", [\"vite\"]],\n [\"sveltekit\", [\"@sveltejs/kit\"]],\n [\"astro\", [\"astro\"]],\n [\"typescript\", [\"typescript\"]],\n [\"monorepo\", [\"turbo\", \"nx\", \"@nrwl/workspace\", \"@nx/workspace\"]],\n];\n\nconst PYTHON_DETECTORS: [DetectableStack, RegExp][] = [\n [\"fastapi\", /\\bfastapi\\b/i],\n [\"django\", /\\bdjango\\b/i],\n [\"flask\", /\\bflask\\b/i],\n];\n\nfunction detectFromPackageJson(deps: Record<string, string>): DetectableStack[] {\n const detected: DetectableStack[] = [];\n for (const [stack, signals] of JS_DETECTORS) {\n if (signals.some((s) => s in deps)) detected.push(stack);\n }\n // Suppress generic 'react' when a framework that includes it is already detected\n if (detected.includes(\"nextjs\") || detected.includes(\"remix\")) {\n return detected.filter((s) => s !== \"react\");\n }\n return detected;\n}\n\nfunction detectFromRequirementsTxt(content: string): DetectableStack[] {\n return PYTHON_DETECTORS.filter(([, re]) => re.test(content)).map(([s]) => s);\n}\n\nfunction detectFromGoMod(content: string): DetectableStack[] {\n // go.mod presence (has a module declaration) → go stack\n return /^\\s*module\\s+\\S/m.test(content) ? [\"go\"] : [];\n}\n\nfunction detectFromPomXml(content: string): DetectableStack[] {\n return /org\\.springframework|spring-boot/.test(content) ? [\"spring\"] : [];\n}\n\nfunction detectFromComposerJson(content: string): DetectableStack[] {\n return /laravel\\/framework|illuminate\\//.test(content) ? [\"laravel\"] : [];\n}\n\nfunction detectFromGemfile(content: string): DetectableStack[] {\n return /^\\s*gem\\s+[\"']rails[\"']/m.test(content) || /\\brails\\b/.test(content) ? [\"rails\"] : [];\n}\n\n/**\n * Detect stacks present in a project from the raw contents of its manifest files.\n * Pure — no I/O. Pass what you have; omit what you don't.\n */\nexport function detectStacksFromManifests(input: DetectStacksInput): DetectableStack[] {\n const seen = new Set<DetectableStack>();\n const add = (stacks: DetectableStack[]) => stacks.forEach((s) => seen.add(s));\n\n if (input.packageJsonDeps) add(detectFromPackageJson(input.packageJsonDeps));\n if (input.requirementsTxt) add(detectFromRequirementsTxt(input.requirementsTxt));\n if (input.goMod) add(detectFromGoMod(input.goMod));\n if (input.pomXml) add(detectFromPomXml(input.pomXml));\n if (input.composerJson) add(detectFromComposerJson(input.composerJson));\n if (input.gemfile) add(detectFromGemfile(input.gemfile));\n if (input.hasCsproj) add([\"dotnet\"]);\n if (input.hasDockerfile) add([\"docker\"]);\n if (input.hasTurboJson || input.hasNxJson) add([\"monorepo\"]);\n\n return Array.from(seen);\n}\n","/**\n * Deterministic 3-way merge for hAIve memory files — kills the `.ai/` conflict-marker pain.\n *\n * Several agents + the human edit this repo in parallel with manual pull/push, so the same memory\n * file (especially the topic-upsert session recap, which churns every session) regularly collides\n * and leaves `<<<<<<<` markers under `.ai/`. A normal text merge can't resolve that; but a hAIve\n * memory has a total order baked into its frontmatter, so we CAN pick a winner deterministically:\n *\n * 1. higher `revision_count` (more topic-upsert refinements) wins\n * 2. else newer `created_at` wins\n * 3. else fall back to \"ours\" (stable, avoids a hard conflict)\n *\n * Registered as a git merge driver via `.gitattributes` (`*.md merge=haive` under `.ai/memories/`).\n * Pure: the CLI driver reads ours/theirs, calls this, writes the result.\n */\nimport { parseMemory } from \"./parser.js\";\n\nexport interface MergeResult {\n /** The chosen file content. */\n content: string;\n /** Which side won. */\n winner: \"ours\" | \"theirs\";\n /** Why (for logging). */\n reason: string;\n}\n\nfunction safeParse(raw: string): ReturnType<typeof parseMemory> | null {\n try {\n return parseMemory(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve two versions of the same memory file. Returns the winning content and the rationale.\n * Falls back to \"ours\" when either side can't be parsed (never throws — a merge driver must not).\n */\nexport function mergeMemoryVersions(ours: string, theirs: string): MergeResult {\n if (ours === theirs) {\n return { content: ours, winner: \"ours\", reason: \"identical\" };\n }\n const a = safeParse(ours);\n const b = safeParse(theirs);\n\n // Unparseable side → keep ours; the driver can still exit cleanly instead of leaving markers.\n if (!a || !b) {\n return { content: ours, winner: \"ours\", reason: \"unparseable side — kept ours\" };\n }\n\n const ra = a.frontmatter.revision_count ?? 0;\n const rb = b.frontmatter.revision_count ?? 0;\n if (ra !== rb) {\n return rb > ra\n ? { content: theirs, winner: \"theirs\", reason: `higher revision_count (${rb} > ${ra})` }\n : { content: ours, winner: \"ours\", reason: `higher revision_count (${ra} > ${rb})` };\n }\n\n const ca = a.frontmatter.created_at ?? \"\";\n const cb = b.frontmatter.created_at ?? \"\";\n const cmp = cb.localeCompare(ca);\n if (cmp > 0) return { content: theirs, winner: \"theirs\", reason: `newer created_at (${cb})` };\n if (cmp < 0) return { content: ours, winner: \"ours\", reason: `newer created_at (${ca})` };\n\n return { content: ours, winner: \"ours\", reason: \"tie — kept ours\" };\n}\n","/**\n * Recap compaction — keep the auto-generated session recap from dominating the briefing head.\n *\n * The MCP server auto-saves a minimal recap on exit (goal = \"Auto-captured session (N tool calls)\",\n * body = a raw tool-call/file dump). It's low signal, yet get_briefing shows the freshest recap's\n * full body at the very top of every briefing. A human/post_task recap (with a real Discoveries\n * section) is far richer. This module detects an auto recap and compresses it to its useful core\n * (the Discoveries, if any) so it informs without crowding. Pure, unit-tested.\n */\n\n/**\n * True when a recap body looks auto-generated (vs. a human/post_task recap). Auto recaps come in a\n * couple of shapes, all low-signal: the session-tracker's \"Auto-captured session (N tool calls)\" and\n * the run-wrapper's \"Edited N files across M tool calls\". The common tell is a raw tool-call count.\n */\nexport function isAutoRecap(body: string): boolean {\n return (\n /Auto-captured session/i.test(body) ||\n /\\bEdited \\d+ files? across \\d+ tool calls?/i.test(body) ||\n /\\b\\d+ tool calls?\\b/i.test(body)\n );\n}\n\n/**\n * Return a compact version of an auto recap body: a one-line header (the Goal line) plus the\n * Discoveries section when it carries real content (e.g. detected failures). Non-auto recaps are\n * returned unchanged.\n */\nexport function compactAutoRecapBody(body: string, maxChars = 600): string {\n if (!isAutoRecap(body)) return body;\n\n // Header = the Goal line if present, else the auto-captured marker, else a generic label.\n const goalMatch = body.match(/##+\\s*Goal[^\\n]*\\n+([^\\n]+)/i);\n const callsMatch = body.match(/Auto-captured session \\(([^)]+)\\)/i);\n const header = goalMatch?.[1]?.trim()\n ? `_${goalMatch[1].trim()}_`\n : callsMatch\n ? `_Auto-captured session (${callsMatch[1]})._`\n : \"_Auto-captured session._\";\n\n // Pull the Discoveries / surprises section if present and non-trivial.\n const discMatch = body.match(/##+\\s*Discoveries[^\\n]*\\n([\\s\\S]*?)(?=\\n##+\\s|\\n*$)/i);\n const discovery = discMatch?.[1]?.trim() ?? \"\";\n const trivialDiscovery =\n discovery === \"\" ||\n /^no (new memories|surprising)/i.test(discovery) ||\n /No new memories saved this session\\.?$/i.test(discovery);\n\n if (trivialDiscovery) {\n return `${header}\\n\\n_No notable discoveries captured. Run post_task / \\`mem_session_end\\` for a richer recap._`;\n }\n const trimmed = discovery.length > maxChars ? discovery.slice(0, maxChars) + \"…\" : discovery;\n return `${header}\\n\\n**Discoveries:**\\n${trimmed}`;\n}\n","/**\n * THE single source of truth for briefing memory priority — must_read / useful / background.\n *\n * This tier decides what an agent reads first. It used to be implemented TWICE: once in the MCP\n * `get_briefing` tool (briefing-helpers) and once in the `haive briefing` CLI command, each on its\n * own data shape. The two drifted (the stack-pack down-rank, then the env-workaround down-rank, both\n * had to be applied in two places, and one was missed). This module is the shared classifier: both\n * call sites map their available evidence into {@link PrioritySignals} and call {@link classifyMemoryPriority}\n * here, so the CLI and MCP can never disagree again. Pure, unit-tested.\n */\nimport { isEnvWorkaroundMemory, isStackPackSeed } from \"./relevance.js\";\n\nexport type MemoryPriority = \"must_read\" | \"useful\" | \"background\";\n\n/**\n * Normalized priority evidence. A caller fills only the signals it can compute; unknown ones default\n * to false (see {@link DEFAULT_PRIORITY_SIGNALS}). The MCP path has semantic scores; the CLI path has\n * lexical scores — both reduce to these booleans.\n */\nexport interface PrioritySignals {\n /** Memory type (attempt, gotcha, skill, decision, …). */\n type: string;\n /** Memory tags — used for the stack-pack / env-workaround down-rank. */\n tags: string[];\n /** The memory demands explicit human approval — always surface first. */\n requiresHumanApproval: boolean;\n /** Anchored to a file the agent is editing. */\n directAnchor: boolean;\n /** Anchored to a symbol the agent requested. */\n directSymbol: boolean;\n /** Exact/literal task match (semantic match_quality \"exact\", or an exact lexical task hit). */\n exactTaskMatch: boolean;\n /** Strong semantic relevance (cosine ≥ 0.65). CLI has no embeddings → passes false. */\n strongSemantic: boolean;\n /** Useful-level relevance: semantic ≥ 0.35, a partial task hit, or a high lexical score. */\n usefulSemantic: boolean;\n /** Matched an inferred module or domain from the touched files. */\n moduleOrDomainMatch: boolean;\n /** A memory tag matched a task token. */\n tagTaskMatch: boolean;\n}\n\nexport const DEFAULT_PRIORITY_SIGNALS: PrioritySignals = {\n type: \"\",\n tags: [],\n requiresHumanApproval: false,\n directAnchor: false,\n directSymbol: false,\n exactTaskMatch: false,\n strongSemantic: false,\n usefulSemantic: false,\n moduleOrDomainMatch: false,\n tagTaskMatch: false,\n};\n\n/** Convenience: build a full signal set from a partial one. */\nexport function prioritySignals(partial: Partial<PrioritySignals>): PrioritySignals {\n return { ...DEFAULT_PRIORITY_SIGNALS, ...partial };\n}\n\n/**\n * Classify a memory's briefing priority from its signals. Order matters:\n * 1. must_read — human-approval gates, direct anchor/symbol matches, and exact/strong hits on\n * negative (attempt) or skill memories: the things an agent must not miss.\n * 2. background (down-rank) — generic stack-pack seeds and local dev-environment workarounds never\n * claim `useful` on a semantic/tag match alone; they'd crowd out repo-specific knowledge. (A\n * direct anchor already promoted them to must_read above, so genuinely-relevant ones still rank.)\n * 3. useful — skills, module/domain matches, exact hits, and useful-level relevance.\n * 4. background — everything else.\n */\nexport function classifyMemoryPriority(signals: PrioritySignals): MemoryPriority {\n const isNegative = signals.type === \"attempt\";\n const isSkill = signals.type === \"skill\";\n\n if (\n signals.requiresHumanApproval ||\n signals.directAnchor ||\n signals.directSymbol ||\n (isNegative && (signals.exactTaskMatch || signals.strongSemantic)) ||\n (isSkill && (signals.exactTaskMatch || signals.strongSemantic))\n ) {\n return \"must_read\";\n }\n\n if (isStackPackSeed({ tags: signals.tags }) || isEnvWorkaroundMemory({ tags: signals.tags })) {\n return \"background\";\n }\n\n if (\n isSkill ||\n signals.moduleOrDomainMatch ||\n signals.exactTaskMatch ||\n signals.usefulSemantic ||\n signals.tagTaskMatch\n ) {\n return \"useful\";\n }\n\n return \"background\";\n}\n\nexport function priorityRank(priority: MemoryPriority): number {\n return priority === \"must_read\" ? 3 : priority === \"useful\" ? 2 : 1;\n}\n","/**\n * Native bridge generator — produces agent-harness-specific config files\n * from the hAIve corpus (validated memories + block sensors).\n *\n * One pure formatter per target; no I/O.\n * The CLI command (cli/commands/bridges.ts) handles file writes and\n * idempotent marker-based updates.\n *\n * Exposed for Lot A (init.ts): call generateBridges() from haive init\n * to seed all bridges at initialisation time.\n */\n\nimport type { Memory } from \"./types.js\";\n\n// ── Target registry ────────────────────────────────────────────────────────\n\nexport type BridgeTarget =\n | \"claude\" // CLAUDE.md\n | \"cursor\" // .cursor/rules/haive-memories.mdc\n | \"cline\" // .clinerules\n | \"windsurf\" // .windsurfrules\n | \"continue\" // .continuerules\n | \"cody\" // .sourcegraph/cody-rules.md\n | \"zed\" // .rules\n | \"roo\" // .roo/rules/haive.md\n | \"gemini\" // GEMINI.md\n | \"aider\" // CONVENTIONS.md\n | \"agents\" // AGENTS.md\n | \"copilot\"; // .github/copilot-instructions.md\n\n/** Canonical relative path from project root for each target. */\nexport const BRIDGE_TARGET_PATH: Record<BridgeTarget, string> = {\n claude: \"CLAUDE.md\",\n cursor: \".cursor/rules/haive-memories.mdc\",\n cline: \".clinerules\",\n windsurf: \".windsurfrules\",\n continue: \".continuerules\",\n cody: \".sourcegraph/cody-rules.md\",\n zed: \".rules\",\n roo: \".roo/rules/haive.md\",\n gemini: \"GEMINI.md\",\n aider: \"CONVENTIONS.md\",\n agents: \"AGENTS.md\",\n copilot: \".github/copilot-instructions.md\",\n};\n\nexport const BRIDGE_TARGETS: BridgeTarget[] = Object.keys(BRIDGE_TARGET_PATH) as BridgeTarget[];\n\n// ── Data types ─────────────────────────────────────────────────────────────\n\n/**\n * Condensed sensor shape for bridge injection.\n * Callers extract this from Memory.frontmatter.sensor — no sensor-module import needed.\n */\nexport interface BridgeSensor {\n id: string;\n severity: \"block\" | \"warn\";\n message: string;\n /** Regex pattern, present when sensor.kind === \"regex\". */\n pattern?: string;\n /** Scoped file paths (sensor.paths ?? anchor.paths). */\n paths: string[];\n}\n\nexport interface BridgeMemoryEntry {\n id: string;\n scope: string;\n type: string;\n summary: string;\n /** Anchor paths the memory applies to (for path-scoped display / Cursor globs). */\n paths: string[];\n}\n\nexport interface GenerateBridgesOptions {\n /** Max memories to inject per bridge (default: 8). */\n maxMemories?: number;\n /** Restrict generation to these targets. Defaults to all BRIDGE_TARGETS. */\n targets?: BridgeTarget[];\n}\n\nexport interface BridgeFileOutput {\n target: BridgeTarget;\n /** Relative path from project root. */\n path: string;\n content: string;\n}\n\n// ── Idempotency markers ────────────────────────────────────────────────────\n\nexport const BRIDGE_MARKERS = {\n memoriesStart: \"<!-- haive:memories-start -->\",\n memoriesEnd: \"<!-- haive:memories-end -->\",\n sensorsStart: \"<!-- haive:sensors-start -->\",\n sensorsEnd: \"<!-- haive:sensors-end -->\",\n} as const;\n\n// ── Pure helpers ───────────────────────────────────────────────────────────\n\n/** First meaningful line of a memory body, condensed for bridge display. */\nexport function bridgeMemorySummary(body: string): string {\n const firstLine = body\n .split(\"\\n\")\n .map((l) => l.replace(/^#+\\s*/, \"\").trim())\n .find((l) => l.length > 0) ?? \"\";\n const oneLine = firstLine.replace(/\\s+/g, \" \");\n return oneLine.length > 140 ? oneLine.slice(0, 137) + \"…\" : oneLine;\n}\n\n/**\n * Filter and rank memories + sensors for bridge injection.\n * Pure — callers load data; this function does not read files.\n */\nexport function prepareBridgeData(\n memories: Memory[],\n sensors: BridgeSensor[],\n opts?: Pick<GenerateBridgesOptions, \"maxMemories\">,\n): { topMemories: BridgeMemoryEntry[]; blockSensors: BridgeSensor[] } {\n const max = opts?.maxMemories ?? 8;\n\n const topMemories: BridgeMemoryEntry[] = memories\n .filter((m) => {\n const s = m.frontmatter.status;\n if (m.frontmatter.type === \"session_recap\") return false;\n // Stack-pack seeds are generic background context, not repo-specific breadcrumbs.\n if (m.frontmatter.tags?.includes(\"stack-pack\") || m.frontmatter.tags?.includes(\"seed\")) return false;\n return s === \"validated\" || s === \"proposed\";\n })\n .sort((a, b) => {\n const score = (m: Memory): number => (m.frontmatter.status === \"validated\" ? 2 : 1);\n return score(b) - score(a);\n })\n .slice(0, max)\n .map((m) => ({\n id: m.frontmatter.id,\n scope: m.frontmatter.scope,\n type: m.frontmatter.type,\n summary: bridgeMemorySummary(m.body),\n paths: m.frontmatter.anchor?.paths ?? [],\n }));\n\n const blockSensors = sensors.filter((s) => s.severity === \"block\");\n\n return { topMemories, blockSensors };\n}\n\n// ── Block renderers ────────────────────────────────────────────────────────\n\nfunction renderMemoriesBlock(topMemories: BridgeMemoryEntry[]): string {\n const lines = [\n BRIDGE_MARKERS.memoriesStart,\n \"<!-- AUTO-GENERATED by haive bridges sync — do not edit between these markers -->\",\n \"<!-- Top memories — call get_briefing / mem_get for the full body. -->\",\n \"\",\n ];\n if (topMemories.length === 0) {\n lines.push(\"_(no validated memories yet — run `haive sync` to populate)_\");\n } else {\n for (const m of topMemories) {\n // Path-scoping: surface the files a lesson applies to so the agent knows\n // *when* it is relevant — the same data Cursor would express via .mdc globs.\n const scopeNote =\n m.paths.length > 0\n ? ` _(applies to: ${m.paths.slice(0, 4).join(\", \")}${m.paths.length > 4 ? \", …\" : \"\"})_`\n : \"\";\n lines.push(`- \\`${m.id}\\` (${m.scope}/${m.type}) — ${m.summary}${scopeNote}`);\n }\n }\n lines.push(\"\", BRIDGE_MARKERS.memoriesEnd);\n return lines.join(\"\\n\");\n}\n\nfunction renderSensorsBlock(blockSensors: BridgeSensor[]): string {\n if (blockSensors.length === 0) return \"\";\n\n const lines = [\n BRIDGE_MARKERS.sensorsStart,\n \"<!-- AUTO-GENERATED by haive bridges sync — do not edit between these markers -->\",\n \"\",\n \"## Hard rules — hAIve block sensors\",\n \"\",\n \"The patterns below are blocked by the repo enforcement gate.\",\n \"Introducing them will fail the pre-commit check (`haive enforce check`).\",\n \"\",\n ];\n for (const s of blockSensors) {\n const pathNote = s.paths.length > 0 ? ` _(applies to: ${s.paths.join(\", \")})_` : \"\";\n lines.push(`- **${s.id}**${pathNote}: ${s.message}`);\n if (s.pattern) lines.push(` - Pattern: \\`${s.pattern}\\``);\n }\n lines.push(\"\", BRIDGE_MARKERS.sensorsEnd);\n return lines.join(\"\\n\");\n}\n\n// ── Shared preamble & formatter skeleton ──────────────────────────────────\n\nconst HAIVE_PREAMBLE =\n \"<!-- Managed by hAIve. Edit OUTSIDE the haive markers only; the marked blocks are regenerated. -->\\n\" +\n \"\\n\" +\n \"This repo uses **[hAIve](https://github.com/Doucs91/hAIve)** for shared, enforced team context.\\n\" +\n \"The corpus lives in `.ai/` and is the source of truth — these files are a generated mirror.\\n\" +\n \"\\n\" +\n \"- `.ai/project-context.md` — project overview, architecture, conventions.\\n\" +\n \"- `.ai/memories/` — decisions, gotchas, conventions, failed attempts (personal/team/module).\\n\" +\n \"- The blocks below are the top current memories + the hard rules enforced on commit.\\n\" +\n \"\\n\" +\n \"## Working through hAIve\\n\" +\n \"\\n\" +\n \"1. **Before editing** for a goal, call `get_briefing` (task + files/symbols) to load ranked context\\n\" +\n \" — or `mem_relevant_to` if project context is already loaded this session.\\n\" +\n \"2. **When an approach fails**, call `mem_tried` right away so the next agent skips the dead end.\\n\" +\n \"3. **Before closing** a substantive session, run the `post_task` prompt to capture what was learned.\\n\" +\n \"4. **Before final response**, run `haive enforce finish`; fix anything it blocks before reporting done.\\n\" +\n \"\\n\" +\n \"If the haive MCP server is not available, tell the developer rather than silently skipping it.\\n\" +\n \"\\n\" +\n \"## Safety\\n\" +\n \"\\n\" +\n \"- If `get_briefing` returns `action_required`, surface each item to the developer (use its\\n\" +\n \" `developer_message`) and wait for explicit confirmation before changing any code.\\n\" +\n \"- Never act autonomously on a cross-repo breaking change (dep bump, contract/API diff) — ask first.\";\n\nfunction renderMarkdownBridge(\n topMemories: BridgeMemoryEntry[],\n blockSensors: BridgeSensor[],\n title: string,\n): string {\n const parts: string[] = [\n `# ${title}`,\n \"\",\n HAIVE_PREAMBLE,\n \"\",\n \"## Memories\",\n \"\",\n renderMemoriesBlock(topMemories),\n ];\n const sensorsBlock = renderSensorsBlock(blockSensors);\n if (sensorsBlock) {\n parts.push(\"\", sensorsBlock);\n }\n return parts.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Cursor reads `.cursor/rules/*.mdc` files, each carrying a small YAML\n * frontmatter (`description`, `globs`, `alwaysApply`). We emit an always-applied\n * rule so the shared corpus is loaded on every Cursor task — the equivalent of\n * memories.sh's \"always-on\" lane, but carrying our block sensors too.\n *\n * The frontmatter sits OUTSIDE the haive markers, so the CLI's idempotent\n * marker-based update never rewrites it — only the memories/sensors blocks\n * refresh on `haive bridges sync`.\n */\nfunction renderCursorBridge(\n topMemories: BridgeMemoryEntry[],\n blockSensors: BridgeSensor[],\n): string {\n const frontmatter = [\n \"---\",\n \"description: hAIve shared memories & block sensors (auto-generated)\",\n \"alwaysApply: true\",\n \"---\",\n \"\",\n ].join(\"\\n\");\n return frontmatter + renderMarkdownBridge(topMemories, blockSensors, \"hAIve rules (Cursor)\");\n}\n\n// ── Per-target formatters (pure functions) ─────────────────────────────────\n\ntype Formatter = (memories: BridgeMemoryEntry[], sensors: BridgeSensor[]) => string;\n\nconst FORMATTERS: Record<BridgeTarget, Formatter> = {\n claude: (m, s) => renderMarkdownBridge(m, s, \"CLAUDE.md — hAIve context\"),\n cursor: (m, s) => renderCursorBridge(m, s),\n cline: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Cline)\"),\n windsurf: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Windsurf)\"),\n continue: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Continue)\"),\n cody: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Cody / Sourcegraph)\"),\n zed: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Zed)\"),\n roo: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Roo Code)\"),\n gemini: (m, s) => renderMarkdownBridge(m, s, \"GEMINI.md — hAIve context\"),\n aider: (m, s) => renderMarkdownBridge(m, s, \"CONVENTIONS.md — hAIve context (Aider)\"),\n agents: (m, s) => renderMarkdownBridge(m, s, \"AGENTS.md — hAIve context\"),\n copilot: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (GitHub Copilot)\"),\n};\n\n// ── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Generate bridge file content for the requested targets.\n *\n * Pure: accepts loaded memories + sensors, returns file content strings.\n * The CLI command handles I/O and idempotent marker-based updates.\n *\n * **Lot A integration point**: call this from `haive init` to seed bridges at initialisation.\n * Signature is intentionally stable — init.ts should call:\n * `generateBridges(memories, sensors, { targets: BRIDGE_TARGETS })`\n */\nexport function generateBridges(\n memories: Memory[],\n sensors: BridgeSensor[],\n opts?: GenerateBridgesOptions,\n): BridgeFileOutput[] {\n const { topMemories, blockSensors } = prepareBridgeData(memories, sensors, opts);\n const targets: BridgeTarget[] = opts?.targets ?? BRIDGE_TARGETS;\n\n return targets.map((target) => ({\n target,\n path: BRIDGE_TARGET_PATH[target],\n content: FORMATTERS[target](topMemories, blockSensors),\n }));\n}\n"],"mappings":"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","names":["path","path","readFile","readdir","existsSync","path","path","path","existsSync","readFile","readdir","readFile","existsSync","path","mkdir","readFile","existsSync","path","path","mkdir","existsSync","readFile","MS_PER_DAY","mkdir","readFile","writeFile","existsSync","path","round3","MS_PER_DAY","mkdir","readFile","readdir","writeFile","existsSync","path","existsSync","readFile","writeFile","path","existsSync","mkdir","readFile","writeFile","path","spawnSync","path","existsSync","readFile","writeFile","mkdir","spawnSync","existsSync","readFile","writeFile","mkdir","path","snapshot","existsSync","readFile","writeFile","mkdir","path","appendFile","mkdir","readFile","stat","existsSync","path","existsSync","path","ROOT_MARKERS","existsSync","path","b","mkdir","readFile","appendFile","existsSync","path","mkdir","readdir","readFile","writeFile","existsSync","path","path","isDistinctiveToken","path","round3","MS_PER_DAY","path","appendFile","mkdir","readFile","existsSync","path","isSkill"]}
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/parser.ts","../src/paths.ts","../src/loader.ts","../src/search.ts","../src/verifier.ts","../src/relevance.ts","../src/usage.ts","../src/impact.ts","../src/prevention.ts","../src/context-throttle.ts","../src/eval.ts","../src/confidence.ts","../src/distinctive.ts","../src/skill-activation.ts","../src/specificity.ts","../src/token-budget.ts","../src/code-map.ts","../src/config.ts","../src/cross-repo.ts","../src/dep-tracker.ts","../src/contract-watcher.ts","../src/usage-log.ts","../src/briefing-preset.ts","../src/briefing-body.ts","../src/resolve-project.ts","../src/topic-suggest.ts","../src/lexical-rank.ts","../src/memory-timeline.ts","../src/conflict-candidates.ts","../src/runtime-journal.ts","../src/enforcement.ts","../src/memory-lifecycle.ts","../src/sensors.ts","../src/sensor-suggest.ts","../src/findings.ts","../src/gate-precision.ts","../src/dashboard.ts","../src/failure-coverage.ts","../src/coverage.ts","../src/eval-history.ts","../src/conflict-resolve.ts","../src/seed-git.ts","../src/seed.ts","../src/merge-memory.ts","../src/recap.ts","../src/priority.ts","../src/bridges.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const MemoryScopeSchema = z.enum([\"personal\", \"team\", \"module\", \"shared\"]);\n\nexport const MemoryStatusSchema = z.enum([\n \"draft\",\n \"proposed\",\n \"validated\",\n \"deprecated\",\n \"stale\",\n \"rejected\",\n]);\n\nexport const MemoryTypeSchema = z.enum([\n \"convention\",\n \"decision\",\n \"gotcha\",\n \"architecture\",\n \"glossary\",\n \"skill\", // reusable procedure/playbook for a recurring task (feedforward harness guide)\n \"attempt\", // failed approach — \"tried X, failed because Y, use Z instead\"\n \"session_recap\", // end-of-session summary: goal / accomplished / discoveries / next steps\n]);\n\nexport const AnchorSchema = z.object({\n commit: z.string().optional(),\n paths: z.array(z.string()).default([]),\n symbols: z.array(z.string()).default([]),\n});\n\n/**\n * An executable check derived from a memory — the \"feedback computational\" layer.\n *\n * A `gotcha`/`attempt` is normally feedforward (text the agent reads). A sensor turns\n * that lesson into a deterministic check: when a touched file matches `pattern`, the\n * memory's warning fires regardless of semantic ranking. This closes the harness loop —\n * a documented mistake becomes a permanent guardrail.\n *\n * Phase 1 implements `kind: \"regex\"` only. `shell`/`test` are reserved for a later phase\n * (they require I/O and must run from the CLI, not core).\n */\nexport const SensorSchema = z.object({\n kind: z.enum([\"regex\", \"shell\", \"test\"]).default(\"regex\"),\n /** Regex source (for kind=regex), matched against added diff lines / file content. */\n pattern: z.string().optional(),\n /** Regex flags (e.g. \"i\", \"m\"). Ignored for non-regex kinds. */\n flags: z.string().optional(),\n /** Shell/test command to run (for kind=shell|test). Executed by the CLI, never by core. */\n command: z.string().optional(),\n /** Glob-ish path prefixes the sensor applies to. Falls back to the memory's anchor paths when empty. */\n paths: z.array(z.string()).default([]),\n /** LLM-facing self-correction message: what was done wrong and what to do instead. */\n message: z.string().min(1),\n /** `warn` surfaces in review; `block` can hard-block the commit (only when the gate opts in). */\n severity: z.enum([\"warn\", \"block\"]).default(\"warn\"),\n /** True when hAIve generated this sensor automatically (vs. hand-authored). */\n autogen: z.boolean().default(false),\n /** ISO timestamp of the last time this sensor matched a diff. */\n last_fired: z.string().nullable().default(null),\n});\n\n/**\n * Progressive-disclosure activation triggers for a `skill` memory.\n *\n * A skill is a reusable playbook (feedforward harness guide). Injecting every skill\n * on every briefing bloats the context and dilutes signal (the \"instruction budget\"\n * problem). An `activation` block makes a skill surface ONLY when it is relevant:\n * its keywords match the task, or its globs match the files being edited. A skill\n * that defines `activation` and matches none of it is suppressed from the briefing;\n * a skill with no `activation` block keeps the legacy always-eligible behavior.\n */\nexport const ActivationSchema = z.object({\n /** Case-insensitive substrings matched against the task text. */\n keywords: z.array(z.string()).default([]),\n /** Glob-ish path patterns matched against the files being edited. */\n globs: z.array(z.string()).default([]),\n /** Always activate (rare — for truly universal playbooks). */\n always: z.boolean().default(false),\n});\n\nconst IsoDateString = z\n .union([z.string(), z.date()])\n .transform((v) => (v instanceof Date ? v.toISOString() : v))\n .pipe(z.string().datetime());\n\nexport const MemoryFrontmatterSchema = z\n .object({\n id: z.string().min(1),\n scope: MemoryScopeSchema.default(\"personal\"),\n module: z.string().optional(),\n type: MemoryTypeSchema,\n status: MemoryStatusSchema.default(\"draft\"),\n anchor: AnchorSchema.default({ paths: [], symbols: [] }),\n /** Optional executable check derived from this memory (feedback computational layer). */\n sensor: SensorSchema.optional(),\n /** Optional progressive-disclosure triggers — only meaningful for `type: skill`. */\n activation: ActivationSchema.optional(),\n tags: z.array(z.string()).default([]),\n domain: z.string().optional(),\n author: z.string().optional(),\n created_at: IsoDateString,\n expires_when: z.string().nullable().default(null),\n verified_at: z.string().nullable().default(null),\n stale_reason: z.string().nullable().default(null),\n related_ids: z.array(z.string()).default([]),\n last_read_at: z.string().nullable().default(null),\n topic: z.string().optional(), // stable key for upsert — same topic in same scope → update instead of create\n revision_count: z.number().int().min(0).default(0), // incremented each time a topic upsert occurs\n /**\n * When true, the AI MUST NOT act on this memory autonomously.\n * It must surface the information to the human developer and wait\n * for explicit confirmation before modifying any code.\n * Used for cross-repo breaking changes, dependency bumps, contract diffs.\n */\n requires_human_approval: z.boolean().default(false),\n })\n .refine(\n (data) => data.scope !== \"module\" || !!data.module,\n { message: \"module name is required when scope is 'module'\", path: [\"module\"] },\n );\n\n// Additional fields for cross-repo provenance (stored in frontmatter of imported memories)\nexport const CrossRepoProvenanceSchema = z.object({\n source_name: z.string(), // the crossRepoSources name from haive.config.json\n source_path: z.string(), // original file path in the source repo\n source_id: z.string(), // original memory id\n imported_at: z.string(), // ISO timestamp of import\n}).optional();\n","import matter from \"gray-matter\";\nimport { MemoryFrontmatterSchema } from \"./schema.js\";\nimport type { Activation, Memory, MemoryFrontmatter, Sensor } from \"./types.js\";\n\nconst PRIVATE_BLOCK_RE = /<private>[\\s\\S]*?<\\/private>/g;\n\nexport function stripPrivate(body: string): string {\n return body.replace(PRIVATE_BLOCK_RE, \"\").trimEnd();\n}\n\nexport function parseMemory(raw: string): Memory {\n const parsed = matter(raw);\n const frontmatter = MemoryFrontmatterSchema.parse(parsed.data);\n return {\n frontmatter,\n body: stripPrivate(parsed.content.trim()),\n };\n}\n\nfunction stripUndefined<T>(value: T): T {\n if (Array.isArray(value)) {\n return value.map((v) => stripUndefined(v)) as unknown as T;\n }\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v === undefined) continue;\n out[k] = stripUndefined(v);\n }\n return out as T;\n }\n return value;\n}\n\nexport function serializeMemory(memory: Memory): string {\n const clean = stripUndefined(memory.frontmatter) as Record<string, unknown>;\n return matter.stringify(memory.body, clean);\n}\n\nexport function newMemoryId(type: string, slug: string, date = new Date()): string {\n const isoDate = date.toISOString().slice(0, 10);\n const safeSlug = slug\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 60);\n return `${isoDate}-${type}-${safeSlug}`;\n}\n\nexport function buildFrontmatter(input: {\n type: MemoryFrontmatter[\"type\"];\n slug: string;\n scope?: MemoryFrontmatter[\"scope\"];\n module?: string;\n tags?: string[];\n domain?: string;\n author?: string;\n paths?: string[];\n symbols?: string[];\n commit?: string;\n topic?: string;\n status?: MemoryFrontmatter[\"status\"];\n relatedIds?: string[];\n sensor?: Sensor;\n activation?: Activation;\n}): MemoryFrontmatter {\n const now = new Date();\n const id = newMemoryId(input.type, input.slug, now);\n return MemoryFrontmatterSchema.parse({\n id,\n scope: input.scope ?? \"personal\",\n module: input.module,\n type: input.type,\n status: input.status ?? \"draft\",\n anchor: {\n commit: input.commit,\n paths: input.paths ?? [],\n symbols: input.symbols ?? [],\n },\n tags: input.tags ?? [],\n domain: input.domain,\n author: input.author,\n created_at: now.toISOString(),\n expires_when: null,\n topic: input.topic,\n sensor: input.sensor,\n activation: input.activation,\n revision_count: 0,\n related_ids: input.relatedIds ?? [],\n });\n}\n","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport const HAIVE_DIR = \".ai\";\n\nconst ROOT_MARKERS = [\".ai\", \".git\", \"package.json\"];\n\nexport function findProjectRoot(startDir: string = process.cwd()): string {\n let current = path.resolve(startDir);\n const fsRoot = path.parse(current).root;\n while (current !== fsRoot) {\n for (const marker of ROOT_MARKERS) {\n if (existsSync(path.join(current, marker))) return current;\n }\n current = path.dirname(current);\n }\n return path.resolve(startDir);\n}\n\nexport const PROJECT_CONTEXT_FILE = \"project-context.md\";\nexport const MEMORIES_DIR = \"memories\";\n\nexport interface HaivePaths {\n root: string;\n haiveDir: string;\n /** Disposable local layer (session journal, caches). Not team truth — see `.ai/.runtime/` layout. */\n runtimeDir: string;\n projectContext: string;\n memoriesDir: string;\n personalDir: string;\n teamDir: string;\n sharedDir: string;\n moduleDir: string;\n modulesContextDir: string;\n}\n\nexport function resolveHaivePaths(projectRoot: string): HaivePaths {\n const haiveDir = path.join(projectRoot, HAIVE_DIR);\n const memoriesDir = path.join(haiveDir, MEMORIES_DIR);\n return {\n root: projectRoot,\n haiveDir,\n runtimeDir: path.join(haiveDir, \".runtime\"),\n projectContext: path.join(haiveDir, PROJECT_CONTEXT_FILE),\n memoriesDir,\n personalDir: path.join(memoriesDir, \"personal\"),\n teamDir: path.join(memoriesDir, \"team\"),\n sharedDir: path.join(memoriesDir, \"shared\"),\n moduleDir: path.join(memoriesDir, \"module\"),\n modulesContextDir: path.join(haiveDir, \"modules\"),\n };\n}\n\nexport function memoryFilePath(\n paths: HaivePaths,\n scope: \"personal\" | \"team\" | \"module\" | \"shared\",\n id: string,\n module?: string,\n): string {\n const base =\n scope === \"personal\"\n ? paths.personalDir\n : scope === \"team\"\n ? paths.teamDir\n : scope === \"shared\"\n ? paths.sharedDir\n : path.join(paths.moduleDir, module ?? \"_unscoped\");\n return path.join(base, `${id}.md`);\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { parseMemory } from \"./parser.js\";\nimport type { Memory } from \"./types.js\";\n\nexport interface LoadedMemory {\n memory: Memory;\n filePath: string;\n}\n\nexport async function listMarkdownFilesRecursive(dir: string): Promise<string[]> {\n const out: string[] = [];\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return out;\n }\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n out.push(...(await listMarkdownFilesRecursive(full)));\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n out.push(full);\n }\n }\n return out;\n}\n\nexport async function loadMemory(filePath: string): Promise<LoadedMemory> {\n const raw = await readFile(filePath, \"utf8\");\n return { memory: parseMemory(raw), filePath };\n}\n\nexport async function loadMemoriesFromDir(dir: string): Promise<LoadedMemory[]> {\n const files = await listMarkdownFilesRecursive(dir);\n const out: LoadedMemory[] = [];\n for (const file of files) {\n try {\n out.push(await loadMemory(file));\n } catch {\n // Skip unparseable files in v0.1; future: surface a warning channel.\n }\n }\n return out;\n}\n","import type { Memory } from \"./types.js\";\n\nexport function tokenizeQuery(query: string): string[] {\n return query\n .toLowerCase()\n .split(/\\s+/)\n .map((t) => t.trim())\n .filter(Boolean);\n}\n\nexport function literalMatchesAllTokens(memory: Memory, tokens: string[]): boolean {\n if (tokens.length === 0) return true;\n const fm = memory.frontmatter;\n const idLower = fm.id.toLowerCase();\n const tagsLower = fm.tags.map((t) => t.toLowerCase());\n const bodyLower = memory.body.toLowerCase();\n const anchorPathTokens = collectAnchorPathTokens(fm.anchor.paths);\n const anchorSymbolsLower = fm.anchor.symbols.map((s) => s.toLowerCase());\n const moduleLower = fm.module?.toLowerCase();\n const domainLower = fm.domain?.toLowerCase();\n\n return tokens.every((rawTok) => {\n const tok = rawTok.toLowerCase();\n return (\n idLower.includes(tok) ||\n tagsLower.some((t) => t.includes(tok)) ||\n bodyLower.includes(tok) ||\n anchorPathTokens.some((p) => p.includes(tok)) ||\n anchorSymbolsLower.some((s) => s.includes(tok)) ||\n (moduleLower !== undefined && moduleLower.includes(tok)) ||\n (domainLower !== undefined && domainLower.includes(tok))\n );\n });\n}\n\nfunction collectAnchorPathTokens(paths: readonly string[]): string[] {\n const out = new Set<string>();\n for (const p of paths) {\n const lower = p.toLowerCase();\n out.add(lower);\n // basename without extension\n const base = lower.split(\"/\").pop() ?? lower;\n const noExt = base.replace(/\\.[a-z0-9]+$/, \"\");\n if (noExt) out.add(noExt);\n // each path segment (helps \"verifier\" match \"src/verifier.ts\")\n for (const segment of lower.split(\"/\")) {\n const seg = segment.replace(/\\.[a-z0-9]+$/, \"\");\n if (seg) out.add(seg);\n }\n }\n return [...out];\n}\n\n/**\n * OR-based fallback: returns true if the memory matches at least one token.\n * Used when all-tokens (AND) search returns 0 results.\n */\nexport function literalMatchesAnyToken(memory: Memory, tokens: string[]): boolean {\n if (tokens.length === 0) return false;\n const fm = memory.frontmatter;\n const idLower = fm.id.toLowerCase();\n const tagsLower = fm.tags.map((t) => t.toLowerCase());\n const bodyLower = memory.body.toLowerCase();\n const anchorPathTokens = collectAnchorPathTokens(fm.anchor.paths);\n const anchorSymbolsLower = fm.anchor.symbols.map((s) => s.toLowerCase());\n const moduleLower = fm.module?.toLowerCase();\n const domainLower = fm.domain?.toLowerCase();\n\n return tokens.some((rawTok) => {\n const tok = rawTok.toLowerCase();\n return (\n idLower.includes(tok) ||\n tagsLower.some((t) => t.includes(tok)) ||\n bodyLower.includes(tok) ||\n anchorPathTokens.some((p) => p.includes(tok)) ||\n anchorSymbolsLower.some((s) => s.includes(tok)) ||\n (moduleLower !== undefined && moduleLower.includes(tok)) ||\n (domainLower !== undefined && domainLower.includes(tok))\n );\n });\n}\n\nexport function pickSnippetNeedle(query: string): string {\n const tokens = tokenizeQuery(query);\n if (tokens.length === 0) return query.toLowerCase();\n return [...tokens].sort((a, b) => b.length - a.length)[0]!;\n}\n\nexport function extractSnippet(body: string, needle: string, radius = 40): string {\n const lower = body.toLowerCase();\n const idx = needle ? lower.indexOf(needle) : -1;\n if (idx < 0) {\n return body.slice(0, radius * 3).replace(/\\s+/g, \" \").trim();\n }\n const start = Math.max(0, idx - radius);\n const end = Math.min(body.length, idx + needle.length + radius);\n const snippet = body.slice(start, end).replace(/\\s+/g, \" \").trim();\n return (start > 0 ? \"…\" : \"\") + snippet + (end < body.length ? \"…\" : \"\");\n}\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { globToRegExp, isGlobPath } from \"./relevance.js\";\nimport type { Memory } from \"./types.js\";\n\nexport interface VerifyResult {\n stale: boolean;\n reason: string | null;\n checkedPaths: string[];\n checkedSymbols: string[];\n possibleRenames: string[];\n}\n\nexport interface VerifyOptions {\n /** Project root used to resolve relative anchor paths. */\n projectRoot: string;\n}\n\n/**\n * Verify that a memory's anchor still matches the current code.\n * - Every anchor.paths entry must exist on disk\n * - Every anchor.symbols entry must appear at least once across the anchor.paths\n * files (or any tracked file if no paths are recorded)\n *\n * Anchorless memories (no paths and no symbols) are always considered fresh —\n * staleness only applies to memories that opted into anchoring.\n */\nexport async function verifyAnchor(\n memory: Memory,\n options: VerifyOptions,\n): Promise<VerifyResult> {\n const anchor = memory.frontmatter.anchor;\n const checkedPaths = anchor.paths;\n const checkedSymbols = anchor.symbols;\n\n if (checkedPaths.length === 0 && checkedSymbols.length === 0) {\n return { stale: false, reason: null, checkedPaths, checkedSymbols, possibleRenames: [] };\n }\n\n const missingPaths: string[] = [];\n const existingAbsPaths: string[] = [];\n for (const rel of checkedPaths) {\n if (isGlobPath(rel)) {\n const matches = await findGlobMatches(rel, options.projectRoot);\n if (matches.length > 0) {\n existingAbsPaths.push(...matches.map((m) => path.join(options.projectRoot, m)));\n } else {\n missingPaths.push(rel);\n }\n continue;\n }\n const abs = path.isAbsolute(rel) ? rel : path.join(options.projectRoot, rel);\n if (existsSync(abs)) {\n existingAbsPaths.push(...await readableFilesForAnchor(abs));\n } else {\n missingPaths.push(rel);\n }\n }\n\n if (missingPaths.length > 0) {\n const possibleRenames = await findPossibleRenames(missingPaths, options.projectRoot);\n return {\n stale: true,\n reason: `anchor path(s) no longer exist: ${missingPaths.join(\", \")}`,\n checkedPaths,\n checkedSymbols,\n possibleRenames,\n };\n }\n\n if (checkedSymbols.length > 0) {\n if (existingAbsPaths.length === 0) {\n return {\n stale: true,\n reason: `cannot verify symbols (${checkedSymbols.join(\", \")}): no anchor paths recorded`,\n checkedPaths,\n checkedSymbols,\n possibleRenames: [],\n };\n }\n const missingSymbols: string[] = [];\n for (const sym of checkedSymbols) {\n let found = false;\n for (const file of existingAbsPaths) {\n try {\n const contents = await readFile(file, \"utf8\");\n if (contents.includes(sym)) {\n found = true;\n break;\n }\n } catch {\n // unreadable file; treat as not finding the symbol here\n }\n }\n if (!found) missingSymbols.push(sym);\n }\n if (missingSymbols.length > 0) {\n return {\n stale: true,\n reason: `anchor symbol(s) not found in any anchor path: ${missingSymbols.join(\", \")}`,\n checkedPaths,\n checkedSymbols,\n possibleRenames: [],\n };\n }\n }\n\n return { stale: false, reason: null, checkedPaths, checkedSymbols, possibleRenames: [] };\n}\n\nasync function findPossibleRenames(\n missingPaths: string[],\n projectRoot: string,\n): Promise<string[]> {\n const basenames = new Set(missingPaths.map((p) => path.basename(p)));\n const found: string[] = [];\n try {\n await walkDir(projectRoot, projectRoot, basenames, found, 0);\n } catch {\n // best-effort\n }\n return found;\n}\n\nasync function findGlobMatches(pattern: string, projectRoot: string): Promise<string[]> {\n const re = globToRegExp(pattern);\n const found: string[] = [];\n try {\n await walkAllFiles(projectRoot, projectRoot, found, 0, re);\n } catch {\n // best-effort\n }\n return found;\n}\n\nasync function readableFilesForAnchor(abs: string): Promise<string[]> {\n try {\n const s = await stat(abs);\n if (s.isDirectory()) {\n const out: string[] = [];\n await walkReadableFiles(abs, out, 0);\n return out;\n }\n if (s.isFile()) return [abs];\n } catch {\n return [abs];\n }\n return [abs];\n}\n\nasync function walkReadableFiles(dir: string, found: string[], depth: number): Promise<void> {\n if (depth > 6) return;\n let entries: string[];\n try {\n entries = await readdir(dir, { encoding: \"utf8\" });\n } catch {\n return;\n }\n for (const name of entries) {\n if (name.startsWith(\".\") || name === \"node_modules\") continue;\n const abs = path.join(dir, name);\n try {\n const s = await stat(abs);\n if (s.isDirectory()) await walkReadableFiles(abs, found, depth + 1);\n else if (s.isFile()) found.push(abs);\n } catch {\n continue;\n }\n }\n}\n\nasync function walkAllFiles(\n dir: string,\n root: string,\n found: string[],\n depth: number,\n match: RegExp,\n): Promise<void> {\n if (depth > 12) return;\n let entries: string[];\n try {\n entries = await readdir(dir, { encoding: \"utf8\" });\n } catch {\n return;\n }\n for (const name of entries) {\n if (name === \"node_modules\" || name === \".git\" || name === \".ai\") continue;\n const abs = path.join(dir, name);\n try {\n const s = await stat(abs);\n if (s.isDirectory()) {\n await walkAllFiles(abs, root, found, depth + 1, match);\n } else if (s.isFile()) {\n const rel = path.relative(root, abs).replace(/\\\\/g, \"/\");\n if (match.test(rel)) found.push(rel);\n }\n } catch {\n continue;\n }\n }\n}\n\nasync function walkDir(\n dir: string,\n root: string,\n targets: Set<string>,\n found: string[],\n depth: number,\n): Promise<void> {\n if (depth > 6) return;\n let entries: string[];\n try {\n entries = await readdir(dir, { encoding: \"utf8\" });\n } catch {\n return;\n }\n for (const name of entries) {\n if (name.startsWith(\".\") || name === \"node_modules\") continue;\n const abs = path.join(dir, name);\n let isDir = false;\n try {\n isDir = (await stat(abs)).isDirectory();\n } catch {\n continue;\n }\n if (isDir) {\n await walkDir(abs, root, targets, found, depth + 1);\n } else if (targets.has(name)) {\n found.push(path.relative(root, abs));\n }\n }\n}\n","import path from \"node:path\";\nimport type { LoadedMemory } from \"./loader.js\";\n\n/**\n * Tag stamped on memories that were pre-seeded from a stack pack at `haive init`\n * (generic framework knowledge the model already largely knows, not repo-specific\n * institutional knowledge). Briefing ranking caps these at `background` priority so\n * a generic seed never displaces a repo-specific memory — unless the seed has been\n * anchored to a file the agent is actually editing.\n */\nexport const STACK_PACK_TAG = \"stack-pack\";\n\n/** True when a memory was pre-seeded from a stack pack (carries {@link STACK_PACK_TAG}). */\nexport function isStackPackSeed(fm: { tags?: string[] } | null | undefined): boolean {\n return Boolean(fm?.tags?.includes(STACK_PACK_TAG));\n}\n\n/**\n * Tags that mark a memory as a *local dev-environment workaround* (hot-swap, nested node_modules,\n * global-install quirks) rather than repo-specific team policy. These are real, but they describe\n * tooling debt, not unguessable team knowledge — and because they get read on almost every session\n * their read_count inflates and they crowd the briefing. Ranking caps them at `background` UNLESS\n * they directly anchor a file being edited, so they stop displacing actual policy. The fix for a\n * recurring one is to repair the environment, not to keep surfacing the note.\n */\nexport const ENV_WORKAROUND_TAGS = new Set([\n \"dev-workflow\",\n \"dev-env\",\n \"hotswap\",\n \"local-setup\",\n \"tooling-debt\",\n]);\n\n/** True when a memory is tagged as a local dev-environment workaround (see {@link ENV_WORKAROUND_TAGS}). */\nexport function isEnvWorkaroundMemory(fm: { tags?: string[] } | null | undefined): boolean {\n return Boolean(fm?.tags?.some((t) => ENV_WORKAROUND_TAGS.has(t)));\n}\n\nconst MODULE_PATTERNS = [\n /^packages\\/([^/]+)\\//,\n /^apps\\/([^/]+)\\//,\n /^modules\\/([^/]+)\\//,\n /^src\\/([^/]+)\\//,\n /^libs\\/([^/]+)\\//,\n /^services\\/([^/]+)\\//,\n /^internal\\/([^/]+)\\//,\n /^projects\\/([^/]+)\\//, // Nx layout\n /^cmd\\/([^/]+)\\//, // Go-style\n];\n\n/**\n * Best-effort inference: given a list of file paths, infer module names from\n * conventional layouts (packages/X/, apps/X/, modules/X/, src/X/).\n */\nexport function inferModulesFromPaths(filePaths: string[]): string[] {\n const out = new Set<string>();\n for (const p of filePaths) {\n const norm = normalize(p);\n for (const re of MODULE_PATTERNS) {\n const m = norm.match(re);\n if (m && m[1]) out.add(m[1]);\n }\n }\n return [...out].sort();\n}\n\n/**\n * Path overlap: returns true if `a` and `b` refer to the same path or one is a\n * parent of the other. Both inputs are treated as POSIX-style relative paths.\n */\nexport function pathsOverlap(a: string, b: string): boolean {\n const na = normalize(a);\n const nb = normalize(b);\n if (isGlobPath(na)) return globOverlapsPath(na, nb);\n if (isGlobPath(nb)) return globOverlapsPath(nb, na);\n if (na === nb) return true;\n return na.startsWith(nb + \"/\") || nb.startsWith(na + \"/\");\n}\n\nexport function memoryMatchesAnchorPaths(\n memory: LoadedMemory[\"memory\"],\n inputPaths: string[],\n): boolean {\n const anchorPaths = memory.frontmatter.anchor.paths;\n if (anchorPaths.length === 0) return false;\n for (const ap of anchorPaths) {\n for (const ip of inputPaths) {\n if (pathsOverlap(ap, ip)) return true;\n }\n }\n return false;\n}\n\nfunction normalize(p: string): string {\n // Strip leading \"./\" and trailing \"/\", normalize separators.\n return p.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n}\n\nexport function isGlobPath(p: string): boolean {\n return /[*?\\[]/.test(p);\n}\n\nexport function globToRegExp(pattern: string): RegExp {\n const norm = normalize(pattern);\n let out = \"^\";\n for (let i = 0; i < norm.length; i++) {\n const ch = norm[i]!;\n const next = norm[i + 1];\n const afterNext = norm[i + 2];\n if (ch === \"*\" && next === \"*\" && afterNext === \"/\") {\n out += \"(?:.*/)?\";\n i += 2;\n } else if (ch === \"*\" && next === \"*\") {\n out += \".*\";\n i++;\n } else if (ch === \"*\") {\n out += \"[^/]*\";\n } else if (ch === \"?\") {\n out += \"[^/]\";\n } else {\n out += ch.replace(/[|\\\\{}()[\\]^$+?.]/g, \"\\\\$&\");\n }\n }\n out += \"$\";\n return new RegExp(out);\n}\n\nfunction globOverlapsPath(globPattern: string, candidate: string): boolean {\n const normalizedCandidate = normalize(candidate);\n if (globToRegExp(globPattern).test(normalizedCandidate)) return true;\n const prefix = globLiteralPrefix(globPattern);\n if (!prefix || prefix.split(\"/\").length < 2) return false;\n return normalizedCandidate === prefix ||\n normalizedCandidate.startsWith(prefix + \"/\") ||\n prefix.startsWith(normalizedCandidate + \"/\");\n}\n\nfunction globLiteralPrefix(pattern: string): string {\n const norm = normalize(pattern);\n const firstGlob = norm.search(/[*?\\[]/);\n if (firstGlob < 0) return norm;\n const slash = norm.slice(0, firstGlob).lastIndexOf(\"/\");\n return slash < 0 ? \"\" : norm.slice(0, slash);\n}\n\nexport function relPathFrom(root: string, abs: string): string {\n return path.relative(root, abs).replace(/\\\\/g, \"/\");\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport interface MemoryUsage {\n read_count: number;\n last_read_at: string | null;\n rejected_count: number;\n last_rejected_at: string | null;\n rejection_reason: string | null;\n /**\n * Number of times the memory was explicitly confirmed *useful* — i.e. an agent\n * or human recorded that it changed what they did (the closed-loop \"applied\"\n * outcome, recorded via `mem_feedback`). A far stronger utility signal than a\n * read: a memory can be surfaced many times and ignored, but `applied` means it\n * demonstrably steered work. Drives impact scoring in {@link ./impact.js}.\n */\n applied_count: number;\n last_applied_at: string | null;\n /**\n * Number of *prevention* events — times this memory's sensor actually fired on a scanned diff,\n * intercepting a known mistake before it landed. This is an OUTCOME signal (defect prevented),\n * the closest proxy hAIve has to \"did the knowledge stop a real problem?\", distinct from\n * retrieval (read) and self-reported usefulness (applied). Recorded by `haive sensors check`.\n */\n prevented_count: number;\n last_prevented_at: string | null;\n}\n\nexport interface UsageIndex {\n version: 1;\n updated_at: string;\n by_id: Record<string, MemoryUsage>;\n}\n\nexport const USAGE_FILE = \"usage.json\";\n\nexport function emptyUsage(): MemoryUsage {\n return {\n read_count: 0,\n last_read_at: null,\n rejected_count: 0,\n last_rejected_at: null,\n rejection_reason: null,\n applied_count: 0,\n last_applied_at: null,\n prevented_count: 0,\n last_prevented_at: null,\n };\n}\n\n/**\n * Normalize a possibly-partial stored usage record (older `usage.json` files\n * predate the `applied_*` fields). Always returns a full {@link MemoryUsage}.\n */\nfunction normalizeUsage(stored: Partial<MemoryUsage> | undefined): MemoryUsage {\n return { ...emptyUsage(), ...(stored ?? {}) };\n}\n\nexport function emptyUsageIndex(): UsageIndex {\n return {\n version: 1,\n updated_at: new Date().toISOString(),\n by_id: {},\n };\n}\n\nexport function usagePath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", USAGE_FILE);\n}\n\nexport async function loadUsageIndex(paths: HaivePaths): Promise<UsageIndex> {\n const file = usagePath(paths);\n if (!existsSync(file)) return emptyUsageIndex();\n const raw = await readFile(file, \"utf8\");\n try {\n const parsed = JSON.parse(raw) as UsageIndex;\n if (parsed.version !== 1) return emptyUsageIndex();\n return parsed;\n } catch {\n return emptyUsageIndex();\n }\n}\n\nexport async function saveUsageIndex(paths: HaivePaths, index: UsageIndex): Promise<void> {\n const file = usagePath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n index.updated_at = new Date().toISOString();\n await writeFile(file, JSON.stringify(index, null, 2), \"utf8\");\n}\n\nexport function getUsage(index: UsageIndex, id: string): MemoryUsage {\n return normalizeUsage(index.by_id[id]);\n}\n\nexport function bumpRead(index: UsageIndex, ids: string[]): UsageIndex {\n if (ids.length === 0) return index;\n const now = new Date().toISOString();\n for (const id of ids) {\n const current = normalizeUsage(index.by_id[id]);\n index.by_id[id] = {\n ...current,\n read_count: current.read_count + 1,\n last_read_at: now,\n };\n }\n return index;\n}\n\nexport function recordRejection(\n index: UsageIndex,\n id: string,\n reason: string | null,\n): UsageIndex {\n const current = normalizeUsage(index.by_id[id]);\n const now = new Date().toISOString();\n index.by_id[id] = {\n ...current,\n rejected_count: current.rejected_count + 1,\n last_rejected_at: now,\n rejection_reason: reason,\n };\n return index;\n}\n\n/**\n * Record that a memory was *applied* — explicitly confirmed to have changed what\n * the agent/human did. This is the closed-loop utility signal that distinguishes\n * a memory that merely got surfaced from one that demonstrably steered work.\n */\nexport function recordApplied(index: UsageIndex, id: string): UsageIndex {\n const current = normalizeUsage(index.by_id[id]);\n const now = new Date().toISOString();\n index.by_id[id] = {\n ...current,\n applied_count: current.applied_count + 1,\n last_applied_at: now,\n };\n return index;\n}\n\n/** Debounce window so re-scanning the same diff within a few minutes doesn't inflate prevention\n * counts (a pre-commit hook can run the check several times for one commit). */\nexport const PREVENTION_DEBOUNCE_MS = 5 * 60 * 1000;\n\n/**\n * Record a *prevention* event: a memory's sensor fired on a scanned diff, intercepting a known\n * mistake before it landed. Outcome signal (defect prevented), stronger than a read. Debounced by\n * {@link PREVENTION_DEBOUNCE_MS}. Returns true if a NEW event was recorded (false if debounced).\n */\nexport function recordPrevention(index: UsageIndex, id: string, now: number = Date.now()): boolean {\n const current = normalizeUsage(index.by_id[id]);\n const last = current.last_prevented_at ? Date.parse(current.last_prevented_at) : 0;\n if (Number.isFinite(last) && last > 0 && now - last < PREVENTION_DEBOUNCE_MS) {\n index.by_id[id] = current; // normalize in place, no count change\n return false;\n }\n index.by_id[id] = {\n ...current,\n prevented_count: current.prevented_count + 1,\n last_prevented_at: new Date(now).toISOString(),\n };\n return true;\n}\n\nexport const DECAY_DAYS = 90;\n\nexport function isDecaying(usage: MemoryUsage, createdAt: string): boolean {\n const threshold = Date.now() - DECAY_DAYS * 24 * 60 * 60 * 1000;\n const anchor = usage.last_read_at ?? createdAt;\n return new Date(anchor).getTime() < threshold;\n}\n\nexport async function trackReads(\n paths: HaivePaths,\n ids: string[],\n): Promise<UsageIndex> {\n if (ids.length === 0) {\n return await loadUsageIndex(paths);\n }\n const index = await loadUsageIndex(paths);\n bumpRead(index, ids);\n await saveUsageIndex(paths, index);\n return index;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport type { MemoryUsage } from \"./usage.js\";\n\n/**\n * Closed-loop memory-utility scoring — the \"did this memory actually help?\" layer.\n *\n * hAIve already tracks reads ({@link ./usage.js}) and derives a trust level from\n * status + read_count ({@link ./confidence.js}). But a read only means a memory was\n * *surfaced*, not that it *helped* — a memory can be injected on every briefing and\n * silently ignored. Harness engineering's core loop (Fowler / LangChain) is to\n * measure what demonstrably steers work and let that feed back into recall.\n *\n * `computeImpact` combines the signals hAIve already records but never correlated:\n * POSITIVE reads · applied outcomes (mem_feedback) · a sensor that actually fired\n * NEGATIVE rejections · stale/deprecated/rejected status · dormancy\n * into a single 0..1 utility score, a tier, and a prune-candidate flag. It is a pure\n * function (no I/O), unit-tested in `packages/core/test/impact.test.ts`.\n */\n\nexport type ImpactTier = \"high\" | \"medium\" | \"low\" | \"dormant\";\n\nexport interface ImpactScore {\n /** Normalized utility score in [0, 1]. */\n score: number;\n tier: ImpactTier;\n /** Human-readable breakdown of the signals that produced the score. */\n signals: string[];\n /**\n * True when the memory looks like dead weight worth reviewing/pruning:\n * more rejections than reads, or never used with no guardrail, or already\n * stale/deprecated/rejected. A memory carrying a `sensor` or with `applied`\n * outcomes is never a prune candidate — it earns its keep as a guardrail.\n */\n pruneCandidate: boolean;\n}\n\nexport interface ImpactOptions {\n /** Days with no read AND no applied outcome after which a memory is \"dormant\". */\n dormantDays?: number;\n now?: Date;\n}\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/** Default dormancy window — half the confidence hard-decay (365d), so impact reacts sooner. */\nexport const DEFAULT_DORMANT_DAYS = 120;\n\n/** Reads needed to saturate the read component of the score. */\nconst READ_SATURATION = 32;\n\nfunction clamp01(n: number): number {\n if (Number.isNaN(n)) return 0;\n return Math.max(0, Math.min(1, n));\n}\n\nfunction hasSensorFired(fm: MemoryFrontmatter): boolean {\n return Boolean(fm.sensor?.last_fired);\n}\n\nfunction isDeadStatus(fm: MemoryFrontmatter): boolean {\n return fm.status === \"stale\" || fm.status === \"deprecated\" || fm.status === \"rejected\";\n}\n\n/**\n * Compute the demonstrated utility of a single memory from its frontmatter + usage.\n * Pure and deterministic given `now`.\n */\nexport function computeImpact(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n options: ImpactOptions = {},\n): ImpactScore {\n const now = options.now ?? new Date();\n const dormantDays = options.dormantDays ?? DEFAULT_DORMANT_DAYS;\n const signals: string[] = [];\n\n let raw = 0;\n\n // POSITIVE — reads (a memory that keeps getting surfaced has some pull). Log-scaled\n // and capped at 0.35 so reads alone can never reach \"high\": being surfaced is not\n // the same as being useful.\n if (usage.read_count > 0) {\n raw += Math.min(1, Math.log2(usage.read_count + 1) / Math.log2(READ_SATURATION + 1)) * 0.35;\n signals.push(`read ${usage.read_count}×`);\n }\n\n // POSITIVE — applied outcomes: the strongest signal. The agent/human confirmed it\n // changed what they did. 4 applications saturate this 0.60 component — enough to\n // reach \"high\" on its own, since a demonstrably-applied memory has earned it.\n if (usage.applied_count > 0) {\n raw += Math.min(1, usage.applied_count / 4) * 0.6;\n signals.push(`applied ${usage.applied_count}×`);\n }\n\n // POSITIVE — prevention events (OUTCOME): the memory's sensor fired on real diffs, intercepting a\n // documented mistake before it landed. The strongest demonstrated-value signal — 3 catches\n // saturate this 0.60 component (enough to reach \"high\" alone, like applied). Falls back to the\n // frontmatter `sensor.last_fired` flag for memories that fired before prevention counting existed.\n if (usage.prevented_count > 0) {\n raw += Math.min(1, usage.prevented_count / 3) * 0.6;\n signals.push(`prevented ${usage.prevented_count}×`);\n } else if (hasSensorFired(fm)) {\n raw += 0.25;\n signals.push(\"sensor fired\");\n }\n\n // NEGATIVE — rejections: explicit \"not useful\" feedback. Heavily weighted.\n if (usage.rejected_count > 0) {\n raw -= Math.min(0.6, usage.rejected_count * 0.25);\n signals.push(`rejected ${usage.rejected_count}×`);\n }\n\n let score = clamp01(raw);\n\n // Dead statuses collapse the score regardless of past reads.\n if (isDeadStatus(fm)) {\n score *= 0.2;\n signals.push(`status=${fm.status}`);\n }\n\n // Dormancy — no read and no application within the window. The clock starts at the\n // most recent activity (applied → read → created).\n const anchor = usage.last_applied_at ?? usage.last_read_at ?? fm.created_at;\n const ageDays = (now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY;\n const dormant =\n Number.isFinite(ageDays) && ageDays >= dormantDays && usage.applied_count === 0;\n if (dormant) {\n score *= 0.5;\n signals.push(`dormant ${Math.floor(ageDays)}d`);\n }\n\n const tier = deriveTier(score, dormant, usage);\n const pruneCandidate = isPruneCandidate(fm, usage, tier);\n\n return { score: round3(score), tier, signals, pruneCandidate };\n}\n\nfunction deriveTier(score: number, dormant: boolean, usage: MemoryUsage): ImpactTier {\n if (dormant && usage.read_count <= 1 && usage.applied_count === 0) return \"dormant\";\n if (score >= 0.55) return \"high\";\n if (score >= 0.2) return \"medium\";\n return \"low\";\n}\n\nfunction isPruneCandidate(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n tier: ImpactTier,\n): boolean {\n // A sensor or any applied outcome means the memory earns its keep.\n if (fm.sensor || usage.applied_count > 0) return false;\n if (isDeadStatus(fm)) return true;\n // More rejected than read = actively unhelpful.\n if (usage.rejected_count > 0 && usage.rejected_count >= usage.read_count) return true;\n // Never used and gone dormant = dead weight.\n if (tier === \"dormant\" && usage.read_count === 0) return true;\n return false;\n}\n\nfunction round3(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\n/** Sort comparator: highest impact first, prune candidates last on ties. */\nexport function compareImpact(a: ImpactScore, b: ImpactScore): number {\n if (b.score !== a.score) return b.score - a.score;\n if (a.pruneCandidate !== b.pruneCandidate) return a.pruneCandidate ? 1 : -1;\n return 0;\n}\n\nexport interface ImpactSummary {\n total: number;\n high: number;\n medium: number;\n low: number;\n dormant: number;\n prune_candidates: number;\n}\n\n/** Roll up a set of impact scores into tier counts. */\nexport function summarizeImpact(scores: ImpactScore[]): ImpactSummary {\n const summary: ImpactSummary = {\n total: scores.length,\n high: 0,\n medium: 0,\n low: 0,\n dormant: 0,\n prune_candidates: 0,\n };\n for (const s of scores) {\n summary[s.tier] += 1;\n if (s.pruneCandidate) summary.prune_candidates += 1;\n }\n return summary;\n}\n\nexport type FeedbackAdjustmentAction = \"none\" | \"downgrade-block-sensor\" | \"deprecate-memory\";\n\nexport interface FeedbackAdjustment {\n action: FeedbackAdjustmentAction;\n reason: string;\n}\n\nexport interface FeedbackAdjustmentOptions {\n /** Rejections needed before deprecating a memory with no positive outcomes. Defaults to 2. */\n rejectionThreshold?: number;\n}\n\n/**\n * Turn explicit human rejection (`mem_feedback outcome=rejected`) into a deterministic\n * noise-reduction action. Pure: callers decide whether to persist the returned change.\n */\nexport function recommendFeedbackAdjustment(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n options: FeedbackAdjustmentOptions = {},\n): FeedbackAdjustment {\n const rejectionThreshold = options.rejectionThreshold ?? 2;\n const hasPositiveOutcome = usage.applied_count > 0 || usage.prevented_count > 0;\n\n if (fm.sensor?.severity === \"block\" && usage.rejected_count >= 1) {\n return {\n action: \"downgrade-block-sensor\",\n reason: \"A human contested a blocking guardrail; downgrade it to warn so the gate stays helpful while the lesson is reviewed.\",\n };\n }\n\n if (!hasPositiveOutcome && usage.rejected_count >= rejectionThreshold) {\n return {\n action: \"deprecate-memory\",\n reason: `${usage.rejected_count} rejection(s) and no applied/prevented outcomes; deprecate until the lesson is refined.`,\n };\n }\n\n return { action: \"none\", reason: \"No automatic adjustment needed.\" };\n}\n\nexport function applyFeedbackAdjustment(\n fm: MemoryFrontmatter,\n adjustment: FeedbackAdjustment,\n now: Date = new Date(),\n): MemoryFrontmatter {\n if (adjustment.action === \"none\") return fm;\n const tags = [...new Set([...fm.tags, \"feedback-contested\"])];\n if (adjustment.action === \"downgrade-block-sensor\" && fm.sensor) {\n return {\n ...fm,\n tags,\n verified_at: now.toISOString(),\n sensor: { ...fm.sensor, severity: \"warn\" },\n };\n }\n if (adjustment.action === \"deprecate-memory\") {\n return {\n ...fm,\n tags,\n status: \"deprecated\",\n stale_reason: adjustment.reason,\n verified_at: now.toISOString(),\n };\n }\n return fm;\n}\n","/**\n * Prevention event log — the time-series behind hAIve's OUTCOME metric.\n *\n * `usage.json` keeps a cumulative `prevented_count` per memory (cheap, drives impact). This log\n * keeps one append-only record PER catch, with a timestamp, so we can answer questions a counter\n * can't: how is prevention trending over time, and which lessons keep getting re-introduced after\n * capture (recurrence). Lives in `.ai/.cache/` (gitignored telemetry) — never committed, never\n * churns a release.\n */\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { LoadedMemory } from \"./loader.js\";\nimport type { HaivePaths } from \"./paths.js\";\nimport {\n getUsage,\n loadUsageIndex,\n recordPrevention,\n saveUsageIndex,\n type UsageIndex,\n} from \"./usage.js\";\n\nexport type PreventionSource = \"sensor\" | \"anti-pattern\";\n\nexport interface PreventionEvent {\n /** ISO timestamp of the catch. */\n at: string;\n /** Memory id whose lesson fired. */\n id: string;\n /** Which gate path recorded it. */\n source: PreventionSource;\n}\n\nexport function preventionLogPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", \"prevention-log.jsonl\");\n}\n\n/** Append one catch to the log. Best-effort, creates the dir on demand. */\nexport async function appendPreventionEvent(paths: HaivePaths, event: PreventionEvent): Promise<void> {\n const file = preventionLogPath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n await appendFile(file, JSON.stringify(event) + \"\\n\", \"utf8\");\n}\n\n/**\n * THE single recorder for \"a documented lesson intercepted a real mistake\". Every gate path —\n * the installed git-hook gate (`enforce check`), the standalone `haive sensors check`, and the\n * `anti_patterns_check` MCP tool — funnels its fired memory ids through here so prevention is\n * recorded once and identically, not bolted onto each entry point (it used to leak: the git-hook\n * gate blocked but never recorded — see the harness-positioning gotcha).\n *\n * Bumps `prevented_count` in usage.json (debounced per memory via {@link recordPrevention}) AND\n * appends one timestamped event per NEW catch to the prevention log. Best-effort: a telemetry\n * write must never break a commit, so failures are swallowed. Returns the ids actually recorded\n * (i.e. not debounced), so callers can report \"caught for you\" without re-counting.\n */\nexport async function recordPreventionHits(\n paths: HaivePaths,\n firedIds: string[],\n source: PreventionSource,\n now: Date = new Date(),\n): Promise<string[]> {\n const unique = [...new Set(firedIds)].filter(Boolean);\n if (unique.length === 0) return [];\n const usage = await loadUsageIndex(paths).catch(() => null);\n if (!usage) return [];\n const recordedIds: string[] = [];\n for (const id of unique) {\n if (recordPrevention(usage, id, now.getTime())) recordedIds.push(id);\n }\n if (recordedIds.length === 0) return [];\n await saveUsageIndex(paths, usage).catch(() => { /* best-effort telemetry */ });\n const at = now.toISOString();\n for (const id of recordedIds) {\n await appendPreventionEvent(paths, { at, id, source }).catch(() => { /* best-effort */ });\n }\n return recordedIds;\n}\n\n/** Read all catch events (skips malformed lines). */\nexport async function loadPreventionEvents(paths: HaivePaths): Promise<PreventionEvent[]> {\n const file = preventionLogPath(paths);\n if (!existsSync(file)) return [];\n const raw = await readFile(file, \"utf8\").catch(() => \"\");\n const events: PreventionEvent[] = [];\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const e = JSON.parse(trimmed) as PreventionEvent;\n if (e && typeof e.at === \"string\" && typeof e.id === \"string\") events.push(e);\n } catch {\n // skip a corrupt line rather than fail the whole read\n }\n }\n return events;\n}\n\n// ── Pure analytics over the event log ───────────────────────────────────────\n\nexport interface PreventionTrend {\n /** Catches in the last 7 days. */\n last_7d: number;\n /** Catches in the last 30 days. */\n last_30d: number;\n /** Catch counts per ISO week, oldest → newest, for the last N weeks (default 6). */\n weekly: number[];\n}\n\nconst MS_PER_DAY = 86_400_000;\n\nexport function computePreventionTrend(\n events: PreventionEvent[],\n now: Date = new Date(),\n weeks = 6,\n): PreventionTrend {\n const nowMs = now.getTime();\n let last7 = 0;\n let last30 = 0;\n const weekly = new Array<number>(weeks).fill(0);\n for (const e of events) {\n const t = Date.parse(e.at);\n if (!Number.isFinite(t)) continue;\n const ageDays = (nowMs - t) / MS_PER_DAY;\n if (ageDays < 0) continue;\n if (ageDays <= 7) last7 += 1;\n if (ageDays <= 30) last30 += 1;\n const weekIdx = weeks - 1 - Math.floor(ageDays / 7);\n if (weekIdx >= 0 && weekIdx < weeks) weekly[weekIdx] = (weekly[weekIdx] ?? 0) + 1;\n }\n return { last_7d: last7, last_30d: last30, weekly };\n}\n\nexport interface RecurrenceRow {\n id: string;\n /** Total catches for this memory. */\n catches: number;\n /** Number of distinct UTC days the lesson fired — the recurrence signal. */\n distinct_days: number;\n last_at: string;\n}\n\nexport interface RecurrenceReport {\n /**\n * Memories whose lesson was caught on >= 2 distinct days — i.e. the mistake was RE-INTRODUCED\n * after it had already been captured and caught once. A high count means a recurring problem the\n * team keeps reintroducing (the guardrail is earning its keep, and the root cause may need a\n * stronger fix than a memory).\n */\n recurring_count: number;\n top: RecurrenceRow[];\n}\n\nexport function computeRecurrence(events: PreventionEvent[]): RecurrenceReport {\n const byId = new Map<string, { catches: number; days: Set<string>; last: string }>();\n for (const e of events) {\n const cur = byId.get(e.id) ?? { catches: 0, days: new Set<string>(), last: e.at };\n cur.catches += 1;\n cur.days.add(e.at.slice(0, 10));\n if (e.at > cur.last) cur.last = e.at;\n byId.set(e.id, cur);\n }\n const rows: RecurrenceRow[] = [];\n for (const [id, v] of byId) {\n if (v.days.size >= 2) {\n rows.push({ id, catches: v.catches, distinct_days: v.days.size, last_at: v.last });\n }\n }\n rows.sort((a, b) => b.distinct_days - a.distinct_days || b.catches - a.catches);\n return { recurring_count: rows.length, top: rows };\n}\n\nexport interface BriefingProofLineOptions {\n /** End of the reporting window. Defaults to now. */\n now?: Date;\n /** Window size in days. Defaults to 30 (\"this month\" in product copy). */\n days?: number;\n}\n\n/**\n * Coordination point for Lot C: turn prevention events into one compact proof line\n * suitable for get_briefing, without coupling this lot to the MCP tool.\n */\nexport function briefingProofLine(\n events: PreventionEvent[],\n options: BriefingProofLineOptions = {},\n): string | null {\n const now = options.now ?? new Date();\n const days = options.days ?? 30;\n const since = now.getTime() - days * MS_PER_DAY;\n let count = 0;\n for (const e of events) {\n const t = Date.parse(e.at);\n if (!Number.isFinite(t)) continue;\n if (t >= since && t <= now.getTime()) count += 1;\n }\n if (count === 0) return null;\n return `This harness prevented ${count} repeated mistake${count === 1 ? \"\" : \"s\"} in the last ${days} days.`;\n}\n\nexport interface CaughtForYouOptions {\n /** Only include events at or after this instant. */\n since?: string | Date;\n /** Only include events at or before this instant. Defaults to now. */\n now?: Date;\n /** Max rows in the summary. Defaults to 5. */\n limit?: number;\n}\n\nexport interface CaughtForYouRow {\n id: string;\n title: string;\n source: PreventionSource;\n catches: number;\n previous_count: number;\n current_count: number;\n last_at: string;\n}\n\nexport interface CaughtForYouSummary {\n total_catches: number;\n since: string | null;\n until: string;\n rows: CaughtForYouRow[];\n}\n\nfunction titleFromMemory(loaded: LoadedMemory | undefined): string {\n if (!loaded) return \"\";\n for (const line of loaded.memory.body.split(\"\\n\")) {\n const heading = /^#+\\s*(.+)$/.exec(line.trim());\n if (heading) return heading[1]!.trim().slice(0, 96);\n }\n for (const line of loaded.memory.body.split(\"\\n\")) {\n const t = line.trim();\n if (t) return t.replace(/^[-*]\\s*/, \"\").slice(0, 96);\n }\n return \"\";\n}\n\nfunction sourceRank(source: PreventionSource): number {\n return source === \"anti-pattern\" ? 0 : 1;\n}\n\n/** Build the end-of-session \"caught for you\" scene from prevention events. Pure. */\nexport function summarizeCaughtForYou(\n events: PreventionEvent[],\n memories: LoadedMemory[],\n usage: UsageIndex,\n options: CaughtForYouOptions = {},\n): CaughtForYouSummary {\n const until = options.now ?? new Date();\n const sinceMs =\n options.since === undefined\n ? null\n : options.since instanceof Date\n ? options.since.getTime()\n : Date.parse(options.since);\n const untilMs = until.getTime();\n const byIdSource = new Map<string, { id: string; source: PreventionSource; catches: number; last_at: string }>();\n\n for (const e of events) {\n const t = Date.parse(e.at);\n if (!Number.isFinite(t)) continue;\n if (sinceMs !== null && Number.isFinite(sinceMs) && t < sinceMs) continue;\n if (t > untilMs) continue;\n const key = `${e.id}\\0${e.source}`;\n const current = byIdSource.get(key) ?? { id: e.id, source: e.source, catches: 0, last_at: e.at };\n current.catches += 1;\n if (e.at > current.last_at) current.last_at = e.at;\n byIdSource.set(key, current);\n }\n\n const memoryById = new Map(memories.map((m) => [m.memory.frontmatter.id, m]));\n const rows = [...byIdSource.values()]\n .map((row): CaughtForYouRow => {\n const current = getUsage(usage, row.id).prevented_count;\n const previous = Math.max(0, current - row.catches);\n return {\n id: row.id,\n title: titleFromMemory(memoryById.get(row.id)) || row.id,\n source: row.source,\n catches: row.catches,\n previous_count: previous,\n current_count: current,\n last_at: row.last_at,\n };\n })\n .sort((a, b) => b.last_at.localeCompare(a.last_at) || sourceRank(a.source) - sourceRank(b.source))\n .slice(0, options.limit ?? 5);\n\n return {\n total_catches: [...byIdSource.values()].reduce((sum, row) => sum + row.catches, 0),\n since: sinceMs !== null && Number.isFinite(sinceMs) ? new Date(sinceMs).toISOString() : null,\n until: until.toISOString(),\n rows,\n };\n}\n\n/** Render a compact human-readable block for CLI/session recaps. */\nexport function renderCaughtForYou(summary: CaughtForYouSummary): string | null {\n if (summary.total_catches === 0 || summary.rows.length === 0) return null;\n const lines = [\n `Caught for you: ${summary.total_catches} prevented repeat${summary.total_catches === 1 ? \"\" : \"s\"} this session.`,\n ];\n for (const row of summary.rows) {\n const gate = row.source === \"anti-pattern\" ? \"Blocked\" : \"Caught\";\n lines.push(\n `- ${gate}: ${row.title} (${row.id}). Prevention ${row.previous_count}->${row.current_count}.`,\n );\n }\n return lines.join(\"\\n\");\n}\n","/**\n * Project-context emission throttle — a token saver for long sessions.\n *\n * `get_briefing` re-emits the full `.ai/project-context.md` on every call. Across a 10-call session\n * that re-sends the same ~1.5k tokens nine times for nothing. This records a tiny marker (content\n * hash + timestamp, in gitignored `.ai/.cache/`) so a briefing can skip re-emitting an UNCHANGED\n * context within a short window — the agent already has it from the earlier call.\n */\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\n/** How long an emitted project context is considered \"still fresh in the agent's context\". */\nexport const PROJECT_CONTEXT_THROTTLE_MS = 8 * 60 * 1000;\n\nfunction throttleMarkerPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", \"briefing-context.json\");\n}\n\nexport function hashProjectContext(content: string): string {\n return createHash(\"sha1\").update(content).digest(\"hex\").slice(0, 16);\n}\n\n/** True if an identical project-context body was already emitted within the throttle window. */\nexport async function projectContextRecentlyEmitted(\n paths: HaivePaths,\n hash: string,\n now: number = Date.now(),\n): Promise<boolean> {\n const file = throttleMarkerPath(paths);\n if (!existsSync(file)) return false;\n try {\n const m = JSON.parse(await readFile(file, \"utf8\")) as { hash?: string; at?: string };\n if (m.hash !== hash || !m.at) return false;\n return now - Date.parse(m.at) < PROJECT_CONTEXT_THROTTLE_MS;\n } catch {\n return false;\n }\n}\n\n/** Record that this exact project-context body was just emitted. Best-effort. */\nexport async function recordProjectContextEmission(\n paths: HaivePaths,\n hash: string,\n now: number = Date.now(),\n): Promise<void> {\n const file = throttleMarkerPath(paths);\n await mkdir(path.dirname(file), { recursive: true }).catch(() => { /* ignore */ });\n await writeFile(file, JSON.stringify({ hash, at: new Date(now).toISOString() }), \"utf8\").catch(() => { /* ignore */ });\n}\n","import type { LoadedMemory } from \"./loader.js\";\n\n/**\n * A rigorous, model-free, repeatable evaluation of hAIve's core promise: surfacing\n * the right knowledge and guardrails at the right moment. Unlike the agent benchmark\n * (which parses human-written reports), this is deterministic and CI-runnable — it\n * produces a numeric quality score from labeled cases, so a regression in ranking or\n * sensor coverage fails the build instead of silently degrading every agent session.\n *\n * Two case families:\n * - RETRIEVAL — given a task (+optional files/symbols), do the expected memories\n * surface in the briefing top-k? Measured by recall and mean reciprocal rank.\n * - SENSORS — given a known-bad diff, does the expected memory's sensor fire?\n * Measured by catch-rate.\n *\n * This module is pure: it defines the case/result types, the scoring math, and case\n * synthesis from a repo's own anchored memories. Orchestration (calling get_briefing\n * / anti_patterns_check) lives in the CLI, since core cannot depend on the MCP layer.\n */\n\nexport interface RetrievalCase {\n name: string;\n task: string;\n files?: string[];\n symbols?: string[];\n /** Memory ids that SHOULD surface in the briefing for this case. */\n expect_ids: string[];\n}\n\nexport interface SensorCase {\n name: string;\n /** Unified diff (or added-line text) the sensors run against. */\n diff: string;\n paths?: string[];\n /** Memory ids whose sensor SHOULD fire on this diff. */\n expect_fire_ids: string[];\n}\n\nexport interface EvalSpec {\n retrieval?: RetrievalCase[];\n sensors?: SensorCase[];\n}\n\nexport interface RetrievalCaseResult {\n name: string;\n expect_ids: string[];\n /** Surfaced memory ids, in ranked order, capped at k. */\n surfaced_ids: string[];\n hits: string[];\n misses: string[];\n precision: number;\n recall: number;\n /** 1-based rank of the first expected id among surfaced ids; null if none surfaced. */\n best_rank: number | null;\n}\n\nexport interface SensorCaseResult {\n name: string;\n expect_fire_ids: string[];\n fired_ids: string[];\n hits: string[];\n misses: string[];\n recall: number;\n}\n\nexport interface RetrievalAggregate {\n cases: RetrievalCaseResult[];\n /**\n * Top-k precision = expected hits ÷ surfaced results. Inherently LOW when only ~1 memory is\n * expected per case but k results are surfaced (e.g. 1/8 ≈ 0.12) — this is a top-k artifact, not\n * a quality defect. Retrieval quality is judged by `mean_recall` and `mrr`; precision is NOT part\n * of the headline eval score (see `scoreEval`). Reported for completeness only.\n */\n mean_precision: number;\n mean_recall: number;\n /** Mean reciprocal rank of the first expected hit — rewards ranking the right memory high. */\n mrr: number;\n}\n\nexport interface SensorAggregate {\n cases: SensorCaseResult[];\n catch_rate: number;\n}\n\nexport interface EvalReport {\n retrieval: RetrievalAggregate | null;\n sensors: SensorAggregate | null;\n /** Overall quality score 0..100. */\n score: number;\n}\n\nfunction round3(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\nfunction uniq(ids: string[]): string[] {\n return [...new Set(ids)];\n}\n\n/**\n * Score one retrieval case from the (ranked) ids the briefing surfaced.\n * `surfacedRanked` should already be capped to the top-k the caller cares about.\n */\nexport function scoreRetrievalCase(\n name: string,\n expectIds: string[],\n surfacedRanked: string[],\n): RetrievalCaseResult {\n const expect = uniq(expectIds);\n const surfaced = uniq(surfacedRanked);\n const surfacedSet = new Set(surfaced);\n const hits = expect.filter((id) => surfacedSet.has(id));\n const misses = expect.filter((id) => !surfacedSet.has(id));\n\n let bestRank: number | null = null;\n for (let i = 0; i < surfaced.length; i++) {\n if (expect.includes(surfaced[i]!)) {\n bestRank = i + 1;\n break;\n }\n }\n\n return {\n name,\n expect_ids: expect,\n surfaced_ids: surfaced,\n hits,\n misses,\n precision: surfaced.length === 0 ? 0 : round3(hits.length / surfaced.length),\n recall: expect.length === 0 ? 1 : round3(hits.length / expect.length),\n best_rank: bestRank,\n };\n}\n\nexport function aggregateRetrieval(cases: RetrievalCaseResult[]): RetrievalAggregate {\n const n = cases.length;\n const mean = (sel: (c: RetrievalCaseResult) => number): number =>\n n === 0 ? 0 : round3(cases.reduce((s, c) => s + sel(c), 0) / n);\n return {\n cases,\n mean_precision: mean((c) => c.precision),\n mean_recall: mean((c) => c.recall),\n mrr: mean((c) => (c.best_rank ? 1 / c.best_rank : 0)),\n };\n}\n\nexport function scoreSensorCase(\n name: string,\n expectFireIds: string[],\n firedIds: string[],\n): SensorCaseResult {\n const expect = uniq(expectFireIds);\n const fired = uniq(firedIds);\n const firedSet = new Set(fired);\n const hits = expect.filter((id) => firedSet.has(id));\n const misses = expect.filter((id) => !firedSet.has(id));\n return {\n name,\n expect_fire_ids: expect,\n fired_ids: fired,\n hits,\n misses,\n recall: expect.length === 0 ? 1 : round3(hits.length / expect.length),\n };\n}\n\nexport function aggregateSensors(cases: SensorCaseResult[]): SensorAggregate {\n const totalExpected = cases.reduce((s, c) => s + c.expect_fire_ids.length, 0);\n const totalHits = cases.reduce((s, c) => s + c.hits.length, 0);\n return {\n cases,\n catch_rate: totalExpected === 0 ? 1 : round3(totalHits / totalExpected),\n };\n}\n\n/** Combine retrieval + sensor aggregates into a single 0..100 quality score. */\nexport function overallScore(\n retrieval: RetrievalAggregate | null,\n sensors: SensorAggregate | null,\n): number {\n if (retrieval && sensors) {\n return Math.round((0.5 * retrieval.mean_recall + 0.2 * retrieval.mrr + 0.3 * sensors.catch_rate) * 100);\n }\n if (retrieval) {\n return Math.round((0.7 * retrieval.mean_recall + 0.3 * retrieval.mrr) * 100);\n }\n if (sensors) {\n return Math.round(sensors.catch_rate * 100);\n }\n return 0;\n}\n\nexport function buildReport(\n retrieval: RetrievalAggregate | null,\n sensors: SensorAggregate | null,\n): EvalReport {\n return { retrieval, sensors, score: overallScore(retrieval, sensors) };\n}\n\n/**\n * Baseline / compare — makes the \"hAIve improves retrieval by N%\" claim reproducible.\n *\n * `haive eval --baseline` snapshots a report; `--compare` re-runs and diffs against it,\n * so a ranking/sensor regression is a number, not a vibe. Pure math here; the CLI does I/O.\n */\nexport interface MetricDelta {\n baseline: number;\n current: number;\n /** current − baseline (positive = improvement for all these metrics). */\n delta: number;\n}\n\nexport interface EvalDelta {\n score: MetricDelta;\n mean_recall: MetricDelta | null;\n mrr: MetricDelta | null;\n catch_rate: MetricDelta | null;\n /** True when the overall score dropped vs the baseline. */\n regressed: boolean;\n /** True when the overall score rose vs the baseline. */\n improved: boolean;\n}\n\nfunction metricDelta(baseline: number, current: number): MetricDelta {\n return { baseline: round3(baseline), current: round3(current), delta: round3(current - baseline) };\n}\n\n/** Diff a current report against a baseline. Pure. */\nexport function compareEvalReports(baseline: EvalReport, current: EvalReport): EvalDelta {\n const recall =\n baseline.retrieval && current.retrieval\n ? metricDelta(baseline.retrieval.mean_recall, current.retrieval.mean_recall)\n : null;\n const mrr =\n baseline.retrieval && current.retrieval\n ? metricDelta(baseline.retrieval.mrr, current.retrieval.mrr)\n : null;\n const catchRate =\n baseline.sensors && current.sensors\n ? metricDelta(baseline.sensors.catch_rate, current.sensors.catch_rate)\n : null;\n return {\n score: metricDelta(baseline.score, current.score),\n mean_recall: recall,\n mrr,\n catch_rate: catchRate,\n regressed: current.score < baseline.score,\n improved: current.score > baseline.score,\n };\n}\n\n/** Extract a short task-like title from a memory body (first heading or first line). */\nexport function titleFromBody(body: string): string {\n const lines = body.split(\"\\n\");\n for (const line of lines) {\n const heading = /^#+\\s*(.+)$/.exec(line.trim());\n if (heading) return heading[1]!.trim().slice(0, 120);\n }\n for (const line of lines) {\n const t = line.trim();\n if (t) return t.replace(/^[-*]\\s*/, \"\").slice(0, 120);\n }\n return \"\";\n}\n\nexport interface SelfEvalOptions {\n /** Include each memory's anchor paths as the case files (tests anchored retrieval). */\n includeFiles?: boolean;\n /** Skip memories with these statuses (default: stale/deprecated/rejected). */\n skipStatuses?: string[];\n}\n\n/**\n * Synthesize retrieval cases from a repo's own anchored memories — zero-setup eval.\n * Each anchored, non-recap, non-dead memory becomes a case: \"when working on the\n * file(s) this memory anchors, with its title as the task, does hAIve surface it?\".\n * With `includeFiles: false` it becomes a harder semantic-only probe (title alone).\n */\nexport function synthesizeSelfEvalCases(\n memories: LoadedMemory[],\n options: SelfEvalOptions = {},\n): RetrievalCase[] {\n const includeFiles = options.includeFiles ?? true;\n const skip = new Set(options.skipStatuses ?? [\"stale\", \"deprecated\", \"rejected\"]);\n const cases: RetrievalCase[] = [];\n for (const { memory } of memories) {\n const fm = memory.frontmatter;\n if (fm.type === \"session_recap\") continue;\n if (skip.has(fm.status)) continue;\n const paths = fm.anchor.paths;\n if (paths.length === 0) continue;\n const task = titleFromBody(memory.body) || fm.id;\n cases.push({\n name: fm.id,\n task,\n ...(includeFiles ? { files: paths } : {}),\n expect_ids: [fm.id],\n });\n }\n return cases;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport type { MemoryUsage } from \"./usage.js\";\n\nexport type ConfidenceLevel =\n | \"unverified\"\n | \"low\"\n | \"trusted\"\n | \"authoritative\"\n | \"stale\";\n\nexport interface ConfidenceThresholds {\n trustedReads: number;\n authoritativeReads: number;\n /** Days without a read after which confidence drops one tier (authoritative → trusted). */\n decayDays: number;\n /** Days without a read after which confidence drops two tiers (e.g. authoritative → low). */\n hardDecayDays: number;\n}\n\nexport const DEFAULT_CONFIDENCE_THRESHOLDS: ConfidenceThresholds = {\n trustedReads: 3,\n authoritativeReads: 10,\n decayDays: 180,\n hardDecayDays: 365,\n};\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/**\n * Compute the trust level of a memory.\n *\n * Base tier is derived from `status + read_count`:\n * - draft → unverified\n * - proposed (low reads) → low\n * - proposed (3+ reads) → trusted\n * - validated (low reads) → trusted\n * - validated (10+ reads) → authoritative\n * - stale / deprecated / rejected → stale\n *\n * On top of the base tier, a TIME DECAY is applied: a memory that has not been\n * read in `decayDays` (default 180) drops one tier, and one not read in\n * `hardDecayDays` (default 365) drops two tiers. The clock starts at\n * `last_read_at` if any, otherwise `created_at` from the frontmatter.\n *\n * The decay never crosses into `stale` (we keep that signal reserved for the\n * verifier). The intent is to surface \"this used to be authoritative but\n * nobody has touched it in a year — verify before quoting it\" without\n * pretending the memory is wrong.\n */\nexport function deriveConfidence(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n thresholds: ConfidenceThresholds = DEFAULT_CONFIDENCE_THRESHOLDS,\n now: Date = new Date(),\n): ConfidenceLevel {\n if (fm.status === \"stale\" || fm.status === \"deprecated\" || fm.status === \"rejected\") return \"stale\";\n\n const baseLevel = baseConfidence(fm, usage, thresholds);\n\n // Apply decay only to tiers worth lowering.\n if (baseLevel !== \"authoritative\" && baseLevel !== \"trusted\") return baseLevel;\n\n const anchor = usage.last_read_at ?? fm.created_at;\n const ageDays = (now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY;\n if (Number.isNaN(ageDays) || ageDays <= 0) return baseLevel;\n\n if (ageDays >= thresholds.hardDecayDays) {\n // Two-tier drop. authoritative → low, trusted → low.\n return \"low\";\n }\n if (ageDays >= thresholds.decayDays) {\n if (baseLevel === \"authoritative\") return \"trusted\";\n if (baseLevel === \"trusted\") return \"low\";\n }\n return baseLevel;\n}\n\nfunction baseConfidence(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n thresholds: ConfidenceThresholds,\n): ConfidenceLevel {\n if (fm.status === \"validated\") {\n return usage.read_count >= thresholds.authoritativeReads\n ? \"authoritative\"\n : \"trusted\";\n }\n if (fm.status === \"proposed\") {\n return usage.read_count >= thresholds.trustedReads ? \"trusted\" : \"low\";\n }\n // draft\n return \"unverified\";\n}\n\nexport interface AutoPromoteRule {\n /** Minimum read_count to promote proposed → validated. */\n minReads: number;\n /** Maximum rejected_count tolerated (memories with more rejections never auto-promote). */\n maxRejections: number;\n}\n\nexport const DEFAULT_AUTO_PROMOTE_RULE: AutoPromoteRule = {\n minReads: 5,\n maxRejections: 0,\n};\n\nexport function isAutoPromoteEligible(\n fm: MemoryFrontmatter,\n usage: MemoryUsage,\n rule: AutoPromoteRule = DEFAULT_AUTO_PROMOTE_RULE,\n): boolean {\n if (fm.status !== \"proposed\") return false;\n if (usage.rejected_count > rule.maxRejections) return false;\n return usage.read_count >= rule.minReads;\n}\n","/**\n * Distinctive-token corroboration for the anti-pattern gate.\n *\n * The pre-commit gate used to hard-block whenever a diff shared ANY ≥4-char token\n * with an anchored gotcha's body. That fires on ubiquitous domain words (\"memory\",\n * \"sensor\", \"scope\", \"input\", \"version\") and on version-bump diffs — blocking agents\n * for nothing. The fix: a `literal` overlap only corroborates a BLOCK when at least\n * one shared token is *distinctive* to that gotcha — i.e. rare across the gotcha\n * corpus (low document frequency), like `BigInt`, `open-in-view`, `rec_7`. Common\n * words can still surface the warning for review; they just can't hard-block.\n *\n * Pure module (no I/O), TF-IDF-style. Unit-tested in `test/distinctive.test.ts`.\n */\n\n/**\n * Language keywords + ubiquitous code words that would match almost any memory body\n * and so carry no distinguishing signal. Shared by the diff tokenizer and the\n * distinctiveness check so \"literal\" stays meaningful.\n */\nexport const CODE_STOPWORDS = new Set([\n \"import\", \"export\", \"function\", \"return\", \"const\", \"let\", \"var\", \"class\", \"public\",\n \"private\", \"protected\", \"static\", \"this\", \"true\", \"false\", \"null\", \"undefined\", \"void\",\n \"async\", \"await\", \"from\", \"type\", \"interface\", \"extends\", \"implements\", \"number\", \"string\",\n \"boolean\", \"value\", \"default\", \"case\", \"break\", \"continue\", \"throw\", \"catch\", \"finally\",\n \"else\", \"while\", \"for\", \"new\", \"super\", \"yield\", \"module\", \"require\", \"console\",\n]);\n\n/** Minimum token length kept for word-level matching (shorter tokens are too noisy). */\nexport const MIN_WORD_LEN = 4;\n\n/** Split text into lowercase word tokens (>= MIN_WORD_LEN, excluding code stopwords). */\nexport function tokenizeWords(text: string): string[] {\n return text\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length >= MIN_WORD_LEN && !CODE_STOPWORDS.has(t));\n}\n\nexport interface DocFrequency {\n /** token -> number of documents (memory bodies) it appears in */\n df: Map<string, number>;\n /** total number of documents */\n total: number;\n}\n\n/** Build per-token document frequency across a corpus of memory bodies. */\nexport function buildDocFrequency(bodies: string[]): DocFrequency {\n const df = new Map<string, number>();\n for (const body of bodies) {\n const unique = new Set(tokenizeWords(body));\n for (const tok of unique) df.set(tok, (df.get(tok) ?? 0) + 1);\n }\n return { df, total: bodies.length };\n}\n\n/**\n * Document-frequency cap at/below which a token counts as distinctive. Deliberately\n * strict — \"distinctive\" means *rare* (≈ the bottom 10% of the corpus), with a floor\n * of 1 so a token appearing in a single memory is always distinctive. Strictness is\n * intentional: blocking is the aggressive action, so we under-block rather than fire\n * on a word that several gotchas happen to share.\n */\nexport function distinctiveCap(total: number): number {\n return Math.max(1, Math.floor(0.1 * total));\n}\n\n/** True when `token` is distinctive (rare) within the corpus. */\nexport function isDistinctiveToken(token: string, freq: DocFrequency): boolean {\n const tok = token.toLowerCase();\n if (tok.length < MIN_WORD_LEN || CODE_STOPWORDS.has(tok)) return false;\n const df = freq.df.get(tok);\n if (df === undefined) return true; // not seen elsewhere in the corpus → distinctive\n return df <= distinctiveCap(freq.total);\n}\n\n/**\n * True when the added diff text shares at least one *distinctive* word token with the\n * memory body. This is the precise corroboration the block decision should require:\n * \"the change actually contains the specific thing this gotcha warns about\", not\n * \"the change happens to mention a common domain word\".\n */\nexport function diffHasDistinctiveOverlap(\n addedDiffText: string,\n memoryBody: string,\n freq: DocFrequency,\n): boolean {\n const memoryTokens = new Set(tokenizeWords(memoryBody));\n if (memoryTokens.size === 0) return false;\n for (const tok of new Set(tokenizeWords(addedDiffText))) {\n if (memoryTokens.has(tok) && isDistinctiveToken(tok, freq)) return true;\n }\n return false;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport { pathsOverlap } from \"./relevance.js\";\n\n/**\n * Progressive disclosure for `skill` memories.\n *\n * Skills are reusable playbooks. Surfacing all of them on every briefing wastes the\n * instruction budget and buries the relevant one. A skill with an `activation` block\n * is disclosed ONLY when it is relevant to the current task/files; a skill without\n * one keeps the legacy always-eligible behavior. This module is pure (no I/O).\n */\n\nexport interface ActivationContext {\n task?: string;\n files?: string[];\n}\n\nexport interface SkillActivation {\n applicable: boolean;\n activated: boolean;\n reasons: string[];\n}\n\nexport function isSkill(fm: Pick<MemoryFrontmatter, \"type\">): boolean {\n return fm.type === \"skill\";\n}\n\n/**\n * Decide whether a skill should be disclosed for the given context.\n * For non-skills, or skills with no `activation` block, returns `activated: true`\n * (never suppress them). Otherwise activates on `always`, a keyword substring match\n * against the task, or a glob match against the edited files.\n */\nexport function evaluateSkillActivation(\n fm: Pick<MemoryFrontmatter, \"type\" | \"activation\">,\n ctx: ActivationContext,\n): SkillActivation {\n if (!isSkill(fm)) return { applicable: false, activated: true, reasons: [] };\n const act = fm.activation;\n if (!act) return { applicable: false, activated: true, reasons: [\"no-activation\"] };\n\n const reasons: string[] = [];\n if (act.always) reasons.push(\"always\");\n\n const task = (ctx.task ?? \"\").toLowerCase();\n if (task) {\n for (const kw of act.keywords) {\n if (kw && task.includes(kw.toLowerCase())) {\n reasons.push(`keyword:${kw}`);\n break;\n }\n }\n }\n\n const files = ctx.files ?? [];\n if (files.length > 0) {\n outer: for (const glob of act.globs) {\n for (const f of files) {\n if (pathsOverlap(glob, f)) {\n reasons.push(`glob:${glob}`);\n break outer;\n }\n }\n }\n }\n\n return { applicable: true, activated: reasons.length > 0, reasons };\n}\n\n/** Convenience: true when a skill defines activation triggers that the context does NOT satisfy. */\nexport function isSkillSuppressed(\n fm: Pick<MemoryFrontmatter, \"type\" | \"activation\">,\n ctx: ActivationContext,\n): boolean {\n const result = evaluateSkillActivation(fm, ctx);\n return result.applicable && !result.activated;\n}\n","/**\n * Specificity (\"surprise\") scoring for memories.\n *\n * hAIve's measured value is preventing agents from reinventing — wrongly — the team's\n * NON-OBVIOUS, arbitrary decisions (e.g. \"public ids are internal id + 100000 prefixed AC-\",\n * \"the status field must be 'OK'/'KO'\"). A capable model already knows generic best practice\n * (\"use Decimal for money\", \"validate input\"), so surfacing that is pure token overhead.\n *\n * `specificityScore` is a cheap, deterministic heuristic that estimates how *unguessable* a\n * memory is: high when it contains concrete, arbitrary signal (string literals, code\n * identifiers, magic numbers, paths, ALLCAPS constants), low when it is generic prose.\n *\n * It is intentionally a heuristic, not a model call — used to (1) bias briefing ranking toward\n * unguessable knowledge, (2) keep a near-empty briefing cheap when nothing team-specific\n * matches, (3) lint low-value memories, and (4) filter auto-capture candidates.\n */\n\n/** Generic best-practice phrases a capable model already knows — low marginal value to surface. */\nconst GENERIC_PHRASES: readonly string[] = [\n \"validate input\", \"sanitize\", \"prepared statement\", \"parameterized quer\",\n \"never commit secret\", \"use environment variable\", \"handle error\", \"write test\",\n \"avoid sql injection\", \"escape html\", \"hash password\", \"use https\", \"least privilege\",\n \"do not hardcode\", \"don't hardcode\", \"single responsibility\", \"keep it dry\",\n \"follow best practice\", \"use meaningful names\", \"add error handling\", \"check for null\",\n \"use try/catch\", \"use async/await\", \"avoid magic number\", \"write clean code\",\n];\n\nconst STRING_LITERAL = /[\"'`][^\"'`\\n]{1,48}[\"'`]/g;\nconst BACKTICK_SPAN = /`[^`\\n]+`/g;\nconst CAMEL_CASE = /\\b[a-zA-Z_][a-zA-Z0-9_]*[a-z][A-Z][a-zA-Z0-9_]*\\b/g;\nconst SNAKE_CASE = /\\b[a-z][a-z0-9]*_[a-z0-9_]+\\b/g;\nconst DOTTED = /\\b\\w+\\.\\w+(?:\\.\\w+)*\\b/g;\nconst MAGIC_NUMBER = /\\b\\d{2,}\\b|\\b\\d+\\.\\d+\\b/g;\nconst FILE_PATH = /\\b[\\w./-]+\\.[a-z]{1,5}\\b/g;\nconst ALLCAPS_CONST = /\\b[A-Z]{2,}(?:_[A-Z0-9]+)+\\b|\\b[A-Z]{3,}\\b/g;\n\nfunction countMatches(text: string, re: RegExp): number {\n const m = text.match(re);\n return m ? m.length : 0;\n}\n\n/**\n * Estimate how unguessable / team-specific a memory body is, in [0, 1].\n * ~0 = generic advice a model already follows by default.\n * ~1 = arbitrary, repo-specific knowledge no model can infer.\n */\nexport function specificityScore(body: string): number {\n const text = (body ?? \"\").trim();\n if (text.length === 0) return 0;\n const lower = text.toLowerCase();\n const words = lower.split(/\\s+/).filter(Boolean).length || 1;\n\n let hits = 0;\n hits += countMatches(text, STRING_LITERAL) * 2;\n hits += countMatches(text, BACKTICK_SPAN) * 2;\n hits += countMatches(text, CAMEL_CASE);\n hits += countMatches(text, SNAKE_CASE);\n hits += countMatches(text, DOTTED);\n hits += countMatches(text, MAGIC_NUMBER);\n hits += countMatches(text, FILE_PATH);\n hits += countMatches(text, ALLCAPS_CONST);\n\n // Density of concrete signal. The denominator scales with length so a long generic\n // paragraph isn't rescued by a single identifier, while a short, dense rule scores high.\n let score = Math.min(1, hits / Math.max(6, words * 0.35));\n\n // A memory that reads like generic advice and carries little concrete signal is capped low.\n const generic = GENERIC_PHRASES.some((p) => lower.includes(p));\n if (generic && hits < 4) score = Math.min(score, 0.22);\n\n return score;\n}\n\n/**\n * True when a body uses generic best-practice phrasing a capable model already follows.\n * Used to SCOPE the LOW_VALUE lint: a low-density body is only \"guessable noise\" when it also\n * reads like generic advice. An arbitrary team *policy* can be prose-y yet unguessable (e.g.\n * \"UI text in English, user content in any language\") — that must NOT be flagged. Positive\n * evidence (a generic phrase) keeps the lint high-precision and kills that false positive.\n */\nexport function looksLikeGenericAdvice(body: string): boolean {\n const lower = (body ?? \"\").toLowerCase();\n return GENERIC_PHRASES.some((p) => lower.includes(p));\n}\n\n/** Default threshold below which a memory is considered likely-guessable (low marginal value). */\nexport const GUESSABLE_THRESHOLD = 0.3;\n\n/** True when a memory body looks like generic knowledge a capable model already has. */\nexport function isLikelyGuessable(body: string, threshold: number = GUESSABLE_THRESHOLD): boolean {\n return specificityScore(body) < threshold;\n}\n\n/**\n * Quality floor for SEEDED memories (stack packs, ingested findings) — the guard against shipping\n * low-value \"use const not var\" starter content. A seed earns its place only if it is either:\n * - ENFORCEABLE: it carries a hand-authored sensor (its value is the gate, not its prose), or\n * - SPECIFIC: it reads as a concrete framework/repo trap (specificity >= floor) and is NOT\n * generic best-practice prose a capable model already follows.\n * Used both at seed time (skip a memory that fails) and as a CI guard over the shipped pack library.\n *\n * The floor (0.2) is intentionally LOWER than {@link GUESSABLE_THRESHOLD} (0.3, used to lint claimed\n * team knowledge): a seed is explicitly background-priority framework REFERENCE, not a claim of\n * non-guessable team policy, so a concrete framework gotcha with a code example clears it — while\n * genuine garbage (\"use const\", \"write tests\") still scores ~0 and/or trips looksLikeGenericAdvice.\n */\nexport const SEED_QUALITY_FLOOR = 0.2;\n\nexport function meetsSeedQualityFloor(\n body: string,\n hasSensor: boolean,\n floor: number = SEED_QUALITY_FLOOR,\n): boolean {\n if (hasSensor) return true;\n if (looksLikeGenericAdvice(body)) return false;\n return specificityScore(body) >= floor;\n}\n","/**\n * Token budgeting helpers. We use the standard heuristic of ~4 chars per token,\n * which is conservative for English/code/markdown. Callers that need exact\n * counts should plug in a real tokenizer; this module only ever over-estimates,\n * so the user's hard limits are respected.\n */\n\nexport const CHARS_PER_TOKEN = 4;\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\nexport interface TruncateOptions {\n /** Maximum tokens allowed in the result (inclusive). */\n maxTokens: number;\n /** Marker inserted where content was dropped. */\n marker?: string;\n /** Where to keep characters from when truncating. Default: head. */\n mode?: \"head\" | \"tail\" | \"middle\";\n}\n\nexport interface TruncateResult {\n text: string;\n truncated: boolean;\n estimatedTokens: number;\n originalTokens: number;\n}\n\nconst DEFAULT_MARKER = \"\\n…[truncated]…\\n\";\n\nexport function truncateToTokens(\n input: string,\n options: TruncateOptions,\n): TruncateResult {\n const originalTokens = estimateTokens(input);\n const max = Math.max(0, options.maxTokens);\n if (originalTokens <= max) {\n return { text: input, truncated: false, estimatedTokens: originalTokens, originalTokens };\n }\n\n if (max === 0) {\n return { text: \"\", truncated: true, estimatedTokens: 0, originalTokens };\n }\n\n const marker = options.marker ?? DEFAULT_MARKER;\n const mode = options.mode ?? \"head\";\n const markerTokens = estimateTokens(marker);\n const budgetChars = Math.max(0, (max - markerTokens) * CHARS_PER_TOKEN);\n\n let result: string;\n if (budgetChars === 0) {\n result = \"\";\n } else if (mode === \"tail\") {\n result = marker + input.slice(input.length - budgetChars);\n } else if (mode === \"middle\") {\n const half = Math.floor(budgetChars / 2);\n result = input.slice(0, half) + marker + input.slice(input.length - half);\n } else {\n result = input.slice(0, budgetChars) + marker;\n }\n\n return {\n text: result,\n truncated: true,\n estimatedTokens: estimateTokens(result),\n originalTokens,\n };\n}\n\n/**\n * Allocate a global token budget across N parts with relative weights, then\n * truncate each part to its share. Returns parts in input order, paired with\n * truncate metadata.\n */\nexport interface BudgetPart {\n key: string;\n text: string;\n weight: number;\n mode?: TruncateOptions[\"mode\"];\n}\n\nexport interface BudgetSlice {\n key: string;\n text: string;\n truncated: boolean;\n estimatedTokens: number;\n originalTokens: number;\n allocatedTokens: number;\n}\n\nexport function allocateBudget(\n parts: BudgetPart[],\n maxTokens: number,\n): BudgetSlice[] {\n if (parts.length === 0) return [];\n const totalWeight = parts.reduce((s, p) => s + Math.max(0, p.weight), 0);\n if (totalWeight === 0) {\n return parts.map((p) => ({\n key: p.key,\n text: \"\",\n truncated: estimateTokens(p.text) > 0,\n estimatedTokens: 0,\n originalTokens: estimateTokens(p.text),\n allocatedTokens: 0,\n }));\n }\n\n // First pass: allocate by weight, but if a part's content fits in less than\n // its share, redistribute the surplus to others proportionally.\n const allocations = new Map<string, number>();\n let remaining = maxTokens;\n let remainingWeight = totalWeight;\n\n // Sort parts by share fit ascending so small ones consume their share first.\n const sortedByFit = [...parts]\n .map((p) => ({\n key: p.key,\n tokens: estimateTokens(p.text),\n share: (p.weight / totalWeight) * maxTokens,\n part: p,\n }))\n .sort((a, b) => a.tokens - b.tokens);\n\n for (const item of sortedByFit) {\n const myShare = remainingWeight > 0\n ? (item.part.weight / remainingWeight) * remaining\n : 0;\n const grant = Math.min(item.tokens, Math.floor(myShare));\n allocations.set(item.key, grant);\n remaining -= grant;\n remainingWeight -= item.part.weight;\n }\n\n return parts.map((p) => {\n const allocated = allocations.get(p.key) ?? 0;\n const truncated = truncateToTokens(p.text, {\n maxTokens: allocated,\n mode: p.mode ?? \"head\",\n });\n return {\n key: p.key,\n text: truncated.text,\n truncated: truncated.truncated,\n estimatedTokens: truncated.estimatedTokens,\n originalTokens: truncated.originalTokens,\n allocatedTokens: allocated,\n };\n });\n}\n","import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const CODE_MAP_FILE = \"code-map.json\";\n\nexport type CodeExportKind =\n | \"function\"\n | \"class\"\n | \"interface\"\n | \"type\"\n | \"const\"\n | \"enum\"\n | \"default\";\n\nexport interface CodeExport {\n name: string;\n kind: CodeExportKind;\n description?: string;\n line: number;\n}\n\nexport interface CodeFileEntry {\n summary?: string;\n exports: CodeExport[];\n loc: number;\n}\n\nexport interface CodeMap {\n version: 1;\n generated_at: string;\n root: string;\n files: Record<string, CodeFileEntry>;\n}\n\nexport interface BuildCodeMapOptions {\n includeExtensions?: string[];\n excludeDirs?: string[];\n /** Include untracked files that are not ignored by git. Default: false when the root is a git repo. */\n includeUntracked?: boolean;\n}\n\nconst DEFAULT_INCLUDE = [\n \".ts\", \".tsx\", \".js\", \".jsx\", \".mjs\", \".cjs\",\n \".java\", \".kt\",\n \".py\",\n \".go\",\n \".rb\",\n \".rs\",\n \".cs\",\n \".php\",\n];\nconst DEFAULT_EXCLUDE = [\n \"node_modules\",\n \"dist\",\n \"build\",\n \"out\",\n \".git\",\n \".next\",\n \".turbo\",\n \".vitest-cache\",\n \"coverage\",\n \"test\",\n \"tests\",\n \"__tests__\",\n \"__mocks__\",\n \"target\", // Maven/Gradle build output\n \".gradle\",\n \"__pycache__\",\n \".pytest_cache\",\n \"vendor\", // Go / PHP\n];\n\nconst TEST_FILE_RE = /\\.(test|spec)\\.[a-z]+$/i;\n\nexport function codeMapPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, CODE_MAP_FILE);\n}\n\nexport async function loadCodeMap(paths: HaivePaths): Promise<CodeMap | null> {\n const file = codeMapPath(paths);\n if (!existsSync(file)) return null;\n return JSON.parse(await readFile(file, \"utf8\")) as CodeMap;\n}\n\nexport async function saveCodeMap(paths: HaivePaths, map: CodeMap): Promise<void> {\n const file = codeMapPath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n await writeFile(file, JSON.stringify(map, null, 2), \"utf8\");\n}\n\nexport async function buildCodeMap(\n root: string,\n options: BuildCodeMapOptions = {},\n): Promise<CodeMap> {\n const include = new Set(options.includeExtensions ?? DEFAULT_INCLUDE);\n const exclude = new Set(options.excludeDirs ?? DEFAULT_EXCLUDE);\n const files: Record<string, CodeFileEntry> = {};\n\n for await (const abs of collectSourceFiles(root, include, exclude, options.includeUntracked)) {\n const rel = path.relative(root, abs).replace(/\\\\/g, \"/\");\n if (rel.startsWith(\".ai/\")) continue;\n const content = await readFile(abs, \"utf8\");\n const ext = path.extname(abs).toLowerCase();\n const entry = parseFile(content, ext);\n if (entry.exports.length > 0) files[rel] = entry;\n }\n\n return {\n version: 1,\n generated_at: new Date().toISOString(),\n root,\n files,\n };\n}\n\nasync function* collectSourceFiles(\n root: string,\n include: Set<string>,\n exclude: Set<string>,\n includeUntracked: boolean | undefined,\n): AsyncGenerator<string> {\n const gitFiles = gitSourceFiles(root, include, exclude, includeUntracked === true);\n if (gitFiles) {\n for (const rel of gitFiles) yield path.join(root, rel);\n return;\n }\n\n yield* walkSourceFiles(root, include, exclude);\n}\n\nfunction gitSourceFiles(\n root: string,\n include: Set<string>,\n exclude: Set<string>,\n includeUntracked: boolean,\n): string[] | null {\n const args = includeUntracked\n ? [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"]\n : [\"ls-files\", \"--cached\"];\n const result = spawnSync(\"git\", args, {\n cwd: root,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n if (result.status !== 0) return null;\n\n return result.stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .filter((rel) => isIncludedSourcePath(rel, include, exclude))\n .sort();\n}\n\nasync function* walkSourceFiles(\n dir: string,\n include: Set<string>,\n exclude: Set<string>,\n): AsyncGenerator<string> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") && entry.name !== \".github\") {\n // Skip hidden dirs except .github (workflows can be useful)\n if (entry.isDirectory()) continue;\n }\n if (exclude.has(entry.name)) continue;\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n yield* walkSourceFiles(full, include, exclude);\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name).toLowerCase();\n if (include.has(ext) && !TEST_FILE_RE.test(entry.name)) yield full;\n }\n }\n}\n\nfunction isIncludedSourcePath(\n rel: string,\n include: Set<string>,\n exclude: Set<string>,\n): boolean {\n const normalized = rel.replace(/\\\\/g, \"/\");\n if (normalized.startsWith(\".ai/\")) return false;\n const parts = normalized.split(\"/\");\n if (parts.some((part) => exclude.has(part))) return false;\n const base = parts.at(-1) ?? \"\";\n const ext = path.extname(base).toLowerCase();\n return include.has(ext) && !TEST_FILE_RE.test(base);\n}\n\nconst EXPORT_RE =\n /^export\\s+(?:default\\s+)?(async\\s+)?(function|class|interface|type|const|let|var|enum)\\s+(\\*?)\\s*([A-Za-z_$][\\w$]*)/gm;\n\nconst NAMED_REEXPORT_RE = /^export\\s*\\{([^}]+)\\}/gm;\n\nconst FILE_HEADER_COMMENT_RE = /^\\/\\*\\*([\\s\\S]*?)\\*\\//;\n\n// Java / Kotlin: public/protected class, interface, enum, record, @interface, fun, @RestController etc.\nconst JAVA_DECL_RE =\n /^(?:[ \\t]*)(?:@\\w+\\s+)*(?:public|protected|private|internal)?\\s*(?:static\\s+|final\\s+|abstract\\s+|open\\s+|data\\s+|sealed\\s+)*(?:(class|interface|enum|record|@interface|object)\\s+([A-Z][A-Za-z0-9_$]*)|(fun|def|func|function)\\s+([a-z_][A-Za-z0-9_$]*))/gm;\n\n// Python: def / class at module level (not indented)\nconst PYTHON_DECL_RE = /^(def|class)\\s+([A-Za-z_][A-Za-z0-9_]*)/gm;\n\n// Go: func declarations\nconst GO_DECL_RE = /^func\\s+(?:\\(\\w+\\s+\\*?[A-Za-z_][\\w]*\\)\\s+)?([A-Za-z_][A-Za-z0-9_]*)/gm;\n\n// Rust: pub fn / pub struct / pub enum / pub trait\nconst RUST_DECL_RE =\n /^pub(?:\\([^)]*\\))?\\s+(fn|struct|enum|trait|type|const|impl|mod)\\s+([A-Za-z_][A-Za-z0-9_]*)/gm;\n\nfunction parseFile(source: string, ext: string): CodeFileEntry {\n if (ext === \".java\" || ext === \".kt\") return parseJvmFile(source);\n if (ext === \".py\") return parsePythonFile(source);\n if (ext === \".go\") return parseGoFile(source);\n if (ext === \".rs\") return parseRustFile(source);\n return parseJsFile(source);\n}\n\nfunction parseJsFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n\n let m: RegExpExecArray | null;\n EXPORT_RE.lastIndex = 0;\n while ((m = EXPORT_RE.exec(source))) {\n const kindRaw = m[2] ?? \"\";\n const name = m[4] ?? \"\";\n if (!name) continue;\n const kind: CodeExportKind =\n kindRaw === \"function\" ? \"function\" :\n kindRaw === \"class\" ? \"class\" :\n kindRaw === \"interface\" ? \"interface\" :\n kindRaw === \"type\" ? \"type\" :\n kindRaw === \"enum\" ? \"enum\" : \"const\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n\n NAMED_REEXPORT_RE.lastIndex = 0;\n while ((m = NAMED_REEXPORT_RE.exec(source))) {\n const inside = m[1] ?? \"\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n for (const part of inside.split(\",\")) {\n const cleaned = part.trim().split(/\\s+as\\s+/).pop()?.trim() ?? \"\";\n if (!cleaned || cleaned.startsWith(\"type \")) continue;\n if (exports.some((e) => e.name === cleaned)) continue;\n exports.push({ name: cleaned, kind: \"const\", line: lineIdx + 1 });\n }\n }\n\n const summary = extractFileSummary(source);\n return { ...(summary ? { summary } : {}), exports, loc: source.split(\"\\n\").length };\n}\n\nfunction parseJvmFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n JAVA_DECL_RE.lastIndex = 0;\n while ((m = JAVA_DECL_RE.exec(source))) {\n const kindRaw = m[1] ?? m[3] ?? \"\";\n const name = m[2] ?? m[4] ?? \"\";\n if (!name) continue;\n const kind: CodeExportKind =\n kindRaw === \"class\" || kindRaw === \"record\" || kindRaw === \"object\" ? \"class\" :\n kindRaw === \"interface\" || kindRaw === \"@interface\" ? \"interface\" :\n kindRaw === \"enum\" ? \"enum\" :\n kindRaw === \"fun\" || kindRaw === \"def\" || kindRaw === \"func\" || kindRaw === \"function\" ? \"function\" :\n \"const\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n const summary = extractJavaSummary(source);\n return { ...(summary ? { summary } : {}), exports, loc: lines.length };\n}\n\nfunction parsePythonFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n PYTHON_DECL_RE.lastIndex = 0;\n while ((m = PYTHON_DECL_RE.exec(source))) {\n const keyword = m[1] ?? \"\";\n const name = m[2] ?? \"\";\n if (!name || name.startsWith(\"_\")) continue;\n const kind: CodeExportKind = keyword === \"class\" ? \"class\" : \"function\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractPythonDocstring(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n const summary = extractPythonModuleDocstring(source);\n return { ...(summary ? { summary } : {}), exports, loc: lines.length };\n}\n\nfunction parseGoFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n GO_DECL_RE.lastIndex = 0;\n while ((m = GO_DECL_RE.exec(source))) {\n const name = m[1] ?? \"\";\n if (!name || !/^[A-Z]/.test(name)) continue; // Only exported (uppercase) in Go\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind: \"function\", ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n return { exports, loc: lines.length };\n}\n\nfunction parseRustFile(source: string): CodeFileEntry {\n const exports: CodeExport[] = [];\n const lines = source.split(\"\\n\");\n const lineOffsets = computeLineOffsets(source);\n let m: RegExpExecArray | null;\n RUST_DECL_RE.lastIndex = 0;\n while ((m = RUST_DECL_RE.exec(source))) {\n const kindRaw = m[1] ?? \"\";\n const name = m[2] ?? \"\";\n if (!name) continue;\n const kind: CodeExportKind =\n kindRaw === \"struct\" || kindRaw === \"impl\" ? \"class\" :\n kindRaw === \"enum\" ? \"enum\" :\n kindRaw === \"trait\" ? \"interface\" :\n kindRaw === \"fn\" ? \"function\" :\n kindRaw === \"type\" ? \"type\" : \"const\";\n const lineIdx = byteToLine(m.index, lineOffsets);\n const description = extractJSDocAbove(lines, lineIdx);\n exports.push({ name, kind, ...(description ? { description } : {}), line: lineIdx + 1 });\n }\n return { exports, loc: lines.length };\n}\n\nfunction extractJavaSummary(source: string): string | undefined {\n // Java/Kotlin: file-level Javadoc before first class/interface\n const m = source.match(/^\\/\\*\\*([\\s\\S]*?)\\*\\//);\n if (!m) return undefined;\n const block = (m[1] ?? \"\")\n .split(\"\\n\")\n .map((l) => l.replace(/^\\s*\\*\\s?/, \"\").trim())\n .filter((l) => l && !l.startsWith(\"@\"))\n .join(\" \");\n return block ? firstSentence(block) : undefined;\n}\n\nfunction extractPythonDocstring(lines: string[], defLine: number): string | undefined {\n const next = lines[defLine + 1] ?? \"\";\n const stripped = next.trim();\n if (stripped.startsWith('\"\"\"') || stripped.startsWith(\"'''\")) {\n const inner = stripped.replace(/^[\"']{3}/, \"\").replace(/[\"']{3}.*$/, \"\").trim();\n return inner || undefined;\n }\n return undefined;\n}\n\nfunction extractPythonModuleDocstring(source: string): string | undefined {\n const m = source.match(/^[\"']{3}([\\s\\S]*?)[\"']{3}/);\n if (!m) return undefined;\n return firstSentence((m[1] ?? \"\").trim());\n}\n\nfunction computeLineOffsets(source: string): number[] {\n const out: number[] = [0];\n for (let i = 0; i < source.length; i++) {\n if (source[i] === \"\\n\") out.push(i + 1);\n }\n return out;\n}\n\nfunction byteToLine(byte: number, offsets: number[]): number {\n let lo = 0;\n let hi = offsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n const off = offsets[mid] ?? 0;\n if (off <= byte) lo = mid;\n else hi = mid - 1;\n }\n return lo;\n}\n\nfunction extractJSDocAbove(lines: string[], exportLine: number): string | undefined {\n let i = exportLine - 1;\n // Skip blank lines between JSDoc and export\n while (i >= 0 && (lines[i] ?? \"\").trim() === \"\") i--;\n if (i < 0) return undefined;\n const line = (lines[i] ?? \"\").trim();\n\n if (line.startsWith(\"//\")) {\n return line.replace(/^\\/\\/\\s*/, \"\").trim() || undefined;\n }\n\n // Single-line JSDoc: /** Adds two numbers. */\n const singleLine = line.match(/^\\/\\*\\*\\s*(.*?)\\s*\\*\\/\\s*$/);\n if (singleLine && singleLine[1]) {\n return firstSentence(singleLine[1]);\n }\n\n if (line.endsWith(\"*/\")) {\n // Walk up until /**\n const collected: string[] = [];\n // First piece: content of the line before */\n const firstPiece = line.replace(/\\*\\/\\s*$/, \"\").replace(/^\\*\\s?/, \"\").trim();\n if (firstPiece) collected.unshift(firstPiece);\n let j = i - 1;\n while (j >= 0) {\n const l = (lines[j] ?? \"\").trim();\n if (l.startsWith(\"/**\")) {\n const inner = l.replace(/^\\/\\*\\*/, \"\").trim();\n if (inner) collected.unshift(inner);\n break;\n }\n collected.unshift(l.replace(/^\\*\\s?/, \"\").trim());\n j--;\n }\n const joined = collected.join(\" \").trim();\n if (!joined) return undefined;\n return firstSentence(joined);\n }\n return undefined;\n}\n\nfunction firstSentence(text: string): string | undefined {\n const trimmed = text.trim();\n if (!trimmed) return undefined;\n return trimmed.split(/(?<=\\.)\\s+/)[0]?.trim();\n}\n\nfunction extractFileSummary(source: string): string | undefined {\n const m = source.match(FILE_HEADER_COMMENT_RE);\n if (!m) return undefined;\n const block = (m[1] ?? \"\")\n .split(\"\\n\")\n .map((l) => l.replace(/^\\s*\\*\\s?/, \"\").trim())\n .filter(Boolean)\n .join(\" \");\n if (!block) return undefined;\n const sentence = block.split(/(?<=\\.)\\s+/)[0]?.trim();\n return sentence;\n}\n\nexport interface CodeMapQueryOptions {\n file?: string;\n symbol?: string;\n}\n\nexport function queryCodeMap(map: CodeMap, options: CodeMapQueryOptions): {\n files: Array<{ path: string; entry: CodeFileEntry }>;\n} {\n const files: Array<{ path: string; entry: CodeFileEntry }> = [];\n for (const [filePath, entry] of Object.entries(map.files)) {\n if (options.file) {\n if (!filePath.includes(options.file)) continue;\n }\n if (options.symbol) {\n const sym = options.symbol.toLowerCase();\n if (!entry.exports.some((e) => e.name.toLowerCase().includes(sym))) continue;\n }\n files.push({ path: filePath, entry });\n }\n return { files };\n}\n","/**\n * hAIve project configuration — .ai/haive.config.json\n *\n * In autopilot mode, hAIve operates with zero human intervention:\n * - Memories go directly to `validated` (no approval cycle)\n * - `haive sync` auto-approves proposed memories after the delay\n * - The MCP server saves a session recap automatically on exit\n * - `get_briefing` auto-generates a minimal project context if none exists\n * - `haive sync` applies safe self-maintenance repairs (context version, headings,\n * needs_anchor tags, code-map refresh) without human intervention\n *\n * Multi-repo support:\n * - crossRepoSources: pull shared memories from other repos on haive sync\n * - contractFiles: watch API contract files for breaking changes\n * - hubPath: local path to a shared team-knowledge hub repo\n */\nimport { existsSync } from \"node:fs\";\nimport { readFileSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const CONFIG_FILE = \"haive.config.json\";\n\n/** A remote or local repo to pull shared memories from. */\nexport interface CrossRepoSource {\n /** Human-readable name for this source (used in imported memory tags). */\n name: string;\n /** Local filesystem path to the other project's root (relative or absolute). */\n path?: string;\n /** Git URL — clone/fetch performed automatically. */\n git?: string;\n /** Only import memories matching all of these filters. */\n filter?: {\n /** Only import memories with these tags. */\n tags?: string[];\n /** Only import memories of these types. */\n types?: string[];\n };\n}\n\n/** An API contract file to snapshot and monitor for breaking changes. */\nexport interface ContractFile {\n /** Human-readable name for this contract. */\n name: string;\n /** Path to the contract file, relative to the project root. */\n path: string;\n /** Format of the contract file. */\n format: \"openapi\" | \"graphql\" | \"proto\" | \"typescript\" | \"json-schema\";\n}\n\nexport interface HaiveConfig {\n /** Autopilot mode: maximum autonomy, minimum human intervention. Default: false. */\n autopilot?: boolean;\n\n /**\n * Adaptive briefing: when get_briefing finds no team-specific (unguessable) memory for the\n * task/files, trim the auto-generated project context so the call stays near-zero-cost.\n * A capable model needs nothing extra in that case. Curated context is never trimmed.\n * Default: true.\n */\n adaptiveBriefing?: boolean;\n\n /** Default scope for new memories. Default: \"personal\". Autopilot sets \"team\". */\n defaultScope?: \"personal\" | \"team\";\n\n /**\n * Default status for new memories saved via mem_save.\n * Autopilot sets \"validated\" — skips the approval cycle entirely.\n * Default: \"draft\".\n */\n defaultStatus?: \"draft\" | \"validated\";\n\n /** Auto-approve proposed memories after N hours without rejection. Default: null (disabled). */\n autoApproveDelayHours?: number | null;\n\n /**\n * Auto-promote proposed→validated after N reads (overrides DEFAULT_AUTO_PROMOTE_RULE).\n * Autopilot sets 1 (immediate on first use).\n */\n autoPromoteMinReads?: number;\n\n /** Auto-save session recap on MCP server exit. Default: true in autopilot, false otherwise. */\n autoSessionEnd?: boolean;\n\n /**\n * Auto-generate a minimal project context from code-map when project-context.md is still\n * the template. Default: true in autopilot, false otherwise.\n */\n autoContext?: boolean;\n\n /**\n * Safe self-maintenance performed automatically in autopilot mode.\n * These repairs are intentionally conservative: no guessed anchor is applied\n * without strong evidence, but headings/tags/indexes/context metadata can be\n * kept fresh by the tool itself.\n */\n autoRepair?: {\n /** Keep .ai/project-context.md version metadata aligned with package.json. */\n context?: boolean;\n /** Apply safe memory lint fixes: headings and `needs_anchor` tags. */\n corpus?: boolean;\n /** Refresh .ai/code-map.json during sync when needed. */\n codeMap?: boolean;\n /** Best-effort build of code-search embeddings when @hiveai/embeddings is available. */\n codeSearch?: boolean;\n };\n\n // ── Multi-repo support ──────────────────────────────────────────────────\n\n /**\n * Other repos to pull `shared`-scoped memories from during `haive sync`.\n * Each source must have either `path` (local) or `git` (remote URL).\n *\n * Example:\n * { \"name\": \"backend\", \"path\": \"../repo-backend\", \"filter\": { \"tags\": [\"api-contract\"] } }\n */\n crossRepoSources?: CrossRepoSource[];\n\n /**\n * API contract files to snapshot and watch for breaking changes.\n * `haive sync` compares the current file against `.ai/contracts/<name>.lock`\n * and creates a `gotcha` memory if a breaking change is detected.\n *\n * Example:\n * { \"name\": \"payment-api\", \"path\": \"docs/openapi.yaml\", \"format\": \"openapi\" }\n */\n contractFiles?: ContractFile[];\n\n /**\n * Local path to a shared team-knowledge hub repo.\n * Used by `haive hub pull` and `haive hub push`.\n * Can be relative (resolved from project root) or absolute.\n */\n hubPath?: string;\n\n /**\n * Lock file paths to watch for dependency version changes.\n * Auto-detected if not specified (package.json, pom.xml, go.mod, etc.).\n * Set to [] to disable dependency tracking entirely.\n */\n dependencyFiles?: string[];\n\n /**\n * Agent-enforcement settings. Enabled by default so initialized projects\n * treat hAIve as infrastructure, not an optional convention.\n */\n enforcement?: {\n /** Enforcement posture: advisory reports only, warn in hooks, or block workflow gates. */\n mode?: \"off\" | \"advisory\" | \"strict\";\n /** Require get_briefing / mem_relevant_to before state-changing MCP tools. */\n requireBriefingFirst?: boolean;\n /**\n * Pre-edit (PreToolUse) behaviour when a file's anchored policy was not yet surfaced:\n * - \"advise\" (default): inject the relevant memory content into the agent's context and record\n * it in the briefing marker, then ALLOW the edit — no round-trip, no separate briefing command.\n * - \"block\": hard-block the edit until a briefing covers the file (the legacy strict behaviour).\n * The commit-time decision-coverage gate and CI enforcement remain the hard backstops either way.\n */\n preEditGate?: \"advise\" | \"block\";\n /** Require a session recap before pre-push / CI gates pass. */\n requireSessionRecap?: boolean;\n /** Require memory anchor verification before pre-commit / CI gates pass. */\n requireMemoryVerify?: boolean;\n /** Block changes when anchored decisions/gotchas have become stale. */\n blockStaleDecisionChanges?: boolean;\n /** Require changed files to be covered by relevant surfaced decisions/policies. */\n requireDecisionCoverage?: boolean;\n /**\n * How hard the pre-commit anti-pattern gate blocks a matching attempt/gotcha:\n * - off: never block on anti-patterns (report only)\n * - review: block only on a very strong semantic match (score ≥ 0.75) — soft, legacy default\n * - anchored: ALSO block when a high-confidence anti-pattern is anchored to a touched file\n * and corroborated by the diff (literal token or semantic ≥ 0.45). High precision.\n * - strict: block on any high-confidence anti-pattern match (anchor, literal, or semantic)\n * Config/docs-only commits are always downgraded regardless of this setting.\n * Default: \"anchored\" — makes \"known bad approaches are blocked\" true for the precise case.\n */\n antiPatternGate?: \"off\" | \"review\" | \"anchored\" | \"strict\";\n /**\n * Pre-commit/pre-push decision-coverage behaviour. When true (default), the gate SURFACES the\n * relevant anchored decisions/policies itself and records them in the session marker at commit\n * time — no separate `haive briefing` step required. Set false for the strict legacy behaviour\n * where the commit is blocked until a prior briefing covered those decisions.\n */\n autoBrief?: boolean;\n /**\n * Execute `kind: \"shell\" | \"test\"` memory sensors during `haive sensors check`.\n * These run arbitrary repo-authored commands, so they are OFF by default; turn on per repo\n * (or pass `--commands`) once the team trusts the sensors. Regex sensors always run. Default false.\n */\n runCommandSensors?: boolean;\n /**\n * How `haive enforce finish` reacts to hard failures observed this session that were never\n * captured as a lesson (`mem_tried`):\n * - off: ignore\n * - warn: surface them as an info finding (default — failure detection has false positives)\n * - block: hard-block finish until each is captured\n * Default: \"warn\".\n */\n failureCaptureGate?: \"off\" | \"warn\" | \"block\";\n /**\n * How `haive eval --ci` reacts to a harness-quality regression vs the recorded baseline:\n * - off: never block\n * - warn: report the drop (default)\n * - block: exit non-zero on any score drop\n * Default: \"warn\".\n */\n evalRegressionGate?: \"off\" | \"warn\" | \"block\";\n /**\n * Default unread-age window (in days) for `haive memory archive` corpus decay.\n * A noisy or stale corpus is actively harmful — it makes the agent follow outdated policy.\n * Default: 180.\n */\n decayAfterDays?: number;\n /** Minimum score required for strict enforcement gates. */\n scoreThreshold?: number;\n /** Remove generated hAIve runtime/cache files during cleanup gates. */\n cleanupGeneratedArtifacts?: boolean;\n /**\n * MCP tool surface:\n * - enforcement: compact default harness for coding agents\n * - maintenance: corpus/admin tools for humans and team stewards\n * - experimental: research/diagnostic tools that are not core product surface\n * - full: legacy alias for experimental\n */\n toolProfile?: \"enforcement\" | \"maintenance\" | \"experimental\" | \"full\";\n /** Named memory/policy families enabled for this project. */\n policyPacks?: string[];\n /**\n * Branch on which `enforce finish` enforces the release discipline (lockstep version bump +\n * matching pushed tag) as a HARD gate. On any other branch — feature/* or an integration branch\n * like `develop` — those same checks are advisory (warn), since the version/tag are produced when\n * releasing from this branch, not on every integration commit. Default: \"main\".\n */\n releaseBranch?: string;\n };\n}\n\nexport const DEFAULT_CONFIG: HaiveConfig = {\n autopilot: false,\n defaultScope: \"personal\",\n defaultStatus: \"draft\",\n autoApproveDelayHours: null,\n autoPromoteMinReads: 5,\n autoSessionEnd: false,\n autoContext: false,\n autoRepair: {\n context: false,\n corpus: false,\n codeMap: false,\n codeSearch: false,\n },\n enforcement: {\n mode: \"strict\",\n requireBriefingFirst: true,\n requireSessionRecap: true,\n requireMemoryVerify: true,\n blockStaleDecisionChanges: true,\n requireDecisionCoverage: true,\n antiPatternGate: \"anchored\",\n scoreThreshold: 80,\n cleanupGeneratedArtifacts: true,\n toolProfile: \"enforcement\",\n policyPacks: [\"architecture\", \"gotchas\", \"security\", \"domain\", \"release\"],\n releaseBranch: \"main\",\n },\n};\n\nexport const AUTOPILOT_DEFAULTS: HaiveConfig = {\n autopilot: true,\n defaultScope: \"team\",\n defaultStatus: \"validated\",\n autoApproveDelayHours: 72,\n autoPromoteMinReads: 1,\n autoSessionEnd: true,\n autoContext: true,\n autoRepair: {\n context: true,\n corpus: true,\n codeMap: true,\n codeSearch: true,\n },\n enforcement: {\n mode: \"strict\",\n requireBriefingFirst: true,\n requireSessionRecap: true,\n requireMemoryVerify: true,\n blockStaleDecisionChanges: true,\n requireDecisionCoverage: true,\n antiPatternGate: \"anchored\",\n scoreThreshold: 85,\n cleanupGeneratedArtifacts: true,\n toolProfile: \"enforcement\",\n policyPacks: [\"architecture\", \"gotchas\", \"security\", \"domain\", \"release\"],\n releaseBranch: \"main\",\n },\n};\n\n/** The pre-commit anti-pattern gate hardness levels. */\nexport type AntiPatternGate = \"off\" | \"review\" | \"anchored\" | \"strict\";\n\n/**\n * Single source of truth mapping a configured `antiPatternGate` to the\n * `pre_commit_check` parameters that implement it. Both the git-hook path\n * (`haive enforce check`) and the standalone `haive precommit` command derive\n * their behavior from this so the two surfaces can never drift apart.\n */\nexport function antiPatternGateParams(\n gate: AntiPatternGate,\n): { block_on: \"any\" | \"high-confidence\" | \"never\"; anchored_blocks: boolean } {\n switch (gate) {\n case \"off\":\n return { block_on: \"never\", anchored_blocks: false };\n case \"review\":\n return { block_on: \"high-confidence\", anchored_blocks: false };\n case \"strict\":\n return { block_on: \"any\", anchored_blocks: true };\n case \"anchored\":\n default:\n return { block_on: \"high-confidence\", anchored_blocks: true };\n }\n}\n\nexport function configPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, CONFIG_FILE);\n}\n\nexport async function loadConfig(paths: HaivePaths): Promise<HaiveConfig> {\n const file = configPath(paths);\n if (!existsSync(file)) return { ...DEFAULT_CONFIG };\n try {\n const raw = await readFile(file, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<HaiveConfig>;\n const merged = mergeConfig(DEFAULT_CONFIG, parsed);\n // In autopilot mode, apply autopilot defaults for any field not explicitly set\n if (merged.autopilot) {\n return mergeConfig(AUTOPILOT_DEFAULTS, parsed);\n }\n return merged;\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport function loadConfigSync(paths: HaivePaths): HaiveConfig {\n const file = configPath(paths);\n if (!existsSync(file)) return { ...DEFAULT_CONFIG };\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as Partial<HaiveConfig>;\n const merged = mergeConfig(DEFAULT_CONFIG, parsed);\n return merged.autopilot\n ? mergeConfig(AUTOPILOT_DEFAULTS, parsed)\n : merged;\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport async function saveConfig(paths: HaivePaths, config: HaiveConfig): Promise<void> {\n await writeFile(configPath(paths), JSON.stringify(config, null, 2) + \"\\n\", \"utf8\");\n}\n\nfunction mergeConfig(base: HaiveConfig, override: Partial<HaiveConfig>): HaiveConfig {\n return {\n ...base,\n ...override,\n autoRepair: {\n ...base.autoRepair,\n ...override.autoRepair,\n },\n enforcement: {\n ...base.enforcement,\n ...override.enforcement,\n },\n };\n}\n","/**\n * Cross-repo memory import — pulls `shared`-scoped memories from other projects.\n *\n * Strategy:\n * 1. For each CrossRepoSource in haive.config.json, resolve the source root.\n * 2. Load memories from <source>/.ai/memories/ where scope=shared (+ optional filter).\n * 3. Track imports via .ai/.cache/cross-repo/<name>/import-map.json\n * (sourceId → localFilePath).\n * 4. Write new/updated memories to .ai/memories/shared/<source-name>/.\n * 5. Return a report: { imported, updated, skipped, errors }.\n *\n * Imported memories are tagged with `cross-repo:<source-name>` so they are\n * identifiable and excluded from cross-repo-push to prevent echo loops.\n */\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport {\n buildFrontmatter,\n loadMemoriesFromDir,\n resolveHaivePaths,\n serializeMemory,\n} from \"./index.js\";\nimport type { CrossRepoSource, HaiveConfig } from \"./config.js\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport interface CrossRepoReport {\n source: string;\n imported: string[];\n updated: string[];\n skipped: string[];\n errors: string[];\n}\n\ntype ImportMap = Record<string, string>; // sourceId → local absolute filePath\n\nasync function loadImportMap(cacheDir: string): Promise<ImportMap> {\n const mapPath = path.join(cacheDir, \"import-map.json\");\n if (!existsSync(mapPath)) return {};\n try {\n return JSON.parse(await readFile(mapPath, \"utf8\")) as ImportMap;\n } catch {\n return {};\n }\n}\n\nasync function saveImportMap(cacheDir: string, map: ImportMap): Promise<void> {\n await writeFile(path.join(cacheDir, \"import-map.json\"), JSON.stringify(map, null, 2) + \"\\n\", \"utf8\");\n}\n\n/**\n * Pull shared memories from all configured cross-repo sources.\n * Returns one report per source.\n */\nexport async function pullCrossRepoSources(\n paths: HaivePaths,\n config: HaiveConfig,\n projectRoot: string,\n): Promise<CrossRepoReport[]> {\n const sources = config.crossRepoSources ?? [];\n if (sources.length === 0) return [];\n\n const reports: CrossRepoReport[] = [];\n for (const source of sources) {\n reports.push(await pullFromSource(paths, source, projectRoot));\n }\n return reports;\n}\n\nasync function pullFromSource(\n paths: HaivePaths,\n source: CrossRepoSource,\n projectRoot: string,\n): Promise<CrossRepoReport> {\n const report: CrossRepoReport = {\n source: source.name,\n imported: [],\n updated: [],\n skipped: [],\n errors: [],\n };\n\n // Resolve source root\n let sourceRoot: string | null = null;\n if (source.path) {\n const resolved = path.resolve(projectRoot, source.path);\n if (!existsSync(resolved)) {\n report.errors.push(`Path not found: ${resolved}`);\n return report;\n }\n sourceRoot = resolved;\n } else if (source.git) {\n sourceRoot = await cloneOrFetchGitSource(source, paths, report);\n if (!sourceRoot) return report;\n } else {\n report.errors.push(`Source \"${source.name}\" has neither path nor git — skipping.`);\n return report;\n }\n\n const sourcePaths = resolveHaivePaths(sourceRoot);\n if (!existsSync(sourcePaths.memoriesDir)) {\n report.errors.push(`No .ai/memories/ found at ${sourceRoot}`);\n return report;\n }\n\n // Load source memories filtered to scope=shared\n const sourceMemories = (await loadMemoriesFromDir(sourcePaths.memoriesDir)).filter(\n ({ memory }) => {\n const fm = memory.frontmatter;\n if (fm.scope !== \"shared\") return false;\n if (fm.status === \"rejected\" || fm.status === \"deprecated\") return false;\n if (source.filter?.tags && source.filter.tags.length > 0) {\n const hasTag = source.filter.tags.some((t) => fm.tags.includes(t));\n if (!hasTag) return false;\n }\n if (source.filter?.types && source.filter.types.length > 0) {\n if (!source.filter.types.includes(fm.type)) return false;\n }\n return true;\n },\n );\n\n if (sourceMemories.length === 0) {\n report.skipped.push(\"no shared memories found in source\");\n return report;\n }\n\n // Destination: .ai/memories/shared/<source-name>/\n const destDir = path.join(paths.memoriesDir, \"shared\", source.name);\n await mkdir(destDir, { recursive: true });\n\n // Cache dir for import tracking\n const cacheDir = path.join(paths.haiveDir, \".cache\", \"cross-repo\", source.name);\n await mkdir(cacheDir, { recursive: true });\n const importMap = await loadImportMap(cacheDir);\n const mapDirty = false;\n let dirty = mapDirty;\n\n for (const { memory } of sourceMemories) {\n const fm = memory.frontmatter;\n const sourceId = fm.id;\n const importTag = `cross-repo:${source.name}`;\n const tags = [...new Set([...fm.tags, importTag])];\n\n const importedBodyPrefix =\n `> **Imported from \\`${source.name}\\`** (original id: \\`${sourceId}\\`) \\n` +\n `> Imported at: ${new Date().toISOString()}\\n\\n`;\n\n const existingLocalPath = importMap[sourceId];\n\n if (existingLocalPath && existsSync(existingLocalPath)) {\n // Already imported — check if body changed in source\n const existingFiles = await loadMemoriesFromDir(destDir);\n const existingEntry = existingFiles.find(({ filePath }) => filePath === existingLocalPath);\n const sourceBodyStripped = memory.body.trim();\n const existingBodyStripped = (existingEntry?.memory.body ?? \"\")\n .replace(/^>.*\\n>.*\\n\\n/m, \"\")\n .trim();\n\n if (existingBodyStripped === sourceBodyStripped) {\n report.skipped.push(sourceId);\n continue;\n }\n\n // Body changed — update\n const updatedBody = importedBodyPrefix + memory.body;\n if (existingEntry) {\n await writeFile(\n existingLocalPath,\n serializeMemory({ frontmatter: existingEntry.memory.frontmatter, body: updatedBody }),\n \"utf8\",\n );\n }\n report.updated.push(sourceId);\n } else {\n // New import\n const slug = `${source.name}-${fm.id.slice(0, 40)}`;\n const newFm = buildFrontmatter({\n type: fm.type,\n slug,\n scope: \"team\" as const,\n module: undefined,\n status: \"validated\",\n tags,\n domain: fm.domain,\n author: fm.author,\n paths: fm.anchor.paths,\n symbols: fm.anchor.symbols,\n commit: fm.anchor.commit,\n topic: fm.topic ? `${source.name}:${fm.topic}` : undefined,\n });\n\n const body = importedBodyPrefix + memory.body;\n const destPath = path.join(destDir, `${newFm.id}.md`);\n await writeFile(destPath, serializeMemory({ frontmatter: newFm, body }), \"utf8\");\n importMap[sourceId] = destPath;\n dirty = true;\n report.imported.push(sourceId);\n }\n }\n\n if (dirty) await saveImportMap(cacheDir, importMap);\n return report;\n}\n\n/**\n * Clone or fetch a git source into .ai/.cache/cross-repo/<name>/.\n * Returns the resolved local path, or null on error.\n */\nasync function cloneOrFetchGitSource(\n source: CrossRepoSource,\n paths: HaivePaths,\n report: CrossRepoReport,\n): Promise<string | null> {\n const cacheDir = path.join(paths.haiveDir, \".cache\", \"cross-repo\", source.name);\n await mkdir(cacheDir, { recursive: true });\n\n if (existsSync(path.join(cacheDir, \".git\"))) {\n const result = spawnSync(\"git\", [\"fetch\", \"--depth=1\", \"origin\"], {\n cwd: cacheDir,\n encoding: \"utf8\",\n });\n if (result.status !== 0) {\n report.errors.push(`git fetch failed for ${source.name}: ${result.stderr}`);\n return null;\n }\n spawnSync(\"git\", [\"reset\", \"--hard\", \"FETCH_HEAD\"], { cwd: cacheDir });\n } else {\n const result = spawnSync(\n \"git\",\n [\"clone\", \"--depth=1\", source.git!, \".\"],\n { cwd: cacheDir, encoding: \"utf8\" },\n );\n if (result.status !== 0) {\n report.errors.push(`git clone failed for ${source.name}: ${result.stderr}`);\n return null;\n }\n }\n\n return cacheDir;\n}\n","/**\n * Dependency version tracker.\n *\n * During `haive sync`, parse the project's dependency manifest files\n * (package.json, pom.xml, go.mod, Cargo.toml, requirements.txt, etc.),\n * compare against a snapshot stored at `.ai/contracts/deps-<name>.lock`,\n * and return memories that should be marked stale because a dependency\n * they reference has changed version (major bump = breaking change risk).\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport interface DependencySnapshot {\n file: string;\n format: string;\n captured_at: string;\n deps: Record<string, string>; // name → version\n}\n\nexport interface DepChange {\n name: string;\n from: string;\n to: string;\n /** true if the major version number changed */\n isMajorBump: boolean;\n}\n\nexport interface DepTrackResult {\n file: string;\n changes: DepChange[];\n}\n\n// ── Manifest parsers ───────────────────────────────────────────────────────\n\n/** Parse package.json (npm/pnpm/yarn) — returns name→version map */\nfunction parsePackageJson(content: string): Record<string, string> {\n try {\n const pkg = JSON.parse(content) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n };\n return {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n } catch {\n return {};\n }\n}\n\n/** Parse go.mod — returns module→version map */\nfunction parseGoMod(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(\"\\n\")) {\n const m = line.trim().match(/^(\\S+)\\s+(v[\\d.]+)/);\n if (m?.[1] && m[2]) result[m[1]] = m[2];\n }\n return result;\n}\n\n/** Parse requirements.txt (Python) — returns package→version map */\nfunction parseRequirementsTxt(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(\"\\n\")) {\n const clean = (line.split(\"#\")[0] ?? \"\").trim();\n const m = clean.match(/^([A-Za-z0-9_.-]+)[=><~!]+(.+)$/);\n if (m?.[1] && m[2]) result[m[1].toLowerCase()] = m[2].trim();\n }\n return result;\n}\n\n/** Parse Cargo.toml (Rust) — returns crate→version map */\nfunction parseCargotoml(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n let inDeps = false;\n for (const line of content.split(\"\\n\")) {\n if (/^\\[(dependencies|dev-dependencies|build-dependencies)\\]/.test(line.trim())) {\n inDeps = true;\n continue;\n }\n if (line.startsWith(\"[\") && !line.includes(\"dependencies\")) {\n inDeps = false;\n continue;\n }\n if (!inDeps) continue;\n const simple = line.match(/^(\\w[\\w-]*)\\s*=\\s*\"([^\"]+)\"/);\n if (simple?.[1] && simple[2]) { result[simple[1]] = simple[2]; continue; }\n const table = line.match(/^(\\w[\\w-]*)\\s*=\\s*\\{[^}]*version\\s*=\\s*\"([^\"]+)\"/);\n if (table?.[1] && table[2]) result[table[1]] = table[2];\n }\n return result;\n}\n\n/** Parse pom.xml (Maven) — returns groupId:artifactId→version map */\nfunction parsePomXml(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n const depRe = /<dependency>[\\s\\S]*?<groupId>([^<]+)<\\/groupId>[\\s\\S]*?<artifactId>([^<]+)<\\/artifactId>[\\s\\S]*?<version>([^<]+)<\\/version>[\\s\\S]*?<\\/dependency>/g;\n let m: RegExpExecArray | null;\n while ((m = depRe.exec(content)) !== null) {\n if (m[1] && m[2] && m[3]) {\n result[`${m[1].trim()}:${m[2].trim()}`] = m[3].trim();\n }\n }\n return result;\n}\n\n// ── Auto-detection of manifest files ──────────────────────────────────────\n\nconst KNOWN_MANIFESTS: Array<{ name: string; parser: (c: string) => Record<string, string> }> = [\n { name: \"package.json\", parser: parsePackageJson },\n { name: \"go.mod\", parser: parseGoMod },\n { name: \"requirements.txt\", parser: parseRequirementsTxt },\n { name: \"Cargo.toml\", parser: parseCargotoml },\n { name: \"pom.xml\", parser: parsePomXml },\n];\n\nfunction getParser(file: string): ((c: string) => Record<string, string>) | null {\n const base = path.basename(file);\n return KNOWN_MANIFESTS.find((m) => m.name === base)?.parser ?? null;\n}\n\n// ── Version comparison ─────────────────────────────────────────────────────\n\nfunction extractMajor(version: string): number | null {\n const clean = version.replace(/^[^0-9]*/, \"\"); // strip ^, ~, >=, v, etc.\n const firstPart = clean.split(\".\")[0];\n if (!firstPart) return null;\n const n = parseInt(firstPart, 10);\n return isNaN(n) ? null : n;\n}\n\nfunction isMajorBump(from: string, to: string): boolean {\n const fromMajor = extractMajor(from);\n const toMajor = extractMajor(to);\n if (fromMajor === null || toMajor === null) return false;\n return toMajor > fromMajor;\n}\n\n// ── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Resolve which manifest files to track.\n * Uses config.dependencyFiles if set, otherwise auto-detects from KNOWN_MANIFESTS.\n */\nexport function resolveManifestFiles(\n projectRoot: string,\n configuredFiles?: string[],\n): string[] {\n if (configuredFiles !== undefined) {\n // Explicitly configured (can be [] to disable)\n return configuredFiles.map((f) => path.resolve(projectRoot, f)).filter(existsSync);\n }\n return KNOWN_MANIFESTS\n .map(({ name }) => path.join(projectRoot, name))\n .filter(existsSync);\n}\n\n/**\n * Check all manifest files for version changes since last snapshot.\n * Returns one result per file that has changes.\n */\nexport async function trackDependencies(\n projectRoot: string,\n haiveDir: string,\n manifestFiles: string[],\n): Promise<DepTrackResult[]> {\n const contractsDir = path.join(haiveDir, \"contracts\");\n await mkdir(contractsDir, { recursive: true });\n\n const results: DepTrackResult[] = [];\n\n for (const manifestPath of manifestFiles) {\n const parser = getParser(manifestPath);\n if (!parser) continue;\n\n const content = await readFile(manifestPath, \"utf8\");\n const currentDeps = parser(content);\n const lockName = `deps-${path.basename(manifestPath)}.lock`;\n const lockPath = path.join(contractsDir, lockName);\n\n if (!existsSync(lockPath)) {\n // First run — save snapshot, no changes to report\n const snapshot: DependencySnapshot = {\n file: path.relative(projectRoot, manifestPath),\n format: path.basename(manifestPath),\n captured_at: new Date().toISOString(),\n deps: currentDeps,\n };\n await writeFile(lockPath, JSON.stringify(snapshot, null, 2) + \"\\n\", \"utf8\");\n continue;\n }\n\n const snapshot = JSON.parse(await readFile(lockPath, \"utf8\")) as DependencySnapshot;\n const changes: DepChange[] = [];\n\n for (const [name, currentVer] of Object.entries(currentDeps)) {\n const prevVer = snapshot.deps[name];\n if (prevVer && prevVer !== currentVer) {\n changes.push({\n name,\n from: prevVer,\n to: currentVer,\n isMajorBump: isMajorBump(prevVer, currentVer),\n });\n }\n }\n\n if (changes.length > 0) {\n results.push({ file: path.relative(projectRoot, manifestPath), changes });\n // Update snapshot\n const updated: DependencySnapshot = {\n ...snapshot,\n captured_at: new Date().toISOString(),\n deps: currentDeps,\n };\n await writeFile(lockPath, JSON.stringify(updated, null, 2) + \"\\n\", \"utf8\");\n }\n }\n\n return results;\n}\n","/**\n * Contract snapshot and diff watcher.\n *\n * Supports:\n * - OpenAPI/Swagger (JSON or YAML)\n * - GraphQL schema\n * - Protocol Buffers (.proto)\n * - TypeScript declaration files (.d.ts)\n * - JSON Schema\n *\n * `haive snapshot --contract <file>` saves a snapshot to .ai/contracts/<name>.lock\n * `haive sync` compares current file against snapshot and returns BreakingChange[].\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type { ContractFile } from \"./config.js\";\n\nexport interface ContractSnapshot {\n name: string;\n path: string;\n format: string;\n captured_at: string;\n hash: string; // SHA-256 of file content\n endpoints?: string[]; // OpenAPI: list of \"METHOD /path\"\n types?: string[]; // GraphQL/TS: list of type/interface/message names\n fields?: Record<string, string[]>; // type → list of field names\n raw_lines?: string[]; // fallback: full file lines for line-by-line diff\n}\n\nexport interface BreakingChange {\n kind:\n | \"endpoint_removed\"\n | \"endpoint_added\"\n | \"type_removed\"\n | \"type_added\"\n | \"field_removed\"\n | \"field_added\"\n | \"content_changed\";\n description: string;\n severity: \"breaking\" | \"additive\" | \"unknown\";\n}\n\nexport interface ContractDiffResult {\n contract: string;\n file: string;\n changes: BreakingChange[];\n unchanged: boolean;\n}\n\n// ── Parsers ────────────────────────────────────────────────────────────────\n\nfunction sha256(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\n/** Parse OpenAPI/Swagger — extract endpoint list and schemas */\nfunction parseOpenApi(content: string, file: string): Partial<ContractSnapshot> {\n try {\n let doc: Record<string, unknown>;\n if (file.endsWith(\".yaml\") || file.endsWith(\".yml\")) {\n // Simple YAML line-based extraction (no full YAML parser dep)\n doc = parseYamlPaths(content);\n } else {\n doc = JSON.parse(content) as Record<string, unknown>;\n }\n const paths = (doc.paths ?? {}) as Record<string, Record<string, unknown>>;\n const endpoints: string[] = [];\n for (const [routePath, methods] of Object.entries(paths)) {\n for (const method of Object.keys(methods)) {\n if ([\"get\",\"post\",\"put\",\"patch\",\"delete\",\"head\",\"options\"].includes(method)) {\n endpoints.push(`${method.toUpperCase()} ${routePath}`);\n }\n }\n }\n // Extract schema/component names\n const schemas = (\n (doc.components as Record<string, unknown> | undefined)?.schemas ??\n (doc.definitions as Record<string, unknown> | undefined) ??\n {}\n ) as Record<string, Record<string, unknown>>;\n const types = Object.keys(schemas);\n const fields: Record<string, string[]> = {};\n for (const [typeName, schema] of Object.entries(schemas)) {\n const props = (schema.properties ?? {}) as Record<string, unknown>;\n fields[typeName] = Object.keys(props);\n }\n return { endpoints, types, fields };\n } catch {\n return {};\n }\n}\n\n/** Naive YAML paths extractor — avoids needing js-yaml dep */\nfunction parseYamlPaths(content: string): Record<string, unknown> {\n const result: Record<string, Record<string, boolean>> = {};\n let currentPath = \"\";\n for (const line of content.split(\"\\n\")) {\n const pathMatch = line.match(/^ (\\/[^\\s:]+):/);\n if (pathMatch?.[1]) {\n currentPath = pathMatch[1];\n result[currentPath] = {};\n continue;\n }\n if (currentPath) {\n const methodMatch = line.match(/^ (get|post|put|patch|delete|head|options):/);\n if (methodMatch?.[1]) (result[currentPath] ??= {})[methodMatch[1]] = true;\n }\n }\n return { paths: result };\n}\n\n/** Parse GraphQL schema — extract type/interface/union/enum names */\nfunction parseGraphQL(content: string): Partial<ContractSnapshot> {\n const types: string[] = [];\n const fields: Record<string, string[]> = {};\n let currentType = \"\";\n\n for (const line of content.split(\"\\n\")) {\n const typeMatch = line.match(/^(?:type|interface|union|enum|input)\\s+(\\w+)/);\n if (typeMatch?.[1]) {\n currentType = typeMatch[1];\n types.push(currentType);\n fields[currentType] = [];\n continue;\n }\n if (currentType && line.trim().startsWith(\"}\")) {\n currentType = \"\";\n continue;\n }\n if (currentType) {\n const fieldMatch = line.match(/^\\s+(\\w+)\\s*[:(]/);\n if (fieldMatch?.[1]) (fields[currentType] ??= []).push(fieldMatch[1]);\n }\n }\n return { types, fields };\n}\n\n/** Parse .proto (Protocol Buffers) — extract message/service names */\nfunction parseProto(content: string): Partial<ContractSnapshot> {\n const types: string[] = [];\n const fields: Record<string, string[]> = {};\n let currentMsg = \"\";\n\n for (const line of content.split(\"\\n\")) {\n const msgMatch = line.match(/^(?:message|service|enum)\\s+(\\w+)/);\n if (msgMatch?.[1]) {\n currentMsg = msgMatch[1];\n types.push(currentMsg);\n fields[currentMsg] = [];\n continue;\n }\n if (currentMsg && line.trim() === \"}\") {\n currentMsg = \"\";\n continue;\n }\n if (currentMsg) {\n const fieldMatch = line.match(/^\\s+(?:optional|required|repeated)?\\s*\\w+\\s+(\\w+)\\s*=/);\n if (fieldMatch?.[1]) (fields[currentMsg] ??= []).push(fieldMatch[1]);\n const rpcMatch = line.match(/^\\s+rpc\\s+(\\w+)/);\n if (rpcMatch?.[1]) (fields[currentMsg] ??= []).push(`rpc:${rpcMatch[1]}`);\n }\n }\n return { types, fields };\n}\n\n/** Parse TypeScript .d.ts — extract exported interface/class/type names */\nfunction parseTypescript(content: string): Partial<ContractSnapshot> {\n const types: string[] = [];\n const fields: Record<string, string[]> = {};\n let currentType = \"\";\n let braceDepth = 0;\n\n for (const line of content.split(\"\\n\")) {\n const exportMatch = line.match(/^export\\s+(?:declare\\s+)?(?:interface|class|type|enum)\\s+(\\w+)/);\n if (exportMatch?.[1]) {\n currentType = exportMatch[1];\n types.push(currentType);\n fields[currentType] = [];\n }\n if (currentType) {\n braceDepth += (line.match(/{/g) ?? []).length;\n braceDepth -= (line.match(/}/g) ?? []).length;\n if (braceDepth <= 0 && line.includes(\"}\")) { currentType = \"\"; braceDepth = 0; continue; }\n const memberMatch = line.match(/^\\s+(?:readonly\\s+)?(\\w+)\\s*[?:(!]/);\n if (memberMatch?.[1] && currentType) (fields[currentType] ??= []).push(memberMatch[1]);\n }\n }\n return { types, fields };\n}\n\nfunction parseByFormat(\n content: string,\n format: ContractFile[\"format\"],\n filePath: string,\n): Partial<ContractSnapshot> {\n switch (format) {\n case \"openapi\": return parseOpenApi(content, filePath);\n case \"graphql\": return parseGraphQL(content);\n case \"proto\": return parseProto(content);\n case \"typescript\": return parseTypescript(content);\n case \"json-schema\": {\n try {\n const schema = JSON.parse(content) as Record<string, Record<string, unknown>>;\n const types = Object.keys((schema.definitions ?? schema.properties ?? {}) as Record<string, unknown>);\n return { types };\n } catch { return {}; }\n }\n default: return {};\n }\n}\n\n// ── Diff logic ─────────────────────────────────────────────────────────────\n\nfunction diffLists(before: string[], after: string[], kind: string): BreakingChange[] {\n const changes: BreakingChange[] = [];\n const beforeSet = new Set(before);\n const afterSet = new Set(after);\n for (const item of beforeSet) {\n if (!afterSet.has(item)) {\n const isBreaking = kind === \"endpoint\" || kind === \"field\" || kind === \"type\";\n changes.push({\n kind: `${kind}_removed` as BreakingChange[\"kind\"],\n description: `${kind} removed: ${item}`,\n severity: isBreaking ? \"breaking\" : \"unknown\",\n });\n }\n }\n for (const item of afterSet) {\n if (!beforeSet.has(item)) {\n changes.push({\n kind: `${kind}_added` as BreakingChange[\"kind\"],\n description: `${kind} added: ${item}`,\n severity: \"additive\",\n });\n }\n }\n return changes;\n}\n\nfunction diffSnapshots(before: ContractSnapshot, after: ContractSnapshot): BreakingChange[] {\n if (before.hash === after.hash) return [];\n\n const changes: BreakingChange[] = [];\n\n // Endpoint diff (OpenAPI)\n if (before.endpoints && after.endpoints) {\n changes.push(...diffLists(before.endpoints, after.endpoints, \"endpoint\"));\n }\n\n // Type diff (all formats)\n if (before.types && after.types) {\n changes.push(...diffLists(before.types, after.types, \"type\"));\n }\n\n // Field diff per type\n if (before.fields && after.fields) {\n const allTypes = new Set([...Object.keys(before.fields), ...Object.keys(after.fields)]);\n for (const typeName of allTypes) {\n const beforeFields = before.fields[typeName] ?? [];\n const afterFields = after.fields[typeName] ?? [];\n const fieldChanges = diffLists(beforeFields, afterFields, \"field\");\n for (const fc of fieldChanges) {\n changes.push({ ...fc, description: `${typeName}.${fc.description}` });\n }\n }\n }\n\n // Fallback: file changed but no structured diff\n if (changes.length === 0) {\n changes.push({\n kind: \"content_changed\",\n description: \"Contract file content changed (no structured diff available)\",\n severity: \"unknown\",\n });\n }\n\n return changes;\n}\n\n// ── Public API ─────────────────────────────────────────────────────────────\n\nexport function contractLockPath(haiveDir: string, name: string): string {\n return path.join(haiveDir, \"contracts\", `${name}.lock`);\n}\n\n/**\n * Take a snapshot of a contract file and save it to .ai/contracts/<name>.lock.\n * Returns the snapshot.\n */\nexport async function snapshotContract(\n projectRoot: string,\n haiveDir: string,\n contract: ContractFile,\n): Promise<ContractSnapshot> {\n const filePath = path.resolve(projectRoot, contract.path);\n if (!existsSync(filePath)) {\n throw new Error(`Contract file not found: ${filePath}`);\n }\n const content = await readFile(filePath, \"utf8\");\n const parsed = parseByFormat(content, contract.format, filePath);\n const snapshot: ContractSnapshot = {\n name: contract.name,\n path: contract.path,\n format: contract.format,\n captured_at: new Date().toISOString(),\n hash: sha256(content),\n ...parsed,\n };\n const contractsDir = path.join(haiveDir, \"contracts\");\n await mkdir(contractsDir, { recursive: true });\n await writeFile(contractLockPath(haiveDir, contract.name), JSON.stringify(snapshot, null, 2) + \"\\n\", \"utf8\");\n return snapshot;\n}\n\n/**\n * Compare a contract file against its stored snapshot.\n * Returns the diff result. If no snapshot exists, creates one and returns unchanged.\n */\nexport async function diffContract(\n projectRoot: string,\n haiveDir: string,\n contract: ContractFile,\n): Promise<ContractDiffResult> {\n const filePath = path.resolve(projectRoot, contract.path);\n if (!existsSync(filePath)) {\n return { contract: contract.name, file: contract.path, changes: [], unchanged: true };\n }\n\n const lockPath = contractLockPath(haiveDir, contract.name);\n\n if (!existsSync(lockPath)) {\n // First time — save snapshot\n await snapshotContract(projectRoot, haiveDir, contract);\n return { contract: contract.name, file: contract.path, changes: [], unchanged: true };\n }\n\n const content = await readFile(filePath, \"utf8\");\n const beforeSnapshot = JSON.parse(await readFile(lockPath, \"utf8\")) as ContractSnapshot;\n const afterParsed = parseByFormat(content, contract.format, filePath);\n const afterSnapshot: ContractSnapshot = {\n ...beforeSnapshot,\n hash: sha256(content),\n captured_at: new Date().toISOString(),\n ...afterParsed,\n };\n\n const changes = diffSnapshots(beforeSnapshot, afterSnapshot);\n\n if (changes.length > 0) {\n // Update snapshot to current state\n await writeFile(lockPath, JSON.stringify(afterSnapshot, null, 2) + \"\\n\", \"utf8\");\n }\n\n return {\n contract: contract.name,\n file: contract.path,\n changes,\n unchanged: changes.length === 0,\n };\n}\n\n/**\n * Check all configured contract files for changes.\n */\nexport async function watchContracts(\n projectRoot: string,\n haiveDir: string,\n contractFiles: ContractFile[],\n): Promise<ContractDiffResult[]> {\n const results: ContractDiffResult[] = [];\n for (const contract of contractFiles) {\n results.push(await diffContract(projectRoot, haiveDir, contract));\n }\n return results.filter((r) => !r.unchanged);\n}\n","import { appendFile, mkdir, readFile, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const USAGE_LOG_FILE = \"tool-usage.jsonl\";\nexport const USAGE_LOG_DIR = \".usage\";\n\nexport interface UsageEvent {\n /** ISO timestamp */\n at: string;\n /** Tool name (MCP tool or CLI command) */\n tool: string;\n /** Truncated, non-sensitive snapshot of the input */\n summary?: string;\n}\n\nexport function usageLogPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, USAGE_LOG_DIR, USAGE_LOG_FILE);\n}\n\n/**\n * Append a single usage event to the rolling log. Best-effort: failures are\n * swallowed since logging must never block tool execution.\n */\nexport async function appendUsageEvent(paths: HaivePaths, event: UsageEvent): Promise<void> {\n try {\n const file = usageLogPath(paths);\n const dir = path.dirname(file);\n if (!existsSync(dir)) await mkdir(dir, { recursive: true });\n await appendFile(file, JSON.stringify(event) + \"\\n\", \"utf8\");\n } catch {\n // Logging is best-effort.\n }\n}\n\n/**\n * Read all usage events from disk. Skips malformed lines silently.\n * For very large logs (>50k lines), prefer `streamUsageEvents` (not implemented yet).\n */\nexport async function readUsageEvents(paths: HaivePaths): Promise<UsageEvent[]> {\n const file = usageLogPath(paths);\n if (!existsSync(file)) return [];\n const raw = await readFile(file, \"utf8\");\n const out: UsageEvent[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line) continue;\n try {\n const parsed = JSON.parse(line) as UsageEvent;\n if (parsed.tool && parsed.at) out.push(parsed);\n } catch {\n // skip malformed lines\n }\n }\n return out;\n}\n\nexport interface UsageAggregate {\n total: number;\n by_tool: Array<{ tool: string; count: number; last_used: string }>;\n /** Most-frequently called tools first */\n top: Array<{ tool: string; count: number }>;\n window_start: string | null;\n window_end: string | null;\n}\n\n/**\n * Bucket events by tool, optionally filtered by a since cutoff (ISO date or relative like '7d').\n */\nexport function aggregateUsage(events: UsageEvent[], since?: Date): UsageAggregate {\n const cutoff = since ? since.getTime() : 0;\n const filtered = cutoff > 0\n ? events.filter((e) => Date.parse(e.at) >= cutoff)\n : events;\n\n const counts = new Map<string, { count: number; last: string }>();\n for (const e of filtered) {\n const prior = counts.get(e.tool);\n if (!prior) counts.set(e.tool, { count: 1, last: e.at });\n else {\n prior.count++;\n if (e.at > prior.last) prior.last = e.at;\n }\n }\n\n const by_tool = [...counts.entries()]\n .map(([tool, { count, last }]) => ({ tool, count, last_used: last }))\n .sort((a, b) => b.count - a.count);\n\n const sorted = filtered.slice().sort((a, b) => a.at.localeCompare(b.at));\n\n return {\n total: filtered.length,\n by_tool,\n top: by_tool.slice(0, 10).map(({ tool, count }) => ({ tool, count })),\n window_start: sorted[0]?.at ?? null,\n window_end: sorted[sorted.length - 1]?.at ?? null,\n };\n}\n\n/**\n * Parse a since string: ISO date, or relative like '7d', '24h', '30m'.\n * Returns null when input is empty/undefined.\n */\nexport function parseSince(input: string | undefined): Date | null {\n if (!input) return null;\n const m = input.match(/^(\\d+)([dhm])$/);\n if (m) {\n const n = parseInt(m[1] ?? \"0\", 10);\n const unit = m[2] ?? \"d\";\n const ms = unit === \"d\" ? n * 86400_000 : unit === \"h\" ? n * 3600_000 : n * 60_000;\n return new Date(Date.now() - ms);\n }\n const parsed = new Date(input);\n if (Number.isNaN(parsed.getTime())) return null;\n return parsed;\n}\n\nexport async function usageLogSize(paths: HaivePaths): Promise<{ exists: boolean; size_bytes: number; lines: number }> {\n const file = usageLogPath(paths);\n if (!existsSync(file)) return { exists: false, size_bytes: 0, lines: 0 };\n const st = await stat(file);\n const raw = await readFile(file, \"utf8\");\n return { exists: true, size_bytes: st.size, lines: raw.split(\"\\n\").filter((l) => l).length };\n}\n","/**\n * Named budgets for get_briefing so agents choose quality vs token cost intentionally.\n */\n\nexport type BriefingBudgetPreset = \"quick\" | \"balanced\" | \"deep\";\n\nexport interface BriefingBudgetNumbers {\n max_tokens: number;\n max_memories: number;\n include_module_contexts: boolean;\n}\n\nexport const BRIEFING_PRESET_DEFAULTS: Record<BriefingBudgetPreset, BriefingBudgetNumbers> = {\n /** Fast session start — minimal tokens, skip module CONTEXT.md slices */\n quick: { max_tokens: 2500, max_memories: 5, include_module_contexts: false },\n /** Historical defaults for get_briefing */\n balanced: { max_tokens: 8000, max_memories: 8, include_module_contexts: true },\n /** Deep refactor / onboarding — richer memory surface */\n deep: { max_tokens: 16_000, max_memories: 14, include_module_contexts: true },\n};\n\n/**\n * Merge preset-derived numbers with caller overrides when no preset was selected.\n */\nexport function resolveBriefingBudget(\n preset: BriefingBudgetPreset | undefined,\n overrides: BriefingBudgetNumbers,\n): BriefingBudgetNumbers {\n if (!preset) return { ...overrides };\n const p = BRIEFING_PRESET_DEFAULTS[preset];\n return {\n max_tokens: p.max_tokens,\n max_memories: p.max_memories,\n include_module_contexts: p.include_module_contexts,\n };\n}\n","/**\n * Strip memory markdown down to actionable bullet lines — cheaper for briefing payloads.\n */\n\nconst MAX_DEFAULT_CHARS = 1200;\n\n/**\n * Prefer markdown list lines; fall back to the first substantive paragraph block.\n */\nexport function extractActionsBriefBody(markdown: string, maxChars = MAX_DEFAULT_CHARS): string {\n const stripped = markdown.replace(/\\r/g, \"\").trim();\n if (!stripped) return \"\";\n\n const lines = stripped.split(\"\\n\");\n const bullets: string[] = [];\n for (const line of lines) {\n const m = line.match(/^\\s*[-*+]\\s+(.+)/);\n if (m?.[1]) {\n bullets.push(`- ${m[1].trim()}`);\n if (bullets.join(\"\\n\").length >= maxChars) break;\n }\n }\n if (bullets.length >= 2) {\n let text = bullets.join(\"\\n\");\n if (text.length > maxChars) text = text.slice(0, maxChars).trimEnd() + \"…\";\n return text;\n }\n\n // Single bullet or none — take contiguous non-empty paragraphs (skip headings)\n const paragraphs: string[] = [];\n let buf: string[] = [];\n for (const line of lines) {\n const t = line.trim();\n if (!t) {\n if (buf.length) {\n paragraphs.push(buf.join(\" \").trim());\n buf = [];\n }\n continue;\n }\n if (t.startsWith(\"#\") || t.startsWith(\"```\")) {\n if (buf.length) {\n paragraphs.push(buf.join(\" \").trim());\n buf = [];\n }\n continue;\n }\n buf.push(t);\n }\n if (buf.length) paragraphs.push(buf.join(\" \").trim());\n\n let out = paragraphs[0] ?? stripped.slice(0, maxChars);\n if (!out.trim()) out = stripped.slice(0, maxChars);\n if (out.length > maxChars) out = out.slice(0, maxChars).trimEnd() + \"…\";\n return out;\n}\n","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { findProjectRoot, resolveHaivePaths } from \"./paths.js\";\n\nconst ROOT_MARKERS = [\".ai\", \".git\", \"package.json\"] as const;\n\nexport interface ResolveProjectInfo {\n cwd: string;\n resolved_root: string;\n haive_project_root_env: string | null;\n explicit_root: boolean;\n haive_dir_exists: boolean;\n memories_dir_exists: boolean;\n runtime_dir: string;\n /** Which of `.ai`, `.git`, `package.json` exist at `resolved_root`. */\n markers_found: string[];\n}\n\nfunction markersAtRoot(root: string): string[] {\n const found: string[] = [];\n for (const m of ROOT_MARKERS) {\n if (existsSync(path.join(root, m))) found.push(m);\n }\n return found;\n}\n\n/**\n * Resolve the hAIve project root for diagnostics (MCP / CLI). Never throws.\n */\nexport function resolveProjectInfo(opts: {\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n} = {}): ResolveProjectInfo {\n const env = opts.env ?? process.env;\n const cwd = path.resolve(opts.cwd ?? process.cwd());\n const raw = env.HAIVE_PROJECT_ROOT;\n const explicit =\n raw !== undefined && raw !== \"\" ? path.resolve(raw) : null;\n const resolvedRoot = explicit ?? findProjectRoot(cwd);\n const paths = resolveHaivePaths(resolvedRoot);\n return {\n cwd,\n resolved_root: resolvedRoot,\n haive_project_root_env: explicit,\n explicit_root: explicit != null,\n haive_dir_exists: existsSync(paths.haiveDir),\n memories_dir_exists: existsSync(paths.memoriesDir),\n runtime_dir: paths.runtimeDir,\n markers_found: markersAtRoot(resolvedRoot),\n };\n}\n","import type { MemoryType } from \"./types.js\";\n\nconst TYPE_TO_FAMILY: Partial<Record<MemoryType, string>> = {\n architecture: \"architecture\",\n convention: \"pattern\",\n decision: \"decision\",\n gotcha: \"bug\",\n attempt: \"bug\",\n glossary: \"discovery\",\n skill: \"skill\",\n session_recap: \"session\",\n};\n\nfunction slugifyTitle(title: string): string {\n const s = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return s.length > 0 ? s.slice(0, 60) : \"untitled\";\n}\n\n/**\n * Suggest a stable `topic` frontmatter key (topic-upsert) from type + title.\n */\nexport function suggestTopicKey(\n type: string,\n titleOrPhrase: string,\n): { topic_key: string; family: string } {\n const family = TYPE_TO_FAMILY[type as MemoryType] ?? \"discovery\";\n const slug = slugifyTitle(titleOrPhrase);\n return { topic_key: `${family}/${slug}`, family };\n}\n","import type { LoadedMemory } from \"./loader.js\";\n\nfunction tokenizeDoc(text: string): string[] {\n return text\n .toLowerCase()\n .split(/[^a-z0-9_]+/)\n .map((w) => w.trim())\n .filter((w) => w.length >= 2);\n}\n\nfunction memorySearchText(loaded: LoadedMemory): string {\n const fm = loaded.memory.frontmatter;\n return [\n fm.id,\n fm.type,\n fm.tags.join(\" \"),\n loaded.memory.body,\n fm.module ?? \"\",\n fm.topic ?? \"\",\n ...fm.anchor.paths,\n ...fm.anchor.symbols,\n ].join(\" \");\n}\n\nexport interface LexicalRankResult {\n ranked: LoadedMemory[];\n scores: number[];\n}\n\n/**\n * Okapi-BM25–style ranking over a small in-memory corpus (no extra index file).\n */\nexport function rankMemoriesLexical(\n loadedMemories: LoadedMemory[],\n query: string,\n limit: number,\n): LexicalRankResult {\n const qTokens = tokenizeDoc(query);\n if (qTokens.length === 0 || loadedMemories.length === 0) {\n return { ranked: [], scores: [] };\n }\n\n const docs = loadedMemories.map((loaded) => ({\n loaded,\n tokens: tokenizeDoc(memorySearchText(loaded)),\n }));\n\n const N = docs.length;\n const df = new Map<string, number>();\n for (const { tokens } of docs) {\n const seen = new Set(tokens);\n for (const t of seen) {\n df.set(t, (df.get(t) ?? 0) + 1);\n }\n }\n\n const avgdl =\n docs.reduce((s, d) => s + d.tokens.length, 0) / Math.max(N, 1);\n const k1 = 1.2;\n const b = 0.75;\n\n function scoreDoc(tokens: string[]): number {\n if (tokens.length === 0) return 0;\n let score = 0;\n const len = tokens.length;\n const tfCounts = new Map<string, number>();\n for (const t of tokens) {\n tfCounts.set(t, (tfCounts.get(t) ?? 0) + 1);\n }\n\n for (const qt of qTokens) {\n const tf = tfCounts.get(qt) ?? 0;\n if (tf === 0) continue;\n const dfi = df.get(qt) ?? 0;\n const idf = Math.log(1 + (N - dfi + 0.5) / (dfi + 0.5));\n const denom = tf + k1 * (1 - b + (b * len) / avgdl);\n const okapiTf = (tf * (k1 + 1)) / denom;\n score += idf * okapiTf;\n }\n return score;\n }\n\n const scored = docs\n .map(({ loaded, tokens }) => ({ loaded, score: scoreDoc(tokens) }))\n .filter((x) => x.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, limit);\n\n return {\n ranked: scored.map((x) => x.loaded),\n scores: scored.map((x) => x.score),\n };\n}\n","import type { LoadedMemory } from \"./loader.js\";\nimport { pathsOverlap } from \"./relevance.js\";\n\nfunction anchorPathsOverlap(\n fmA: LoadedMemory[\"memory\"][\"frontmatter\"],\n fmB: LoadedMemory[\"memory\"][\"frontmatter\"],\n): boolean {\n for (const a of fmA.anchor.paths) {\n for (const b of fmB.anchor.paths) {\n if (pathsOverlap(a, b)) return true;\n }\n }\n return false;\n}\n\nexport function firstMemoryOneLine(body: string): string {\n const heading = body.match(/^\\s*#\\s+(.+)$/m)?.[1]?.trim();\n const line =\n heading ??\n body\n .split(\"\\n\")\n .map((l) => l.trim())\n .find((l) => l.length > 0);\n return (line ?? \"\").slice(0, 280);\n}\n\nexport interface TimelineEntry {\n id: string;\n type: string;\n scope: string;\n created_at: string;\n one_line: string;\n topic?: string;\n}\n\nexport interface CollectTimelineOpts {\n memoryId?: string;\n topic?: string;\n limit: number;\n}\n\n/**\n * Memories related by id seed (related_ids, shared topic, anchor overlap) or by topic alone.\n */\nexport function collectTimelineEntries(\n all: LoadedMemory[],\n opts: CollectTimelineOpts,\n): { entries: TimelineEntry[]; notice?: string } {\n if (!opts.memoryId && !opts.topic) {\n return { entries: [], notice: \"Provide memory_id and/or topic\" };\n }\n\n const byId = new Map(all.map((l) => [l.memory.frontmatter.id, l]));\n\n if (opts.topic && !opts.memoryId) {\n const matches = all.filter((l) => l.memory.frontmatter.topic === opts.topic);\n matches.sort((a, b) =>\n a.memory.frontmatter.created_at.localeCompare(b.memory.frontmatter.created_at),\n );\n return {\n entries: matches.slice(0, opts.limit).map((l) => toEntry(l)),\n };\n }\n\n const seed = byId.get(opts.memoryId!);\n if (!seed) {\n return { entries: [], notice: `No memory with id \"${opts.memoryId}\"` };\n }\n\n const collected = new Set<string>();\n const add = (id: string) => {\n if (byId.has(id)) collected.add(id);\n };\n\n add(seed.memory.frontmatter.id);\n for (const rid of seed.memory.frontmatter.related_ids) add(rid);\n\n const seedTopic = seed.memory.frontmatter.topic;\n if (seedTopic) {\n for (const l of all) {\n if (l.memory.frontmatter.topic === seedTopic) add(l.memory.frontmatter.id);\n }\n }\n\n for (const l of all) {\n if (anchorPathsOverlap(seed.memory.frontmatter, l.memory.frontmatter)) {\n add(l.memory.frontmatter.id);\n }\n }\n\n const firstHop = [...collected];\n for (const id of firstHop) {\n const m = byId.get(id);\n if (!m) continue;\n for (const rid of m.memory.frontmatter.related_ids) add(rid);\n }\n\n let sorted = [...collected]\n .map((id) => byId.get(id)!)\n .filter(Boolean)\n .sort((a, b) =>\n a.memory.frontmatter.created_at.localeCompare(b.memory.frontmatter.created_at),\n );\n\n if (opts.topic) {\n sorted = sorted.filter((l) => l.memory.frontmatter.topic === opts.topic);\n }\n\n return {\n entries: sorted.slice(0, opts.limit).map((l) => toEntry(l)),\n };\n}\n\nfunction toEntry(l: LoadedMemory): TimelineEntry {\n const fm = l.memory.frontmatter;\n const base: TimelineEntry = {\n id: fm.id,\n type: fm.type,\n scope: fm.scope,\n created_at: fm.created_at,\n one_line: firstMemoryOneLine(l.memory.body),\n };\n if (fm.topic !== undefined && fm.topic !== \"\") {\n return { ...base, topic: fm.topic };\n }\n return base;\n}\n","import type { LoadedMemory } from \"./loader.js\";\n\nfunction tokenSetForConflict(loaded: LoadedMemory): Set<string> {\n const fm = loaded.memory.frontmatter;\n const heading = loaded.memory.body.match(/^\\s*#\\s+(.+)$/m)?.[1] ?? \"\";\n const blob = `${fm.id} ${heading} ${loaded.memory.body.slice(0, 2000)}`;\n const tokens = blob\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .map((w) => w.trim())\n .filter((w) => w.length >= 3);\n return new Set(tokens);\n}\n\nfunction jaccard(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 || b.size === 0) return 0;\n let inter = 0;\n for (const x of a) {\n if (b.has(x)) inter++;\n }\n const uni = a.size + b.size - inter;\n return uni === 0 ? 0 : inter / uni;\n}\n\nexport interface ConflictCandidatesOpts {\n sinceDays: number;\n types: string[];\n minJaccard: number;\n maxPairs: number;\n /** Hard cap on memories considered ( avoids O(n²) explosions). */\n maxScan: number;\n}\n\nexport interface ConflictCandidatePair {\n id_a: string;\n id_b: string;\n jaccard: number;\n}\n\nexport interface TopicStatusPair {\n id_a: string;\n id_b: string;\n topic: string;\n status_a: string;\n status_b: string;\n}\n\n/**\n * Same `topic` key with opposed trust (validated vs rejected) — advisory; use `mem_conflicts_with` per id next.\n */\nexport function findTopicStatusConflictPairs(\n memories: LoadedMemory[],\n maxPairs: number,\n): TopicStatusPair[] {\n const byTopic = new Map<string, LoadedMemory[]>();\n for (const l of memories) {\n const topic = l.memory.frontmatter.topic;\n if (!topic || topic.trim() === \"\") continue;\n const g = byTopic.get(topic);\n if (g) g.push(l);\n else byTopic.set(topic, [l]);\n }\n const out: TopicStatusPair[] = [];\n for (const [topic, group] of byTopic) {\n if (group.length < 2) continue;\n for (let i = 0; i < group.length && out.length < maxPairs; i++) {\n for (let j = i + 1; j < group.length && out.length < maxPairs; j++) {\n const sa = group[i]!.memory.frontmatter.status;\n const sb = group[j]!.memory.frontmatter.status;\n if (\n (sa === \"validated\" && sb === \"rejected\") ||\n (sa === \"rejected\" && sb === \"validated\")\n ) {\n out.push({\n id_a: group[i]!.memory.frontmatter.id,\n id_b: group[j]!.memory.frontmatter.id,\n topic,\n status_a: sa,\n status_b: sb,\n });\n }\n }\n }\n }\n return out;\n}\n\n/**\n * Bulk heuristic: lexical similarity pairs for human review → often followed by `mem_conflicts_with`.\n */\nexport function findLexicalConflictPairs(\n memories: LoadedMemory[],\n opts: ConflictCandidatesOpts,\n): { pairs: ConflictCandidatePair[]; scanned: number; truncated: boolean } {\n const cutoff = Date.now() - opts.sinceDays * 86_400_000;\n let pool = memories.filter((l) => {\n const fm = l.memory.frontmatter;\n if (!opts.types.includes(fm.type)) return false;\n const t = Date.parse(fm.created_at);\n return !Number.isNaN(t) && t >= cutoff;\n });\n pool.sort((a, b) =>\n b.memory.frontmatter.created_at.localeCompare(a.memory.frontmatter.created_at),\n );\n let truncated = false;\n if (pool.length > opts.maxScan) {\n pool = pool.slice(0, opts.maxScan);\n truncated = true;\n }\n const sets = pool.map((l) => ({\n id: l.memory.frontmatter.id,\n set: tokenSetForConflict(l),\n }));\n\n const pairs: ConflictCandidatePair[] = [];\n for (let i = 0; i < sets.length; i++) {\n for (let j = i + 1; j < sets.length; j++) {\n const jac = jaccard(sets[i]!.set, sets[j]!.set);\n if (jac >= opts.minJaccard) {\n pairs.push({ id_a: sets[i]!.id, id_b: sets[j]!.id, jaccard: jac });\n }\n }\n }\n pairs.sort((a, b) => b.jaccard - a.jaccard);\n return {\n pairs: pairs.slice(0, opts.maxPairs),\n scanned: pool.length,\n truncated,\n };\n}\n","import { mkdir, readFile, appendFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const RUNTIME_JOURNAL_FILENAME = \"session-journal.ndjson\";\n\nexport interface RuntimeJournalEntry {\n ts: string;\n kind: \"note\" | \"session_end\" | \"mcp\";\n /** Short human or agent message */\n message: string;\n /** Optional MCP tool name for kind=mcp */\n tool?: string;\n /** Arbitrary JSON-serializable metadata */\n meta?: Record<string, unknown>;\n}\n\nexport function runtimeJournalPath(paths: HaivePaths): string {\n return path.join(paths.runtimeDir, RUNTIME_JOURNAL_FILENAME);\n}\n\n/**\n * Append one NDJSON line under `.ai/.runtime/` (untracked by default).\n * Never throws to callers of shutdown hooks — wraps internally.\n */\nexport async function appendRuntimeJournalEntry(\n paths: HaivePaths,\n entry: Omit<RuntimeJournalEntry, \"ts\"> & { ts?: string },\n): Promise<void> {\n try {\n await mkdir(paths.runtimeDir, { recursive: true });\n const line: RuntimeJournalEntry = {\n ts: entry.ts ?? new Date().toISOString(),\n kind: entry.kind,\n message: entry.message,\n ...(entry.tool !== undefined ? { tool: entry.tool } : {}),\n ...(entry.meta !== undefined ? { meta: entry.meta } : {}),\n };\n await appendFile(\n runtimeJournalPath(paths),\n JSON.stringify(line) + \"\\n\",\n \"utf8\",\n );\n } catch {\n // non-fatal — runtime layer must not break tools\n }\n}\n\n/** Read last N valid JSON lines (oldest-first in returned array). */\nexport async function readRuntimeJournalTail(\n paths: HaivePaths,\n limit: number,\n): Promise<RuntimeJournalEntry[]> {\n const file = runtimeJournalPath(paths);\n if (!existsSync(file) || limit <= 0) return [];\n try {\n const raw = await readFile(file, \"utf8\");\n const lines = raw.trim().split(\"\\n\").filter(Boolean);\n const parsed: RuntimeJournalEntry[] = [];\n for (const line of lines.slice(-limit)) {\n try {\n parsed.push(JSON.parse(line) as RuntimeJournalEntry);\n } catch {\n /* skip corrupt line */\n }\n }\n return parsed;\n } catch {\n return [];\n }\n}\n","import { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport const BRIEFING_MARKER_TTL_MS = 12 * 60 * 60 * 1000;\nexport const SESSION_RECAP_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\nexport interface BriefingMarker {\n session_id: string;\n task?: string;\n source: string;\n created_at: string;\n root: string;\n memory_ids?: string[];\n files?: string[];\n}\n\nexport function enforcementDir(paths: HaivePaths): string {\n return path.join(paths.runtimeDir, \"enforcement\");\n}\n\nexport function briefingMarkersDir(paths: HaivePaths): string {\n return path.join(enforcementDir(paths), \"briefings\");\n}\n\nexport function normalizeSessionId(sessionId?: string): string {\n return (sessionId?.trim() || \"default\").replace(/[^a-zA-Z0-9_.-]+/g, \"-\").slice(0, 120);\n}\n\nexport function briefingMarkerPath(paths: HaivePaths, sessionId?: string): string {\n return path.join(briefingMarkersDir(paths), `${normalizeSessionId(sessionId)}.json`);\n}\n\nexport async function writeBriefingMarker(\n paths: HaivePaths,\n input: {\n sessionId?: string;\n task?: string;\n source: string;\n memoryIds?: string[];\n files?: string[];\n /**\n * Accumulate memory_ids/files with the existing fresh marker for THIS session instead of\n * overwriting (default true). This is what lets decision-coverage build up as the agent works:\n * every get_briefing call, every pre-edit injection, every `haive briefing` ADDS to the\n * session's consulted set — so a broad commit no longer requires one giant briefing covering\n * every relevant decision at once. Pass false to replace (e.g. starting a brand-new session).\n */\n accumulate?: boolean;\n },\n): Promise<BriefingMarker> {\n const sessionId = normalizeSessionId(input.sessionId);\n const accumulate = input.accumulate ?? true;\n\n // Union with the existing fresh marker for the same session, so consulted memories accrue.\n let priorIds: string[] = [];\n let priorFiles: string[] = [];\n if (accumulate) {\n const existing = await readSessionBriefingMarker(paths, sessionId);\n if (existing) {\n priorIds = existing.memory_ids ?? [];\n priorFiles = existing.files ?? [];\n }\n }\n\n const mergedIds = [...new Set([...priorIds, ...(input.memoryIds ?? [])])];\n const mergedFiles = [...new Set([...priorFiles, ...(input.files ?? [])])];\n\n const marker: BriefingMarker = {\n session_id: sessionId,\n ...(input.task?.trim() ? { task: input.task.trim() } : {}),\n ...(mergedIds.length > 0 ? { memory_ids: mergedIds } : {}),\n ...(mergedFiles.length > 0 ? { files: mergedFiles } : {}),\n source: input.source,\n created_at: new Date().toISOString(),\n root: paths.root,\n };\n await mkdir(briefingMarkersDir(paths), { recursive: true });\n await writeFile(\n briefingMarkerPath(paths, marker.session_id),\n JSON.stringify(marker, null, 2) + \"\\n\",\n \"utf8\",\n );\n return marker;\n}\n\n/** Read THIS session's marker if it exists and is still fresh (within TTL). Null otherwise. */\nasync function readSessionBriefingMarker(\n paths: HaivePaths,\n sessionId: string,\n ttlMs = BRIEFING_MARKER_TTL_MS,\n): Promise<BriefingMarker | null> {\n const file = briefingMarkerPath(paths, sessionId);\n if (!existsSync(file)) return null;\n try {\n const marker = JSON.parse(await readFile(file, \"utf8\")) as BriefingMarker;\n const created = Date.parse(marker.created_at);\n if (!Number.isFinite(created) || Date.now() - created > ttlMs) return null;\n return marker;\n } catch {\n return null;\n }\n}\n\nexport async function hasRecentBriefingMarker(\n paths: HaivePaths,\n sessionId?: string,\n ttlMs = BRIEFING_MARKER_TTL_MS,\n): Promise<boolean> {\n const now = Date.now();\n const candidates: string[] = [];\n const exact = briefingMarkerPath(paths, sessionId);\n if (existsSync(exact)) candidates.push(exact);\n try {\n const dir = briefingMarkersDir(paths);\n const files = await readdir(dir);\n for (const file of files) {\n if (file.endsWith(\".json\")) candidates.push(path.join(dir, file));\n }\n } catch {\n // no marker directory yet\n }\n\n for (const file of new Set(candidates)) {\n try {\n const marker = JSON.parse(await readFile(file, \"utf8\")) as BriefingMarker;\n const created = Date.parse(marker.created_at);\n if (Number.isFinite(created) && now - created <= ttlMs) return true;\n } catch {\n // ignore corrupt markers\n }\n }\n return false;\n}\n\nexport async function readRecentBriefingMarker(\n paths: HaivePaths,\n sessionId?: string,\n ttlMs = BRIEFING_MARKER_TTL_MS,\n): Promise<BriefingMarker | null> {\n const now = Date.now();\n const candidates: string[] = [];\n const exact = briefingMarkerPath(paths, sessionId);\n if (existsSync(exact)) candidates.push(exact);\n try {\n const dir = briefingMarkersDir(paths);\n const files = await readdir(dir);\n for (const file of files) {\n if (file.endsWith(\".json\")) candidates.push(path.join(dir, file));\n }\n } catch {\n // no marker directory yet\n }\n\n let freshest: BriefingMarker | null = null;\n let freshestTs = 0;\n for (const file of new Set(candidates)) {\n try {\n const marker = JSON.parse(await readFile(file, \"utf8\")) as BriefingMarker;\n const created = Date.parse(marker.created_at);\n if (!Number.isFinite(created) || now - created > ttlMs) continue;\n if (created > freshestTs) {\n freshest = marker;\n freshestTs = created;\n }\n } catch {\n // ignore corrupt markers\n }\n }\n return freshest;\n}\n\nexport function isFreshIsoDate(value: string | Date, ttlMs: number, now = Date.now()): boolean {\n const ts = value instanceof Date ? value.getTime() : Date.parse(value);\n return Number.isFinite(ts) && now - ts <= ttlMs;\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\n\nexport interface RetirementSignal {\n retired: boolean;\n reason?: string;\n}\n\nconst RETIRED_TAGS = new Set([\"superseded\", \"obsolete\", \"archived\"]);\n\nconst RETIRED_BODY_PATTERNS: Array<{ re: RegExp; reason: string }> = [\n { re: /\\bfixed\\s+in\\b[\\s\\S]{0,160}\\b(audit|history|historical|obsolete|no longer applies)\\b/i, reason: \"body says this fixed record is audit/history only\" },\n { re: /\\bresolved\\s+in\\b/i, reason: \"body says this was resolved\" },\n { re: /\\bsuperseded\\s+by\\b/i, reason: \"body says this was superseded\" },\n { re: /\\bno\\s+longer\\s+(applies|true|valid)\\b/i, reason: \"body says this no longer applies\" },\n { re: /\\bobsolete\\b/i, reason: \"body says this is obsolete\" },\n];\n\n/**\n * Explicit lifecycle gate for records that should not be fed back to agents as active policy.\n *\n * `status=deprecated/rejected/stale` is already the hard lifecycle signal. This helper covers\n * softer signals that teams naturally write while curating a corpus: an `expires_when` date,\n * a `superseded`/`obsolete` tag, or a short body note saying the attempt is now obsolete.\n *\n * Note: a plain `fixed` tag is intentionally NOT retired by itself. Many teams keep fixed\n * gotchas active as regression guards. To retire one, mark it deprecated, set expires_when,\n * use `obsolete`/`superseded`, or write that the fixed record is kept for audit/history only.\n */\nexport function retirementSignal(\n fm: MemoryFrontmatter,\n body = \"\",\n now: Date = new Date(),\n): RetirementSignal {\n if (fm.status === \"deprecated\" || fm.status === \"rejected\" || fm.status === \"stale\") {\n return { retired: true, reason: `status=${fm.status}` };\n }\n\n if (fm.expires_when) {\n const expiresAt = Date.parse(fm.expires_when);\n if (Number.isFinite(expiresAt) && expiresAt <= now.getTime()) {\n return { retired: true, reason: `expired on ${fm.expires_when.slice(0, 10)}` };\n }\n }\n\n const retiredTag = fm.tags.find((tag) => RETIRED_TAGS.has(tag.toLowerCase()));\n if (retiredTag) {\n return { retired: true, reason: `tagged ${retiredTag}` };\n }\n\n for (const pattern of RETIRED_BODY_PATTERNS) {\n if (pattern.re.test(body)) return { retired: true, reason: pattern.reason };\n }\n\n return { retired: false };\n}\n\nexport function isRetiredMemory(\n fm: MemoryFrontmatter,\n body = \"\",\n now: Date = new Date(),\n): boolean {\n return retirementSignal(fm, body, now).retired;\n}\n","import type { Memory, Sensor } from \"./types.js\";\n\n/**\n * Sensors — the feedback *computational* layer of the harness.\n *\n * A memory's `sensor` turns a documented lesson (gotcha/attempt) into a deterministic\n * check. Unlike semantic anti-pattern matching (probabilistic, warmup-sensitive), a\n * regex sensor fires the same way every time, so a known mistake becomes a permanent\n * guardrail. Phase 1 supports `kind: \"regex\"` only — pure, no I/O. `shell`/`test`\n * sensors are recognized but not executed here (they must run from the CLI).\n */\n\nexport interface SensorHit {\n /** The memory id whose sensor matched. */\n memory_id: string;\n /** The sensor that matched. */\n sensor: Sensor;\n /** Project-relative file the match was found in (when known). */\n file?: string;\n /** The matched line (trimmed, capped) — useful for review output. */\n matched_line?: string;\n /** LLM-facing self-correction message carried from the sensor. */\n message: string;\n severity: Sensor[\"severity\"];\n}\n\n/** A unit of code to scan: a file path plus the text to match against. */\nexport interface SensorTarget {\n /** Project-relative path (used for path scoping and reporting). */\n path: string;\n /**\n * Text to scan. For a diff, pass only the added lines (callers should pre-filter)\n * so a sensor fires on \"you introduced the bad pattern\", not \"you touched a file\n * that merely mentions it\".\n */\n content: string;\n}\n\nfunction normalizeProjectPath(value: string): string {\n return value\n .replace(/\\\\/g, \"/\")\n .replace(/^\\.\\//, \"\")\n .replace(/^[ab]\\//, \"\")\n .replace(/\\/+$/g, \"\");\n}\n\n/**\n * Does this sensor apply to `path`? A sensor with no explicit `paths` (and whose\n * memory has no anchor paths) applies everywhere. Otherwise it applies only to the\n * exact file or directory prefix. Use an explicit directory path (`src/foo/`) when a\n * sensor should cover a whole subtree.\n */\nexport function sensorAppliesToPath(\n sensor: Sensor,\n anchorPaths: string[],\n path: string,\n): boolean {\n const scopes = sensor.paths.length > 0 ? sensor.paths : anchorPaths;\n if (scopes.length === 0) return true;\n const target = normalizeProjectPath(path);\n return scopes.some((rawScope) => {\n const scope = normalizeProjectPath(rawScope);\n if (!scope) return false;\n return target === scope || target.startsWith(`${scope}/`);\n });\n}\n\n/**\n * Compile a regex sensor. Returns null when the sensor is not a runnable regex\n * (wrong kind, missing/invalid pattern) so callers can skip it safely.\n */\nexport function compileRegexSensor(sensor: Sensor): RegExp | null {\n if (sensor.kind !== \"regex\" || !sensor.pattern) return null;\n try {\n // Always multiline so `^`/`$` work per added line; merge with caller flags.\n const flags = new Set([\"m\", ...(sensor.flags ?? \"\").split(\"\")].filter(Boolean));\n return new RegExp(sensor.pattern, [...flags].join(\"\"));\n } catch {\n return null;\n }\n}\n\n/**\n * Run a single regex sensor over one target. Returns the first matching line as a hit,\n * or null. Deterministic and side-effect-free.\n */\nexport function runRegexSensor(\n memoryId: string,\n sensor: Sensor,\n target: SensorTarget,\n): SensorHit | null {\n const re = compileRegexSensor(sensor);\n if (!re) return null;\n for (const rawLine of target.content.split(\"\\n\")) {\n // Fresh lastIndex each line (no global flag is forced, but be defensive).\n re.lastIndex = 0;\n if (re.test(rawLine)) {\n return {\n memory_id: memoryId,\n sensor,\n file: target.path,\n matched_line: rawLine.trim().slice(0, 200),\n message: sensor.message,\n severity: sensor.severity,\n };\n }\n }\n return null;\n}\n\n/**\n * Run every memory's regex sensor against every applicable target.\n *\n * Memories without a sensor, or with a non-regex sensor, are skipped (non-regex kinds\n * are the CLI's responsibility). At most one hit per (memory, file) pair is returned.\n */\nexport function runSensors(\n memories: Memory[],\n targets: SensorTarget[],\n): SensorHit[] {\n const hits: SensorHit[] = [];\n for (const memory of memories) {\n const sensor = memory.frontmatter.sensor;\n if (!sensor || sensor.kind !== \"regex\") continue;\n const anchorPaths = memory.frontmatter.anchor.paths;\n for (const target of targets) {\n if (!sensorAppliesToPath(sensor, anchorPaths, target.path)) continue;\n const hit = runRegexSensor(memory.frontmatter.id, sensor, target);\n if (hit) hits.push(hit);\n }\n }\n return hits;\n}\n\n/**\n * A shell/test sensor selected for execution — the feedback *computational* layer that a regex\n * can't express. The schema reserves `kind: \"shell\" | \"test\"`; this picks the ones whose memory\n * applies to the changed paths so the CLI can run `command` (core stays pure — it never executes).\n */\nexport interface CommandSensorSpec {\n memory_id: string;\n /** Command to execute (shell or test runner invocation). */\n command: string;\n kind: \"shell\" | \"test\";\n severity: Sensor[\"severity\"];\n /** LLM-facing self-correction message carried from the sensor. */\n message: string;\n /** Anchor/scoped paths this sensor cares about (for reporting). */\n paths: string[];\n}\n\n/**\n * Select the shell/test sensors that apply to `changedPaths`. With no changed paths (or a sensor\n * scoped to everywhere) the sensor is selected unconditionally. Pure: the caller executes commands.\n */\nexport function selectCommandSensors(\n memories: Memory[],\n changedPaths: string[],\n): CommandSensorSpec[] {\n const specs: CommandSensorSpec[] = [];\n for (const memory of memories) {\n const sensor = memory.frontmatter.sensor;\n if (!sensor) continue;\n if (sensor.kind !== \"shell\" && sensor.kind !== \"test\") continue;\n const command = sensor.command?.trim();\n if (!command) continue;\n const anchorPaths = memory.frontmatter.anchor.paths;\n const applies =\n changedPaths.length === 0\n ? true\n : changedPaths.some((p) => sensorAppliesToPath(sensor, anchorPaths, p));\n if (!applies) continue;\n specs.push({\n memory_id: memory.frontmatter.id,\n command,\n kind: sensor.kind,\n severity: sensor.severity,\n message: sensor.message,\n paths: sensor.paths.length > 0 ? sensor.paths : anchorPaths,\n });\n }\n return specs;\n}\n\n/** Split a unified diff into per-file targets containing only added lines. */\nexport function sensorTargetsFromDiff(diff: string): SensorTarget[] {\n const targets: SensorTarget[] = [];\n let currentPath: string | null = null;\n let added: string[] = [];\n\n const flush = (): void => {\n if (!currentPath || added.length === 0) return;\n targets.push({ path: currentPath, content: added.join(\"\\n\") });\n added = [];\n };\n\n for (const line of diff.split(\"\\n\")) {\n if (line.startsWith(\"diff --git \")) {\n flush();\n currentPath = null;\n continue;\n }\n\n if (line.startsWith(\"+++ \")) {\n flush();\n const raw = line.slice(4).trim();\n currentPath = raw === \"/dev/null\" ? null : normalizeProjectPath(raw);\n continue;\n }\n\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n if (!currentPath) currentPath = \"\";\n added.push(line.slice(1));\n }\n }\n flush();\n return targets;\n}\n\n/**\n * Extract the added lines from a unified diff (lines starting with a single `+`,\n * excluding the `+++` file header). Mirrors the diff-handling already used by the\n * anti-pattern tokenizer so sensors fire on introductions, not mere mentions.\n */\nexport function addedLinesFromDiff(diff: string): string {\n const targets = sensorTargetsFromDiff(diff);\n if (targets.length > 0) return targets.map((target) => target.content).join(\"\\n\");\n return diff\n .split(\"\\n\")\n .filter((l) => l.startsWith(\"+\") && !l.startsWith(\"+++\"))\n .map((l) => l.slice(1))\n .join(\"\\n\");\n}\n","import type { Sensor } from \"./types.js\";\n\nconst CODE_TOKEN_RE = /`([^`\\n]{3,80})`|[\"']([A-Za-z0-9_.:-]{3,80})[\"']|\\b([A-Za-z][A-Za-z0-9_.:-]{2,79})\\b/g;\n\nconst SENSOR_STOPWORDS = new Set([\n \"about\", \"after\", \"again\", \"agent\", \"always\", \"anchor\", \"approach\", \"because\",\n \"before\", \"break\", \"broken\", \"cannot\", \"change\", \"code\", \"commit\", \"correct\",\n \"could\", \"default\", \"detect\", \"direct\", \"directory\", \"does\", \"error\", \"failed\",\n \"fails\", \"file\", \"files\", \"future\", \"instead\", \"memory\", \"never\", \"project\",\n \"recorded\", \"repo\", \"return\", \"should\", \"source\", \"string\", \"this\",\n \"tried\", \"true\", \"type\", \"undefined\", \"value\", \"when\", \"where\", \"which\", \"with\",\n \"without\",\n]);\n\nexport interface SensorSuggestionOptions {\n /** Extra paths to put on the sensor. Defaults to the memory anchor paths. */\n paths?: string[];\n}\n\n/**\n * Conservatively suggest a regex sensor from a gotcha/attempt body.\n *\n * This helper intentionally returns null more often than it guesses. Autogenerated\n * sensors start as `warn`, never `block`; humans can promote them after seeing them fire.\n */\nexport function suggestSensorFromMemory(\n body: string,\n anchorPaths: string[],\n options: SensorSuggestionOptions = {},\n): Sensor | null {\n const paths = options.paths ?? anchorPaths;\n if (paths.length === 0) return null;\n\n const negativeText = body.split(/\\*\\*Instead,\\s*use:\\*\\*|^##\\s+Instead\\b/im)[0] ?? body;\n const assignment = pickAssignmentPattern(negativeText);\n const lowercaseValue = assignment ? null : pickLowercaseValuePattern(negativeText);\n const token = assignment?.label ?? lowercaseValue?.label ?? pickDistinctiveToken(negativeText);\n if (!token) return null;\n\n return {\n kind: \"regex\",\n pattern: assignment?.pattern ?? lowercaseValue?.pattern ?? escapeRegExp(token),\n paths,\n message: sensorMessageFromBody(body, token),\n severity: \"warn\",\n autogen: true,\n last_fired: null,\n };\n}\n\nfunction pickLowercaseValuePattern(text: string): { label: string; pattern: string; score: number } | null {\n const candidates: Array<{ label: string; pattern: string; score: number }> = [];\n for (const match of text.matchAll(/\\blowercase\\s+([A-Za-z][A-Za-z0-9_.:-]{2,79})\\s+([a-z][a-z0-9_.:-]{1,40})\\b/g)) {\n const key = match[1] ?? \"\";\n const value = match[2] ?? \"\";\n if (!isDistinctiveToken(key, true) || isBoringValue(value)) continue;\n candidates.push({\n label: `${key}=${value}`,\n pattern: `${escapeRegExp(key)}\\\\s*[:=]\\\\s*[\"']?${escapeRegExp(value)}[\"']?`,\n score: key.length + value.length + 35,\n });\n }\n return candidates.sort((a, b) => b.score - a.score)[0] ?? null;\n}\n\nfunction pickAssignmentPattern(text: string): { label: string; pattern: string; score: number } | null {\n const candidates: Array<{ label: string; pattern: string; score: number }> = [];\n for (const source of assignmentSources(text)) {\n for (const match of source.matchAll(/\\b([A-Za-z][A-Za-z0-9_.:-]{2,79})\\b\\s*(=|:)\\s*[\"']?([A-Za-z0-9_.:-]{2,80})[\"']?/g)) {\n const key = match[1] ?? \"\";\n const operator = match[2] ?? \"\";\n const value = match[3] ?? \"\";\n if (!isDistinctiveToken(key, true) || isBoringValue(value)) continue;\n const label = `${key}${operator}${value}`;\n candidates.push({\n label,\n pattern: `${escapeRegExp(key)}\\\\s*${escapeRegExp(operator)}\\\\s*[\"']?${escapeRegExp(value)}[\"']?`,\n score: label.length + assignmentContextScore(source, match.index ?? 0, match[0].length),\n });\n }\n }\n return candidates.sort((a, b) => b.score - a.score)[0] ?? null;\n}\n\nfunction assignmentContextScore(source: string, index: number, length: number): number {\n const before = source.slice(Math.max(0, index - 50), index).toLowerCase();\n const after = source.slice(index + length, Math.min(source.length, index + length + 50)).toLowerCase();\n const window = `${before} ${after}`;\n let score = 0;\n if (/\\b(bad|failed|fails|broke|broken|wrong|avoid|forbid|forbidden|leaks?)\\b/.test(after)) score += 50;\n if (/do\\s+not|don't|never|should\\s+not|must\\s+not/.test(window)) score += 40;\n if (/\\b(keep|instead|correct|right|use|prefer|allowed)\\b/.test(before)) score -= 60;\n if (/\\b(keep|instead|correct|right|use|prefer|allowed)\\b/.test(after)) score -= 25;\n return score;\n}\n\nfunction assignmentSources(text: string): string[] {\n return [text];\n}\n\nfunction pickDistinctiveToken(text: string): string | null {\n const candidates = new Map<string, { raw: string; score: number }>();\n for (const match of text.matchAll(CODE_TOKEN_RE)) {\n const raw = (match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n const token = raw.replace(/^[^\\w.-]+|[^\\w.-]+$/g, \"\");\n const isCodeLike = Boolean(match[1] ?? match[2]);\n if (!isDistinctiveToken(token, isCodeLike)) continue;\n const key = token.toLowerCase();\n const codeSpanBonus = match[1] ? 20 : match[2] ? 8 : 0;\n const shapeBonus =\n /[-_.:]/.test(token) ? 3 :\n /[A-Z]/.test(token.slice(1)) ? 2 :\n /\\d/.test(token) ? 1 : 0;\n const score = token.length + codeSpanBonus + shapeBonus;\n const existing = candidates.get(key);\n if (!existing || score > existing.score) candidates.set(key, { raw: token, score });\n }\n const best = [...candidates.values()].sort((a, b) => b.score - a.score)[0];\n return best?.raw ?? null;\n}\n\n/**\n * Reject tokens that produce nonsensical sensors: pure numbers, number ranges / line refs\n * (`1131-1186`), version-ish strings, and bare filenames (`enforce.ts`). A sensor built from these\n * fires on noise and trains agents to ignore the gate — the false-positive failure mode the harness\n * must avoid. (Real reproduced miss: a gotcha body referencing `enforce.ts:1131-1186` produced the\n * regex `enforce\\.ts\\s*:\\s*1131-1186`.)\n */\nconst FILE_EXT_REF = /\\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|rb|php|cs|cpp|c|h|md|json|ya?ml|toml|lock)\\b/i;\nfunction isDegenerateToken(token: string): boolean {\n if (/^[\\d.\\-:_]+$/.test(token)) return true; // pure number / range / line ref like 1131-1186\n if (/\\d+\\s*-\\s*\\d+/.test(token)) return true; // a numeric / line range embedded anywhere (e.g. 1131-1186)\n if (FILE_EXT_REF.test(token)) return true; // contains a filename reference (e.g. enforce.ts, enforce.ts:1131)\n // mostly digits (e.g. a version or id with a stray letter): <=1 letter among many digits\n const letters = (token.match(/[A-Za-z]/g) ?? []).length;\n const digits = (token.match(/\\d/g) ?? []).length;\n if (digits >= 3 && letters <= 1) return true;\n return false;\n}\n\nfunction isDistinctiveToken(token: string, isCodeLike: boolean): boolean {\n if (token.length < 4 || token.length > 80) return false;\n if (/^https?:\\/\\//i.test(token)) return false;\n if (/^\\d+$/.test(token)) return false;\n if (isDegenerateToken(token)) return false;\n const lower = token.toLowerCase();\n if (SENSOR_STOPWORDS.has(lower)) return false;\n if (!/[A-Za-z]/.test(token)) return false;\n const shaped = /[-_.:\\d]/.test(token) || /[A-Z]/.test(token.slice(1));\n return shaped || isCodeLike;\n}\n\nfunction isBoringValue(value: string): boolean {\n if (!value || value.length > 80) return true;\n const lower = value.toLowerCase();\n if (lower === \"true\" || lower === \"false\") return false;\n if (isDegenerateToken(value)) return true; // numbers / ranges / line refs / filenames are not real values\n return SENSOR_STOPWORDS.has(lower);\n}\n\nfunction sensorMessageFromBody(body: string, token: string): string {\n const instead = body.match(/\\*\\*Instead,\\s*use:\\*\\*\\s*([^\\n]+)/i)?.[1]?.trim();\n if (instead) return `Avoid ${token}; ${instead}`;\n const firstGuidance = body\n .split(\"\\n\")\n .map((line) => line.replace(/^#+\\s*/, \"\").trim())\n .find((line) => line.length > 0 && !line.startsWith(\"---\"));\n return firstGuidance?.slice(0, 180) || `Avoid ${token}; this matched an autogenerated hAIve sensor.`;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","import type { MemoryFrontmatter } from \"./types.js\";\nimport { buildFrontmatter } from \"./parser.js\";\nimport { suggestSensorFromMemory } from \"./sensor-suggest.js\";\nimport { meetsSeedQualityFloor } from \"./specificity.js\";\n\n/**\n * Findings ingestion — the self-feeding half of the sensors story (feature B).\n *\n * Phase 1/2 turned a documented mistake into an executable `sensor`. But someone still has\n * to *document* the mistake. Findings ingestion closes the review↔memory loop: a real defect\n * reported by a scanner (SonarQube, or any SARIF-emitting tool like ESLint/Semgrep/CodeQL)\n * becomes an anchored `gotcha`/`convention` memory, pre-filled with a conservative autogen\n * sensor, so the *next* agent is steered away from it before it writes the same code.\n *\n * This module is pure: parsers + draft synthesis, no I/O. The CLI (`haive ingest`) and the\n * MCP tool (`ingest_findings`) read files / write memories around these functions.\n *\n * Safety: every draft is `status: proposed` and every suggested sensor is `severity: warn`\n * + `autogen: true`. Ingestion never auto-validates and never auto-blocks (safety rules +\n * `2026-05-07-attempt-strict-precommit-gate-on-haive`). A human promotes both.\n */\n\nexport type FindingSeverity = \"info\" | \"minor\" | \"major\" | \"critical\" | \"blocker\";\n\nexport interface Finding {\n /** Source tool, e.g. \"sonar\", \"eslint\", \"semgrep\". */\n tool: string;\n /** Rule key, e.g. \"typescript:S1234\" or \"no-unused-vars\". */\n ruleId: string;\n /** Human-readable description of the problem. */\n message: string;\n severity: FindingSeverity;\n /** Project-relative file path. */\n path: string;\n /** 1-based line number, when known. */\n line?: number;\n /** Offending source snippet, when the report provides one. */\n snippet?: string;\n /**\n * Stable dedup key: `tool:ruleId:path`. Deliberately excludes the line so re-running a\n * scan after unrelated edits (which shift line numbers) does not re-propose the same memory.\n */\n key: string;\n}\n\nexport interface MemoryDraft {\n key: string;\n /** `ingest:<key>` — used as the memory `topic` so re-ingestion upserts instead of duplicating. */\n topic: string;\n frontmatter: MemoryFrontmatter;\n body: string;\n finding: Finding;\n /** True when a conservative sensor could be derived from the finding. */\n has_sensor: boolean;\n}\n\nexport interface DraftOptions {\n /** Memory type for the draft. Default \"gotcha\". */\n type?: \"gotcha\" | \"convention\";\n /** Scope for the draft. Default \"team\". */\n scope?: \"personal\" | \"team\" | \"module\";\n module?: string;\n author?: string;\n}\n\nexport interface DraftsOptions extends DraftOptions {\n /** Cap on number of drafts produced (after in-batch dedup). */\n limit?: number;\n /** Only ingest findings at or above this severity. Default: none (all). */\n minSeverity?: FindingSeverity;\n /** Include auto-fixable stylistic rules (semi/quotes/indent/prefer-const…). Default false — they are\n * linter-autofix noise, not lessons worth a memory. */\n includeStylistic?: boolean;\n}\n\n/**\n * Auto-fixable stylistic / formatting rules. Seeding a memory for \"missing semicolon\" or\n * \"prefer const\" is pure clutter: a linter fixes them and a capable model already follows them. We\n * match the rule's last segment so prefixed ids (`@typescript-eslint/semi`, `prettier/prettier`) are\n * caught. This is the ingest-side quality floor — specificity scoring can't catch it (a finding body\n * is always concrete: it has a file path and line).\n */\nconst STYLISTIC_RULE_RE =\n /(?:^|[/:])(?:prettier|semi|semi-spacing|no-extra-semi|quotes|jsx-quotes|quote-props|indent|comma-dangle|comma-spacing|comma-style|eol-last|linebreak-style|no-trailing-spaces|no-multiple-empty-lines|no-multi-spaces|object-curly-spacing|array-bracket-spacing|block-spacing|space-before-blocks|space-before-function-paren|space-infix-ops|space-in-parens|keyword-spacing|arrow-spacing|key-spacing|func-call-spacing|padded-blocks|padding-line-between-statements|brace-style|spaced-comment|max-len|prefer-const|no-var)(?:$|[/:])/i;\n\n/** True when a finding's rule is pure auto-fixable formatting/style (no lesson value as a seed). */\nexport function isStylisticRule(ruleId: string): boolean {\n return STYLISTIC_RULE_RE.test(ruleId ?? \"\");\n}\n\nconst SEVERITY_RANK: Record<FindingSeverity, number> = {\n info: 0,\n minor: 1,\n major: 2,\n critical: 3,\n blocker: 4,\n};\n\n/** Normalize a tool-specific severity string to the shared scale. */\nexport function normalizeFindingSeverity(raw: string | undefined | null): FindingSeverity {\n const v = (raw ?? \"\").toString().trim().toLowerCase();\n switch (v) {\n case \"blocker\":\n return \"blocker\";\n case \"critical\":\n case \"error\":\n case \"fatal\":\n return \"critical\";\n case \"major\":\n case \"warning\":\n case \"warn\":\n return \"major\";\n case \"minor\":\n case \"note\":\n case \"info\":\n case \"information\":\n case \"informational\":\n return v === \"minor\" ? \"minor\" : \"info\";\n default:\n return \"info\";\n }\n}\n\nfunction findingKey(tool: string, ruleId: string, path: string): string {\n return `${tool}:${ruleId}:${path}`;\n}\n\nfunction coerceJson(input: string | unknown): unknown {\n if (typeof input === \"string\") {\n try {\n return JSON.parse(input);\n } catch (err) {\n throw new Error(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n return input;\n}\n\nfunction asArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n}\n\n/**\n * Parse SARIF 2.1.0 (`runs[].results[]`). Works for any SARIF emitter (ESLint, Semgrep,\n * CodeQL, etc.). The tool name comes from `runs[].tool.driver.name`.\n */\nexport function parseSarif(input: string | unknown): Finding[] {\n const doc = asRecord(coerceJson(input));\n const findings: Finding[] = [];\n for (const runRaw of asArray(doc.runs)) {\n const run = asRecord(runRaw);\n const driver = asRecord(asRecord(run.tool).driver);\n const tool = (typeof driver.name === \"string\" ? driver.name : \"sarif\").toLowerCase();\n for (const resultRaw of asArray(run.results)) {\n const result = asRecord(resultRaw);\n const ruleId =\n (typeof result.ruleId === \"string\" && result.ruleId) ||\n (typeof asRecord(result.rule).id === \"string\" ? (asRecord(result.rule).id as string) : \"\") ||\n \"unknown-rule\";\n const message =\n (typeof asRecord(result.message).text === \"string\"\n ? (asRecord(result.message).text as string)\n : \"\") || ruleId;\n const severity = normalizeFindingSeverity(typeof result.level === \"string\" ? result.level : \"warning\");\n const location = asRecord(asArray(result.locations)[0]);\n const physical = asRecord(location.physicalLocation);\n const artifact = asRecord(physical.artifactLocation);\n const region = asRecord(physical.region);\n const path = typeof artifact.uri === \"string\" ? normalizeUri(artifact.uri) : \"\";\n if (!path) continue;\n const line = typeof region.startLine === \"number\" ? region.startLine : undefined;\n const snippet =\n typeof asRecord(region.snippet).text === \"string\"\n ? (asRecord(region.snippet).text as string).trim()\n : undefined;\n findings.push({\n tool,\n ruleId,\n message: message.trim(),\n severity,\n path,\n ...(line !== undefined ? { line } : {}),\n ...(snippet ? { snippet } : {}),\n key: findingKey(tool, ruleId, path),\n });\n }\n }\n return findings;\n}\n\n/**\n * Parse the SonarQube issues payload (`issues[]` from `/api/issues/search`). The file path\n * lives in `component` as `projectKey:relative/path`; we strip the project key.\n */\nexport function parseSonar(input: string | unknown): Finding[] {\n const doc = asRecord(coerceJson(input));\n const findings: Finding[] = [];\n for (const issueRaw of asArray(doc.issues)) {\n const issue = asRecord(issueRaw);\n const ruleId = typeof issue.rule === \"string\" ? issue.rule : \"unknown-rule\";\n const message = typeof issue.message === \"string\" ? issue.message.trim() : ruleId;\n // Sonar exposes either `severity` (legacy) or `impacts[].severity` (MQR mode).\n const impacts = asArray(issue.impacts);\n const impactSeverity =\n impacts.length > 0 && typeof asRecord(impacts[0]).severity === \"string\"\n ? (asRecord(impacts[0]).severity as string)\n : undefined;\n const severity = normalizeFindingSeverity(\n (typeof issue.severity === \"string\" ? issue.severity : undefined) ?? impactSeverity,\n );\n const component = typeof issue.component === \"string\" ? issue.component : \"\";\n const path = componentToPath(component);\n if (!path) continue;\n const line = typeof issue.line === \"number\" ? issue.line : undefined;\n findings.push({\n tool: \"sonar\",\n ruleId,\n message,\n severity,\n path,\n ...(line !== undefined ? { line } : {}),\n key: findingKey(\"sonar\", ruleId, path),\n });\n }\n return findings;\n}\n\n/**\n * Parse the ESLint JSON formatter output (`eslint --format json`): an array of\n * `{ filePath, messages: [{ ruleId, severity, message, line }] }`. No SARIF formatter\n * package needed — this is ESLint's built-in format. `severity` is 2=error, 1=warning.\n * `opts.cwd`, when given, makes absolute `filePath`s project-relative so anchoring works.\n */\nexport function parseEslintJson(input: string | unknown, opts: { cwd?: string } = {}): Finding[] {\n const docs = asArray(coerceJson(input));\n const findings: Finding[] = [];\n const cwd = opts.cwd ? opts.cwd.replace(/\\/+$/, \"\") + \"/\" : \"\";\n for (const fileRaw of docs) {\n const file = asRecord(fileRaw);\n const rawPath = typeof file.filePath === \"string\" ? file.filePath : \"\";\n if (!rawPath) continue;\n const path = cwd && rawPath.startsWith(cwd) ? rawPath.slice(cwd.length) : rawPath;\n for (const msgRaw of asArray(file.messages)) {\n const msg = asRecord(msgRaw);\n const ruleId = typeof msg.ruleId === \"string\" && msg.ruleId ? msg.ruleId : \"parse-error\";\n const message = typeof msg.message === \"string\" ? msg.message.trim() : ruleId;\n const severity = normalizeFindingSeverity(msg.severity === 2 ? \"error\" : \"warning\");\n const line = typeof msg.line === \"number\" ? msg.line : undefined;\n findings.push({\n tool: \"eslint\",\n ruleId,\n message,\n severity,\n path,\n ...(line !== undefined ? { line } : {}),\n key: findingKey(\"eslint\", ruleId, path),\n });\n }\n }\n return findings;\n}\n\nconst NPM_AUDIT_SEVERITY: Record<string, FindingSeverity> = {\n critical: \"blocker\",\n high: \"critical\",\n moderate: \"major\",\n low: \"minor\",\n info: \"info\",\n};\n\n/**\n * Parse `npm audit --json` output (`vulnerabilities` map). Each vulnerable package becomes one\n * finding anchored to `package.json` (vulnerabilities are dependency-level, not file-level), so\n * the next agent is warned before re-introducing or ignoring the advisory.\n */\nexport function parseNpmAudit(input: string | unknown): Finding[] {\n const doc = asRecord(coerceJson(input));\n const vulns = asRecord(doc.vulnerabilities);\n const findings: Finding[] = [];\n for (const [name, vulnRaw] of Object.entries(vulns)) {\n const vuln = asRecord(vulnRaw);\n const sev = typeof vuln.severity === \"string\" ? vuln.severity.toLowerCase() : \"info\";\n const severity = NPM_AUDIT_SEVERITY[sev] ?? \"info\";\n const via = asArray(vuln.via);\n const firstAdvisory = via.map(asRecord).find((v) => typeof v.title === \"string\");\n const title =\n firstAdvisory && typeof firstAdvisory.title === \"string\"\n ? (firstAdvisory.title as string)\n : `Vulnerable dependency: ${name}`;\n const range = typeof vuln.range === \"string\" ? ` (affected range: ${vuln.range})` : \"\";\n findings.push({\n tool: \"npm-audit\",\n ruleId: name,\n message: `${title}${range}`,\n severity,\n path: \"package.json\",\n key: findingKey(\"npm-audit\", name, \"package.json\"),\n });\n }\n return findings;\n}\n\nexport type FindingFormat = \"sarif\" | \"sonar\" | \"eslint\" | \"npm-audit\";\n\n/** Dispatch to the right parser by declared format. */\nexport function parseFindings(\n format: FindingFormat,\n input: string | unknown,\n opts: { cwd?: string } = {},\n): Finding[] {\n switch (format) {\n case \"sonar\":\n return parseSonar(input);\n case \"eslint\":\n return parseEslintJson(input, opts);\n case \"npm-audit\":\n return parseNpmAudit(input);\n default:\n return parseSarif(input);\n }\n}\n\nfunction normalizeUri(uri: string): string {\n return uri.replace(/^file:\\/\\//, \"\").replace(/^\\.\\//, \"\");\n}\n\nfunction componentToPath(component: string): string {\n const idx = component.indexOf(\":\");\n return idx === -1 ? component : component.slice(idx + 1);\n}\n\nfunction sanitize(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 40);\n}\n\nfunction basename(p: string): string {\n const parts = p.split(\"/\");\n return parts[parts.length - 1] || p;\n}\n\n/** Build the markdown body for a finding-derived memory. */\nexport function findingBody(finding: Finding): string {\n const lines: string[] = [\n `# ${finding.ruleId} in ${finding.path}`,\n \"\",\n `**Source:** ${finding.tool} finding (severity: ${finding.severity})`,\n \"\",\n finding.message,\n \"\",\n `**Location:** ${finding.path}${finding.line !== undefined ? `:${finding.line}` : \"\"}`,\n ];\n if (finding.snippet) {\n lines.push(\"\", \"**Offending code:**\", \"```\", finding.snippet, \"```\");\n }\n lines.push(\"\", `**Instead, use:** Resolve the ${finding.tool} finding — ${finding.message}`);\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/** Convert one finding into a proposed memory draft (with a conservative sensor when derivable). */\nexport function findingToDraft(finding: Finding, options: DraftOptions = {}): MemoryDraft {\n const type = options.type ?? \"gotcha\";\n const scope = options.scope ?? \"team\";\n const topic = `ingest:${finding.key}`;\n const slug = `${sanitize(finding.tool)}-${sanitize(finding.ruleId)}-${sanitize(basename(finding.path))}`;\n const body = findingBody(finding);\n\n const frontmatter = buildFrontmatter({\n type,\n slug,\n scope,\n module: options.module,\n author: options.author,\n paths: [finding.path],\n tags: [\"ingested\", finding.tool, finding.severity],\n topic,\n status: \"proposed\",\n });\n\n const sensor = suggestSensorFromMemory(body, [finding.path]);\n if (sensor) frontmatter.sensor = sensor;\n\n return { key: finding.key, topic, frontmatter, body, finding, has_sensor: Boolean(sensor) };\n}\n\n/** Convert a batch of findings into drafts, deduped within the batch and capped/filtered. */\nexport function draftsFromFindings(findings: Finding[], options: DraftsOptions = {}): MemoryDraft[] {\n const minRank = options.minSeverity ? SEVERITY_RANK[options.minSeverity] : -1;\n const seen = new Set<string>();\n const drafts: MemoryDraft[] = [];\n for (const finding of findings) {\n if (SEVERITY_RANK[finding.severity] < minRank) continue;\n if (seen.has(finding.key)) continue;\n seen.add(finding.key);\n // Quality floor (ingest): drop auto-fixable stylistic noise, and drop a draft that has no sensor\n // and reads as generic/low-signal (backstop — finding bodies are usually concrete, so this rarely\n // fires, but it keeps the corpus free of empty seeds).\n if (!options.includeStylistic && isStylisticRule(finding.ruleId)) continue;\n const draft = findingToDraft(finding, options);\n if (!meetsSeedQualityFloor(draft.body, draft.has_sensor)) continue;\n drafts.push(draft);\n if (options.limit !== undefined && drafts.length >= options.limit) break;\n }\n return drafts;\n}\n\n/** Drop drafts whose topic already exists in the corpus (cross-run dedup). */\nexport function filterNewDrafts(drafts: MemoryDraft[], existingTopics: Iterable<string>): MemoryDraft[] {\n const existing = new Set(existingTopics);\n return drafts.filter((d) => !existing.has(d.topic));\n}\n","/**\n * Gate signal-quality — is the inferential (anti-pattern) gate earning trust or crying wolf?\n *\n * hAIve's anti-pattern gate is probabilistic and warmup-sensitive, so it is deliberately calibrated\n * NOT to hard-block on weak matches. But a team needs to SEE whether the gate's signal is precise:\n * are its catches turning out to be real (prevented mistakes, applied lessons) or noise (rejected by\n * humans via `mem_feedback`)? This module turns the signals hAIve already records — prevention events\n * (by source) and per-memory rejection counts — into a precision indicator and an actionable tuning\n * suggestion for `enforcement.antiPatternGate`. Pure: no I/O.\n */\nimport type { PreventionEvent } from \"./prevention.js\";\nimport type { UsageIndex } from \"./usage.js\";\nimport type { AntiPatternGate } from \"./config.js\";\n\nexport interface GatePrecision {\n /** Catches recorded by deterministic regex/command sensors. */\n sensor_catches: number;\n /** Catches recorded by the inferential anti-pattern gate. */\n anti_pattern_catches: number;\n /** Total \"useful\" outcomes (catches + human-applied lessons). */\n useful: number;\n /** Total human rejections (mem_feedback \"not useful\"). Proxy for false positives. */\n rejections: number;\n /** useful / (useful + rejections), 0..1. Null when there is no signal yet. */\n precision: number | null;\n /** A tuning recommendation for enforcement.antiPatternGate, or null when current looks right. */\n suggestion: GateTuningSuggestion | null;\n}\n\nexport interface GateTuningSuggestion {\n recommended: AntiPatternGate;\n reason: string;\n}\n\nexport interface GatePrecisionMetricDelta {\n baseline: number | null;\n current: number | null;\n delta: number | null;\n}\n\nexport interface GatePrecisionDelta {\n precision: GatePrecisionMetricDelta;\n rejections: GatePrecisionMetricDelta;\n /** True when humans rejected more gate output than the baseline run. */\n false_positives_increased: boolean;\n /** True when precision is known on both sides and dropped. */\n precision_regressed: boolean;\n /** CI-friendly rollup: either more false positives or lower known precision. */\n regressed: boolean;\n}\n\nfunction round3(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\n/**\n * Compute the gate's signal quality from prevention events + usage.\n * @param currentGate the configured antiPatternGate, used to decide whether to suggest a change.\n */\nexport function computeGatePrecision(\n events: PreventionEvent[],\n usage: UsageIndex,\n currentGate: AntiPatternGate = \"anchored\",\n): GatePrecision {\n let sensorCatches = 0;\n let antiPatternCatches = 0;\n for (const e of events) {\n if (e.source === \"sensor\") sensorCatches += 1;\n else if (e.source === \"anti-pattern\") antiPatternCatches += 1;\n }\n\n let applied = 0;\n let rejections = 0;\n for (const mem of Object.values(usage.by_id ?? {})) {\n applied += mem.applied_count ?? 0;\n rejections += mem.rejected_count ?? 0;\n }\n\n const useful = sensorCatches + antiPatternCatches + applied;\n const denom = useful + rejections;\n const precision = denom === 0 ? null : round3(useful / denom);\n\n return {\n sensor_catches: sensorCatches,\n anti_pattern_catches: antiPatternCatches,\n useful,\n rejections,\n precision,\n suggestion: suggestGate(precision, rejections, currentGate),\n };\n}\n\n/**\n * Suggest loosening the gate when it is noisy (low precision with real rejection volume), or\n * tightening it when it is precise but currently soft. Returns null when current looks right or\n * there isn't enough signal to act on.\n */\nexport function suggestGate(\n precision: number | null,\n rejections: number,\n currentGate: AntiPatternGate,\n): GateTuningSuggestion | null {\n // Need a meaningful sample before recommending a change.\n if (precision === null || rejections < 3) return null;\n\n if (precision < 0.5 && (currentGate === \"anchored\" || currentGate === \"strict\")) {\n return {\n recommended: \"review\",\n reason: `Gate precision ${precision} with ${rejections} rejection(s) — the gate is crying wolf. Loosen to \"review\" (surface, don't hard-block) until the corpus is cleaner.`,\n };\n }\n if (precision >= 0.85 && currentGate === \"review\") {\n return {\n recommended: \"anchored\",\n reason: `Gate precision ${precision} — catches are reliably real. Tighten to \"anchored\" so corroborated anti-patterns hard-block.`,\n };\n }\n return null;\n}\n\nfunction nullableMetricDelta(baseline: number | null, current: number | null): GatePrecisionMetricDelta {\n if (baseline === null || current === null) return { baseline, current, delta: null };\n return { baseline: round3(baseline), current: round3(current), delta: round3(current - baseline) };\n}\n\n/** Compare gate signal quality against a baseline for CI regression gates. Pure. */\nexport function compareGatePrecision(\n baseline: GatePrecision,\n current: GatePrecision,\n): GatePrecisionDelta {\n const precision = nullableMetricDelta(baseline.precision, current.precision);\n const rejections = nullableMetricDelta(baseline.rejections, current.rejections);\n const falsePositivesIncreased = current.rejections > baseline.rejections;\n const precisionRegressed = precision.delta !== null && precision.delta < 0;\n return {\n precision,\n rejections,\n false_positives_increased: falsePositivesIncreased,\n precision_regressed: precisionRegressed,\n regressed: falsePositivesIncreased || precisionRegressed,\n };\n}\n","import type { LoadedMemory } from \"./loader.js\";\nimport type { MemoryFrontmatter } from \"./types.js\";\nimport { computeImpact, compareImpact, summarizeImpact, type ImpactSummary, type ImpactScore } from \"./impact.js\";\nimport { isRetiredMemory } from \"./memory-lifecycle.js\";\nimport { DECAY_DAYS, getUsage, isDecaying, type UsageIndex } from \"./usage.js\";\nimport {\n computePreventionTrend,\n computeRecurrence,\n type PreventionEvent,\n type PreventionTrend,\n type RecurrenceReport,\n} from \"./prevention.js\";\nimport { computeGatePrecision, type GatePrecision } from \"./gate-precision.js\";\nimport type { AntiPatternGate } from \"./config.js\";\n\n/**\n * Observability rollup — the \"is the corpus healthy and earning its keep?\" view.\n *\n * hAIve already has the pieces (impact scoring, usage tracking, sensors, retirement,\n * decay) but no single non-interactive snapshot that an agent, a CI job, or a human\n * can read in one shot. `haive tui` exists but needs a TTY; `haive stats` only covers\n * tool-call volume. This module aggregates the full picture deterministically so the\n * CLI can print it (or emit JSON). Pure: no I/O, unit-tested in `test/dashboard.test.ts`.\n */\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\nexport interface DashboardOptions {\n /** How many rows to include in each \"top\" list. Default 10. */\n top?: number;\n /** Dormancy window for impact scoring. Defaults to impact's own default. */\n dormantDays?: number;\n now?: Date;\n /** Prevention event log (from `loadPreventionEvents`) — powers the trend + recurrence rollups. */\n preventionEvents?: PreventionEvent[];\n /** Configured anti-pattern gate — lets the gate-precision rollup suggest tightening/loosening. */\n antiPatternGate?: AntiPatternGate;\n}\n\nexport interface ImpactRow {\n id: string;\n score: number;\n tier: ImpactScore[\"tier\"];\n signals: string[];\n prune_candidate: boolean;\n}\n\nexport interface SensorRow {\n id: string;\n severity: \"warn\" | \"block\";\n last_fired: string;\n}\n\nexport interface DormantRow {\n id: string;\n last_read_at: string | null;\n age_days: number;\n}\n\nexport interface PreventionRow {\n id: string;\n type: string;\n prevented_count: number;\n last_prevented_at: string | null;\n}\n\nexport interface DashboardReport {\n generated_at: string;\n inventory: {\n /** Policy corpus size (excludes session_recap). */\n total: number;\n session_recaps: number;\n active: number;\n retired: number;\n by_scope: Record<string, number>;\n by_type: Record<string, number>;\n by_status: Record<string, number>;\n };\n /** OUTCOME measurement: prevention events = times a memory's sensor/anti-pattern fired on a real\n * diff, intercepting a known mistake. Distinct from retrieval (reads) — demonstrated value. */\n prevention: {\n total_events: number;\n memories_with_catches: number;\n top: PreventionRow[];\n /** Catch volume over time (from the prevention event log). */\n trend: PreventionTrend;\n /** Lessons re-introduced after capture (caught on >= 2 distinct days). */\n recurrence: RecurrenceReport;\n };\n /** Inferential-gate signal quality: are catches real (useful) or noise (rejected)? + tuning hint. */\n gate_precision: GatePrecision;\n impact: ImpactSummary & { top: ImpactRow[] };\n sensors: {\n total: number;\n warn: number;\n block: number;\n autogen: number;\n fired: number;\n recently_fired: SensorRow[];\n };\n health: {\n stale: number;\n retired: number;\n /** Validated decision/gotcha/architecture memories with no anchor paths or symbols. */\n anchorless: number;\n /** Memories awaiting review (draft/proposed). */\n pending: number;\n prune_candidates: number;\n };\n decay: {\n decay_days: number;\n decaying: number;\n top_dormant: DormantRow[];\n };\n corpus: {\n /** Number of memory files (policy corpus, excludes session_recap). */\n memory_files: number;\n body_chars: number;\n /** Rough token estimate (~chars/4) — how heavy the corpus is to inject. */\n est_tokens: number;\n };\n}\n\nfunction isAnchorless(fm: MemoryFrontmatter): boolean {\n if (![\"decision\", \"gotcha\", \"architecture\"].includes(fm.type)) return false;\n if (fm.status !== \"validated\") return false;\n return fm.anchor.paths.length === 0 && fm.anchor.symbols.length === 0;\n}\n\nfunction inc(map: Record<string, number>, key: string): void {\n map[key] = (map[key] ?? 0) + 1;\n}\n\n/** Build the full observability rollup from the loaded corpus + usage index. Pure. */\nexport function buildDashboard(\n memories: LoadedMemory[],\n usage: UsageIndex,\n options: DashboardOptions = {},\n): DashboardReport {\n const now = options.now ?? new Date();\n const top = options.top ?? 10;\n\n const inventory = {\n total: 0,\n session_recaps: 0,\n active: 0,\n retired: 0,\n by_scope: {} as Record<string, number>,\n by_type: {} as Record<string, number>,\n by_status: {} as Record<string, number>,\n };\n\n const impactScores: ImpactScore[] = [];\n const impactRows: ImpactRow[] = [];\n const sensorRows: SensorRow[] = [];\n let sensorTotal = 0;\n let sensorWarn = 0;\n let sensorBlock = 0;\n let sensorAutogen = 0;\n let sensorFired = 0;\n let stale = 0;\n let retired = 0;\n let anchorless = 0;\n let pending = 0;\n let decaying = 0;\n let bodyChars = 0;\n const dormantRows: DormantRow[] = [];\n let preventionEvents = 0;\n const preventionRows: PreventionRow[] = [];\n\n for (const { memory } of memories) {\n const fm = memory.frontmatter;\n\n if (fm.type === \"session_recap\") {\n inventory.session_recaps += 1;\n continue;\n }\n\n inventory.total += 1;\n inc(inventory.by_scope, fm.scope);\n inc(inventory.by_type, fm.type);\n inc(inventory.by_status, fm.status);\n bodyChars += memory.body.length;\n\n const isRetired = isRetiredMemory(fm, memory.body, now);\n if (isRetired) {\n inventory.retired += 1;\n retired += 1;\n } else {\n inventory.active += 1;\n }\n if (fm.status === \"stale\") stale += 1;\n if (isAnchorless(fm)) anchorless += 1;\n if (fm.status === \"draft\" || fm.status === \"proposed\") pending += 1;\n\n // ── Sensors ──\n if (fm.sensor) {\n sensorTotal += 1;\n if (fm.sensor.severity === \"block\") sensorBlock += 1;\n else sensorWarn += 1;\n if (fm.sensor.autogen) sensorAutogen += 1;\n if (fm.sensor.last_fired) {\n sensorFired += 1;\n sensorRows.push({ id: fm.id, severity: fm.sensor.severity, last_fired: fm.sensor.last_fired });\n }\n }\n\n // ── Impact ──\n const memUsage = getUsage(usage, fm.id);\n const impact = computeImpact(fm, memUsage, {\n now,\n ...(options.dormantDays !== undefined ? { dormantDays: options.dormantDays } : {}),\n });\n impactScores.push(impact);\n impactRows.push({\n id: fm.id,\n score: impact.score,\n tier: impact.tier,\n signals: impact.signals,\n prune_candidate: impact.pruneCandidate,\n });\n\n // ── Prevention (outcome) ──\n if (memUsage.prevented_count > 0) {\n preventionEvents += memUsage.prevented_count;\n preventionRows.push({\n id: fm.id,\n type: fm.type,\n prevented_count: memUsage.prevented_count,\n last_prevented_at: memUsage.last_prevented_at,\n });\n }\n\n // ── Decay ──\n if (isDecaying(memUsage, fm.created_at)) decaying += 1;\n if (impact.tier === \"dormant\") {\n const anchor = memUsage.last_read_at ?? fm.created_at;\n const ageDays = Math.floor((now.getTime() - new Date(anchor).getTime()) / MS_PER_DAY);\n dormantRows.push({ id: fm.id, last_read_at: memUsage.last_read_at, age_days: ageDays });\n }\n }\n\n impactRows.sort((a, b) =>\n compareImpact(\n { score: a.score, tier: a.tier, signals: a.signals, pruneCandidate: a.prune_candidate },\n { score: b.score, tier: b.tier, signals: b.signals, pruneCandidate: b.prune_candidate },\n ),\n );\n sensorRows.sort((a, b) => b.last_fired.localeCompare(a.last_fired));\n dormantRows.sort((a, b) => b.age_days - a.age_days);\n const eventLog = options.preventionEvents ?? [];\n const recurrence = computeRecurrence(eventLog);\n\n return {\n generated_at: now.toISOString(),\n inventory,\n prevention: {\n total_events: preventionEvents,\n memories_with_catches: preventionRows.length,\n top: preventionRows\n .sort((a, b) => b.prevented_count - a.prevented_count)\n .slice(0, top),\n trend: computePreventionTrend(eventLog, now),\n recurrence: {\n ...recurrence,\n top: recurrence.top.slice(0, top),\n },\n },\n gate_precision: computeGatePrecision(\n eventLog,\n usage,\n options.antiPatternGate ?? \"anchored\",\n ),\n impact: { ...summarizeImpact(impactScores), top: impactRows.slice(0, top) },\n sensors: {\n total: sensorTotal,\n warn: sensorWarn,\n block: sensorBlock,\n autogen: sensorAutogen,\n fired: sensorFired,\n recently_fired: sensorRows.slice(0, top),\n },\n health: {\n stale,\n retired,\n anchorless,\n pending,\n prune_candidates: impactScores.filter((s) => s.pruneCandidate).length,\n },\n decay: {\n decay_days: DECAY_DAYS,\n decaying,\n top_dormant: dormantRows.slice(0, top),\n },\n corpus: {\n memory_files: inventory.total,\n body_chars: bodyChars,\n est_tokens: Math.round(bodyChars / 4),\n },\n };\n}\n","/**\n * Failure-capture coverage — the gate behind hAIve's \"never silently fix the same mistake\" loop.\n *\n * `haive observe` (the PostToolUse hook) appends an observation per tool call to\n * `.ai/.cache/observations.jsonl`, tagging hard failures with `failure_hint: true`\n * (non-zero Bash exit, `error TSxxxx`, ENOENT, …). Those failures are exactly the\n * `mem_tried` candidates the harness wants captured — otherwise the next session repeats them.\n *\n * This module is the pure decision layer: given the failure observations and the corpus's\n * `attempt`/`gotcha` memories, which failures look UNCAPTURED (no lesson recorded after them)?\n * The CLI reads the files and turns the result into an `enforce finish` finding. No I/O here.\n */\n\nexport interface FailureObservation {\n /** ISO timestamp of the observation. */\n ts: string;\n /** Tool that failed (Bash / Edit / …). */\n tool: string;\n /** Short human-readable summary of what was attempted. */\n summary: string;\n}\n\nexport interface UncapturedFailure {\n ts: string;\n tool: string;\n summary: string;\n}\n\nexport interface FailureCoverageOptions {\n /** Only consider failures newer than this many hours (avoid stale observations blocking forever). Default 24. */\n windowHours?: number;\n /** Collapse near-identical failures (same normalized summary) to one row. Default true. */\n dedupe?: boolean;\n now?: Date;\n}\n\nconst MS_PER_HOUR = 3_600_000;\n\nfunction normalizeSummary(summary: string): string {\n return summary.toLowerCase().replace(/\\s+/g, \" \").trim().slice(0, 160);\n}\n\n/**\n * A failure is CAPTURED when an `attempt`/`gotcha` lesson was recorded at or after it\n * (within the window) — the agent stopped and wrote the lesson down. Failures that pre-date\n * every recent capture are uncaptured: the gate should nudge (or block) on those.\n *\n * @param failures failure-tagged observations (any order)\n * @param captureTimes ISO created_at of every attempt/gotcha memory in the corpus\n */\nexport function findUncapturedFailures(\n failures: FailureObservation[],\n captureTimes: string[],\n options: FailureCoverageOptions = {},\n): UncapturedFailure[] {\n const now = (options.now ?? new Date()).getTime();\n const windowMs = (options.windowHours ?? 24) * MS_PER_HOUR;\n const dedupe = options.dedupe ?? true;\n\n // The freshest capture timestamp within the window — a lesson recorded after a failure covers it.\n let latestCapture = 0;\n for (const iso of captureTimes) {\n const t = Date.parse(iso);\n if (Number.isFinite(t) && now - t <= windowMs && t > latestCapture) latestCapture = t;\n }\n\n const seen = new Set<string>();\n const out: UncapturedFailure[] = [];\n for (const f of failures) {\n const t = Date.parse(f.ts);\n if (!Number.isFinite(t)) continue;\n if (now - t > windowMs) continue; // too old to act on\n if (t <= latestCapture) continue; // a capture happened after this failure → covered\n if (dedupe) {\n const key = normalizeSummary(f.summary);\n if (seen.has(key)) continue;\n seen.add(key);\n }\n out.push({ ts: f.ts, tool: f.tool, summary: f.summary });\n }\n out.sort((a, b) => a.ts.localeCompare(b.ts));\n return out;\n}\n","/**\n * Harness coverage-gap detection — \"which churny files have NO team knowledge on them?\".\n *\n * hAIve's `eval` synthesizes cases from the memories that EXIST (does the corpus surface\n * correctly?). It cannot tell you what knowledge is MISSING. This module answers the inverse,\n * proactive question Fowler frames as an open challenge: of the files the team edits most, which\n * carry no covering decision/convention/gotcha/architecture memory? Those are the blind spots\n * where a confident agent is most likely to violate an unwritten rule.\n *\n * Pure: the caller supplies hot files (from git history / briefing-radar) and the loaded corpus.\n */\nimport type { LoadedMemory } from \"./loader.js\";\n\n/** Where a file's \"heat\" came from: committed git churn, agent edits this/recent sessions, or both. */\nexport type HotFileSource = \"git\" | \"agent\" | \"both\";\n\nexport interface HotFile {\n path: string;\n /** Number of times the file changed in the lookback window (the \"heat\"). */\n changes: number;\n /** Provenance of the heat. Optional for back-compat with git-only callers. */\n source?: HotFileSource;\n}\n\nexport interface CoverageGap {\n path: string;\n changes: number;\n /** Provenance of the heat that made this file a blind spot. */\n source?: HotFileSource;\n}\n\nexport interface CoverageOptions {\n /** Only flag files with at least this many changes. Default 3. */\n minChanges?: number;\n /** Memory types that count as \"covering\" a file. Default decision/convention/gotcha/architecture. */\n coveringTypes?: string[];\n /** Cap on returned gaps. Default 20. */\n limit?: number;\n}\n\nconst DEFAULT_COVERING_TYPES = [\"decision\", \"convention\", \"gotcha\", \"architecture\"];\n\nfunction normalizePath(value: string): string {\n return value.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/+$/g, \"\");\n}\n\n/**\n * Build the set of path prefixes the corpus covers: every anchor path of a non-dead,\n * non-recap covering memory. A file is covered if it equals, or sits under, one of them.\n */\nexport function buildCoverageIndex(\n memories: LoadedMemory[],\n coveringTypes: string[] = DEFAULT_COVERING_TYPES,\n): Set<string> {\n const types = new Set(coveringTypes);\n const covered = new Set<string>();\n for (const { memory } of memories) {\n const fm = memory.frontmatter;\n if (!types.has(fm.type)) continue;\n if (fm.status === \"stale\" || fm.status === \"deprecated\" || fm.status === \"rejected\") continue;\n for (const p of fm.anchor.paths) {\n const norm = normalizePath(p);\n if (norm) covered.add(norm);\n }\n }\n return covered;\n}\n\n/** True when `file` equals or is nested under any covered path prefix. */\nexport function isCovered(file: string, coverage: Set<string>): boolean {\n const target = normalizePath(file);\n if (coverage.has(target)) return true;\n for (const scope of coverage) {\n if (target === scope || target.startsWith(`${scope}/`)) return true;\n }\n return false;\n}\n\n/**\n * Cross hot files with the coverage index → the uncovered, frequently-edited files.\n * Highest heat first. These are the highest-value places to add a memory or sensor.\n */\nexport function findCoverageGaps(\n hotFiles: HotFile[],\n memories: LoadedMemory[],\n options: CoverageOptions = {},\n): CoverageGap[] {\n const minChanges = options.minChanges ?? 3;\n const limit = options.limit ?? 20;\n const coverage = buildCoverageIndex(memories, options.coveringTypes);\n\n const gaps: CoverageGap[] = [];\n for (const hot of hotFiles) {\n if (hot.changes < minChanges) continue;\n if (isCovered(hot.path, coverage)) continue;\n gaps.push({ path: normalizePath(hot.path), changes: hot.changes, ...(hot.source ? { source: hot.source } : {}) });\n }\n gaps.sort((a, b) => b.changes - a.changes);\n return gaps.slice(0, limit);\n}\n\n/**\n * Tally a flat list of edited file paths into HotFiles — the agent-edit heat signal from the\n * PostToolUse observation log (files agents actually touch), complementary to committed git churn.\n * Pure: the caller reads/normalizes the observation paths.\n */\nexport function tallyHotFiles(paths: string[], source: HotFileSource = \"agent\"): HotFile[] {\n const counts = new Map<string, number>();\n for (const raw of paths) {\n const norm = normalizePath(raw);\n if (!norm) continue;\n counts.set(norm, (counts.get(norm) ?? 0) + 1);\n }\n return [...counts.entries()]\n .map(([path, changes]) => ({ path, changes, source }))\n .sort((a, b) => b.changes - a.changes);\n}\n\n/**\n * Merge two HotFile lists, summing heat per path. A file hot in both lists is tagged `both` so the\n * report can show that agents AND git churn both point at the same uncovered file (the strongest gap).\n */\nexport function mergeHotFiles(a: HotFile[], b: HotFile[]): HotFile[] {\n const merged = new Map<string, HotFile>();\n for (const hot of [...a, ...b]) {\n const norm = normalizePath(hot.path);\n if (!norm) continue;\n const existing = merged.get(norm);\n if (!existing) {\n merged.set(norm, { path: norm, changes: hot.changes, ...(hot.source ? { source: hot.source } : {}) });\n continue;\n }\n existing.changes += hot.changes;\n if (hot.source && existing.source && hot.source !== existing.source) existing.source = \"both\";\n else existing.source = existing.source ?? hot.source;\n }\n return [...merged.values()].sort((x, y) => y.changes - x.changes);\n}\n","/**\n * Eval-score history — makes harness QUALITY a trended number, not a one-off.\n *\n * `eval.ts` produces a 0..100 score (retrieval recall/MRR + sensor catch-rate). A single score\n * answers \"is the harness good right now?\"; this append-only log answers \"is it getting better or\n * regressing over releases?\" — the question Fowler flags as an open challenge (\"evaluating harness\n * coverage as it grows\"). Mirrors `prevention.ts`: one JSONL line per run in `.ai/.cache/` so it\n * never churns a release, plus pure trend math the CLI/dashboard can render.\n */\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { HaivePaths } from \"./paths.js\";\n\nexport interface EvalHistoryEntry {\n /** ISO timestamp of the eval run. */\n at: string;\n /** Overall 0..100 score. */\n score: number;\n /** Optional component metrics for richer trend views. */\n mean_recall?: number;\n mrr?: number;\n catch_rate?: number;\n /** Optional version/commit the run was taken at. */\n ref?: string;\n}\n\nexport function evalHistoryPath(paths: HaivePaths): string {\n return path.join(paths.haiveDir, \".cache\", \"eval-history.jsonl\");\n}\n\n/** Append one eval run to the history. Best-effort, creates the dir on demand. */\nexport async function appendEvalHistory(paths: HaivePaths, entry: EvalHistoryEntry): Promise<void> {\n const file = evalHistoryPath(paths);\n await mkdir(path.dirname(file), { recursive: true });\n await appendFile(file, JSON.stringify(entry) + \"\\n\", \"utf8\");\n}\n\n/** Read all eval runs (skips malformed lines). */\nexport async function loadEvalHistory(paths: HaivePaths): Promise<EvalHistoryEntry[]> {\n const file = evalHistoryPath(paths);\n if (!existsSync(file)) return [];\n const raw = await readFile(file, \"utf8\").catch(() => \"\");\n const out: EvalHistoryEntry[] = [];\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const e = JSON.parse(trimmed) as EvalHistoryEntry;\n if (e && typeof e.at === \"string\" && typeof e.score === \"number\") out.push(e);\n } catch {\n // skip a corrupt line\n }\n }\n return out;\n}\n\nexport interface EvalTrend {\n /** Most recent score, or null when there is no history. */\n latest: number | null;\n /** Score before the latest, or null. */\n previous: number | null;\n /** latest − previous (positive = improving). */\n delta: number | null;\n /** Best score ever recorded. */\n best: number | null;\n /** Number of runs recorded. */\n runs: number;\n /** Last N scores oldest → newest for a sparkline. */\n recent: number[];\n /** True when the latest run dropped vs the previous one. */\n regressed: boolean;\n}\n\n/** Pure trend over the history (chronological order is enforced internally). */\nexport function computeEvalTrend(entries: EvalHistoryEntry[], recentN = 10): EvalTrend {\n const sorted = [...entries].sort((a, b) => a.at.localeCompare(b.at));\n const scores = sorted.map((e) => e.score);\n const latest = scores.length > 0 ? scores[scores.length - 1]! : null;\n const previous = scores.length > 1 ? scores[scores.length - 2]! : null;\n const delta = latest !== null && previous !== null ? Math.round((latest - previous) * 1000) / 1000 : null;\n const best = scores.length > 0 ? Math.max(...scores) : null;\n return {\n latest,\n previous,\n delta,\n best,\n runs: scores.length,\n recent: scores.slice(-recentN),\n regressed: delta !== null && delta < 0,\n };\n}\n","/**\n * Contradiction resolution planning — turns \"two memories conflict\" into \"do THIS\".\n *\n * `conflict-candidates.ts` surfaces pairs (same topic with opposed status, or lexically near-\n * duplicate). That's detection, not resolution — and Fowler lists incoherence-at-scale (a harness\n * full of contradictory guides) as a core open challenge. This module decides, deterministically,\n * which memory of a pair should WIN and which should be superseded (deprecated), so the CLI can\n * apply it. Pure: no I/O, unit-tested.\n *\n * Decision order (strongest signal first):\n * 1. status — a `validated` memory beats a `rejected`/`deprecated`/`stale` one.\n * 2. revision — higher `revision_count` (more refined via topic-upsert) wins.\n * 3. recency — newer `created_at` wins (the team's latest word).\n */\nimport type { LoadedMemory } from \"./loader.js\";\nimport type { MemoryFrontmatter } from \"./types.js\";\n\nexport interface ConflictResolution {\n /** Memory id to keep authoritative. */\n keep_id: string;\n /** Memory id to deprecate (superseded). */\n supersede_id: string;\n /** Human-readable reason the winner was chosen. */\n reason: string;\n /** stale_reason to stamp on the superseded memory. */\n stale_reason: string;\n}\n\nconst STATUS_RANK: Record<string, number> = {\n validated: 4,\n proposed: 3,\n draft: 2,\n stale: 1,\n deprecated: 0,\n rejected: 0,\n};\n\nfunction statusRank(fm: MemoryFrontmatter): number {\n return STATUS_RANK[fm.status] ?? 2;\n}\n\n/** Compare two memories; returns the one that should WIN plus the reason. Pure. */\nexport function planConflictResolution(\n a: LoadedMemory,\n b: LoadedMemory,\n): ConflictResolution {\n const fa = a.memory.frontmatter;\n const fb = b.memory.frontmatter;\n\n const ra = statusRank(fa);\n const rb = statusRank(fb);\n let winner: LoadedMemory;\n let loser: LoadedMemory;\n let reason: string;\n\n if (ra !== rb) {\n [winner, loser] = ra > rb ? [a, b] : [b, a];\n reason = `status (${winner.memory.frontmatter.status} beats ${loser.memory.frontmatter.status})`;\n } else if (fa.revision_count !== fb.revision_count) {\n [winner, loser] = fa.revision_count > fb.revision_count ? [a, b] : [b, a];\n reason = `revision_count (${winner.memory.frontmatter.revision_count} > ${loser.memory.frontmatter.revision_count})`;\n } else {\n const cmp = fa.created_at.localeCompare(fb.created_at);\n [winner, loser] = cmp >= 0 ? [a, b] : [b, a];\n reason = `recency (${winner.memory.frontmatter.created_at} is newer)`;\n }\n\n const keepId = winner.memory.frontmatter.id;\n const supersedeId = loser.memory.frontmatter.id;\n return {\n keep_id: keepId,\n supersede_id: supersedeId,\n reason,\n stale_reason: `Superseded by ${keepId} (conflict resolved on ${reason}).`,\n };\n}\n\nexport interface AppliedConflictResolution {\n /** Updated frontmatter for the memory to keep (promoted). */\n winner: MemoryFrontmatter;\n /** Updated frontmatter for the memory to supersede (deprecated). */\n loser: MemoryFrontmatter;\n /** Topic the winner now carries — the consolidation target for future `mem_save` upserts. Null when neither carried one. */\n topic: string | null;\n /** True when the winner adopted the loser's topic because it had none. */\n topic_adopted: boolean;\n}\n\n/**\n * Turn a {@link ConflictResolution} plan into the two concrete frontmatter updates — the guided\n * supersede the backlog called for, wired into topic-upsert/revision_count:\n * - loser → deprecated, stamped with stale_reason + a related_ids link to the winner.\n * - winner → revision_count++ (it absorbed a contradiction), verified now, linked to the loser,\n * and it ADOPTS the loser's topic when it had none — so the next `mem_save` on this subject\n * upserts into the winner instead of spawning a third conflicting memory. An existing winner\n * topic is never overwritten. Pure: the caller persists both.\n */\nexport function applyConflictResolution(\n winner: LoadedMemory,\n loser: LoadedMemory,\n plan: ConflictResolution,\n now: Date = new Date(),\n): AppliedConflictResolution {\n const ts = now.toISOString();\n const wf = winner.memory.frontmatter;\n const lf = loser.memory.frontmatter;\n\n const winnerHasTopic = Boolean(wf.topic && wf.topic.trim() !== \"\");\n const loserHasTopic = Boolean(lf.topic && lf.topic.trim() !== \"\");\n const topicAdopted = !winnerHasTopic && loserHasTopic;\n const topic = winnerHasTopic ? wf.topic! : topicAdopted ? lf.topic! : null;\n\n const winnerFm: MemoryFrontmatter = {\n ...wf,\n revision_count: wf.revision_count + 1,\n verified_at: ts,\n related_ids: [...new Set([...wf.related_ids, plan.supersede_id])],\n ...(topic ? { topic } : {}),\n };\n\n const loserFm: MemoryFrontmatter = {\n ...lf,\n status: \"deprecated\",\n stale_reason: plan.stale_reason,\n verified_at: ts,\n related_ids: [...new Set([...lf.related_ids, plan.keep_id])],\n };\n\n return { winner: winnerFm, loser: loserFm, topic, topic_adopted: topicAdopted };\n}\n","/**\n * Cold-start seeding from git history — the harness has value only once the corpus is populated,\n * and a fresh repo starts empty (Fowler's \"harnessability\": greenfield is easy, legacy is hard).\n *\n * Reverts and fixups are the cheapest signal of a real, repo-specific mistake: a commit that had to\n * be undone or hot-fixed encodes a lesson the team already paid for. This module parses a list of\n * commits (the CLI runs `git log`) and proposes DRAFT `attempt` seeds — never validated, always\n * human-reviewed. Pure: the caller does the git I/O and the memory writes.\n */\n\nexport interface GitCommit {\n sha: string;\n subject: string;\n /** Files touched by the commit (optional — improves anchoring). */\n files?: string[];\n}\n\nexport interface SeedProposal {\n /** Kebab-ish slug derived from the reverted subject. */\n slug: string;\n /** What was tried (the thing that had to be reverted/fixed). */\n what: string;\n /** Why it failed (inferred from the revert/fixup). */\n why_failed: string;\n /** Suggested anchor paths (from the commit's files). */\n paths: string[];\n /** The source commit, for provenance. */\n source_sha: string;\n /** Detected signal kind. */\n kind: \"revert\" | \"fixup\" | \"workaround\";\n}\n\nconst REVERT_RE = /^Revert\\s+\"(.+)\"\\s*$/i;\nconst FIXUP_RE = /^(?:fixup!|hotfix[:!]|fix[:!]\\s*revert|revert\\s+revert)/i;\nconst URGENT_FIX_RE = /\\b(hotfix|urgent fix|emergency fix|critical fix|broke production|broken build)\\b/i;\n// A commit that admits a stop-gap encodes a known trap: the \"right\" fix is still owed.\n// The leading `(?<![\\w-])` stops compound *nouns* (a feature literally named \"env-workaround\",\n// \"X-workaround\") from being mistaken for an admission of bricolage — that produced a meaningless\n// seed for `chore: apply env-workaround down-rank to corpus`. FIXME/XXX are deliberately excluded:\n// they belong in code, not commit subjects, where they were pure noise.\nconst WORKAROUND_RE = /(?<![\\w-])(?:work[\\s-]?around|band[\\s-]?aid|temporary fix|temp fix|quick[\\s-]?fix|kludge|monkey[\\s-]?patch|stop[\\s-]?gap)(?![\\w-])|\\bhack(?:y|ish)?\\b/i;\n\n/**\n * Quality floor for git seeds: a reverted/fixed *merge*, *version bump*, *dependency update* or *wip*\n * commit is mechanical noise, not a repo-specific lesson — seeding it just clutters the corpus. The\n * specificity floor doesn't fit here (a seed body is mostly boilerplate prose), so the right gate is a\n * subject denylist on the thing that was reverted/fixed.\n */\nconst SUBJECT_NOISE_RE =\n /^(?:merge\\b|merge branch|merge pull request|bump\\b|bumps?\\b|release\\b|releases?\\b|v?\\d+\\.\\d+\\.\\d+(?:[-.\\w]*)?$|wip\\b|update (?:deps|dependencies|lockfile|snapshots?|submodules?)|dependenc(?:y|ies) updates?|chore\\(deps|deps:|lint(?:ing)?\\b|format(?:ting)?\\b|prettier\\b|reformat\\b|typo\\b)/i;\n\n/** True when a reverted/fixed subject is mechanical noise (merge/bump/deps/wip/format), not a lesson. */\nexport function isNoiseSubject(subject: string): boolean {\n return SUBJECT_NOISE_RE.test(subject.trim());\n}\n\nfunction slugify(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60) || \"reverted-change\"\n );\n}\n\n/**\n * Turn commits into seed proposals. A `Revert \"X\"` commit proposes an attempt about X; an obvious\n * hotfix/fixup commit proposes an attempt about the fixed area. Deduped by slug. Pure.\n */\nexport function proposeSeedsFromCommits(\n commits: GitCommit[],\n limit = 20,\n): SeedProposal[] {\n const out: SeedProposal[] = [];\n const seen = new Set<string>();\n\n for (const commit of commits) {\n const subject = commit.subject.trim();\n let what: string | null = null;\n let kind: SeedProposal[\"kind\"] | null = null;\n\n const revert = subject.match(REVERT_RE);\n if (revert) {\n what = revert[1]!.trim();\n kind = \"revert\";\n } else if (FIXUP_RE.test(subject) || URGENT_FIX_RE.test(subject)) {\n what = subject.replace(FIXUP_RE, \"\").trim() || subject;\n kind = \"fixup\";\n } else if (WORKAROUND_RE.test(subject)) {\n what = subject;\n kind = \"workaround\";\n }\n\n if (!what || !kind) continue;\n if (isNoiseSubject(what)) continue; // merge/bump/deps/wip/format — mechanical, not a lesson\n const slug = slugify(what);\n if (seen.has(slug)) continue;\n seen.add(slug);\n\n out.push({\n slug,\n what,\n why_failed:\n kind === \"revert\"\n ? `This change was reverted in commit ${commit.sha} — it caused a regression and was backed out. Verify the root cause before re-attempting.`\n : kind === \"workaround\"\n ? `This area carries a known workaround/stop-gap (commit ${commit.sha}: \"${subject}\") — the proper fix is still owed. Understand why the workaround exists before changing it.`\n : `This area required an urgent fix (commit ${commit.sha}: \"${subject}\") — it shipped broken once. Treat changes here with extra care.`,\n paths: (commit.files ?? []).slice(0, 8),\n source_sha: commit.sha,\n kind,\n });\n if (out.length >= limit) break;\n }\n\n return out;\n}\n","/**\n * Pure stack-detection helpers for cold-start seeding.\n *\n * Multi-language: reads package.json deps (JS/TS), requirements.txt (Python),\n * go.mod (Go), and pom.xml (Java/Spring) to produce the list of detected stacks.\n * No I/O — the caller reads the files and passes contents in, making this fully testable.\n */\n\nexport interface DetectStacksInput {\n /** Merged deps from package.json (dependencies + devDependencies). */\n packageJsonDeps?: Record<string, string>;\n /** Raw text of requirements.txt (or any requirements file). */\n requirementsTxt?: string;\n /** Raw text of go.mod. */\n goMod?: string;\n /** Raw text of pom.xml. */\n pomXml?: string;\n /** Raw text of composer.json (PHP). */\n composerJson?: string;\n /** Raw text of Gemfile (Ruby). */\n gemfile?: string;\n /** True when at least one .csproj/.sln file is present (.NET). */\n hasCsproj?: boolean;\n /** True when a Dockerfile is present. */\n hasDockerfile?: boolean;\n /** True when turbo.json is present (Turborepo). */\n hasTurboJson?: boolean;\n /** True when nx.json is present (Nx). */\n hasNxJson?: boolean;\n}\n\nexport type DetectableStack =\n | \"nestjs\" | \"nextjs\" | \"remix\" | \"react\" | \"express\" | \"fastify\"\n | \"prisma\" | \"drizzle\" | \"zustand\" | \"redux\" | \"reactquery\" | \"trpc\"\n | \"mongoose\" | \"graphql\" | \"vue\"\n | \"tailwind\" | \"vite\" | \"sveltekit\" | \"astro\" | \"typescript\" | \"monorepo\"\n | \"fastapi\" | \"django\" | \"flask\"\n | \"go\"\n | \"spring\"\n | \"laravel\" | \"rails\" | \"dotnet\" | \"docker\";\n\nconst JS_DETECTORS: [DetectableStack, string[]][] = [\n [\"nestjs\", [\"@nestjs/core\"]],\n [\"nextjs\", [\"next\"]],\n [\"remix\", [\"@remix-run/react\", \"@remix-run/node\"]],\n [\"react\", [\"react\"]],\n [\"express\", [\"express\"]],\n [\"fastify\", [\"fastify\"]],\n [\"prisma\", [\"@prisma/client\", \"prisma\"]],\n [\"drizzle\", [\"drizzle-orm\"]],\n [\"zustand\", [\"zustand\"]],\n [\"redux\", [\"@reduxjs/toolkit\", \"redux\"]],\n [\"reactquery\", [\"@tanstack/react-query\", \"react-query\"]],\n [\"trpc\", [\"@trpc/server\", \"@trpc/client\"]],\n [\"mongoose\", [\"mongoose\"]],\n [\"graphql\", [\"@apollo/client\", \"@apollo/server\", \"apollo-server\", \"graphql\"]],\n [\"vue\", [\"vue\", \"@vue/core\"]],\n [\"tailwind\", [\"tailwindcss\"]],\n [\"vite\", [\"vite\"]],\n [\"sveltekit\", [\"@sveltejs/kit\"]],\n [\"astro\", [\"astro\"]],\n [\"typescript\", [\"typescript\"]],\n [\"monorepo\", [\"turbo\", \"nx\", \"@nrwl/workspace\", \"@nx/workspace\"]],\n];\n\nconst PYTHON_DETECTORS: [DetectableStack, RegExp][] = [\n [\"fastapi\", /\\bfastapi\\b/i],\n [\"django\", /\\bdjango\\b/i],\n [\"flask\", /\\bflask\\b/i],\n];\n\nfunction detectFromPackageJson(deps: Record<string, string>): DetectableStack[] {\n const detected: DetectableStack[] = [];\n for (const [stack, signals] of JS_DETECTORS) {\n if (signals.some((s) => s in deps)) detected.push(stack);\n }\n // Suppress generic 'react' when a framework that includes it is already detected\n if (detected.includes(\"nextjs\") || detected.includes(\"remix\")) {\n return detected.filter((s) => s !== \"react\");\n }\n return detected;\n}\n\nfunction detectFromRequirementsTxt(content: string): DetectableStack[] {\n return PYTHON_DETECTORS.filter(([, re]) => re.test(content)).map(([s]) => s);\n}\n\nfunction detectFromGoMod(content: string): DetectableStack[] {\n // go.mod presence (has a module declaration) → go stack\n return /^\\s*module\\s+\\S/m.test(content) ? [\"go\"] : [];\n}\n\nfunction detectFromPomXml(content: string): DetectableStack[] {\n return /org\\.springframework|spring-boot/.test(content) ? [\"spring\"] : [];\n}\n\nfunction detectFromComposerJson(content: string): DetectableStack[] {\n return /laravel\\/framework|illuminate\\//.test(content) ? [\"laravel\"] : [];\n}\n\nfunction detectFromGemfile(content: string): DetectableStack[] {\n return /^\\s*gem\\s+[\"']rails[\"']/m.test(content) || /\\brails\\b/.test(content) ? [\"rails\"] : [];\n}\n\n/**\n * Detect stacks present in a project from the raw contents of its manifest files.\n * Pure — no I/O. Pass what you have; omit what you don't.\n */\nexport function detectStacksFromManifests(input: DetectStacksInput): DetectableStack[] {\n const seen = new Set<DetectableStack>();\n const add = (stacks: DetectableStack[]) => stacks.forEach((s) => seen.add(s));\n\n if (input.packageJsonDeps) add(detectFromPackageJson(input.packageJsonDeps));\n if (input.requirementsTxt) add(detectFromRequirementsTxt(input.requirementsTxt));\n if (input.goMod) add(detectFromGoMod(input.goMod));\n if (input.pomXml) add(detectFromPomXml(input.pomXml));\n if (input.composerJson) add(detectFromComposerJson(input.composerJson));\n if (input.gemfile) add(detectFromGemfile(input.gemfile));\n if (input.hasCsproj) add([\"dotnet\"]);\n if (input.hasDockerfile) add([\"docker\"]);\n if (input.hasTurboJson || input.hasNxJson) add([\"monorepo\"]);\n\n return Array.from(seen);\n}\n","/**\n * Deterministic 3-way merge for hAIve memory files — kills the `.ai/` conflict-marker pain.\n *\n * Several agents + the human edit this repo in parallel with manual pull/push, so the same memory\n * file (especially the topic-upsert session recap, which churns every session) regularly collides\n * and leaves `<<<<<<<` markers under `.ai/`. A normal text merge can't resolve that; but a hAIve\n * memory has a total order baked into its frontmatter, so we CAN pick a winner deterministically:\n *\n * 1. higher `revision_count` (more topic-upsert refinements) wins\n * 2. else newer `created_at` wins\n * 3. else fall back to \"ours\" (stable, avoids a hard conflict)\n *\n * Registered as a git merge driver via `.gitattributes` (`*.md merge=haive` under `.ai/memories/`).\n * Pure: the CLI driver reads ours/theirs, calls this, writes the result.\n */\nimport { parseMemory } from \"./parser.js\";\n\nexport interface MergeResult {\n /** The chosen file content. */\n content: string;\n /** Which side won. */\n winner: \"ours\" | \"theirs\";\n /** Why (for logging). */\n reason: string;\n}\n\nfunction safeParse(raw: string): ReturnType<typeof parseMemory> | null {\n try {\n return parseMemory(raw);\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve two versions of the same memory file. Returns the winning content and the rationale.\n * Falls back to \"ours\" when either side can't be parsed (never throws — a merge driver must not).\n */\nexport function mergeMemoryVersions(ours: string, theirs: string): MergeResult {\n if (ours === theirs) {\n return { content: ours, winner: \"ours\", reason: \"identical\" };\n }\n const a = safeParse(ours);\n const b = safeParse(theirs);\n\n // Unparseable side → keep ours; the driver can still exit cleanly instead of leaving markers.\n if (!a || !b) {\n return { content: ours, winner: \"ours\", reason: \"unparseable side — kept ours\" };\n }\n\n const ra = a.frontmatter.revision_count ?? 0;\n const rb = b.frontmatter.revision_count ?? 0;\n if (ra !== rb) {\n return rb > ra\n ? { content: theirs, winner: \"theirs\", reason: `higher revision_count (${rb} > ${ra})` }\n : { content: ours, winner: \"ours\", reason: `higher revision_count (${ra} > ${rb})` };\n }\n\n const ca = a.frontmatter.created_at ?? \"\";\n const cb = b.frontmatter.created_at ?? \"\";\n const cmp = cb.localeCompare(ca);\n if (cmp > 0) return { content: theirs, winner: \"theirs\", reason: `newer created_at (${cb})` };\n if (cmp < 0) return { content: ours, winner: \"ours\", reason: `newer created_at (${ca})` };\n\n return { content: ours, winner: \"ours\", reason: \"tie — kept ours\" };\n}\n","/**\n * Recap compaction — keep the auto-generated session recap from dominating the briefing head.\n *\n * The MCP server auto-saves a minimal recap on exit (goal = \"Auto-captured session (N tool calls)\",\n * body = a raw tool-call/file dump). It's low signal, yet get_briefing shows the freshest recap's\n * full body at the very top of every briefing. A human/post_task recap (with a real Discoveries\n * section) is far richer. This module detects an auto recap and compresses it to its useful core\n * (the Discoveries, if any) so it informs without crowding. Pure, unit-tested.\n */\n\n/**\n * True when a recap body looks auto-generated (vs. a human/post_task recap). Auto recaps come in a\n * couple of shapes, all low-signal: the session-tracker's \"Auto-captured session (N tool calls)\" and\n * the run-wrapper's \"Edited N files across M tool calls\". The common tell is a raw tool-call count.\n */\nexport function isAutoRecap(body: string): boolean {\n return (\n /Auto-captured session/i.test(body) ||\n /\\bEdited \\d+ files? across \\d+ tool calls?/i.test(body) ||\n /\\b\\d+ tool calls?\\b/i.test(body)\n );\n}\n\n/**\n * Return a compact version of an auto recap body: a one-line header (the Goal line) plus the\n * Discoveries section when it carries real content (e.g. detected failures). Non-auto recaps are\n * returned unchanged.\n */\nexport function compactAutoRecapBody(body: string, maxChars = 600): string {\n if (!isAutoRecap(body)) return body;\n\n // Header = the Goal line if present, else the auto-captured marker, else a generic label.\n const goalMatch = body.match(/##+\\s*Goal[^\\n]*\\n+([^\\n]+)/i);\n const callsMatch = body.match(/Auto-captured session \\(([^)]+)\\)/i);\n const header = goalMatch?.[1]?.trim()\n ? `_${goalMatch[1].trim()}_`\n : callsMatch\n ? `_Auto-captured session (${callsMatch[1]})._`\n : \"_Auto-captured session._\";\n\n // Pull the Discoveries / surprises section if present and non-trivial.\n const discMatch = body.match(/##+\\s*Discoveries[^\\n]*\\n([\\s\\S]*?)(?=\\n##+\\s|\\n*$)/i);\n const discovery = discMatch?.[1]?.trim() ?? \"\";\n const trivialDiscovery =\n discovery === \"\" ||\n /^no (new memories|surprising)/i.test(discovery) ||\n /No new memories saved this session\\.?$/i.test(discovery);\n\n if (trivialDiscovery) {\n return `${header}\\n\\n_No notable discoveries captured. Run post_task / \\`mem_session_end\\` for a richer recap._`;\n }\n const trimmed = discovery.length > maxChars ? discovery.slice(0, maxChars) + \"…\" : discovery;\n return `${header}\\n\\n**Discoveries:**\\n${trimmed}`;\n}\n","/**\n * THE single source of truth for briefing memory priority — must_read / useful / background.\n *\n * This tier decides what an agent reads first. It used to be implemented TWICE: once in the MCP\n * `get_briefing` tool (briefing-helpers) and once in the `haive briefing` CLI command, each on its\n * own data shape. The two drifted (the stack-pack down-rank, then the env-workaround down-rank, both\n * had to be applied in two places, and one was missed). This module is the shared classifier: both\n * call sites map their available evidence into {@link PrioritySignals} and call {@link classifyMemoryPriority}\n * here, so the CLI and MCP can never disagree again. Pure, unit-tested.\n */\nimport { isEnvWorkaroundMemory, isStackPackSeed } from \"./relevance.js\";\n\nexport type MemoryPriority = \"must_read\" | \"useful\" | \"background\";\n\n/**\n * Normalized priority evidence. A caller fills only the signals it can compute; unknown ones default\n * to false (see {@link DEFAULT_PRIORITY_SIGNALS}). The MCP path has semantic scores; the CLI path has\n * lexical scores — both reduce to these booleans.\n */\nexport interface PrioritySignals {\n /** Memory type (attempt, gotcha, skill, decision, …). */\n type: string;\n /** Memory tags — used for the stack-pack / env-workaround down-rank. */\n tags: string[];\n /** The memory demands explicit human approval — always surface first. */\n requiresHumanApproval: boolean;\n /** Anchored to a file the agent is editing. */\n directAnchor: boolean;\n /** Anchored to a symbol the agent requested. */\n directSymbol: boolean;\n /** Exact/literal task match (semantic match_quality \"exact\", or an exact lexical task hit). */\n exactTaskMatch: boolean;\n /** Strong semantic relevance (cosine ≥ 0.65). CLI has no embeddings → passes false. */\n strongSemantic: boolean;\n /** Useful-level relevance: semantic ≥ 0.35, a partial task hit, or a high lexical score. */\n usefulSemantic: boolean;\n /** Matched an inferred module or domain from the touched files. */\n moduleOrDomainMatch: boolean;\n /** A memory tag matched a task token. */\n tagTaskMatch: boolean;\n}\n\nexport const DEFAULT_PRIORITY_SIGNALS: PrioritySignals = {\n type: \"\",\n tags: [],\n requiresHumanApproval: false,\n directAnchor: false,\n directSymbol: false,\n exactTaskMatch: false,\n strongSemantic: false,\n usefulSemantic: false,\n moduleOrDomainMatch: false,\n tagTaskMatch: false,\n};\n\n/** Convenience: build a full signal set from a partial one. */\nexport function prioritySignals(partial: Partial<PrioritySignals>): PrioritySignals {\n return { ...DEFAULT_PRIORITY_SIGNALS, ...partial };\n}\n\n/**\n * Classify a memory's briefing priority from its signals. Order matters:\n * 1. must_read — human-approval gates, direct anchor/symbol matches, and exact/strong hits on\n * negative (attempt) or skill memories: the things an agent must not miss.\n * 2. background (down-rank) — generic stack-pack seeds and local dev-environment workarounds never\n * claim `useful` on a semantic/tag match alone; they'd crowd out repo-specific knowledge. (A\n * direct anchor already promoted them to must_read above, so genuinely-relevant ones still rank.)\n * 3. useful — skills, module/domain matches, exact hits, and useful-level relevance.\n * 4. background — everything else.\n */\nexport function classifyMemoryPriority(signals: PrioritySignals): MemoryPriority {\n const isNegative = signals.type === \"attempt\";\n const isSkill = signals.type === \"skill\";\n\n if (\n signals.requiresHumanApproval ||\n signals.directAnchor ||\n signals.directSymbol ||\n (isNegative && (signals.exactTaskMatch || signals.strongSemantic)) ||\n (isSkill && (signals.exactTaskMatch || signals.strongSemantic))\n ) {\n return \"must_read\";\n }\n\n if (isStackPackSeed({ tags: signals.tags }) || isEnvWorkaroundMemory({ tags: signals.tags })) {\n return \"background\";\n }\n\n if (\n isSkill ||\n signals.moduleOrDomainMatch ||\n signals.exactTaskMatch ||\n signals.usefulSemantic ||\n signals.tagTaskMatch\n ) {\n return \"useful\";\n }\n\n return \"background\";\n}\n\nexport function priorityRank(priority: MemoryPriority): number {\n return priority === \"must_read\" ? 3 : priority === \"useful\" ? 2 : 1;\n}\n","/**\n * Native bridge generator — produces agent-harness-specific config files\n * from the hAIve corpus (validated memories + block sensors).\n *\n * One pure formatter per target; no I/O.\n * The CLI command (cli/commands/bridges.ts) handles file writes and\n * idempotent marker-based updates.\n *\n * Exposed for Lot A (init.ts): call generateBridges() from haive init\n * to seed all bridges at initialisation time.\n */\n\nimport type { Memory } from \"./types.js\";\n\n// ── Target registry ────────────────────────────────────────────────────────\n\nexport type BridgeTarget =\n | \"claude\" // CLAUDE.md\n | \"cursor\" // .cursor/rules/haive-memories.mdc\n | \"cline\" // .clinerules\n | \"windsurf\" // .windsurfrules\n | \"continue\" // .continuerules\n | \"cody\" // .sourcegraph/cody-rules.md\n | \"zed\" // .rules\n | \"roo\" // .roo/rules/haive.md\n | \"gemini\" // GEMINI.md\n | \"aider\" // CONVENTIONS.md\n | \"agents\" // AGENTS.md\n | \"copilot\"; // .github/copilot-instructions.md\n\n/** Canonical relative path from project root for each target. */\nexport const BRIDGE_TARGET_PATH: Record<BridgeTarget, string> = {\n claude: \"CLAUDE.md\",\n cursor: \".cursor/rules/haive-memories.mdc\",\n cline: \".clinerules\",\n windsurf: \".windsurfrules\",\n continue: \".continuerules\",\n cody: \".sourcegraph/cody-rules.md\",\n zed: \".rules\",\n roo: \".roo/rules/haive.md\",\n gemini: \"GEMINI.md\",\n aider: \"CONVENTIONS.md\",\n agents: \"AGENTS.md\",\n copilot: \".github/copilot-instructions.md\",\n};\n\nexport const BRIDGE_TARGETS: BridgeTarget[] = Object.keys(BRIDGE_TARGET_PATH) as BridgeTarget[];\n\n// ── Data types ─────────────────────────────────────────────────────────────\n\n/**\n * Condensed sensor shape for bridge injection.\n * Callers extract this from Memory.frontmatter.sensor — no sensor-module import needed.\n */\nexport interface BridgeSensor {\n id: string;\n severity: \"block\" | \"warn\";\n message: string;\n /** Regex pattern, present when sensor.kind === \"regex\". */\n pattern?: string;\n /** Scoped file paths (sensor.paths ?? anchor.paths). */\n paths: string[];\n}\n\nexport interface BridgeMemoryEntry {\n id: string;\n scope: string;\n type: string;\n summary: string;\n /** Anchor paths the memory applies to (for path-scoped display / Cursor globs). */\n paths: string[];\n}\n\nexport interface GenerateBridgesOptions {\n /** Max memories to inject per bridge (default: 8). */\n maxMemories?: number;\n /** Restrict generation to these targets. Defaults to all BRIDGE_TARGETS. */\n targets?: BridgeTarget[];\n}\n\nexport interface BridgeFileOutput {\n target: BridgeTarget;\n /** Relative path from project root. */\n path: string;\n content: string;\n}\n\n// ── Idempotency markers ────────────────────────────────────────────────────\n\nexport const BRIDGE_MARKERS = {\n memoriesStart: \"<!-- haive:memories-start -->\",\n memoriesEnd: \"<!-- haive:memories-end -->\",\n sensorsStart: \"<!-- haive:sensors-start -->\",\n sensorsEnd: \"<!-- haive:sensors-end -->\",\n} as const;\n\n// ── Pure helpers ───────────────────────────────────────────────────────────\n\n/** First meaningful line of a memory body, condensed for bridge display. */\nexport function bridgeMemorySummary(body: string): string {\n const firstLine = body\n .split(\"\\n\")\n .map((l) => l.replace(/^#+\\s*/, \"\").trim())\n .find((l) => l.length > 0) ?? \"\";\n const oneLine = firstLine.replace(/\\s+/g, \" \");\n return oneLine.length > 140 ? oneLine.slice(0, 137) + \"…\" : oneLine;\n}\n\n/**\n * Filter and rank memories + sensors for bridge injection.\n * Pure — callers load data; this function does not read files.\n */\nexport function prepareBridgeData(\n memories: Memory[],\n sensors: BridgeSensor[],\n opts?: Pick<GenerateBridgesOptions, \"maxMemories\">,\n): { topMemories: BridgeMemoryEntry[]; blockSensors: BridgeSensor[] } {\n const max = opts?.maxMemories ?? 8;\n\n const topMemories: BridgeMemoryEntry[] = memories\n .filter((m) => {\n const s = m.frontmatter.status;\n if (m.frontmatter.type === \"session_recap\") return false;\n // Stack-pack seeds are generic background context, not repo-specific breadcrumbs.\n if (m.frontmatter.tags?.includes(\"stack-pack\") || m.frontmatter.tags?.includes(\"seed\")) return false;\n return s === \"validated\" || s === \"proposed\";\n })\n .sort((a, b) => {\n const score = (m: Memory): number => (m.frontmatter.status === \"validated\" ? 2 : 1);\n return score(b) - score(a);\n })\n .slice(0, max)\n .map((m) => ({\n id: m.frontmatter.id,\n scope: m.frontmatter.scope,\n type: m.frontmatter.type,\n summary: bridgeMemorySummary(m.body),\n paths: m.frontmatter.anchor?.paths ?? [],\n }));\n\n const blockSensors = sensors.filter((s) => s.severity === \"block\");\n\n return { topMemories, blockSensors };\n}\n\n// ── Block renderers ────────────────────────────────────────────────────────\n\nfunction renderMemoriesBlock(topMemories: BridgeMemoryEntry[]): string {\n const lines = [\n BRIDGE_MARKERS.memoriesStart,\n \"<!-- AUTO-GENERATED by haive bridges sync — do not edit between these markers -->\",\n \"<!-- Top memories — call get_briefing / mem_get for the full body. -->\",\n \"\",\n ];\n if (topMemories.length === 0) {\n lines.push(\"_(no validated memories yet — run `haive sync` to populate)_\");\n } else {\n for (const m of topMemories) {\n // Path-scoping: surface the files a lesson applies to so the agent knows\n // *when* it is relevant — the same data Cursor would express via .mdc globs.\n const scopeNote =\n m.paths.length > 0\n ? ` _(applies to: ${m.paths.slice(0, 4).join(\", \")}${m.paths.length > 4 ? \", …\" : \"\"})_`\n : \"\";\n lines.push(`- \\`${m.id}\\` (${m.scope}/${m.type}) — ${m.summary}${scopeNote}`);\n }\n }\n lines.push(\"\", BRIDGE_MARKERS.memoriesEnd);\n return lines.join(\"\\n\");\n}\n\nfunction renderSensorsBlock(blockSensors: BridgeSensor[]): string {\n if (blockSensors.length === 0) return \"\";\n\n const lines = [\n BRIDGE_MARKERS.sensorsStart,\n \"<!-- AUTO-GENERATED by haive bridges sync — do not edit between these markers -->\",\n \"\",\n \"## Hard rules — hAIve block sensors\",\n \"\",\n \"The patterns below are blocked by the repo enforcement gate.\",\n \"Introducing them will fail the pre-commit check (`haive enforce check`).\",\n \"\",\n ];\n for (const s of blockSensors) {\n const pathNote = s.paths.length > 0 ? ` _(applies to: ${s.paths.join(\", \")})_` : \"\";\n lines.push(`- **${s.id}**${pathNote}: ${s.message}`);\n if (s.pattern) lines.push(` - Pattern: \\`${s.pattern}\\``);\n }\n lines.push(\"\", BRIDGE_MARKERS.sensorsEnd);\n return lines.join(\"\\n\");\n}\n\n// ── Shared preamble & formatter skeleton ──────────────────────────────────\n\nconst HAIVE_PREAMBLE =\n \"<!-- Managed by hAIve. Edit OUTSIDE the haive markers only; the marked blocks are regenerated. -->\\n\" +\n \"\\n\" +\n \"This repo uses **[hAIve](https://github.com/Doucs91/hAIve)** for shared, enforced team context.\\n\" +\n \"The corpus lives in `.ai/` and is the source of truth — these files are a generated mirror.\\n\" +\n \"\\n\" +\n \"- `.ai/project-context.md` — project overview, architecture, conventions.\\n\" +\n \"- `.ai/memories/` — decisions, gotchas, conventions, failed attempts (personal/team/module).\\n\" +\n \"- The blocks below are the top current memories + the hard rules enforced on commit.\\n\" +\n \"\\n\" +\n \"## Working through hAIve\\n\" +\n \"\\n\" +\n \"1. **Before editing** for a goal, call `get_briefing` (task + files/symbols) to load ranked context\\n\" +\n \" — or `mem_relevant_to` if project context is already loaded this session.\\n\" +\n \"2. **When an approach fails**, call `mem_tried` right away so the next agent skips the dead end.\\n\" +\n \"3. **Before closing** a substantive session, run the `post_task` prompt to capture what was learned.\\n\" +\n \"4. **Before final response**, run `haive enforce finish`; fix anything it blocks before reporting done.\\n\" +\n \"\\n\" +\n \"If the haive MCP server is not available, tell the developer rather than silently skipping it.\\n\" +\n \"\\n\" +\n \"## Safety\\n\" +\n \"\\n\" +\n \"- If `get_briefing` returns `action_required`, surface each item to the developer (use its\\n\" +\n \" `developer_message`) and wait for explicit confirmation before changing any code.\\n\" +\n \"- Never act autonomously on a cross-repo breaking change (dep bump, contract/API diff) — ask first.\";\n\nfunction renderMarkdownBridge(\n topMemories: BridgeMemoryEntry[],\n blockSensors: BridgeSensor[],\n title: string,\n): string {\n const parts: string[] = [\n `# ${title}`,\n \"\",\n HAIVE_PREAMBLE,\n \"\",\n \"## Memories\",\n \"\",\n renderMemoriesBlock(topMemories),\n ];\n const sensorsBlock = renderSensorsBlock(blockSensors);\n if (sensorsBlock) {\n parts.push(\"\", sensorsBlock);\n }\n return parts.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Cursor reads `.cursor/rules/*.mdc` files, each carrying a small YAML\n * frontmatter (`description`, `globs`, `alwaysApply`). We emit an always-applied\n * rule so the shared corpus is loaded on every Cursor task — the equivalent of\n * memories.sh's \"always-on\" lane, but carrying our block sensors too.\n *\n * The frontmatter sits OUTSIDE the haive markers, so the CLI's idempotent\n * marker-based update never rewrites it — only the memories/sensors blocks\n * refresh on `haive bridges sync`.\n */\nfunction renderCursorBridge(\n topMemories: BridgeMemoryEntry[],\n blockSensors: BridgeSensor[],\n): string {\n const frontmatter = [\n \"---\",\n \"description: hAIve shared memories & block sensors (auto-generated)\",\n \"alwaysApply: true\",\n \"---\",\n \"\",\n ].join(\"\\n\");\n return frontmatter + renderMarkdownBridge(topMemories, blockSensors, \"hAIve rules (Cursor)\");\n}\n\n// ── Per-target formatters (pure functions) ─────────────────────────────────\n\ntype Formatter = (memories: BridgeMemoryEntry[], sensors: BridgeSensor[]) => string;\n\nconst FORMATTERS: Record<BridgeTarget, Formatter> = {\n claude: (m, s) => renderMarkdownBridge(m, s, \"CLAUDE.md — hAIve context\"),\n cursor: (m, s) => renderCursorBridge(m, s),\n cline: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Cline)\"),\n windsurf: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Windsurf)\"),\n continue: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Continue)\"),\n cody: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Cody / Sourcegraph)\"),\n zed: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Zed)\"),\n roo: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (Roo Code)\"),\n gemini: (m, s) => renderMarkdownBridge(m, s, \"GEMINI.md — hAIve context\"),\n aider: (m, s) => renderMarkdownBridge(m, s, \"CONVENTIONS.md — hAIve context (Aider)\"),\n agents: (m, s) => renderMarkdownBridge(m, s, \"AGENTS.md — hAIve context\"),\n copilot: (m, s) => renderMarkdownBridge(m, s, \"hAIve rules (GitHub Copilot)\"),\n};\n\n// ── Public API ─────────────────────────────────────────────────────────────\n\n/**\n * Generate bridge file content for the requested targets.\n *\n * Pure: accepts loaded memories + sensors, returns file content strings.\n * The CLI command handles I/O and idempotent marker-based updates.\n *\n * **Lot A integration point**: call this from `haive init` to seed bridges at initialisation.\n * Signature is intentionally stable — init.ts should call:\n * `generateBridges(memories, sensors, { targets: BRIDGE_TARGETS })`\n */\nexport function generateBridges(\n memories: Memory[],\n sensors: BridgeSensor[],\n opts?: GenerateBridgesOptions,\n): BridgeFileOutput[] {\n const { topMemories, blockSensors } = prepareBridgeData(memories, sensors, opts);\n const targets: BridgeTarget[] = opts?.targets ?? BRIDGE_TARGETS;\n\n return targets.map((target) => ({\n target,\n path: BRIDGE_TARGET_PATH[target],\n content: FORMATTERS[target](topMemories, blockSensors),\n }));\n}\n"],"mappings":"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","names":["path","path","readFile","readdir","existsSync","path","path","path","existsSync","readFile","readdir","readFile","existsSync","path","mkdir","readFile","existsSync","path","path","mkdir","existsSync","readFile","MS_PER_DAY","mkdir","readFile","writeFile","existsSync","path","round3","MS_PER_DAY","mkdir","readFile","readdir","writeFile","existsSync","path","existsSync","readFile","writeFile","path","existsSync","mkdir","readFile","writeFile","path","spawnSync","path","existsSync","readFile","writeFile","mkdir","spawnSync","existsSync","readFile","writeFile","mkdir","path","snapshot","existsSync","readFile","writeFile","mkdir","path","appendFile","mkdir","readFile","stat","existsSync","path","existsSync","path","ROOT_MARKERS","existsSync","path","b","mkdir","readFile","appendFile","existsSync","path","mkdir","readdir","readFile","writeFile","existsSync","path","path","isDistinctiveToken","path","round3","MS_PER_DAY","path","appendFile","mkdir","readFile","existsSync","path","isSkill"]}
|